import { test, expect } from '@playwright/test'; import { createNewDoc } from './helpers'; test.describe('Docs - Advanced Features', () => { test.beforeEach(async ({ page }) => { await createNewDoc(page); }); test('slash command menu appears when typing /', async ({ page }) => { const editor = page.locator('.tiptap'); await editor.click(); await page.keyboard.type('/'); // Slash command menu should appear await expect(page.locator('.slash-menu')).toBeVisible({ timeout: 5000 }); // Should have menu items await expect(page.locator('.slash-menu-item').first()).toBeVisible(); // Dismiss with Escape await page.keyboard.press('Escape'); await expect(page.locator('.slash-menu')).not.toBeVisible(); }); test('slash command inserts heading', async ({ page }) => { const editor = page.locator('.tiptap'); await editor.click(); await page.keyboard.type('/'); await expect(page.locator('.slash-menu')).toBeVisible({ timeout: 5000 }); // Type to filter for heading await page.keyboard.type('heading'); // Click the first heading option await page.locator('.slash-menu-item').first().click(); // Should have created a heading element const headings = editor.locator('h1, h2, h3'); await expect(headings.first()).toBeVisible(); }); test('find and replace opens with Cmd+F', async ({ page }) => { const editor = page.locator('.tiptap'); await editor.click(); await page.keyboard.type('Find this text in the document'); // Open find await page.keyboard.press('Meta+f'); const searchBar = page.locator('.search-bar, .find-replace-bar, [class*="search"]').first(); await expect(searchBar).toBeVisible({ timeout: 5000 }); }); test('zen mode toggles with Cmd+Shift+F', async ({ page }) => { // Type some content first const editor = page.locator('.tiptap'); await editor.click(); await page.keyboard.type('Zen mode content'); // Toggle zen mode await page.keyboard.press('Meta+Shift+f'); // Body or app should have zen class await expect(page.locator('.zen-mode, body.zen-mode, .app-shell.zen-mode')).toBeVisible({ timeout: 5000 }); // Exit button should be visible await expect(page.locator('#zen-exit')).toBeVisible(); // Toggle back await page.keyboard.press('Meta+Shift+f'); await expect(page.locator('#zen-exit')).not.toBeVisible(); }); test('markdown toggle with Cmd+Shift+M', async ({ page }) => { const editor = page.locator('.tiptap'); await editor.click(); await page.keyboard.type('# Hello Markdown'); // Toggle to markdown view await page.keyboard.press('Meta+Shift+m'); // Markdown source textarea should be visible const mdSource = page.locator('#markdown-source'); await expect(mdSource).toBeVisible({ timeout: 5000 }); // It should contain markdown text const mdValue = await mdSource.inputValue(); expect(mdValue).toContain('Hello Markdown'); // Toggle back await page.keyboard.press('Meta+Shift+m'); await expect(mdSource).not.toBeVisible(); }); test('word count updates in footer', async ({ page }) => { const editor = page.locator('.tiptap'); await editor.click(); // Initially should show 0 words await expect(page.locator('#word-count')).toContainText('0 words'); // Type some text await page.keyboard.type('one two three four five'); // Word count should update await expect(page.locator('#word-count')).toContainText('5 words', { timeout: 5000 }); }); test('character count updates in footer', async ({ page }) => { const editor = page.locator('.tiptap'); await editor.click(); await page.keyboard.type('Hello'); await expect(page.locator('#char-count')).toContainText('5 characters', { timeout: 5000 }); }); test('outline sidebar shows headings', async ({ page }) => { const editor = page.locator('.tiptap'); await editor.click(); // Create some headings await page.keyboard.type('# First Heading'); await page.keyboard.press('Enter'); await page.keyboard.type('Some paragraph text'); await page.keyboard.press('Enter'); await page.keyboard.type('## Second Heading'); // Open outline sidebar await page.click('#btn-outline'); const sidebar = page.locator('#outline-sidebar'); await expect(sidebar).toBeVisible({ timeout: 5000 }); // Should list the headings const items = sidebar.locator('.outline-item, .outline-link, [class*="outline"]'); // At least the headings should appear (wait for rendering) await expect(items.first()).toBeVisible({ timeout: 5000 }); }); test('heading select in toolbar changes paragraph to heading', async ({ page }) => { const editor = page.locator('.tiptap'); await editor.click(); await page.keyboard.type('Make me a heading'); await page.keyboard.press('Meta+a'); // Change heading level via toolbar select await page.selectOption('#tb-heading', '1'); await expect(editor.locator('h1')).toContainText('Make me a heading'); }); test('version history panel opens with Cmd+Shift+H', async ({ page }) => { // Type something to create content const editor = page.locator('.tiptap'); await editor.click(); await page.keyboard.type('Version test content'); // Wait for save await expect(page.locator('#save-text')).toHaveText('Saved', { timeout: 10000 }); // Open version history via button (Cmd+Shift+H might not be bound, use button) await page.click('#btn-history'); const versionSidebar = page.locator('#version-sidebar'); await expect(versionSidebar).toBeVisible({ timeout: 5000 }); // Close it await page.click('#version-sidebar-close'); await expect(versionSidebar).not.toBeVisible(); }); test('share dialog opens', async ({ page }) => { await page.click('#btn-share'); const shareDialog = page.locator('#share-dialog'); await expect(shareDialog).toBeVisible({ timeout: 5000 }); // Should have a sharing link input await expect(page.locator('#share-link-input')).toBeVisible(); // Close await page.click('#share-dialog-close'); await expect(shareDialog).not.toBeVisible(); }); });