diff --git a/packages/docs/fluent-editor/demos/add-toolbar-item.spec.ts b/packages/docs/fluent-editor/demos/add-toolbar-item.spec.ts index bfe2d1f1..1599f2a0 100644 --- a/packages/docs/fluent-editor/demos/add-toolbar-item.spec.ts +++ b/packages/docs/fluent-editor/demos/add-toolbar-item.spec.ts @@ -2,7 +2,7 @@ import { expect, test } from '@playwright/test' test.describe('AddToolbarItem.vue', () => { test.beforeEach(async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/add-toolbar-item') + await page.goto('/tiny-editor/docs/demo/add-toolbar-item') }) test('should render the editor', async ({ page }) => { @@ -36,8 +36,9 @@ test.describe('AddToolbarItem.vue', () => { await page.keyboard.type(' Bad') const editorHtml = await editor.innerHTML() - expect(editorHtml).toContain(' Good') - expect(editorHtml).toContain(' Bad') + // Quill stores a leading space in inline formats as   + expect(editorHtml).toContain(' Good') + expect(editorHtml).toContain(' Bad') }) // 添加更多测试用例 diff --git a/packages/docs/fluent-editor/demos/ai.spec.ts b/packages/docs/fluent-editor/demos/ai.spec.ts new file mode 100644 index 00000000..09045296 --- /dev/null +++ b/packages/docs/fluent-editor/demos/ai.spec.ts @@ -0,0 +1,19 @@ +import { expect, test } from '@playwright/test' + +test('has toolbar AI button and opens AI input dialog', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/ai') + + const toolbar = page.locator('.ql-toolbar').first() + const editor = page.locator('#editor-add-toolbar-item .ql-editor') + const aiBtn = toolbar.locator('.ql-ai') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(editor).toContainText('我曾经跨过山和大海') + await expect(aiBtn).toBeVisible() + + await editor.click() + await aiBtn.click() + await expect(page.locator('.ql-ai-dialog')).toBeVisible() + await expect(page.locator('.ql-ai-input')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/basic-usage.spec.ts b/packages/docs/fluent-editor/demos/basic-usage.spec.ts index 7d8cfc6b..db629b5b 100644 --- a/packages/docs/fluent-editor/demos/basic-usage.spec.ts +++ b/packages/docs/fluent-editor/demos/basic-usage.spec.ts @@ -2,7 +2,7 @@ import { expect, test } from '@playwright/test' test('has toolbar', async ({ page }) => { // page.on('pageerror', exception => expect(exception).toBeNull()) - await page.goto('http://localhost:5173/tiny-editor/docs/demo/basic-usage') + await page.goto('/tiny-editor/docs/demo/basic-usage') const toolbar = page.locator('.ql-toolbar') const editor = page.locator('.ql-editor') diff --git a/packages/docs/fluent-editor/demos/code-block-highlight.spec.ts b/packages/docs/fluent-editor/demos/code-block-highlight.spec.ts new file mode 100644 index 00000000..d8e160b1 --- /dev/null +++ b/packages/docs/fluent-editor/demos/code-block-highlight.spec.ts @@ -0,0 +1,24 @@ +import { expect, test } from '@playwright/test' + +test('has toolbar, code-block button and golang language option', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/code-block-highlight') + + const toolbar = page.locator('.ql-toolbar').first() + const editor = page.locator('#editor .ql-editor') + const codeBlockBtn = toolbar.locator('.ql-code-block') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(codeBlockBtn).toBeVisible() + + await editor.click() + await codeBlockBtn.click() + + const codeBlock = editor.locator('.ql-code-block-container').first() + await expect(codeBlock).toBeVisible() + await expect(codeBlock.locator('option[value="go"]')).toHaveText('Golang') + + await editor.locator('.ql-code-block').first().click() + await page.keyboard.type('func main() {}') + await expect(editor.locator('.ql-code-block').first()).toContainText('func main() {}') +}) diff --git a/packages/docs/fluent-editor/demos/collaborative-editing.spec.ts b/packages/docs/fluent-editor/demos/collaborative-editing.spec.ts index fbe2cfbd..fb73cc90 100644 --- a/packages/docs/fluent-editor/demos/collaborative-editing.spec.ts +++ b/packages/docs/fluent-editor/demos/collaborative-editing.spec.ts @@ -1,12 +1,21 @@ -import { type Browser, chromium, expect, firefox, type Page, test } from '@playwright/test' - -const DEMO_URL = 'http://localhost:5173/tiny-editor/docs/demo/collaborative-editing' +import { type Browser, chromium, expect, type Page, test } from '@playwright/test' test.describe.configure({ mode: 'serial' }) -async function openTwoPages(): Promise<[Page, Page, Browser, Browser]> { +let DEMO_URL = '' +let collabWsReachable = false + +// Must match collaborative-editing.vue: serverUrl + roomName +const COLLAB_WS_URL = 'wss://ai.opentiny.design/tiny-editor/tiny-editor-document-demo-roomName' + +function collabUrl(baseURL: string): string { + return `${baseURL.replace(/\/$/, '')}/tiny-editor/docs/demo/collaborative-editing` +} + +async function openTwoPages(baseURL: string): Promise<[Page, Page, Browser, Browser]> { + DEMO_URL = collabUrl(baseURL) const browser1 = await chromium.launch() - const browser2 = await firefox.launch() + const browser2 = await chromium.launch() const page1 = await browser1.newPage() const page2 = await browser2.newPage() @@ -17,15 +26,17 @@ async function openTwoPages(): Promise<[Page, Page, Browser, Browser]> { ]) const editor1 = page1.locator('.ql-editor') const editor2 = page2.locator('.ql-editor') - await expect(editor1).toBeVisible() - await expect(editor2).toBeVisible() + await expect(editor1).toBeVisible({ timeout: 30_000 }) + await expect(editor2).toBeVisible({ timeout: 30_000 }) return [page1, page2, browser1, browser2] } async function typeSync(page1: Page, page2: Page, text: string): Promise { await page1.locator('.ql-editor').click() await page1.keyboard.type(text) - await expect.poll(async () => (await page2.locator('.ql-editor').textContent() || '').includes(text)).toBeTruthy() + await expect.poll(async () => (await page2.locator('.ql-editor').textContent() || '').includes(text), { + timeout: 15_000, + }).toBeTruthy() } async function selectAll(page: Page): Promise { @@ -34,24 +45,62 @@ async function selectAll(page: Page): Promise { let p1: Page, p2: Page, b1: Browser, b2: Browser -test.beforeEach(async () => { - [p1, p2, b1, b2] = await openTwoPages() +test.beforeAll(async ({ browser }) => { + const page = await browser.newPage() + try { + collabWsReachable = await page.evaluate((wsUrl) => new Promise((resolve) => { + const ws = new WebSocket(wsUrl) + const timer = window.setTimeout(() => { + ws.close() + resolve(false) + }, 5000) + ws.addEventListener('open', () => { + window.clearTimeout(timer) + ws.close() + resolve(true) + }) + ws.addEventListener('error', () => { + window.clearTimeout(timer) + resolve(false) + }) + }), COLLAB_WS_URL) + } + finally { + await page.close() + } +}) + +test.beforeEach(async ({ baseURL }, testInfo) => { + const needsSync = testInfo.title !== 'startup collaborative-editing test' + if (needsSync && !collabWsReachable) + test.skip(true, 'remote collaborative websocket is not reachable') + + ;[p1, p2, b1, b2] = await openTwoPages(baseURL!) }) test.afterEach(async () => { for (const page of [p1, p2]) { - if (!page) continue - const editor = page.locator('.ql-editor') - if (await editor.count()) { - await editor.first().click({ timeout: 2000 }).catch(() => {}) - await selectAll(page) - await page.keyboard.press('Delete').catch(() => {}) + if (!page || page.isClosed()) continue + try { + const editor = page.locator('.ql-editor') + if (await editor.count()) { + await editor.first().click({ timeout: 2000 }).catch(() => {}) + await selectAll(page) + await page.keyboard.press('Delete').catch(() => {}) + } + } + catch { + // page may already be closed when a test is skipped } } await Promise.all([ b1?.close().catch(() => {}), b2?.close().catch(() => {}), ]) + p1 = undefined as unknown as Page + p2 = undefined as unknown as Page + b1 = undefined as unknown as Browser + b2 = undefined as unknown as Browser }) test('startup collaborative-editing test', async () => { diff --git a/packages/docs/fluent-editor/demos/counter-count.spec.ts b/packages/docs/fluent-editor/demos/counter-count.spec.ts index da8ba12c..ab307ccc 100644 --- a/packages/docs/fluent-editor/demos/counter-count.spec.ts +++ b/packages/docs/fluent-editor/demos/counter-count.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@playwright/test' test('has toolbar and custom max character counter', async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/counter') + await page.goto('/tiny-editor/docs/demo/counter') const toolbar = page.locator('.ql-toolbar').nth(1) const editor = page.locator('.ql-editor').nth(1) diff --git a/packages/docs/fluent-editor/demos/counter.spec.ts b/packages/docs/fluent-editor/demos/counter.spec.ts index 68728a12..965bf033 100644 --- a/packages/docs/fluent-editor/demos/counter.spec.ts +++ b/packages/docs/fluent-editor/demos/counter.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@playwright/test' test('has toolbar and default max character counter', async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/counter') + await page.goto('/tiny-editor/docs/demo/counter') const toolbar = page.locator('.ql-toolbar').first() const editor = page.locator('.ql-editor').first() diff --git a/packages/docs/fluent-editor/demos/custom-toolbar.spec.ts b/packages/docs/fluent-editor/demos/custom-toolbar.spec.ts new file mode 100644 index 00000000..56a3f1d6 --- /dev/null +++ b/packages/docs/fluent-editor/demos/custom-toolbar.spec.ts @@ -0,0 +1,19 @@ +import { expect, test } from '@playwright/test' + +test('renders full custom toolbar with extra tools and placeholder', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/custom-toolbar') + + const block = page.locator('.vp-raw').first() + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(editor).toHaveAttribute('data-placeholder', '请输入内容...') + await expect(toolbar.locator('.ql-undo')).toBeVisible() + await expect(toolbar.locator('.ql-redo')).toBeVisible() + await expect(toolbar.locator('.ql-emoji')).toBeVisible() + await expect(toolbar.locator('.ql-screenshot')).toBeVisible() + await expect(toolbar.locator('.ql-format-painter')).toBeVisible() + await expect(toolbar.locator('.ql-picker.ql-font')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/emoji.spec.ts b/packages/docs/fluent-editor/demos/emoji.spec.ts new file mode 100644 index 00000000..714af210 --- /dev/null +++ b/packages/docs/fluent-editor/demos/emoji.spec.ts @@ -0,0 +1,17 @@ +import { expect, test } from '@playwright/test' + +test('has toolbar emoji button and opens emoji picker', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/emoji') + + const toolbar = page.locator('.ql-toolbar').first() + const editor = page.locator('#editor .ql-editor') + const emojiBtn = toolbar.locator('.ql-emoji') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(emojiBtn).toBeVisible() + + await editor.click() + await emojiBtn.click() + await expect(page.locator('#emoji-picker')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/file-upload-handle.spec.ts b/packages/docs/fluent-editor/demos/file-upload-handle.spec.ts new file mode 100644 index 00000000..805cb5e5 --- /dev/null +++ b/packages/docs/fluent-editor/demos/file-upload-handle.spec.ts @@ -0,0 +1,31 @@ +import { expect, test } from '@playwright/test' + +const pngBuffer = Buffer.from( + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==', + 'base64', +) + +test('uploads image and uses fail handler placeholder', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/file-upload') + + const block = page.locator('.vp-raw').nth(1) + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(toolbar.getByLabel('image')).toBeVisible() + await expect(toolbar.getByLabel('video')).toBeVisible() + await expect(toolbar.getByLabel('file')).toBeVisible() + + await toolbar.getByLabel('image').click() + await toolbar.locator('input.ql-image').setInputFiles({ + name: 'a.png', + mimeType: 'image/png', + buffer: pngBuffer, + }) + + const image = editor.getByRole('img').first() + await expect(image).toBeVisible({ timeout: 10_000 }) + await expect(image).toHaveAttribute('src', /edge/) +}) diff --git a/packages/docs/fluent-editor/demos/file-upload.spec.ts b/packages/docs/fluent-editor/demos/file-upload.spec.ts index 8a68b8a8..f33f861b 100644 --- a/packages/docs/fluent-editor/demos/file-upload.spec.ts +++ b/packages/docs/fluent-editor/demos/file-upload.spec.ts @@ -7,7 +7,7 @@ const currentDirectory = path.dirname(__filename) const baseUrl = path.dirname(currentDirectory) test('image-upload', async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/file-upload') + await page.goto('/tiny-editor/docs/demo/file-upload') // upload await page.getByLabel('image').first().click() diff --git a/packages/docs/fluent-editor/demos/flow-chart-background.spec.ts b/packages/docs/fluent-editor/demos/flow-chart-background.spec.ts new file mode 100644 index 00000000..ed64069f --- /dev/null +++ b/packages/docs/fluent-editor/demos/flow-chart-background.spec.ts @@ -0,0 +1,16 @@ +import { expect, test } from '@playwright/test' + +test('renders flow chart background demo with initial nodes', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/flow-chart') + + const block = page.locator('.vp-raw').nth(2) + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + const chart = editor.locator('.ql-flow-chart-item') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(toolbar.locator('.ql-flow-chart')).toBeVisible() + await expect(chart).toBeVisible({ timeout: 30_000 }) + await expect(editor.locator('.lf-node')).toHaveCount(2) + await expect(editor.locator('.lf-edge')).toHaveCount(1) +}) diff --git a/packages/docs/fluent-editor/demos/flow-chart-grid.spec.ts b/packages/docs/fluent-editor/demos/flow-chart-grid.spec.ts new file mode 100644 index 00000000..daa7193b --- /dev/null +++ b/packages/docs/fluent-editor/demos/flow-chart-grid.spec.ts @@ -0,0 +1,15 @@ +import { expect, test } from '@playwright/test' + +test('renders flow chart grid demo with initial nodes', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/flow-chart') + + const block = page.locator('.vp-raw').nth(1) + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(toolbar.locator('.ql-flow-chart')).toBeVisible() + await expect(editor.locator('.ql-flow-chart-item')).toBeVisible({ timeout: 30_000 }) + await expect(editor.locator('.lf-node')).toHaveCount(2) + await expect(editor.locator('.lf-edge')).toHaveCount(1) +}) diff --git a/packages/docs/fluent-editor/demos/flow-chart-resize.spec.ts b/packages/docs/fluent-editor/demos/flow-chart-resize.spec.ts new file mode 100644 index 00000000..7eb5bb2f --- /dev/null +++ b/packages/docs/fluent-editor/demos/flow-chart-resize.spec.ts @@ -0,0 +1,15 @@ +import { expect, test } from '@playwright/test' + +test('renders flow chart with resize handles', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/flow-chart') + + const block = page.locator('.vp-raw').nth(3) + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + const chart = editor.locator('.ql-flow-chart-item') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(toolbar.locator('.ql-flow-chart')).toBeVisible() + await expect(chart).toBeVisible({ timeout: 30_000 }) + await expect(chart.locator('.ql-flow-chart-resize-handle')).toHaveCount(4) +}) diff --git a/packages/docs/fluent-editor/demos/flow-chart.spec.ts b/packages/docs/fluent-editor/demos/flow-chart.spec.ts index d562c33c..26084f69 100644 --- a/packages/docs/fluent-editor/demos/flow-chart.spec.ts +++ b/packages/docs/fluent-editor/demos/flow-chart.spec.ts @@ -2,7 +2,7 @@ import { expect, test } from '@playwright/test' test.describe('FlowChart.vue', () => { test.beforeEach(async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/flow-chart') + await page.goto('/tiny-editor/docs/demo/flow-chart') }) test('should render the editor', async ({ page }) => { diff --git a/packages/docs/fluent-editor/demos/format-painter.spec.ts b/packages/docs/fluent-editor/demos/format-painter.spec.ts new file mode 100644 index 00000000..ad5550e1 --- /dev/null +++ b/packages/docs/fluent-editor/demos/format-painter.spec.ts @@ -0,0 +1,25 @@ +import { expect, test } from '@playwright/test' + +test('copies bold format with format painter', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/format-painter') + + const toolbar = page.locator('.ql-toolbar').first() + const editor = page.locator('#editor .ql-editor') + const painterBtn = toolbar.locator('.ql-format-painter') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(painterBtn).toBeVisible() + + await editor.click() + await toolbar.locator('.ql-bold').click() + await page.keyboard.type('Bold') + await page.keyboard.press('ControlOrMeta+a') + await painterBtn.click() + await expect(painterBtn).toHaveClass(/ql-active/) + + await page.keyboard.press('End') + await page.keyboard.type(' Text') + await expect(editor.locator('strong')).toContainText('Bold') + await expect(editor.locator('strong')).toContainText('Text') +}) diff --git a/packages/docs/fluent-editor/demos/formula-chemistry.spec.ts b/packages/docs/fluent-editor/demos/formula-chemistry.spec.ts new file mode 100644 index 00000000..32684842 --- /dev/null +++ b/packages/docs/fluent-editor/demos/formula-chemistry.spec.ts @@ -0,0 +1,22 @@ +import { expect, test } from '@playwright/test' + +test('inserts chemistry formula with mhchem', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/formula') + + const block = page.locator('.vp-raw').filter({ has: page.locator('#chemistry-editor') }) + const toolbar = block.locator('.ql-toolbar').first() + const editor = page.locator('#chemistry-editor .ql-editor') + const formulaBtn = toolbar.locator('.ql-formula') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(formulaBtn).toBeVisible() + + await editor.click() + await formulaBtn.click() + const input = page.locator('.ql-tooltip[data-mode="formula"] input[data-formula]') + await expect(input).toBeVisible() + await input.fill('\\ce{H2O}') + await input.blur() + await expect(editor.locator('.katex')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/formula-mathlive.spec.ts b/packages/docs/fluent-editor/demos/formula-mathlive.spec.ts new file mode 100644 index 00000000..17332d04 --- /dev/null +++ b/packages/docs/fluent-editor/demos/formula-mathlive.spec.ts @@ -0,0 +1,15 @@ +import { expect, test } from '@playwright/test' + +test('renders mathlive formulas and has formula button', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/formula') + + const block = page.locator('.vp-raw').filter({ has: page.locator('#mathliveEditor') }) + const toolbar = block.locator('.ql-toolbar').first() + const editor = page.locator('#mathliveEditor .ql-editor') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(editor.locator('math-field.ql-math-field').first()).toBeVisible() + await expect(editor).toContainText('正弦交流电') + await expect(toolbar.locator('.ql-formula')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/formula.spec.ts b/packages/docs/fluent-editor/demos/formula.spec.ts new file mode 100644 index 00000000..23df8cbc --- /dev/null +++ b/packages/docs/fluent-editor/demos/formula.spec.ts @@ -0,0 +1,20 @@ +import { expect, test } from '@playwright/test' + +test('inserts katex formula from toolbar', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/formula') + + const block = page.locator('.vp-raw').first() + const editor = page.locator('#editor .ql-editor') + const formulaBtn = block.locator('.ql-formula') + + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(formulaBtn).toBeVisible() + + await editor.click() + await formulaBtn.click() + const input = page.locator('.ql-tooltip[data-mode="formula"] input[data-formula]') + await expect(input).toBeVisible() + await input.fill('e=mc^2') + await input.blur() + await expect(editor.locator('.katex')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/get-content-delta.spec.ts b/packages/docs/fluent-editor/demos/get-content-delta.spec.ts index 728d3a86..642a6209 100644 --- a/packages/docs/fluent-editor/demos/get-content-delta.spec.ts +++ b/packages/docs/fluent-editor/demos/get-content-delta.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@playwright/test' test('has toolbar and syncs Delta preview on text change', async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/get-content') + await page.goto('/tiny-editor/docs/demo/get-content') const block = page.locator('.vp-raw').filter({ has: page.locator('#editor-get-content-delta') }) const toolbar = block.locator('.ql-toolbar').first() diff --git a/packages/docs/fluent-editor/demos/get-content-html.spec.ts b/packages/docs/fluent-editor/demos/get-content-html.spec.ts index 7adec3b4..6b1f50d2 100644 --- a/packages/docs/fluent-editor/demos/get-content-html.spec.ts +++ b/packages/docs/fluent-editor/demos/get-content-html.spec.ts @@ -9,7 +9,7 @@ const initialHtml = [ ].join('') test('has toolbar and syncs HTML preview on text change', async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/get-content') + await page.goto('/tiny-editor/docs/demo/get-content') const block = page.locator('.vp-raw').filter({ has: page.locator('#editor-get-content-html') }) const toolbar = block.locator('.ql-toolbar').first() diff --git a/packages/docs/fluent-editor/demos/header-list-container.spec.ts b/packages/docs/fluent-editor/demos/header-list-container.spec.ts index 42a84639..40565bb5 100644 --- a/packages/docs/fluent-editor/demos/header-list-container.spec.ts +++ b/packages/docs/fluent-editor/demos/header-list-container.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@playwright/test' test('has toolbar, headings and header list with scroll container config', async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/header-list') + await page.goto('/tiny-editor/docs/demo/header-list') const block = page.locator('.vp-raw').nth(1) const toolbar = block.locator('.ql-toolbar').first() diff --git a/packages/docs/fluent-editor/demos/header-list.spec.ts b/packages/docs/fluent-editor/demos/header-list.spec.ts index 611b21b5..271696a8 100644 --- a/packages/docs/fluent-editor/demos/header-list.spec.ts +++ b/packages/docs/fluent-editor/demos/header-list.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@playwright/test' test('has toolbar, headings and toggles header list panel', async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/header-list') + await page.goto('/tiny-editor/docs/demo/header-list') const block = page.locator('.vp-raw').nth(0) const toolbar = block.locator('.ql-toolbar').first() diff --git a/packages/docs/fluent-editor/demos/i18n-custom.spec.ts b/packages/docs/fluent-editor/demos/i18n-custom.spec.ts new file mode 100644 index 00000000..308987ca --- /dev/null +++ b/packages/docs/fluent-editor/demos/i18n-custom.spec.ts @@ -0,0 +1,24 @@ +import { expect, test } from '@playwright/test' + +test('uses custom i18n tip texts and switches locale', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/i18n') + + const block = page.locator('.vp-raw').nth(1) + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + const boldBtn = toolbar.locator('.ql-bold') + const switchBtn = block.getByRole('button', { name: /switch between Chinese and English/i }) + const tip = page.locator('.toolbar-tip__tooltip:visible') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(boldBtn).toBeVisible() + + await boldBtn.hover() + await expect(tip).toBeVisible({ timeout: 5_000 }) + await expect(tip).toHaveText('替换粗体文本') + + await switchBtn.click() + await boldBtn.hover() + await expect(tip).toHaveText('Replace bold text') +}) diff --git a/packages/docs/fluent-editor/demos/i18n.spec.ts b/packages/docs/fluent-editor/demos/i18n.spec.ts new file mode 100644 index 00000000..a60275bc --- /dev/null +++ b/packages/docs/fluent-editor/demos/i18n.spec.ts @@ -0,0 +1,19 @@ +import { expect, test } from '@playwright/test' + +test('switches counter language between English and Chinese', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/i18n') + + const block = page.locator('.vp-raw').first() + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + const counter = block.locator('.ql-counter').first() + const switchBtn = block.getByRole('button', { name: /switch between Chinese and English/i }) + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(counter).toBeVisible() + await expect(counter).toHaveText('0/500 characters') + + await switchBtn.click() + await expect(counter).toHaveText('0/500') +}) diff --git a/packages/docs/fluent-editor/demos/image-toolbar-button.spec.ts b/packages/docs/fluent-editor/demos/image-toolbar-button.spec.ts new file mode 100644 index 00000000..5d667bd0 --- /dev/null +++ b/packages/docs/fluent-editor/demos/image-toolbar-button.spec.ts @@ -0,0 +1,21 @@ +import { expect, test } from '@playwright/test' + +test('custom image toolbar hides copy/download and applies clean', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/image-tool') + + const block = page.locator('.vp-raw').nth(1) + const editor = block.locator('.ql-editor').first() + const image = editor.getByRole('img').first() + + await expect(image).toBeVisible({ timeout: 30_000 }) + await expect(image).toHaveAttribute('width', '400px') + + await image.click() + const overlay = page.locator('.blot-formatter__overlay') + await expect(overlay).toBeVisible() + const buttons = overlay.locator('.blot-formatter__toolbar-button') + await expect(buttons).toHaveCount(5) + + await buttons.last().click({ force: true }) + await expect(image).not.toHaveAttribute('width', '400px') +}) diff --git a/packages/docs/fluent-editor/demos/image-toolbar.spec.ts b/packages/docs/fluent-editor/demos/image-toolbar.spec.ts new file mode 100644 index 00000000..a39223c1 --- /dev/null +++ b/packages/docs/fluent-editor/demos/image-toolbar.spec.ts @@ -0,0 +1,22 @@ +import { expect, test } from '@playwright/test' + +test('shows image toolbar overlay and preview button', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/image-tool') + + const block = page.locator('.vp-raw').first() + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + const image = editor.getByRole('img').first() + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(image).toBeVisible({ timeout: 30_000 }) + + await image.click() + const overlay = page.locator('.blot-formatter__overlay') + await expect(overlay).toBeVisible() + const buttons = overlay.locator('.blot-formatter__toolbar-button') + await expect(buttons).toHaveCount(6) + + await buttons.last().click({ force: true }) + await expect(page.locator('.image-preview-overlay')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/markdown.spec.ts b/packages/docs/fluent-editor/demos/markdown.spec.ts new file mode 100644 index 00000000..1bbfc929 --- /dev/null +++ b/packages/docs/fluent-editor/demos/markdown.spec.ts @@ -0,0 +1,19 @@ +import { expect, test } from '@playwright/test' + +test('has toolbar and converts markdown shortcuts', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/markdown') + + const toolbar = page.locator('.ql-toolbar').first() + const editor = page.locator('#editor .ql-editor') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + + await editor.click() + await page.keyboard.type('# Hello') + await expect(editor.locator('h1')).toHaveText('Hello') + + await page.keyboard.press('Enter') + await page.keyboard.type('- item') + await expect(editor.locator('li').first()).toContainText('item') +}) diff --git a/packages/docs/fluent-editor/demos/mention-custom-list.spec.ts b/packages/docs/fluent-editor/demos/mention-custom-list.spec.ts new file mode 100644 index 00000000..cf1b7e22 --- /dev/null +++ b/packages/docs/fluent-editor/demos/mention-custom-list.spec.ts @@ -0,0 +1,19 @@ +import { expect, test } from '@playwright/test' + +test('renders custom mention list with avatar and follower info', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/mention') + + const editor = page.locator('#editor-mention-custom-list .ql-editor') + await expect(editor).toBeVisible({ timeout: 30_000 }) + + await editor.click() + await editor.pressSequentially('@') + const list = page.locator('.ql-mention-list-container__custom-list .ql-mention-list:not(.ql-mention-list--hide)') + await expect(list).toBeVisible() + await expect(list.locator('.item-name')).toContainText(['卡哥', '超哥', '小伍哥']) + await expect(list.locator('.item-desc').first()).toContainText('粉丝') + await expect(list.locator('.item-avatar img').first()).toBeVisible() + + await list.locator('.ql-mention-item').first().click() + await expect(editor.locator('.ql-mention-link')).toContainText('卡哥') +}) diff --git a/packages/docs/fluent-editor/demos/mention-link.spec.ts b/packages/docs/fluent-editor/demos/mention-link.spec.ts new file mode 100644 index 00000000..0e7845d3 --- /dev/null +++ b/packages/docs/fluent-editor/demos/mention-link.spec.ts @@ -0,0 +1,28 @@ +import { expect, test } from '@playwright/test' + +test('inserts mention link and toggles editable state', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/mention') + + const block = page.locator('.vp-raw').nth(2) + const editor = block.locator('.ql-editor').first() + const toggleBtn = block.getByRole('button', { name: /toggle editable/i }) + + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(toggleBtn).toBeVisible() + await expect(block).toContainText('enabled') + + await editor.click() + await editor.pressSequentially('@') + const list = block.locator('.ql-mention-list:not(.ql-mention-list--hide)') + await expect(list).toBeVisible() + await expect(list).toContainText('Jack 杰克') + await list.locator('.ql-mention-item').first().click() + + const mention = editor.locator('a.ql-mention-link') + await expect(mention).toHaveAttribute('href', '#/use/Jack') + await expect(mention).toHaveAttribute('target', '_blank') + + await toggleBtn.click() + await expect(block).toContainText('disabled') + await expect(editor).toHaveAttribute('contenteditable', 'false') +}) diff --git a/packages/docs/fluent-editor/demos/mention.spec.ts b/packages/docs/fluent-editor/demos/mention.spec.ts new file mode 100644 index 00000000..46451685 --- /dev/null +++ b/packages/docs/fluent-editor/demos/mention.spec.ts @@ -0,0 +1,19 @@ +import { expect, test } from '@playwright/test' + +test('shows mention list on @ and inserts selected item', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/mention') + + const block = page.locator('.vp-raw').filter({ has: page.locator('#editor') }) + const editor = page.locator('#editor .ql-editor') + await expect(editor).toBeVisible({ timeout: 30_000 }) + + await editor.click() + await editor.pressSequentially('@') + const list = block.locator('.ql-mention-list:not(.ql-mention-list--hide)') + await expect(list).toBeVisible() + await expect(list).toContainText('Jack 杰克') + await expect(list).toContainText('Lucy 露西') + + await list.locator('.ql-mention-item').first().click() + await expect(editor.locator('.ql-mention-link')).toContainText('Jack 杰克') +}) diff --git a/packages/docs/fluent-editor/demos/mind-map-background.spec.ts b/packages/docs/fluent-editor/demos/mind-map-background.spec.ts new file mode 100644 index 00000000..d9678762 --- /dev/null +++ b/packages/docs/fluent-editor/demos/mind-map-background.spec.ts @@ -0,0 +1,23 @@ +import { expect, test } from '@playwright/test' + +test('renders mind map with custom background color', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/mind-map') + + const block = page.locator('.vp-raw').nth(1) + const toolbar = block.locator('.ql-toolbar').first() + const map = block.locator('.ql-mind-map-item').first() + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(toolbar.locator('.ql-mind-map')).toBeVisible() + await expect(map).toBeVisible({ timeout: 30_000 }) + await expect(map).toContainText('根节点') + + await expect.poll(async () => { + const color = await map.evaluate((el) => { + const svg = el.querySelector('svg') + const style = svg ? getComputedStyle(svg) : getComputedStyle(el) + return `${(el as HTMLElement).style.backgroundColor} ${style.backgroundColor}` + }) + return color.includes('164, 221, 0') || color.toLowerCase().includes('a4dd00') + }).toBeTruthy() +}) diff --git a/packages/docs/fluent-editor/demos/mind-map-line.spec.ts b/packages/docs/fluent-editor/demos/mind-map-line.spec.ts new file mode 100644 index 00000000..42c0b074 --- /dev/null +++ b/packages/docs/fluent-editor/demos/mind-map-line.spec.ts @@ -0,0 +1,15 @@ +import { expect, test } from '@playwright/test' + +test('renders mind map line demo with root and child nodes', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/mind-map') + + const block = page.locator('.vp-raw').nth(3) + const toolbar = block.locator('.ql-toolbar').first() + const map = block.locator('.ql-mind-map-item').first() + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(toolbar.locator('.ql-mind-map')).toBeVisible() + await expect(map).toBeVisible({ timeout: 30_000 }) + await expect(map).toContainText('根节点') + await expect(map).toContainText('二级节点') +}) diff --git a/packages/docs/fluent-editor/demos/mind-map-resize.spec.ts b/packages/docs/fluent-editor/demos/mind-map-resize.spec.ts new file mode 100644 index 00000000..0a0a6bae --- /dev/null +++ b/packages/docs/fluent-editor/demos/mind-map-resize.spec.ts @@ -0,0 +1,14 @@ +import { expect, test } from '@playwright/test' + +test('renders mind map with resize handles', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/mind-map') + + const block = page.locator('.vp-raw').nth(2) + const toolbar = block.locator('.ql-toolbar').first() + const map = block.locator('.ql-mind-map-item').first() + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(toolbar.locator('.ql-mind-map')).toBeVisible() + await expect(map).toBeVisible({ timeout: 30_000 }) + await expect(map.locator('.ql-mind-map-resize-handle')).toHaveCount(4) +}) diff --git a/packages/docs/fluent-editor/demos/mind-map-theme.spec.ts b/packages/docs/fluent-editor/demos/mind-map-theme.spec.ts new file mode 100644 index 00000000..835ccc42 --- /dev/null +++ b/packages/docs/fluent-editor/demos/mind-map-theme.spec.ts @@ -0,0 +1,15 @@ +import { expect, test } from '@playwright/test' + +test('renders mind map theme demo with root and child nodes', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/mind-map') + + const block = page.locator('.vp-raw').nth(4) + const toolbar = block.locator('.ql-toolbar').first() + const map = block.locator('.ql-mind-map-item').first() + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(toolbar.locator('.ql-mind-map')).toBeVisible() + await expect(map).toBeVisible({ timeout: 30_000 }) + await expect(map).toContainText('根节点') + await expect(map).toContainText('二级节点') +}) diff --git a/packages/docs/fluent-editor/demos/mind-map.spec.ts b/packages/docs/fluent-editor/demos/mind-map.spec.ts index ee92b0cc..ca4903dd 100644 --- a/packages/docs/fluent-editor/demos/mind-map.spec.ts +++ b/packages/docs/fluent-editor/demos/mind-map.spec.ts @@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test' test.describe('MindMap.vue', () => { test.beforeEach(async ({ page }) => { // 根据实际的路由调整这个URL - await page.goto('http://localhost:5173/tiny-editor/docs/demo/mind-map') + await page.goto('/tiny-editor/docs/demo/mind-map') }) test('should render the editor', async ({ page }) => { diff --git a/packages/docs/fluent-editor/demos/readonly.spec.ts b/packages/docs/fluent-editor/demos/readonly.spec.ts index 50ee88ba..2fa53fa6 100644 --- a/packages/docs/fluent-editor/demos/readonly.spec.ts +++ b/packages/docs/fluent-editor/demos/readonly.spec.ts @@ -17,7 +17,7 @@ const initialHtml = [ ].join('') test('renders readonly editor without toolbar', async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/readonly') + await page.goto('/tiny-editor/docs/demo/readonly') const block = page.locator('.vp-raw').first() const editor = page.locator('#editor-readonly .ql-editor') diff --git a/packages/docs/fluent-editor/demos/screenshot-upload-to-server.spec.ts b/packages/docs/fluent-editor/demos/screenshot-upload-to-server.spec.ts new file mode 100644 index 00000000..f8238d4d --- /dev/null +++ b/packages/docs/fluent-editor/demos/screenshot-upload-to-server.spec.ts @@ -0,0 +1,13 @@ +import { expect, test } from '@playwright/test' + +test('has screenshot button in server-upload demo', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/screenshot') + + const block = page.locator('.vp-raw').nth(1) + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(toolbar.locator('.ql-screenshot')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/screenshot.spec.ts b/packages/docs/fluent-editor/demos/screenshot.spec.ts new file mode 100644 index 00000000..4b2f12ac --- /dev/null +++ b/packages/docs/fluent-editor/demos/screenshot.spec.ts @@ -0,0 +1,13 @@ +import { expect, test } from '@playwright/test' + +test('has screenshot button in toolbar', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/screenshot') + + const block = page.locator('.vp-raw').first() + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(toolbar.locator('.ql-screenshot')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/set-content-delta.spec.ts b/packages/docs/fluent-editor/demos/set-content-delta.spec.ts index 15b76967..6ad6a09c 100644 --- a/packages/docs/fluent-editor/demos/set-content-delta.spec.ts +++ b/packages/docs/fluent-editor/demos/set-content-delta.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@playwright/test' test('should initialize editor with Delta content', async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/set-content') + await page.goto('/tiny-editor/docs/demo/set-content') const toolbar = page.locator('.ql-toolbar').nth(1) const editor = page.locator('#editor-set-content-delta .ql-editor') diff --git a/packages/docs/fluent-editor/demos/set-content-html.spec.ts b/packages/docs/fluent-editor/demos/set-content-html.spec.ts index 6b506760..1a4a6d06 100644 --- a/packages/docs/fluent-editor/demos/set-content-html.spec.ts +++ b/packages/docs/fluent-editor/demos/set-content-html.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@playwright/test' test('should initialize editor with HTML content', async ({ page }) => { - await page.goto('http://localhost:5173/tiny-editor/docs/demo/set-content') + await page.goto('/tiny-editor/docs/demo/set-content') const editor = page.locator('#editor-set-content-html .ql-editor') await expect(editor).toBeVisible() diff --git a/packages/docs/fluent-editor/demos/shortcut-key.spec.ts b/packages/docs/fluent-editor/demos/shortcut-key.spec.ts new file mode 100644 index 00000000..7f54b0ed --- /dev/null +++ b/packages/docs/fluent-editor/demos/shortcut-key.spec.ts @@ -0,0 +1,18 @@ +import { expect, test } from '@playwright/test' + +test('shows shortcut placeholder and opens slash menu', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/shortcut-key') + + const toolbar = page.locator('.ql-toolbar').first() + const editor = page.locator('#editor .ql-editor') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(page.locator('.qsf-placeholder__wrapper')).toBeVisible() + + await editor.click() + await page.keyboard.type('/') + const menu = page.locator('.qsf-menu') + await expect(menu).toBeVisible({ timeout: 10_000 }) + await expect(menu).toContainText('Heading 1') +}) diff --git a/packages/docs/fluent-editor/demos/table-up-clipboard.spec.ts b/packages/docs/fluent-editor/demos/table-up-clipboard.spec.ts new file mode 100644 index 00000000..11519696 --- /dev/null +++ b/packages/docs/fluent-editor/demos/table-up-clipboard.spec.ts @@ -0,0 +1,14 @@ +import { expect, test } from '@playwright/test' + +test('has toolbar and pasteStyleSheet clipboard demo', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/table-up') + + const block = page.locator('.vp-raw').nth(3) + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(block).toContainText('pasteStyleSheet') + await expect(toolbar.locator('.ql-picker.ql-table-up')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/table-up-menu.spec.ts b/packages/docs/fluent-editor/demos/table-up-menu.spec.ts new file mode 100644 index 00000000..daf60534 --- /dev/null +++ b/packages/docs/fluent-editor/demos/table-up-menu.spec.ts @@ -0,0 +1,17 @@ +import { expect, test } from '@playwright/test' + +test('inserts table from toolbar in contextmenu and select menu editors', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/table-up') + + const block = page.locator('.vp-raw').first() + const editors = block.locator('.ql-editor') + await expect(editors.first()).toBeVisible({ timeout: 30_000 }) + await expect(editors).toHaveCount(2) + await expect(block).toContainText('右击菜单') + await expect(block).toContainText('选择菜单') + + const firstToolbar = block.locator('.ql-toolbar').first() + await firstToolbar.locator('.ql-table-up > .ql-picker-label').click() + await page.locator('.table-up-select-box__item[data-row="2"][data-col="2"]:visible').click() + await expect(editors.first().locator('.ql-table-wrapper')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/table-up-resize.spec.ts b/packages/docs/fluent-editor/demos/table-up-resize.spec.ts new file mode 100644 index 00000000..553edeaf --- /dev/null +++ b/packages/docs/fluent-editor/demos/table-up-resize.spec.ts @@ -0,0 +1,18 @@ +import { expect, test } from '@playwright/test' + +test('renders three table resize editors and inserts a table', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/table-up') + + const block = page.locator('.vp-raw').nth(1) + const editors = block.locator('.ql-editor') + await expect(editors.first()).toBeVisible({ timeout: 30_000 }) + await expect(editors).toHaveCount(3) + await expect(block).toContainText('包围盒') + await expect(block).toContainText('内部隐藏线') + await expect(block).toContainText('整体单元格调整') + + const firstToolbar = block.locator('.ql-toolbar').first() + await firstToolbar.locator('.ql-table-up > .ql-picker-label').click() + await page.locator('.table-up-select-box__item[data-row="2"][data-col="2"]:visible').click() + await expect(editors.first().locator('.ql-table-wrapper')).toBeVisible() +}) diff --git a/packages/docs/fluent-editor/demos/table-up-shortcut.spec.ts b/packages/docs/fluent-editor/demos/table-up-shortcut.spec.ts new file mode 100644 index 00000000..7092f904 --- /dev/null +++ b/packages/docs/fluent-editor/demos/table-up-shortcut.spec.ts @@ -0,0 +1,21 @@ +import { expect, test } from '@playwright/test' + +test('has language switcher, table button and slash menu table item', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/table-up') + + const block = page.locator('.vp-raw').nth(2) + const toolbar = block.locator('.ql-toolbar').first() + const editor = block.locator('.ql-editor').first() + const localeSelect = block.locator('#locale-select') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(localeSelect).toBeVisible() + await expect(toolbar.locator('.ql-picker.ql-table-up')).toBeVisible() + + await editor.click() + await page.keyboard.type('/') + const menu = page.locator('.qsf-menu') + await expect(menu).toBeVisible({ timeout: 10_000 }) + await expect(menu).toContainText(/Table|表格/) +}) diff --git a/packages/docs/fluent-editor/demos/toolbar-tip.spec.ts b/packages/docs/fluent-editor/demos/toolbar-tip.spec.ts new file mode 100644 index 00000000..d2837881 --- /dev/null +++ b/packages/docs/fluent-editor/demos/toolbar-tip.spec.ts @@ -0,0 +1,18 @@ +import { expect, test } from '@playwright/test' + +test('has toolbar and shows tip on hover', async ({ page }) => { + await page.goto('/tiny-editor/docs/demo/toolbar-tip') + + const toolbar = page.locator('.ql-toolbar').first() + const editor = page.locator('.ql-editor').first() + const boldBtn = toolbar.locator('.ql-bold') + + await expect(toolbar).toBeVisible({ timeout: 30_000 }) + await expect(editor).toBeVisible({ timeout: 30_000 }) + await expect(boldBtn).toBeVisible() + + await boldBtn.hover() + const tip = page.locator('.toolbar-tip__tooltip:visible') + await expect(tip).toBeVisible({ timeout: 5_000 }) + await expect(tip).toContainText(/Bold|粗体/) +}) diff --git a/packages/docs/fluent-editor/public/banner-dark.svg b/packages/docs/fluent-editor/public/banner-dark.svg new file mode 100644 index 00000000..f52cba88 --- /dev/null +++ b/packages/docs/fluent-editor/public/banner-dark.svg @@ -0,0 +1,726 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e20186bc..be902d84 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -204,6 +204,9 @@ importers: quill-shortcut-key: specifier: ^0.2.1 version: 0.2.1(quill@2.0.3(patch_hash=dnirvjhpzdmsvdidsclwslxxji)) + quill-table-up: + specifier: ^3.5.0 + version: 3.5.1(quill@2.0.3(patch_hash=dnirvjhpzdmsvdidsclwslxxji)) devDependencies: '@emoji-mart/data': specifier: ^1.2.1