import assert from 'node:assert/strict'; import process from 'node:process'; const { chromium } = await import( process.env.PLAYWRIGHT_MODULE ?? 'playwright' ); const browser = await chromium.launch({ channel: 'chrome', headless: true }); const context = await browser.newContext({ reducedMotion: 'reduce' }); const page = await context.newPage(); page.setDefaultTimeout(10000); const errors = []; page.on('pageerror', (error) => errors.push(error.message)); const base = 'http://127.0.0.1:4197'; const result = (value) => context.addCookies([{ name: 'teams_result', value, url: base }]); const visit = async (query = '') => { await result('success'); await page.goto(base + '/teams?reset' + query); await page.getByRole('heading', { name: 'Teams', exact: true }).waitFor(); }; const button = (name) => page.getByRole('button', { name, exact: true }); const dialog = () => page.getByRole('dialog'); const state = (value) => dialog() .locator('[data-form-state="' + value + '"]') .waitFor({ state: 'visible' }); const noOverflow = async () => assert.equal( await page.evaluate( () => document.documentElement.scrollWidth <= innerWidth, ), true, ); const save = async (label) => { const request = page.waitForRequest((r) => ['POST', 'PATCH'].includes(r.method()), ); await dialog().getByRole('button', { name: label, exact: true }).click(); return (await request).postDataJSON(); }; try { for (const width of [1440, 390, 320]) { await page.setViewportSize({ width, height: 900 }); for (const theme of ['light', 'dark']) { await page.emulateMedia({ colorScheme: theme }); await visit(); await noOverflow(); await page.screenshot({ path: '/private/tmp/kan47-' + width + '-' + theme + '.png', fullPage: true, }); const trigger = button('Manage members of Platform team'); await trigger.focus(); await page.keyboard.press('Enter'); await dialog().waitFor(); await page.keyboard.press('Tab'); assert.equal( await dialog().evaluate((el) => el.contains(document.activeElement), ), true, ); await noOverflow(); await page.screenshot({ path: '/private/tmp/kan47-members-' + width + '-' + theme + '.png', fullPage: true, }); await page.keyboard.press('Escape'); await dialog().waitFor({ state: 'hidden' }); assert.equal( await trigger.evaluate((el) => document.activeElement === el), true, ); } } await visit('&manager'); assert.equal(await button('Create team').count(), 0); await visit('&empty'); await page.getByText('No teams to manage', { exact: true }).waitFor(); await visit(); await page.getByLabel('Search teams', { exact: true }).fill('missing'); await page.getByText('No matching teams', { exact: true }).waitFor(); await button('Clear search').click(); await button('Create team').click(); await page.getByLabel('Team name', { exact: true }).fill('New team'); await result('validation'); assert.deepEqual(await save('Create team'), { name: 'New team' }); await state('validation'); assert.equal( await page.getByLabel('Team name', { exact: true }).inputValue(), 'New team', ); await page .getByText('This team name is already taken.', { exact: true }) .waitFor(); await result('success'); await save('Create team'); await dialog().waitFor({ state: 'hidden' }); await page .getByRole('heading', { name: 'New team', exact: true }) .waitFor(); await button('Manage members of Platform team').click(); const person = (name) => dialog().getByRole('checkbox', { name: new RegExp(name) }); await page.getByLabel('Find people').fill('sam@'); await person('Sam Taylor').check(); await page.getByLabel('Find people').fill(''); assert.equal(await person('Alex Morgan').isChecked(), true); let dismissed = false; page.once('dialog', async (d) => { dismissed = true; await d.dismiss(); }); await dialog().getByRole('button', { name: 'Cancel', exact: true }).click(); assert.equal(dismissed, true); assert.equal(await dialog().isVisible(), true); await result('validation'); assert.deepEqual(await save('Save members'), { user_ids: [1, 2] }); await state('validation'); await page .getByText('This user is unavailable.', { exact: true }) .waitFor(); assert.equal(await person('Sam Taylor').isChecked(), true); await page.route('**/teams/1/members', (route) => route.abort('failed')); await save('Save members'); await state('network'); await page.unroute('**/teams/1/members'); await result('server'); await save('Save members'); await state('server'); await result('success'); await dialog() .getByRole('button', { name: 'Try again', exact: true }) .click(); await dialog().waitFor({ state: 'hidden' }); await button('Manage members of Platform team').click(); await person('Alex Morgan').uncheck(); await person('Sam Taylor').uncheck(); assert.deepEqual(await save('Save members'), { user_ids: [] }); await dialog().waitFor({ state: 'hidden' }); await button('Manage permissions for Platform team').click(); assert.equal( await dialog() .getByRole('button', { name: 'Save permissions', exact: true }) .isDisabled(), true, ); await page.getByLabel('User', { exact: true }).selectOption('2'); assert.equal(await person('Team invite').isChecked(), true); await person('Team manage').check(); page.once('dialog', (d) => d.dismiss()); await page.getByLabel('User', { exact: true }).selectOption('3'); assert.equal( await page.getByLabel('User', { exact: true }).inputValue(), '2', ); await result('validation'); assert.deepEqual(await save('Save permissions'), { permissions: ['team:invite', 'team:manage'], }); await state('validation'); await page .getByText('This permission is unavailable.', { exact: true }) .waitFor(); await result('forbidden'); await save('Save permissions'); await state('server'); await page .getByText('You no longer have permission', { exact: true }) .waitFor(); assert.equal( await dialog() .getByRole('button', { name: 'Try again', exact: true }) .count(), 0, ); assert.equal(await person('Team manage').isChecked(), true); await result('success'); await save('Save permissions'); await dialog().waitFor({ state: 'hidden' }); await button('Manage permissions for Platform team').click(); await page.getByLabel('User', { exact: true }).selectOption('2'); assert.equal(await person('Team manage').isChecked(), true); await person('Team invite').uncheck(); await person('Team manage').uncheck(); assert.deepEqual(await save('Save permissions'), { permissions: [] }); await dialog().waitFor({ state: 'hidden' }); assert.deepEqual(errors, []); console.log( 'Teams browser checks passed: creation, membership, permissions, empty selections, validation, network/server/403, draft protection, focus, keyboard, themes and mobile.', ); } finally { await browser.close(); }