main
ts 99 lines 3.72 KB
Raw
1 import { test, expect, Page } from '@playwright/test'
2 import { clickAdminMenu, loginAdmin } from './common'
3
4 const pluginId = 'test'
5
6 function pluginRow(page: Page) {
7 // target the fixture plugin row because other running plugins can expose their own Options button
8 return page.getByRole('grid').getByRole('row', { name: new RegExp(`\\b${pluginId}\\b`) })
9 }
10
11 async function ensureAuthAndGoPlugins(page: Page) {
12 // loginAdmin doesn't wait for auth completion — navigate to Options first to confirm
13 await clickAdminMenu(page, 'Options')
14 await expect(page.getByText('Correctly working on port')).toBeVisible({ timeout: 10_000 })
15 await clickAdminMenu(page, 'Plugins')
16 // wouter navigation settles slightly after the click; wait until the transient dialog marker is gone before using the page as a baseline
17 await expect.poll(() => page.evaluate(() => history.state?.$dialog), { timeout: 10_000 }).toBeUndefined()
18 await page.waitForTimeout(1000)
19 const row = pluginRow(page)
20 await expect(row).toBeVisible({ timeout: 10_000 })
21 const startButton = row.getByRole('button', { name: new RegExp(`^Start ${pluginId}$`) })
22 if (await startButton.count())
23 await startButton.click()
24 }
25
26 async function open3NestedDialogs(page: Page) {
27 // dialog 1: test plugin config
28 const row = pluginRow(page)
29 await row.getByRole('button', { name: 'Options' }).click()
30 await expect(page.getByText(`Options for ${pluginId}`)).toBeVisible({ timeout: 5000 })
31
32 // dialog 2: Add entry in ArrayField
33 await page.getByRole('button', { name: 'Add' }).click()
34 const addDialog = page.getByRole('dialog', { name: /Add/ })
35 await expect(addDialog).toBeVisible({ timeout: 5000 })
36
37 // dialog 3: Browse files picker (inside Add dialog)
38 await addDialog.getByRole('button', { name: 'Browse files...' }).click()
39 await expect(page.locator('.MuiDialog-root')).toHaveCount(3, { timeout: 5000 })
40 }
41
42 async function pressTopDialogEscape(page: Page, remainingDialogs: number) {
43 await page.locator('.MuiDialog-container').last().press('Escape')
44 await expect(page.locator('.MuiDialog-root')).toHaveCount(remainingDialogs, { timeout: 5000 })
45 }
46
47 async function expectDialogsClosed(page: Page) {
48 await expect(page.locator('.MuiDialog-root')).toHaveCount(0, { timeout: 10_000 })
49 await page.waitForTimeout(3000)
50 await expect(page.getByRole('heading', { name: 'Plugins' })).toBeVisible({ timeout: 10_000 })
51 }
52
53 test('nested dialog ESC does not overshoot history', async ({ page }) => {
54 await loginAdmin(page)
55 await ensureAuthAndGoPlugins(page)
56
57 await open3NestedDialogs(page)
58
59 // close all 3 dialogs via ESC
60 for (const remainingDialogs of [2, 1, 0])
61 await pressTopDialogEscape(page, remainingDialogs)
62
63 await expectDialogsClosed(page)
64 expect(page.url()).toContain('~/admin')
65 })
66
67 test('nested dialog browser-back does not overshoot', async ({ page }) => {
68 await loginAdmin(page)
69 await ensureAuthAndGoPlugins(page)
70
71 await open3NestedDialogs(page)
72
73 // rapid browser back ×3
74 await page.evaluate(() => {
75 setTimeout(() => history.back(), 0)
76 setTimeout(() => history.back(), 1000)
77 setTimeout(() => history.back(), 2000)
78 })
79
80 await page.waitForTimeout(3000)
81
82 await expectDialogsClosed(page)
83 expect(page.url()).toContain('~/admin')
84 })
85
86 test('repeated nested dialog open/close cycles', async ({ page }) => {
87 await loginAdmin(page)
88 await ensureAuthAndGoPlugins(page)
89
90 for (let cycle = 0; cycle < 5; cycle++) {
91 await open3NestedDialogs(page)
92
93 for (const remainingDialogs of [2, 1, 0])
94 await pressTopDialogEscape(page, remainingDialogs)
95
96 await expectDialogsClosed(page)
97 expect(page.url()).toContain('~/admin')
98 }
99 })