This is an automated email from the ASF dual-hosted git repository.
bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 0f7f45f674c Fix XComs e2e filter tests: scope the filter input by
testid (#72438)
0f7f45f674c is described below
commit 0f7f45f674cbd2575c365107f843d2872980760f
Author: Kunal <[email protected]>
AuthorDate: Fri Sep 4 22:11:30 2026 +0530
Fix XComs e2e filter tests: scope the filter input by testid (#72438)
* Fix XComs e2e filter tests: scope the filter input by testid
xcoms.spec.ts's filter tests locate the active filter pill's input via
page.locator("div").filter({ hasText: `${filterName}:` }), which
matches any ancestor whose descendant text contains that string.
#71554 restructured the filter bar's DOM so more than one ancestor now
matches, and .first() no longer reliably picks the actual pill -
getByRole("textbox") on it resolves to every textbox inside whichever
div wins, throwing "resolved to 12 elements instead of 1".
Give the actively-editing pill's input a stable data-testid
(filter-pill-input) instead of relying on ancestor text matching, and
scope XComsPage.applyFilter() to it directly. Only one pill is ever in
edit mode at a time, so the testid alone is enough - no per-filter key
plumbing needed.
Added a FilterBar test that fails without the fix (verified locally by
reverting the testid and confirming the new test - and only that
test - breaks).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015kAvbZ6SeKgp6jbGcvpXSh
* Add newsfragment
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015kAvbZ6SeKgp6jbGcvpXSh
* Revert "Add newsfragment"
This reverts commit 06fd055afb8fa6f4f3c6b7ea31d5c0920ee850ed.
---------
Co-authored-by: Claude <[email protected]>
Co-authored-by: Kunal8954 <[email protected]>
---
.../ui/src/components/FilterBar/FilterBar.test.tsx | 18 ++++++++++++++++++
.../components/FilterBar/filters/TextSearchFilter.tsx | 1 +
.../src/airflow/ui/tests/e2e/pages/XComsPage.ts | 11 ++++++-----
3 files changed, 25 insertions(+), 5 deletions(-)
diff --git
a/airflow-core/src/airflow/ui/src/components/FilterBar/FilterBar.test.tsx
b/airflow-core/src/airflow/ui/src/components/FilterBar/FilterBar.test.tsx
index 3b324a891e2..7b4e7326cfb 100644
--- a/airflow-core/src/airflow/ui/src/components/FilterBar/FilterBar.test.tsx
+++ b/airflow-core/src/airflow/ui/src/components/FilterBar/FilterBar.test.tsx
@@ -198,6 +198,24 @@ describe("FilterBar abandoned filters", () => {
});
});
+describe("FilterBar text filter input testid", () => {
+ it("exposes the actively-editing pill's input via a stable, unique testid",
async () => {
+ render(<FilterBar configs={[textConfig]} onFiltersChange={vi.fn()} />, {
wrapper });
+
+ fireEvent.click(screen.getByTestId("add-filter-button"));
+ fireEvent.click(await screen.findByTestId("add-filter-dag_id"));
+
+ // Regression guard for #72433: e2e tests locate this input via
`filter-pill-input`
+ // rather than `page.locator("div").filter({ hasText })`, which matched
any ancestor
+ // whose descendant text contained the filter label and broke once the
filter bar's
+ // DOM was restructured. `getByTestId` throws if more than one match is
found, so this
+ // also proves the testid stays unique while a pill is being edited.
+ const input = screen.getByTestId("filter-pill-input");
+
+ expect(input).toBe(screen.getByRole("textbox"));
+ });
+});
+
describe("FilterBar keyboard handling", () => {
it("leaves Enter to editors that use it to commit a value", async () => {
render(<FilterBar configs={[multiSelectConfig]} onFiltersChange={vi.fn()}
/>, { wrapper });
diff --git
a/airflow-core/src/airflow/ui/src/components/FilterBar/filters/TextSearchFilter.tsx
b/airflow-core/src/airflow/ui/src/components/FilterBar/filters/TextSearchFilter.tsx
index 045900f10e5..b0754174385 100644
---
a/airflow-core/src/airflow/ui/src/components/FilterBar/filters/TextSearchFilter.tsx
+++
b/airflow-core/src/airflow/ui/src/components/FilterBar/filters/TextSearchFilter.tsx
@@ -77,6 +77,7 @@ export const TextSearchFilter = ({ filter, onChange, onRemove
}: FilterPluginPro
renderInput={(props) => (
<InputWithAddon
{...props}
+ data-testid="filter-pill-input"
endAddon={
showAdvancedToggle ? (
<AdvancedSearchToggle enabled={advanced.enabled}
onToggle={advanced.onToggle} variant="addon" />
diff --git a/airflow-core/src/airflow/ui/tests/e2e/pages/XComsPage.ts
b/airflow-core/src/airflow/ui/tests/e2e/pages/XComsPage.ts
index 88c9566ffde..30e5b8b2f8f 100644
--- a/airflow-core/src/airflow/ui/tests/e2e/pages/XComsPage.ts
+++ b/airflow-core/src/airflow/ui/tests/e2e/pages/XComsPage.ts
@@ -53,11 +53,12 @@ export class XComsPage extends BasePage {
await filterOption.click();
- const filterPill = this.page
- .locator("div")
- .filter({ hasText: `${filterName}:` })
- .first();
- const filterInput = filterPill.getByRole("textbox");
+ // The newly added pill enters edit mode immediately, and
`filter-pill-input` is only
+ // rendered on the pill that is actively being edited — so this resolves
to exactly one
+ // element. Previously this scoped through `page.locator("div").filter({
hasText: ... })`,
+ // which matches any ancestor whose descendant text contains
"<filterName>:" and broke
+ // (matched 12 elements instead of 1) once #71554 restructured the filter
bar's DOM.
+ const filterInput = this.page.getByTestId("filter-pill-input");
await expect(filterInput).toBeVisible({ timeout: 30_000 });
await filterInput.fill(value);