Skip to content

Commit f1a48f1

Browse files
committed
test(systemtags): migrate from Cypress to PlayWright
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
1 parent 8fc2e1c commit f1a48f1

15 files changed

Lines changed: 574 additions & 645 deletions

cypress/e2e/systemtags/files-bulk-action.cy.ts

Lines changed: 0 additions & 468 deletions
This file was deleted.

cypress/e2e/systemtags/files-inline-action.cy.ts

Lines changed: 0 additions & 78 deletions
This file was deleted.

cypress/e2e/systemtags/files-sidebar.cy.ts

Lines changed: 0 additions & 41 deletions
This file was deleted.

cypress/e2e/systemtags/files-view.cy.ts

Lines changed: 0 additions & 42 deletions
This file was deleted.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import { runOcc } from '@nextcloud/e2e-test-server'
7+
import { expect } from '@playwright/test'
8+
import { test } from '../../support/fixtures/systemtags-files-page.ts'
9+
import { uploadContent } from '../../support/utils/dav.ts'
10+
import { clearTags, createTag } from '../../support/utils/systemtags.ts'
11+
12+
test.beforeAll(async () => await runOcc(['config:app:set', 'systemtags', 'restrict_creation_to_admin', '--value', '1']))
13+
test.afterAll(async () => await runOcc(['config:app:delete', 'systemtags', 'restrict_creation_to_admin']))
14+
test.afterAll(async () => await clearTags())
15+
16+
test.beforeEach(async ({ filesListPage, page, user }) => {
17+
await uploadContent(page.request, user, Buffer.alloc(0), 'text/plain', '/file1.txt')
18+
await uploadContent(page.request, user, Buffer.alloc(0), 'text/plain', '/file2.txt')
19+
await filesListPage.open()
20+
})
21+
22+
test('Cannot create tag if restriction is in place', async ({ filesListPage }) => {
23+
const tag = crypto.randomUUID()
24+
await createTag(tag, 'public')
25+
26+
await filesListPage.expectInlineTagsForFile('file1.txt', [])
27+
await filesListPage.selectAll()
28+
const picker = await filesListPage.openTagPickerForSelection()
29+
30+
// When restricted, the input label changes and create/color buttons are absent
31+
await expect(picker.getByLabel('Search or create tag')).toHaveCount(0)
32+
await expect(picker.getByLabel('Search tag')).toBeVisible()
33+
34+
await picker.getByLabel('Search tag').fill(crypto.randomUUID())
35+
await expect(picker.getByRole('button', { name: /Create new tag/i })).toHaveCount(0)
36+
37+
await picker.getByLabel('Search tag').clear()
38+
await picker.getByLabel('Search tag').fill(tag)
39+
40+
await expect(picker.getByRole('checkbox')).toHaveCount(1)
41+
await expect(picker.getByRole('button', { name: /Create new tag/i })).toHaveCount(0)
42+
await expect(picker.getByRole('button', { name: 'Change tag color' })).toHaveCount(0)
43+
44+
// Can still assign the existing admin-created tag
45+
await picker.getByRole('checkbox', { name: tag }).click({ force: true })
46+
await filesListPage.applyTagPicker()
47+
await filesListPage.expectInlineTagsForFile('file1.txt', [tag])
48+
})

tests/playwright/e2e/systemtags/admin-settings.spec.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,17 @@
66
import { expect } from '@playwright/test'
77
import { runOcc } from '@nextcloud/e2e-test-server/docker'
88
import { test } from '../../support/fixtures/admin-session.ts'
9+
import { createTag, deleteTag, listTags } from '../../support/utils/systemtags.ts'
910

1011
const tagName = 'foo'
1112
const updatedTagName = 'bar'
1213

1314
test.describe('System tags admin settings', () => {
14-
// Tests are sequential: update depends on create, delete depends on update
15-
test.describe.configure({ mode: 'serial' })
16-
17-
test.beforeAll(async () => {
18-
// Delete all existing tags so each test run starts from a clean state
19-
const output = await runOcc(['tag:list', '--output=json'])
20-
const tags = JSON.parse(output) as Record<string, unknown>
21-
await Promise.all(Object.keys(tags).map((id) => runOcc(['tag:delete', id]).catch(() => {})))
15+
test.beforeEach(async () => {
16+
const tags = await listTags()
17+
for (const tag of tags) {
18+
await deleteTag(tag.id)
19+
}
2220
})
2321

2422
test('Can create a tag', async ({ page }) => {
@@ -44,6 +42,8 @@ test.describe('System tags admin settings', () => {
4442
})
4543

4644
test('Can update a tag', async ({ page }) => {
45+
const tag = await createTag(tagName)
46+
4747
await page.goto('settings/admin/server')
4848
await page.getByRole('heading', { name: 'Collaborative tags' }).scrollIntoViewIfNeeded()
4949

@@ -69,24 +69,25 @@ test.describe('System tags admin settings', () => {
6969
await page.getByRole('button', { name: 'Update' }).click()
7070
expect((await updateResponse).status()).toBe(207)
7171

72+
await page.getByRole('combobox', { name: 'Search for a tag to edit' }).click()
7273
// NcEllipsisedOption splits names ≥ 10 chars across two spans, breaking the accessible name.
7374
// "bar (invisible)" (15 chars) splits at position 8 → accessible name "bar (inv isible)".
7475
// Use filter({ hasText }) to match on text content instead of the exact accessible name.
75-
await page.getByRole('combobox', { name: 'Search for a tag to edit' }).click()
7676
await expect(page.getByRole('option').filter({ hasText: updatedTagName })).toBeVisible()
7777
})
7878

7979
test('Can delete a tag', async ({ page }) => {
80+
await createTag(tagName)
81+
8082
await page.goto('settings/admin/server')
8183
await page.getByRole('heading', { name: 'Collaborative tags' }).scrollIntoViewIfNeeded()
8284

8385
// Select the invisible tag to delete
8486
await page.getByRole('combobox', { name: 'Search for a tag to edit' }).click()
85-
await page.getByRole('option').filter({ hasText: updatedTagName }).click()
87+
await page.getByRole('option').filter({ hasText: tagName }).click()
8688

8789
// Verify the form reflects the selected tag
88-
await expect(page.getByLabel('Tag name')).toHaveValue(updatedTagName)
89-
await expect(page.locator('.system-tag-form__group:has(#system-tag-level) .vs__selected')).toContainText('Invisible')
90+
await expect(page.getByLabel('Tag name')).toHaveValue(tagName)
9091

9192
const deleteResponse = page.waitForResponse(
9293
(r) => r.url().includes('/remote.php/dav/systemtags/') && r.request().method() === 'DELETE',
@@ -96,6 +97,6 @@ test.describe('System tags admin settings', () => {
9697

9798
// Verify the tag is gone from the dropdown
9899
await page.getByRole('combobox', { name: 'Search for a tag to edit' }).click()
99-
await expect(page.getByRole('option').filter({ hasText: updatedTagName })).not.toBeVisible()
100+
await expect(page.getByRole('option').filter({ hasText: tagName })).not.toBeVisible()
100101
})
101102
})

0 commit comments

Comments
 (0)