Skip to content

Commit e64f3c7

Browse files
authored
Merge pull request #8072 from nextcloud/test/editor_api_test
test(playwright): add basic tests for editor API
2 parents d358157 + dff0bac commit e64f3c7

3 files changed

Lines changed: 179 additions & 40 deletions

File tree

playwright/e2e/create-table-api.spec.ts renamed to playwright/e2e/editor-api-create-table.spec.ts

Lines changed: 18 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,10 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55

6-
import type { Page } from '@playwright/test'
76
import { expect } from '@playwright/test'
8-
import { test } from '../support/fixtures/random-user'
7+
import { test } from '../support/fixtures/editor-api'
98

109
test.describe('createTable API', () => {
11-
const containerId = 'test-table'
12-
13-
const createTable = async (
14-
page: Page,
15-
options: { content: string; readOnly: boolean },
16-
) => {
17-
await page.evaluate(
18-
async ({ containerId, content, readOnly }) => {
19-
const container = document.createElement('div')
20-
container.id = containerId
21-
container.style.position = 'fixed'
22-
container.style.top = '0'
23-
container.style.left = '0'
24-
container.style.width = '100%'
25-
container.style.height = '100%'
26-
container.style.padding = '50px'
27-
container.style.zIndex = '10000'
28-
container.style.background = 'white'
29-
document.body.appendChild(container)
30-
31-
// @ts-expect-error - OCA.Text is a global
32-
await window.OCA.Text.createTable({
33-
el: container,
34-
content,
35-
readOnly,
36-
})
37-
},
38-
{ containerId, ...options },
39-
)
40-
}
41-
4210
test.beforeEach(async ({ page }) => {
4311
// Open the files app so we're somewhere with `window.OCA.Text` available
4412
await page.goto('/apps/files')
@@ -50,8 +18,9 @@ test.describe('createTable API', () => {
5018
})
5119
})
5220

53-
test('renders table editor', async ({ page }) => {
54-
await createTable(page, {
21+
test('renders table editor', async ({ page, createEditor, containerId }) => {
22+
await createEditor({
23+
type: 'table',
5524
content: '| A | B |\n|---|---|\n| 1 | 2 |',
5625
readOnly: false,
5726
})
@@ -61,8 +30,13 @@ test.describe('createTable API', () => {
6130
await expect(page.locator(`#${containerId} td`).first()).toContainText('1')
6231
})
6332

64-
test('allows editing when not readonly', async ({ page }) => {
65-
await createTable(page, {
33+
test('allows editing when not readonly', async ({
34+
page,
35+
createEditor,
36+
containerId,
37+
}) => {
38+
await createEditor({
39+
type: 'table',
6640
content: '| A |\n|---|\n| x |',
6741
readOnly: false,
6842
})
@@ -75,9 +49,13 @@ test.describe('createTable API', () => {
7549

7650
await expect(cell).toContainText('edited')
7751
})
78-
79-
test('prevents editing when readonly', async ({ page }) => {
80-
await createTable(page, {
52+
test('prevents editing when readonly', async ({
53+
page,
54+
createEditor,
55+
containerId,
56+
}) => {
57+
await createEditor({
58+
type: 'table',
8159
content: '| A |\n|---|---|\n| 1 |',
8260
readOnly: true,
8361
})

playwright/e2e/editor-api.spec.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import { expect, mergeTests } from '@playwright/test'
7+
import { test } from '../support/fixtures/editor-api'
8+
import { test as uploadFileTest } from '../support/fixtures/upload-file'
9+
10+
const fileTest = mergeTests(uploadFileTest, test)
11+
12+
test.describe('editor API at window.OCA.Text - MarkdownContentEditor.vue without collaboration session', () => {
13+
test.beforeEach(async ({ page }) => {
14+
// Open the files app so we're somewhere with `window.OCA.Text` available
15+
await page.goto('/apps/files')
16+
17+
// Load the editor API bundle
18+
await page.addScriptTag({
19+
url: '/apps/text/js/text-editor.mjs',
20+
type: 'module',
21+
})
22+
})
23+
24+
test('opens editor in write mode with predefined content', async ({
25+
page,
26+
createEditor,
27+
containerId,
28+
}) => {
29+
await createEditor({
30+
type: 'editor',
31+
content: '# heading\n',
32+
})
33+
34+
await expect(page.locator(`#${containerId} h1`)).toHaveText('#heading')
35+
36+
const content = page.locator(`#${containerId} .ProseMirror`)
37+
await content.click()
38+
await page.keyboard.type('More text.')
39+
await expect(content).toContainText('#headingMore text.')
40+
})
41+
42+
test('opens editor readonly with predefined content', async ({
43+
page,
44+
createEditor,
45+
containerId,
46+
}) => {
47+
await createEditor({
48+
type: 'editor',
49+
content: '# heading\n',
50+
readOnly: true,
51+
})
52+
53+
await expect(page.locator(`#${containerId} h1`)).toHaveText('#heading')
54+
const content = page.locator(`#${containerId} .ProseMirror`)
55+
await expect(content).toHaveAttribute('contenteditable', 'false')
56+
})
57+
})
58+
59+
fileTest.describe(
60+
'editor API at window.OCA.Text - Editor.vue with collaboration session',
61+
() => {
62+
fileTest.use({ fileContent: 'some content\n' })
63+
64+
fileTest.beforeEach(async ({ page }) => {
65+
// Open the files app so we're somewhere with `window.OCA.Text` available
66+
await page.goto('/apps/files')
67+
68+
// Load the editor API bundle
69+
await page.addScriptTag({
70+
url: '/apps/text/js/text-editor.mjs',
71+
type: 'module',
72+
})
73+
})
74+
75+
fileTest(
76+
'opens editor with session for existing file',
77+
async ({ file, page, createEditor, containerId }) => {
78+
await createEditor({
79+
type: 'editor',
80+
fileId: file.id,
81+
readOnly: true,
82+
})
83+
84+
await expect(page.locator(`#${containerId}`)).toContainText(
85+
'some content',
86+
)
87+
88+
const content = page.locator(`#${containerId} .ProseMirror`)
89+
await content.click()
90+
await page.keyboard.type('More text.')
91+
await expect(content).toContainText('More text.')
92+
},
93+
)
94+
},
95+
)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import { test as base } from './random-user'
7+
8+
const containerId = 'test-editor-api'
9+
10+
export interface EditorApiFixture {
11+
createEditor: (options: {
12+
type: 'editor' | 'table',
13+
content?: string,
14+
fileId?: number,
15+
readOnly?: boolean,
16+
}) => Promise<void>
17+
containerId: string
18+
}
19+
20+
/**
21+
* This test fixture provides helpers to create an editor or table using the Text API
22+
* - createEditor: If a `fileId` is passed, an editor with session is created, if `content` is passed,
23+
* an editor without session is created.
24+
* - createTable: Creates a table editor with the given content
25+
*/
26+
export const test = base.extend<EditorApiFixture>({
27+
createEditor: async ({ page }, use) => {
28+
const createEditor = async (
29+
options: {
30+
type: 'editor' | 'table',
31+
content?: string,
32+
fileId?: number,
33+
readOnly?: boolean,
34+
},
35+
) => {
36+
37+
await page.evaluate(
38+
async ({ containerId, type, content, fileId, readOnly }) => {
39+
const container = document.createElement('div')
40+
container.id = containerId
41+
container.style.position = 'fixed'
42+
container.style.top = '0'
43+
container.style.left = '0'
44+
container.style.width = '100%'
45+
container.style.height = '100%'
46+
container.style.padding = '50px'
47+
container.style.zIndex = '10000'
48+
container.style.background = 'white'
49+
document.body.appendChild(container)
50+
51+
const method = type === 'editor' ? 'createEditor' : 'createTable'
52+
// @ts-expect-error - OCA.Text is a global
53+
await window.OCA.Text[method]({
54+
el: container,
55+
...(fileId != null ? { fileId } : { content }),
56+
readOnly,
57+
})
58+
},
59+
{ containerId, type: options.type, content: options.content, fileId: options.fileId, readOnly: options.readOnly },
60+
)
61+
}
62+
63+
await use(createEditor)
64+
},
65+
containerId,
66+
})

0 commit comments

Comments
 (0)