From f14f393d1a88db25d7095388d5618d321d156590 Mon Sep 17 00:00:00 2001 From: Joe Li Date: Wed, 20 May 2026 14:45:00 -0700 Subject: [PATCH] fix(playwright): inject data-test attrs via antd rowSelection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `TableCollection` uses antd Table's `rowSelection` API, which renders its own checkbox column. The `data-test="header-toggle-all"` and `data-test="row-select-checkbox"` attributes in `ListView.tsx`'s `bulkSelectColumnConfig` were processed by `mapColumns` but its `Header` function was captured as a non-invoked ReactNode and its `Cell` received a row missing react-table's prepared selection props — so neither attribute actually reached the DOM. Wrap antd's default checkbox nodes via `rowSelection.columnTitle` and `rowSelection.renderCell` so the existing Playwright selectors resolve against the real checkboxes that antd renders. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/TableCollection/index.tsx | 13 ++++++++++++- .../playwright/components/ListView/BulkSelect.ts | 15 ++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/superset-frontend/packages/superset-ui-core/src/components/TableCollection/index.tsx b/superset-frontend/packages/superset-ui-core/src/components/TableCollection/index.tsx index b9e00f5940f..6c1ca38a131 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/TableCollection/index.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/TableCollection/index.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { HTMLAttributes, memo, useMemo, useCallback } from 'react'; +import { HTMLAttributes, ReactNode, memo, useMemo, useCallback } from 'react'; import { ColumnInstance, HeaderGroup, @@ -196,6 +196,11 @@ function TableCollection({ const rowSelection: TableRowSelection | undefined = useMemo(() => { if (!bulkSelectEnabled) return undefined; + // antd Table's `rowSelection` API renders its own checkbox column; + // wrap the header and per-row checkboxes with stable `data-test` + // attributes so Playwright selectors (which previously targeted + // `bulkSelectColumnConfig` in ListView — a column that no longer + // reaches the rendered DOM) can resolve them. return { selectedRowKeys, onSelect: (record, selected) => { @@ -204,6 +209,12 @@ function TableCollection({ onSelectAll: (selected: boolean) => { toggleAllRowsSelected?.(selected); }, + columnTitle: (originNode: ReactNode) => ( + {originNode} + ), + renderCell: (_value, _record, _index, originNode) => ( + {originNode} + ), }; }, [ bulkSelectEnabled, diff --git a/superset-frontend/playwright/components/ListView/BulkSelect.ts b/superset-frontend/playwright/components/ListView/BulkSelect.ts index 94f52d7885a..0187fe6b8db 100644 --- a/superset-frontend/playwright/components/ListView/BulkSelect.ts +++ b/superset-frontend/playwright/components/ListView/BulkSelect.ts @@ -68,18 +68,15 @@ export class BulkSelect { /** * Enables bulk selection mode by clicking the toggle button. * - * Waits for the bulk-select column header checkbox to be present in the - * DOM (state: 'attached') so the next row interaction does not race the - * table re-render that adds the checkbox column. We can't wait for - * 'visible' because `data-test="header-toggle-all"` ends up on antd's - * inner ``, which renders with opacity:0 and a zero bounding box - * — never "visible" by Playwright's definition. + * Waits for the bulk-select column header to render so the next row + * interaction does not race the table re-render that adds the checkbox + * column. The `data-test="header-toggle-all"` attribute is on a wrapper + * span around antd's select-all checkbox (see `TableCollection`'s + * `rowSelection.columnTitle`), which is a real visible element. */ async enable(): Promise { await this.getToggleButton().click(); - await this.page - .locator(BULK_SELECT_SELECTORS.HEADER_TOGGLE) - .waitFor({ state: 'attached' }); + await this.page.locator(BULK_SELECT_SELECTORS.HEADER_TOGGLE).waitFor(); } /**