Improve Linear filter test clarity and fix e2e overlay dismissal for CI

- Convert parameterized filter-pruning test to sequential assertions
- Fix dismissOverlayChrome to toggle overlay triggers instead of
  force-clicking inert page elements in headless CI
This commit is contained in:
Jinjing
2026-08-07 20:21:53 -07:00
parent c17a41826b
commit 4a395007be
2 changed files with 38 additions and 39 deletions
@@ -182,10 +182,7 @@ describe('LinearIssueAttributeFilterDropdowns', () => {
// Why: restored filters render before the team fetch settles, when availableTeams is
// still the issue-scraped subset — pruning there deletes another team's facets for good.
it.each([
[false, false],
[true, true]
])('prunes unknown facet ids only once teams are settled (%s)', (teamsSettled, expectPrune) => {
it('prunes unknown facet ids only once teams settle on the mounted component', () => {
const team: LinearTeam = { id: 'team-1', name: 'Engineering', key: 'ENG' }
const onChange = vi.fn()
const container = document.createElement('div')
@@ -193,31 +190,33 @@ describe('LinearIssueAttributeFilterDropdowns', () => {
const root = createRoot(container)
roots.push(root)
act(() => {
root.render(
<LinearIssueAttributeFilterDropdowns
value={{
stateIds: ['state-from-another-team'],
priorities: [],
assignee: null,
labelIds: []
}}
onChange={onChange}
workspaceId="workspace-1"
primaryTeam={team}
selectedTeamIds={[]}
availableTeams={[team]}
teamsSettled={teamsSettled}
/>
)
})
if (expectPrune) {
expect(onChange).toHaveBeenCalledWith(
expect.objectContaining({ stateIds: [], labelIds: [], assignee: null })
)
} else {
expect(onChange).not.toHaveBeenCalled()
const renderWith = (teamsSettled: boolean): void => {
act(() => {
root.render(
<LinearIssueAttributeFilterDropdowns
value={{
stateIds: ['state-from-another-team'],
priorities: [],
assignee: null,
labelIds: []
}}
onChange={onChange}
workspaceId="workspace-1"
primaryTeam={team}
selectedTeamIds={[]}
availableTeams={[team]}
teamsSettled={teamsSettled}
/>
)
})
}
renderWith(false)
expect(onChange).not.toHaveBeenCalled()
renderWith(true)
expect(onChange).toHaveBeenCalledWith(
expect.objectContaining({ stateIds: [], labelIds: [], assignee: null })
)
})
})
+10 -10
View File
@@ -253,17 +253,17 @@ async function openViewMenu(page: Page): Promise<void> {
}
async function dismissOverlayChrome(page: Page): Promise<void> {
// Why: open Radix menus aria-hide the rest of the page so later getByRole for
// Filters/chips fails. Escape is unsafe (Tasks treats it as leave-page). Click
// the issues heading, which stays outside the menu portal.
if (
(await page.getByRole('menuitemradio', { name: 'Board' }).count()) === 0 &&
(await page.locator('[data-slot="popover-content"]').count()) === 0
) {
return
// Why: open Radix menus aria-hide/inert the rest of the page so later getByRole
// for Filters/chips fails. Escape is unsafe (Tasks treats it as leave-page).
// Force-clicking inert page chrome does not close modal menus in headless CI —
// toggle the View trigger (not inert) and the Filters button for popovers.
if ((await page.getByRole('menuitemradio', { name: 'Board' }).count()) > 0) {
await page.getByRole('button', { name: 'View', exact: true }).click()
}
if ((await page.locator('[data-slot="popover-content"]').count()) > 0) {
const filtersButton = page.getByRole('button', { name: 'Filters', exact: true })
await ((await filtersButton.count()) > 0 ? filtersButton.click() : page.mouse.click(24, 24))
}
const heading = page.getByText('Linear issues', { exact: true }).first()
await ((await heading.count()) > 0 ? heading.click({ force: true }) : page.mouse.click(24, 24))
await expect(page.getByRole('menuitemradio', { name: 'Board' })).toHaveCount(0)
await expect(page.locator('[data-slot="popover-content"]')).toHaveCount(0)
}