Problem
The e2e test Check that the filter tags match the selected filter for an arbitrary filter on the BioSamples tab (e2e/anvil/anvil-filters.spec.ts:139) is intermittently failing in CI.
Latest failure
[chromium] › e2e/anvil/anvil-filters.spec.ts:139:5
Error: expect(locator).toBeVisible() failed
Locator: locator('#sidebar-positioner').getByText('.md5', { exact: true })
Expected: visible
Timeout: 15000ms
Error: element(s) not found
at testFunctions.ts:632
630 | // Click the filter tag
631 | const filterTagLocator = getFilterTagLocator(page, firstFilterOptionName);
> 632 | await expect(filterTagLocator).toBeVisible();
128/129 passed; 1 failed.
Likely root cause
The shared helper testFilterTags in e2e/testFunctions.ts:608-644 is brittle:
- Positional first-option locator —
getFirstFilterOptionLocator(page) selects the first item by index. If the option list re-sorts after a click (selected items often float to the top, or counts change ordering), the helper's subsequent assertions can target the wrong row.
- Text-only filter tag lookup —
getFilterTagLocator (line 595) does page.locator('#sidebar-positioner').getByText(filterTagName, { exact: true }). For an option name like .md5, this is exact-text in a CSS-positional container with no test-id; it's susceptible to layout/timing differences (chip not rendered yet, surrounding wrapper slightly different).
innerText().split("\n") — the option name is extracted by splitting innerText on newlines and finding the first non-empty piece. Fragile to whitespace/markup changes.
- Generic load-state waits —
page.waitForLoadState("load") doesn't wait for the post-filter-application UI updates; the chip can still be mid-mount when the assertion runs.
Proposed fix
Rewrite e2e/anvil/anvil-filters.spec.ts (and the shared helpers in e2e/testFunctions.ts it depends on) in the style of the recently updated e2e/anvil-catalog/anvilcatalog-filters.spec.ts:
- Use test-id-based locators (
TEST_IDS.FILTERS, TEST_IDS.FILTER_POPOVER, TEST_IDS.FILTER_ITEM, TEST_IDS.FILTER_TERM) instead of CSS IDs and text-only matches.
- Extract the option display name via
getByTestId(TEST_IDS.FILTER_TERM).innerText() rather than innerText().split("\n").
- Re-locate selected items by name after each interaction (see
namedPopoverFilterItem / namedFilterItem in the catalog spec) so list re-sorts don't desynchronize the assertion target from the actual selected item.
- Locate filter tags via the MUI Chip class scoped to the filters container (see
filterTag() helper in catalog spec) — more specific than #sidebar-positioner text.
- Add explicit popover open/close waits (
expectFilterPopoverOpen / expectFilterPopoverClosed) instead of generic waitForLoadState("load").
- Escape RegExp special chars in option names with
escapeRegExp (option names like .md5 would otherwise be interpreted as regex if matched without exactness).
Acceptance criteria
- The BioSamples filter-tag test runs reliably in CI (no flakes across multiple runs).
- The Files tab equivalent (line 129) is migrated to the same pattern.
- Test-id-based locators replace
#sidebar-positioner text lookups in this spec.
- Helpers shared with this spec in
e2e/testFunctions.ts are either updated or replaced with locally-defined helpers in the catalog-spec style.
Reference
- Failing helper:
e2e/testFunctions.ts:608-644 (testFilterTags), e2e/testFunctions.ts:595 (getFilterTagLocator)
- Reference style:
e2e/anvil-catalog/anvilcatalog-filters.spec.ts
Problem
The e2e test
Check that the filter tags match the selected filter for an arbitrary filter on the BioSamples tab(e2e/anvil/anvil-filters.spec.ts:139) is intermittently failing in CI.Latest failure
128/129 passed; 1 failed.
Likely root cause
The shared helper
testFilterTagsine2e/testFunctions.ts:608-644is brittle:getFirstFilterOptionLocator(page)selects the first item by index. If the option list re-sorts after a click (selected items often float to the top, or counts change ordering), the helper's subsequent assertions can target the wrong row.getFilterTagLocator(line 595) doespage.locator('#sidebar-positioner').getByText(filterTagName, { exact: true }). For an option name like.md5, this is exact-text in a CSS-positional container with no test-id; it's susceptible to layout/timing differences (chip not rendered yet, surrounding wrapper slightly different).innerText().split("\n")— the option name is extracted by splitting innerText on newlines and finding the first non-empty piece. Fragile to whitespace/markup changes.page.waitForLoadState("load")doesn't wait for the post-filter-application UI updates; the chip can still be mid-mount when the assertion runs.Proposed fix
Rewrite
e2e/anvil/anvil-filters.spec.ts(and the shared helpers ine2e/testFunctions.tsit depends on) in the style of the recently updatede2e/anvil-catalog/anvilcatalog-filters.spec.ts:TEST_IDS.FILTERS,TEST_IDS.FILTER_POPOVER,TEST_IDS.FILTER_ITEM,TEST_IDS.FILTER_TERM) instead of CSS IDs and text-only matches.getByTestId(TEST_IDS.FILTER_TERM).innerText()rather thaninnerText().split("\n").namedPopoverFilterItem/namedFilterItemin the catalog spec) so list re-sorts don't desynchronize the assertion target from the actual selected item.filterTag()helper in catalog spec) — more specific than#sidebar-positionertext.expectFilterPopoverOpen/expectFilterPopoverClosed) instead of genericwaitForLoadState("load").escapeRegExp(option names like.md5would otherwise be interpreted as regex if matched without exactness).Acceptance criteria
#sidebar-positionertext lookups in this spec.e2e/testFunctions.tsare either updated or replaced with locally-defined helpers in the catalog-spec style.Reference
e2e/testFunctions.ts:608-644(testFilterTags),e2e/testFunctions.ts:595(getFilterTagLocator)e2e/anvil-catalog/anvilcatalog-filters.spec.ts