Skip to content

Commit 620d734

Browse files
committed
test(dialog): add Playwright component tests for the dialog
Set up Playwright component testing (@playwright/experimental-ct-vue) and cover the recipient/permission UI in a real browser: - PermissionEditor: notice visibility, per-permission toggles, over-cap toggles disabled, toggles hidden outside custom mode. - RecipientRow (via an in-browser fixture, since a Share with methods cannot be passed as a serialized prop): preset subtitle, remove from the menu, and the custom-permissions modal opening. - RecipientList: one row per recipient, excluding the link (token). Specs are named *.ct.ts so Vitest (which globs *.spec/*.test) ignores them. Assisted-by: ClaudeCode:claude-opus-4-8 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
1 parent 65fab90 commit 620d734

11 files changed

Lines changed: 936 additions & 4 deletions

File tree

‎.gitignore‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,8 @@ typings/
6363
.next
6464

6565
/dist
66+
67+
# Playwright
68+
test-results/
69+
playwright-report/
70+
playwright/.cache/
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*/
5+
6+
import { expect, test } from '@playwright/experimental-ct-vue'
7+
import PermissionEditor from './PermissionEditor.vue'
8+
9+
const baseProps = {
10+
presetOptions: [{ value: 'View', label: 'Can view' }, { value: 'custom', label: 'Can…' }],
11+
selectedPreset: { value: 'custom', label: 'Can…' },
12+
showPermissions: true,
13+
permissions: [
14+
{ class: 'read', source_class: null, display_name: 'Read', hint: null, priority: 0, presets: [], enabled: true, available: true },
15+
{ class: 'write', source_class: null, display_name: 'Write', hint: null, priority: 0, presets: [], enabled: false, available: false },
16+
],
17+
}
18+
19+
test('shows the cap notice only when provided', async ({ mount }) => {
20+
const withNotice = await mount(PermissionEditor, { props: { ...baseProps, notice: 'Limited to Can view' } })
21+
await expect(withNotice).toContainText('Limited to Can view')
22+
23+
const withoutNotice = await mount(PermissionEditor, { props: { ...baseProps, notice: null } })
24+
await expect(withoutNotice).not.toContainText('Limited to Can view')
25+
})
26+
27+
test('renders a toggle per permission and disables those over the cap', async ({ mount }) => {
28+
const component = await mount(PermissionEditor, { props: baseProps })
29+
await expect(component.getByText('Read')).toBeVisible()
30+
await expect(component.getByText('Write')).toBeVisible()
31+
await expect(component.getByRole('switch', { name: 'Read' })).toBeEnabled()
32+
await expect(component.getByRole('switch', { name: 'Write' })).toBeDisabled()
33+
})
34+
35+
test('hides the toggles when not in custom mode', async ({ mount }) => {
36+
const component = await mount(PermissionEditor, { props: { ...baseProps, showPermissions: false } })
37+
await expect(component.getByText('Read')).toBeHidden()
38+
})
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*/
5+
6+
import { expect, test } from '@playwright/experimental-ct-vue'
7+
import Fixture from '../../../tests/ct/fixtures/RecipientListFixture.vue'
8+
9+
test('renders a row per recipient, excluding the link (token)', async ({ mount }) => {
10+
const component = await mount(Fixture)
11+
await expect(component.getByText('Alice')).toBeVisible()
12+
await expect(component.getByText('Devs')).toBeVisible()
13+
// The token recipient is managed by the "Anyone" tab, not listed here.
14+
await expect(component.getByText('Public link')).toHaveCount(0)
15+
await expect(component.locator('.recipient-row')).toHaveCount(2)
16+
})
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*/
5+
6+
import { expect, test } from '@playwright/experimental-ct-vue'
7+
import Fixture from '../../../tests/ct/fixtures/RecipientRowFixture.vue'
8+
9+
test('shows the recipient name and a static preset subtitle', async ({ mount }) => {
10+
const component = await mount(Fixture)
11+
await expect(component.getByText('alice')).toBeVisible()
12+
// No preset matches an empty share max → "Custom permissions".
13+
await expect(component.locator('.recipient-row__subtitle')).toHaveText('Custom permissions')
14+
})
15+
16+
test('removes the recipient from the menu', async ({ mount, page }) => {
17+
let removed = false
18+
const onRemoved = () => {
19+
removed = true
20+
}
21+
const component = await mount(Fixture, { on: { removed: onRemoved } })
22+
await component.getByRole('button', { name: 'Recipient actions' }).click()
23+
await page.getByRole('menuitem', { name: 'Remove' }).click()
24+
expect(removed).toBe(true)
25+
})
26+
27+
test('opens the custom permissions modal from the menu', async ({ mount, page }) => {
28+
const component = await mount(Fixture)
29+
await component.getByRole('button', { name: 'Recipient actions' }).click()
30+
await page.getByRole('menuitem', { name: 'Custom permissions' }).click()
31+
await expect(page.getByRole('dialog')).toBeVisible()
32+
})

0 commit comments

Comments
 (0)