This is an automated email from the ASF dual-hosted git repository. michael-s-molina pushed a commit to branch 6.2 in repository https://gitbox.apache.org/repos/asf/superset.git
commit a7dbbcb6a9d9dfb13f58c88211f89c82925c1fef Author: Michael S. Molina <[email protected]> AuthorDate: Mon Jul 13 10:37:56 2026 -0300 fix: playwright-tests-experimental failures --- superset-frontend/playwright/helpers/navigation.ts | 57 ++++++++++++++++++++++ .../playwright/pages/ChartCreationPage.ts | 3 +- .../playwright/pages/ChartListPage.ts | 3 +- .../playwright/pages/CreateDatasetPage.ts | 3 +- .../playwright/pages/DashboardListPage.ts | 3 +- .../playwright/pages/DashboardPage.ts | 5 +- .../playwright/pages/DatasetListPage.ts | 3 +- 7 files changed, 70 insertions(+), 7 deletions(-) diff --git a/superset-frontend/playwright/helpers/navigation.ts b/superset-frontend/playwright/helpers/navigation.ts new file mode 100644 index 00000000000..0a1baf9eb3f --- /dev/null +++ b/superset-frontend/playwright/helpers/navigation.ts @@ -0,0 +1,57 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Page, Response } from '@playwright/test'; + +/** + * Werkzeug (Flask's dev server, used in CI) periodically drops connections + * during page navigation under concurrent load — surfacing as + * `ERR_EMPTY_RESPONSE`, `ERR_CONNECTION_RESET`, or a socket hang up. These + * are transport-layer failures, not application errors, so retrying the + * navigation is safe: the next request hits a fresh werkzeug worker thread. + * + * Application errors (4xx/5xx, JS exceptions during load) bubble up + * unchanged — the matcher is narrow on purpose. + */ +const TRANSIENT_NAV_ERROR = + /ERR_EMPTY_RESPONSE|ERR_CONNECTION_RESET|ERR_CONNECTION_CLOSED|socket hang up|ECONNRESET/i; +const NAV_RETRY_ATTEMPTS = 3; +const NAV_RETRY_BACKOFF_MS = 400; + +export async function gotoWithRetry( + page: Page, + url: string, + options?: Parameters<Page['goto']>[1], +): Promise<Response | null> { + let lastError: unknown; + for (let attempt = 0; attempt < NAV_RETRY_ATTEMPTS; attempt += 1) { + try { + return await page.goto(url, options); + } catch (error) { + lastError = error; + if (!TRANSIENT_NAV_ERROR.test(String(error))) { + throw error; + } + await new Promise(resolve => { + setTimeout(resolve, NAV_RETRY_BACKOFF_MS * (attempt + 1)); + }); + } + } + throw lastError; +} diff --git a/superset-frontend/playwright/pages/ChartCreationPage.ts b/superset-frontend/playwright/pages/ChartCreationPage.ts index 8dc38142938..ec7541b07d4 100644 --- a/superset-frontend/playwright/pages/ChartCreationPage.ts +++ b/superset-frontend/playwright/pages/ChartCreationPage.ts @@ -19,6 +19,7 @@ import { expect, Locator, Page } from '@playwright/test'; import { Button, Select } from '../components/core'; +import { gotoWithRetry } from '../helpers/navigation'; /** * Chart Creation Page object for the "Create a new chart" wizard. @@ -74,7 +75,7 @@ export class ChartCreationPage { * Navigate to the chart creation page */ async goto(): Promise<void> { - await this.page.goto('chart/add'); + await gotoWithRetry(this.page, 'chart/add'); } /** diff --git a/superset-frontend/playwright/pages/ChartListPage.ts b/superset-frontend/playwright/pages/ChartListPage.ts index 74f75181d24..d5a9ff3a86f 100644 --- a/superset-frontend/playwright/pages/ChartListPage.ts +++ b/superset-frontend/playwright/pages/ChartListPage.ts @@ -20,6 +20,7 @@ import { Page, Locator } from '@playwright/test'; import { Table } from '../components/core'; import { BulkSelect } from '../components/ListView'; +import { gotoWithRetry } from '../helpers/navigation'; import { URL } from '../utils/urls'; /** @@ -52,7 +53,7 @@ export class ChartListPage { * (ListviewsDefaultCardView feature flag may enable card view). */ async goto(): Promise<void> { - await this.page.goto(`${URL.CHART_LIST}?viewMode=table`); + await gotoWithRetry(this.page, `${URL.CHART_LIST}?viewMode=table`); } /** diff --git a/superset-frontend/playwright/pages/CreateDatasetPage.ts b/superset-frontend/playwright/pages/CreateDatasetPage.ts index ff129c7364c..411212b2b7e 100644 --- a/superset-frontend/playwright/pages/CreateDatasetPage.ts +++ b/superset-frontend/playwright/pages/CreateDatasetPage.ts @@ -19,6 +19,7 @@ import { Page } from '@playwright/test'; import { Button, Select } from '../components/core'; +import { gotoWithRetry } from '../helpers/navigation'; /** * Create Dataset Page object for the dataset creation wizard. @@ -75,7 +76,7 @@ export class CreateDatasetPage { * Navigate to the create dataset page */ async goto(): Promise<void> { - await this.page.goto('dataset/add/'); + await gotoWithRetry(this.page, 'dataset/add/'); } /** diff --git a/superset-frontend/playwright/pages/DashboardListPage.ts b/superset-frontend/playwright/pages/DashboardListPage.ts index 8c8472f0224..d432dd29fdf 100644 --- a/superset-frontend/playwright/pages/DashboardListPage.ts +++ b/superset-frontend/playwright/pages/DashboardListPage.ts @@ -20,6 +20,7 @@ import { Page, Locator } from '@playwright/test'; import { Button, Table } from '../components/core'; import { BulkSelect } from '../components/ListView'; +import { gotoWithRetry } from '../helpers/navigation'; import { URL } from '../utils/urls'; /** @@ -52,7 +53,7 @@ export class DashboardListPage { * (ListviewsDefaultCardView feature flag may enable card view). */ async goto(): Promise<void> { - await this.page.goto(`${URL.DASHBOARD_LIST}?viewMode=table`); + await gotoWithRetry(this.page, `${URL.DASHBOARD_LIST}?viewMode=table`); } /** diff --git a/superset-frontend/playwright/pages/DashboardPage.ts b/superset-frontend/playwright/pages/DashboardPage.ts index f94695ad4fd..a61ff3415c1 100644 --- a/superset-frontend/playwright/pages/DashboardPage.ts +++ b/superset-frontend/playwright/pages/DashboardPage.ts @@ -19,6 +19,7 @@ import { Page, Download } from '@playwright/test'; import { Menu } from '../components/core'; +import { gotoWithRetry } from '../helpers/navigation'; import { TIMEOUT } from '../utils/constants'; /** @@ -43,7 +44,7 @@ export class DashboardPage { * @param slug - The dashboard slug (e.g., 'world_health') */ async gotoBySlug(slug: string): Promise<void> { - await this.page.goto(`superset/dashboard/${slug}/`); + await gotoWithRetry(this.page, `superset/dashboard/${slug}/`); } /** @@ -51,7 +52,7 @@ export class DashboardPage { * @param id - The dashboard ID */ async gotoById(id: number): Promise<void> { - await this.page.goto(`superset/dashboard/${id}/`); + await gotoWithRetry(this.page, `superset/dashboard/${id}/`); } /** diff --git a/superset-frontend/playwright/pages/DatasetListPage.ts b/superset-frontend/playwright/pages/DatasetListPage.ts index 77e9a87db25..a184ca3d126 100644 --- a/superset-frontend/playwright/pages/DatasetListPage.ts +++ b/superset-frontend/playwright/pages/DatasetListPage.ts @@ -20,6 +20,7 @@ import { Page, Locator } from '@playwright/test'; import { Button, Table } from '../components/core'; import { BulkSelect } from '../components/ListView'; +import { gotoWithRetry } from '../helpers/navigation'; import { URL } from '../utils/urls'; /** @@ -54,7 +55,7 @@ export class DatasetListPage { * Navigate to the dataset list page */ async goto(): Promise<void> { - await this.page.goto(URL.DATASET_LIST); + await gotoWithRetry(this.page, URL.DATASET_LIST); } /**
