Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions playwright/helpers/app-test-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,18 @@
page: Page,
{ kind = 'component' }: { kind?: 'component' | 'styles' } = {},
) => {
await page.getByRole('button', { name: 'Add tab options' }).click()
await page.getByRole('button', { name: 'Add workspace tab' }).click()
if (kind === 'styles') {
await page.getByRole('menuitem', { name: 'styles' }).click()
await page.getByRole('button', { name: 'Add styles tab' }).click()
return
}

await page.getByRole('menuitem', { name: 'module' }).click()
await page.getByRole('button', { name: 'Add module tab' }).click()
}

export const openWorkspaceTab = async (page: Page, fileName: string) => {
const pattern = new RegExp(`^Open tab ${escapeRegex(fileName)}$`)
await page.getByRole('tab', { name: pattern }).click()
await page.getByRole('button', { name: pattern }).click()
}

export const setWorkspaceTabSource = async (
Expand All @@ -162,7 +162,7 @@
}

export const setComponentEditorSource = async (page: Page, source: string) => {
await page.getByRole('tab', { name: 'Open tab App.tsx' }).click()
await page.getByRole('button', { name: 'Open tab App.tsx' }).click()
const editorContent = page
.locator('.editor-panel[data-editor-kind="component"] .cm-content')
.first()
Expand All @@ -173,7 +173,7 @@
}

export const setStylesEditorSource = async (page: Page, source: string) => {
await page.getByRole('tab', { name: 'Open tab app.css' }).click()
await page.getByRole('button', { name: 'Open tab app.css' }).click()
const editorContent = page
.locator('.editor-panel[data-editor-kind="styles"] .cm-content')
.first()
Expand Down Expand Up @@ -227,9 +227,9 @@
panelName: 'component' | 'styles',
) => {
if (panelName === 'styles') {
await page.getByRole('tab', { name: 'Open tab app.css' }).click()
await page.getByRole('button', { name: 'Open tab app.css' }).click()
} else {
await page.getByRole('tab', { name: 'Open tab App.tsx' }).click()
await page.getByRole('button', { name: 'Open tab App.tsx' }).click()
}

const button = getToolsButton(page, panelName)
Expand All @@ -249,7 +249,7 @@
await toggle.click()
}

await expect(page.getByRole('complementary', { name: 'Diagnostics' })).toBeVisible()

Check failure on line 252 in playwright/helpers/app-test-helpers.ts

View workflow job for this annotation

GitHub Actions / E2E (Playwright, webkit, shard 2/3)

[webkit] › playwright/rendering-modes.spec.ts:99:1 › react mode typecheck loads types without malformed URL fetches

1) [webkit] › playwright/rendering-modes.spec.ts:99:1 › react mode typecheck loads types without malformed URL fetches Error: expect(locator).toBeVisible() failed Locator: getByRole('complementary', { name: 'Diagnostics' }) Expected: visible Timeout: 90000ms Error: element(s) not found Call log: - Expect "toBeVisible" with timeout 90000ms - waiting for getByRole('complementary', { name: 'Diagnostics' }) at helpers/app-test-helpers.ts:252 250 | } 251 | > 252 | await expect(page.getByRole('complementary', { name: 'Diagnostics' })).toBeVisible() | ^ 253 | } 254 | 255 | export const ensureDiagnosticsDrawerClosed = async (page: Page) => { at ensureDiagnosticsDrawerOpen (/home/runner/work/develop/develop/playwright/helpers/app-test-helpers.ts:252:74) at /home/runner/work/develop/develop/playwright/rendering-modes.spec.ts:125:3
}

export const ensureDiagnosticsDrawerClosed = async (page: Page) => {
Expand Down
40 changes: 36 additions & 4 deletions playwright/layout-panels.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,38 @@ test('supports theme toggles', async ({ page }) => {
expect(previewBackgroundColor).toBe('rgb(36, 86, 168)')
})

test('light theme defaults preview background to white', async ({ page }) => {
await waitForInitialRender(page)

await page.getByLabel('Use light theme').click()

const previewBackgroundColor = await page.evaluate(() => {
const previewHost = document.getElementById('preview-host')
return previewHost ? getComputedStyle(previewHost).backgroundColor : ''
})

expect(previewBackgroundColor).toBe('rgb(255, 255, 255)')
})

test('dark theme defaults preview background to editor background', async ({ page }) => {
await waitForInitialRender(page)

const colors = await page.evaluate(() => {
const previewHost = document.getElementById('preview-host')
const componentPanel = document.getElementById('editor-panel-component')

return {
preview: previewHost ? getComputedStyle(previewHost).backgroundColor : '',
editor: componentPanel ? getComputedStyle(componentPanel).backgroundColor : '',
}
})

const toRgbChannels = (value: string) =>
(value.match(/\d+/g) ?? []).slice(0, 3).map(entry => Number.parseInt(entry, 10))

expect(toRgbChannels(colors.preview)).toEqual(toRgbChannels(colors.editor))
})

test('fixed layout keeps preview panel height within editor stack height', async ({
page,
}) => {
Expand Down Expand Up @@ -122,7 +154,7 @@ test('prevents collapsing all three panels at once', async ({ page }) => {
const stylesPanel = page.locator('#editor-panel-styles')

await getCollapseButton(page, 'component').click()
await page.getByRole('tab', { name: 'Open tab app.css' }).click()
await page.getByRole('button', { name: 'Open tab app.css' }).click()
await getCollapseButton(page, 'styles').click()

await expect(componentPanel).toHaveClass(/panel--collapsed-vertical/)
Expand All @@ -139,7 +171,7 @@ test('prevents collapsing all three panels at once', async ({ page }) => {
'At least one panel must remain expanded.',
)

await page.getByRole('tab', { name: 'Open tab App.tsx' }).click()
await page.getByRole('button', { name: 'Open tab App.tsx' }).click()
await getCollapseButton(page, 'component').click()
await expectCollapseButtonState(page, 'preview', {
axis: 'horizontal',
Expand Down Expand Up @@ -199,7 +231,7 @@ test('gear tools toggles default inactive and switch active/inactive per panel',
await expect(componentTools).toHaveAttribute('aria-pressed', 'false')
await expect(componentTools).toHaveAttribute('title', 'Show component tools')

await page.getByRole('tab', { name: 'Open tab app.css' }).click()
await page.getByRole('button', { name: 'Open tab app.css' }).click()
await stylesTools.click()
await expect(stylesPanel).not.toHaveClass(/panel--tools-hidden/)
await expect(stylesTools).toHaveAttribute('aria-pressed', 'true')
Expand All @@ -213,7 +245,7 @@ test('fixed layout keeps inactive editor panel hidden', async ({ page }) => {
const stylesPanel = page.locator('#editor-panel-styles')

const assertEntryPanelVisible = async () => {
await page.getByRole('tab', { name: 'Open tab App.tsx' }).click()
await page.getByRole('button', { name: 'Open tab App.tsx' }).click()
await expect(componentPanel).toBeVisible()
await expect(stylesPanel).toBeHidden()
}
Expand Down
10 changes: 5 additions & 5 deletions playwright/rendering-modes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ test('renders in react mode with css modules', async ({ page }) => {
await ensurePanelToolsVisible(page, 'component')
await ensurePanelToolsVisible(page, 'styles')

await page.getByRole('tab', { name: 'Open tab App.tsx' }).click()
await page.getByRole('button', { name: 'Open tab App.tsx' }).click()
await page.getByRole('combobox', { name: 'Render mode' }).selectOption('react')
await page.getByRole('tab', { name: 'Open tab app.css' }).click()
await page.getByRole('button', { name: 'Open tab app.css' }).click()
await page.getByRole('combobox', { name: 'Style mode' }).selectOption('module')
await expect(page.getByRole('status', { name: 'App status' })).toHaveText('Rendered')
await expectPreviewHasRenderedContent(page)
Expand Down Expand Up @@ -416,13 +416,13 @@ test('requires render button when auto render is disabled', async ({ page }) =>
const autoRenderToggle = page.getByLabel('Auto render')
const renderButton = page.getByRole('button', { name: 'Render' })

await page.getByRole('tab', { name: 'Open tab App.tsx' }).click()
await page.getByRole('button', { name: 'Open tab App.tsx' }).click()
await autoRenderToggle.uncheck()
await expect(renderButton).toBeVisible()

await page.getByRole('tab', { name: 'Open tab app.css' }).click()
await page.getByRole('button', { name: 'Open tab app.css' }).click()
await page.getByRole('combobox', { name: 'Style mode' }).selectOption('module')
await page.getByRole('tab', { name: 'Open tab App.tsx' }).click()
await page.getByRole('button', { name: 'Open tab App.tsx' }).click()

await renderButton.click()
await expect(page.getByRole('status', { name: 'App status' })).toHaveText('Rendered')
Expand Down
112 changes: 63 additions & 49 deletions playwright/workspace-tabs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,18 @@ test('removing active tab selects deterministic adjacent tab', async ({ page })
await addWorkspaceTab(page)
await addWorkspaceTab(page)

await page.getByRole('tab', { name: 'Open tab module-2.tsx' }).click()
await expect(page.getByRole('tab', { name: 'Open tab module-2.tsx' })).toHaveAttribute(
'aria-selected',
'true',
)
await page.getByRole('button', { name: 'Open tab module-2.tsx' }).click()
await expect(
page.getByRole('button', { name: 'Open tab module-2.tsx' }),
).toHaveAttribute('aria-current', 'true')

await page.getByRole('button', { name: 'Remove tab module-2.tsx' }).click()
await confirmRemoveDialog(page)

await expect(page.getByRole('tab', { name: 'Open tab module-2.tsx' })).toHaveCount(0)
await expect(page.getByRole('tab', { name: 'Open tab module-3.tsx' })).toHaveAttribute(
'aria-selected',
'true',
)
await expect(page.getByRole('button', { name: 'Open tab module-2.tsx' })).toHaveCount(0)
await expect(
page.getByRole('button', { name: 'Open tab module-3.tsx' }),
).toHaveAttribute('aria-current', 'true')
})

test('removing non-active tab does not change active tab', async ({ page }) => {
Expand All @@ -62,20 +60,18 @@ test('removing non-active tab does not change active tab', async ({ page }) => {
await addWorkspaceTab(page)
await addWorkspaceTab(page)

await page.getByRole('tab', { name: 'Open tab module-3.tsx' }).click()
await expect(page.getByRole('tab', { name: 'Open tab module-3.tsx' })).toHaveAttribute(
'aria-selected',
'true',
)
await page.getByRole('button', { name: 'Open tab module-3.tsx' }).click()
await expect(
page.getByRole('button', { name: 'Open tab module-3.tsx' }),
).toHaveAttribute('aria-current', 'true')

await page.getByRole('button', { name: 'Remove tab module-2.tsx' }).click()
await confirmRemoveDialog(page)

await expect(page.getByRole('tab', { name: 'Open tab module-2.tsx' })).toHaveCount(0)
await expect(page.getByRole('tab', { name: 'Open tab module-3.tsx' })).toHaveAttribute(
'aria-selected',
'true',
)
await expect(page.getByRole('button', { name: 'Open tab module-2.tsx' })).toHaveCount(0)
await expect(
page.getByRole('button', { name: 'Open tab module-3.tsx' }),
).toHaveAttribute('aria-current', 'true')
})

test('renaming module tab keeps name and path synchronized', async ({ page }) => {
Expand All @@ -87,9 +83,9 @@ test('renaming module tab keeps name and path synchronized', async ({ page }) =>
to: 'card-item.tsx',
})

const tab = page.getByRole('tab', { name: 'Open tab card-item.tsx' })
const tab = page.getByRole('button', { name: 'Open tab card-item.tsx' })
await expect(tab).toHaveAttribute('title', 'src/components/card-item.tsx')
await expect(page.getByRole('tab', { name: 'Open tab module.tsx' })).toHaveCount(0)
await expect(page.getByRole('button', { name: 'Open tab module.tsx' })).toHaveCount(0)
})

test('renaming module tab preserves source content', async ({ page }) => {
Expand All @@ -107,8 +103,8 @@ test('renaming module tab preserves source content', async ({ page }) => {
to: 'value-card.tsx',
})

await page.getByRole('tab', { name: 'Open tab App.tsx' }).click()
await page.getByRole('tab', { name: 'Open tab value-card.tsx' }).click()
await page.getByRole('button', { name: 'Open tab App.tsx' }).click()
await page.getByRole('button', { name: 'Open tab value-card.tsx' }).click()

const editorContent = page
.locator('.editor-panel[data-editor-kind="component"] .cm-content')
Expand All @@ -125,27 +121,26 @@ test('active tab remains source of truth for visible editor panel', async ({ pag
const componentPanel = page.locator('#editor-panel-component')
const stylesPanel = page.locator('#editor-panel-styles')

await page.getByRole('tab', { name: 'Open tab app.css' }).click()
await expect(page.getByRole('tab', { name: 'Open tab app.css' })).toHaveAttribute(
'aria-selected',
await page.getByRole('button', { name: 'Open tab app.css' }).click()
await expect(page.getByRole('button', { name: 'Open tab app.css' })).toHaveAttribute(
'aria-current',
'true',
)
await expect(stylesPanel).not.toHaveAttribute('hidden', '')
await expect(componentPanel).toHaveAttribute('hidden', '')

await page.getByRole('tab', { name: 'Open tab module-2.tsx' }).click()
await expect(page.getByRole('tab', { name: 'Open tab module-2.tsx' })).toHaveAttribute(
'aria-selected',
'true',
)
await page.getByRole('button', { name: 'Open tab module-2.tsx' }).click()
await expect(
page.getByRole('button', { name: 'Open tab module-2.tsx' }),
).toHaveAttribute('aria-current', 'true')
await expect(componentPanel).not.toHaveAttribute('hidden', '')
await expect(stylesPanel).toHaveAttribute('hidden', '')

await page.locator('#collapse-component').click()
await page.getByRole('tab', { name: 'Open tab app.css' }).click()
await page.getByRole('button', { name: 'Open tab app.css' }).click()

await expect(page.getByRole('tab', { name: 'Open tab app.css' })).toHaveAttribute(
'aria-selected',
await expect(page.getByRole('button', { name: 'Open tab app.css' })).toHaveAttribute(
'aria-current',
'true',
)
await expect(stylesPanel).not.toHaveAttribute('hidden', '')
Expand All @@ -158,31 +153,29 @@ test('startup restores last active workspace tab after reload', async ({ page })
await addWorkspaceTab(page)
await addWorkspaceTab(page)

await page.getByRole('tab', { name: 'Open tab module-2.tsx' }).click()
await expect(page.getByRole('tab', { name: 'Open tab module-2.tsx' })).toHaveAttribute(
'aria-selected',
'true',
)
await page.getByRole('button', { name: 'Open tab module-2.tsx' }).click()
await expect(
page.getByRole('button', { name: 'Open tab module-2.tsx' }),
).toHaveAttribute('aria-current', 'true')

await page.reload()
await waitForInitialRender(page)

await expect(page.getByRole('tab', { name: 'Open tab module-2.tsx' })).toHaveAttribute(
'aria-selected',
'true',
)
await expect(
page.getByRole('button', { name: 'Open tab module-2.tsx' }),
).toHaveAttribute('aria-current', 'true')
await expect(page.locator('#editor-panel-component')).not.toHaveAttribute('hidden', '')
await expect(page.locator('#editor-panel-styles')).toHaveAttribute('hidden', '')
})

test('add menu can create styles tab while component tab is active', async ({ page }) => {
await waitForInitialRender(page)

await page.getByRole('tab', { name: 'Open tab App.tsx' }).click()
await page.getByRole('button', { name: 'Open tab App.tsx' }).click()
await addWorkspaceTab(page, { kind: 'styles' })

await expect(page.getByRole('tab', { name: 'Open tab module.css' })).toHaveAttribute(
'aria-selected',
await expect(page.getByRole('button', { name: 'Open tab module.css' })).toHaveAttribute(
'aria-current',
'true',
)
await expect(page.locator('#editor-panel-styles')).not.toHaveAttribute('hidden', '')
Expand All @@ -197,8 +190,8 @@ test('add menu stays closed until triggered and closes on outside click', async
}) => {
await waitForInitialRender(page)

const addButton = page.getByRole('button', { name: 'Add tab options' })
const addMenu = page.getByRole('menu', { name: 'Add tab type' })
const addButton = page.getByRole('button', { name: 'Add workspace tab' })
const addMenu = page.getByRole('group', { name: 'Add workspace tab' })

await expect(addMenu).toBeHidden()
await addButton.click()
Expand All @@ -207,3 +200,24 @@ test('add menu stays closed until triggered and closes on outside click', async
await page.getByRole('status', { name: 'App status' }).click()
await expect(addMenu).toBeHidden()
})

test('add menu keyboard interaction manages focus on open and escape close', async ({
page,
}) => {
await waitForInitialRender(page)

const addButton = page.getByRole('button', { name: 'Add workspace tab' })
const addMenu = page.getByRole('group', { name: 'Add workspace tab' })
const addModuleButton = page.getByRole('button', { name: 'Add module tab' })

await addButton.focus()
await page.keyboard.press('ArrowDown')

await expect(addMenu).toBeVisible()
await expect(addModuleButton).toBeFocused()

await page.keyboard.press('Escape')

await expect(addMenu).toBeHidden()
await expect(addButton).toBeFocused()
})
Loading
Loading