This is an automated email from the ASF dual-hosted git repository. jli pushed a commit to branch feat/dataset-playwright-tests in repository https://gitbox.apache.org/repos/asf/superset.git
commit fa114e8693b3438bd985df7e3064c1505c0ea9cd Author: Joe Li <[email protected]> AuthorDate: Wed Nov 12 13:13:02 2025 -0800 refactor(playwright): harden dataset E2E tests - Remove hardcoded birth_names dependency (create test data via API) - Fix JSON template injection in createGsheetsDatabase (use JSON.stringify) - Add TypeScript interfaces for API payloads (DatabaseCreatePayload, DatasetCreatePayload) Tests remain in experimental/ directory until proven stable. Keeps test.describe structure per Playwright best practices. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> --- .../playwright/helpers/api/database.factories.ts | 9 ++++++- .../playwright/helpers/api/database.ts | 31 ++++++++++++++++++++-- .../playwright/helpers/api/dataset.ts | 13 ++++++++- .../experimental/dataset/dataset-list.spec.ts | 23 ++++++++++------ 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/superset-frontend/playwright/helpers/api/database.factories.ts b/superset-frontend/playwright/helpers/api/database.factories.ts index 7e1ede2855..6fa5c764e0 100644 --- a/superset-frontend/playwright/helpers/api/database.factories.ts +++ b/superset-frontend/playwright/helpers/api/database.factories.ts @@ -49,7 +49,14 @@ export async function createGsheetsDatabase( }, driver: 'apsw', sqlalchemy_uri_placeholder: 'gsheets://', - extra: `{"allows_virtual_table_explore":true,"engine_params":{"catalog":{"${tableName}":"${NETFLIX_TITLES_SHEET}"}}}`, + extra: JSON.stringify({ + allows_virtual_table_explore: true, + engine_params: { + catalog: { + [tableName]: NETFLIX_TITLES_SHEET, + }, + }, + }), expose_in_sqllab: true, catalog: [ { diff --git a/superset-frontend/playwright/helpers/api/database.ts b/superset-frontend/playwright/helpers/api/database.ts index e3fac9e5fc..31955393ca 100644 --- a/superset-frontend/playwright/helpers/api/database.ts +++ b/superset-frontend/playwright/helpers/api/database.ts @@ -24,15 +24,42 @@ const ENDPOINTS = { DATABASE: 'api/v1/database/', } as const; +/** + * TypeScript interface for database creation API payload + * Provides compile-time safety for required fields + */ +export interface DatabaseCreatePayload { + database_name: string; + engine: string; + configuration_method?: string; + engine_information?: { + disable_ssh_tunneling?: boolean; + supports_dynamic_catalog?: boolean; + supports_file_upload?: boolean; + supports_oauth2?: boolean; + }; + driver?: string; + sqlalchemy_uri_placeholder?: string; + extra?: string; + expose_in_sqllab?: boolean; + catalog?: Array<{ name: string; value: string }>; + parameters?: { + service_account_info?: string; + catalog?: Record<string, string>; + }; + masked_encrypted_extra?: string; + impersonate_user?: boolean; +} + /** * POST request to create a database connection * @param page - Playwright page instance (provides authentication context) - * @param requestBody - Database configuration object + * @param requestBody - Database configuration object with type safety * @returns API response from database creation */ export async function apiPostDatabase( page: Page, - requestBody: object, + requestBody: DatabaseCreatePayload, ): Promise<APIResponse> { return apiPost(page, ENDPOINTS.DATABASE, requestBody); } diff --git a/superset-frontend/playwright/helpers/api/dataset.ts b/superset-frontend/playwright/helpers/api/dataset.ts index b126781311..46166ffcdc 100644 --- a/superset-frontend/playwright/helpers/api/dataset.ts +++ b/superset-frontend/playwright/helpers/api/dataset.ts @@ -24,6 +24,17 @@ const ENDPOINTS = { DATASET: 'api/v1/dataset/', } as const; +/** + * TypeScript interface for dataset creation API payload + * Provides compile-time safety for required fields + */ +export interface DatasetCreatePayload { + database: number; + catalog: string | null; + schema: string; + table_name: string; +} + /** * POST request to create a dataset * @param page - Playwright page instance (provides authentication context) @@ -32,7 +43,7 @@ const ENDPOINTS = { */ export async function apiPostDataset( page: Page, - requestBody: object, + requestBody: DatasetCreatePayload, ): Promise<APIResponse> { return apiPost(page, ENDPOINTS.DATASET, requestBody); } diff --git a/superset-frontend/playwright/tests/experimental/dataset/dataset-list.spec.ts b/superset-frontend/playwright/tests/experimental/dataset/dataset-list.spec.ts index 11783bf0dc..a95c4e5b8a 100644 --- a/superset-frontend/playwright/tests/experimental/dataset/dataset-list.spec.ts +++ b/superset-frontend/playwright/tests/experimental/dataset/dataset-list.spec.ts @@ -71,22 +71,29 @@ test.describe('Dataset List', () => { return Promise.all(promises); } - test('should navigate to Explore when dataset name is clicked', async () => { - // Test uses existing fixture dataset 'birth_names' - // (available in Superset examples database) + test('should navigate to Explore when dataset name is clicked', async ({ + page, + }) => { + // Create test dataset (hermetic - no dependency on sample data) + const datasetName = `test_nav_${Date.now()}`; + testResources = await createTestDataset(page, datasetName); + + // Refresh page to see new dataset + await datasetListPage.goto(); + await datasetListPage.waitForTableLoad(); // Verify dataset is visible in list (uses page object + Playwright auto-wait) - await expect(datasetListPage.getDatasetRow('birth_names')).toBeVisible(); + await expect(datasetListPage.getDatasetRow(datasetName)).toBeVisible(); // Click on dataset name to navigate to Explore - await datasetListPage.clickDatasetName('birth_names'); + await datasetListPage.clickDatasetName(datasetName); // Wait for Explore page to load (validates URL + datasource control) await explorePage.waitForPageLoad(); // Verify correct dataset is loaded in datasource control - const datasetName = await explorePage.getDatasetName(); - expect(datasetName).toContain('birth_names'); + const loadedDatasetName = await explorePage.getDatasetName(); + expect(loadedDatasetName).toContain(datasetName); // Verify visualization switcher shows default viz type (indicates full page load) await expect(explorePage.getVizSwitcher()).toBeVisible(); @@ -94,7 +101,7 @@ test.describe('Dataset List', () => { }); test('should delete a dataset with confirmation', async ({ page }) => { - // Create test dataset + // Create test dataset (hermetic - creates own test data) const datasetName = `test_delete_${Date.now()}`; testResources = await createTestDataset(page, datasetName);
