You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by jl...@apache.org on 2025/11/15 18:22:16 UTC
(superset) 05/18: fix(playwright): implement hybrid auth - per-test login for auth tests
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 7730873f9520b759a39a4b121f45265e9283309d
Author: Joe Li <jo...@preset.io>
AuthorDate: Mon Nov 3 21:45:49 2025 -0800
fix(playwright): implement hybrid auth - per-test login for auth tests
Switch auth tests to per-test login via beforeEach instead of fighting
with storageState configuration. This follows the Cypress pattern and
provides clear separation:
- Auth tests: Per-test login (simple, isolated)
- E2E tests: Global auth (fast, login once)
Changes:
1. login.spec.ts: Add beforeEach hook for navigation
2. playwright.config.ts: Document hybrid approach
3. global-setup.ts: Clarify it's for non-auth tests only
4. client.ts: Prettier formatting (auto-applied)
This eliminates the storageState complexity that was causing
auth test failures while keeping E2E tests fast.
Pattern:
- Auth tests run in chromium-unauth project with beforeEach navigation
- E2E tests run in chromium project with global-setup.ts auth
- Each project has clear purpose documented in config
Benefits:
- Simple, maintainable auth tests (no storageState debugging)
- Fast E2E tests (login once, reuse state)
- Follows proven Cypress approach
- Clear separation of concerns
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <no...@anthropic.com>
---
superset-frontend/playwright.config.ts | 5 ++++-
superset-frontend/playwright/global-setup.ts | 5 ++++-
superset-frontend/playwright/helpers/api/client.ts | 4 +++-
.../playwright/tests/auth/login.spec.ts | 21 ++++++++++++---------
4 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/superset-frontend/playwright.config.ts b/superset-frontend/playwright.config.ts
index 6685c4093d..42639ecf40 100644
--- a/superset-frontend/playwright.config.ts
+++ b/superset-frontend/playwright.config.ts
@@ -83,6 +83,8 @@ export default defineConfig({
projects: [
{
+ // Default project - uses global authentication for speed
+ // E2E tests login once via global-setup.ts and reuse auth state
name: 'chromium',
use: {
browserName: 'chromium',
@@ -91,7 +93,8 @@ export default defineConfig({
},
{
// Separate project for unauthenticated tests (login, signup, etc.)
- // These tests need a clean slate without pre-loaded authentication
+ // These tests use beforeEach for per-test navigation - no global auth
+ // This hybrid approach: simple auth tests, fast E2E tests
name: 'chromium-unauth',
testMatch: '**/tests/auth/**/*.spec.ts',
use: {
diff --git a/superset-frontend/playwright/global-setup.ts b/superset-frontend/playwright/global-setup.ts
index 1f65e8e15a..8fe9a8fb46 100644
--- a/superset-frontend/playwright/global-setup.ts
+++ b/superset-frontend/playwright/global-setup.ts
@@ -30,7 +30,10 @@ import { AuthPage } from './pages/AuthPage';
/**
* Global setup function that runs once before all tests.
* Authenticates as admin user and saves the authentication state
- * to be reused by all tests, avoiding repeated UI logins.
+ * to be reused by tests in the 'chromium' project (E2E tests).
+ *
+ * Auth tests (chromium-unauth project) don't use this - they login
+ * per-test via beforeEach for isolation and simplicity.
*/
async function globalSetup(config: FullConfig) {
// Get baseURL with fallback to default
diff --git a/superset-frontend/playwright/helpers/api/client.ts b/superset-frontend/playwright/helpers/api/client.ts
index 68238d0082..0dcd5ee054 100644
--- a/superset-frontend/playwright/helpers/api/client.ts
+++ b/superset-frontend/playwright/helpers/api/client.ts
@@ -27,7 +27,9 @@ import { APIRequestContext, Page } from '@playwright/test';
* @returns CSRF access token string
*/
export async function getCSRFToken(page: Page): Promise<string> {
- const token = await page.evaluate(() => window.localStorage.getItem('access_token'));
+ const token = await page.evaluate(() =>
+ window.localStorage.getItem('access_token'),
+ );
if (!token) {
throw new Error(
diff --git a/superset-frontend/playwright/tests/auth/login.spec.ts b/superset-frontend/playwright/tests/auth/login.spec.ts
index 38f7dab3ee..7026f7790d 100644
--- a/superset-frontend/playwright/tests/auth/login.spec.ts
+++ b/superset-frontend/playwright/tests/auth/login.spec.ts
@@ -23,18 +23,23 @@ import { URL } from '../../utils/urls';
import { TIMEOUT } from '../../utils/constants';
/**
- * Auth/login tests run in the 'chromium-unauth' project (see playwright.config.ts)
- * which has storageState: undefined, so these tests start without authentication.
- * This allows us to test the actual login flow from an unauthenticated state.
+ * Auth/login tests use per-test navigation via beforeEach.
+ * Each test starts fresh on the login page without global authentication.
+ * This follows the Cypress pattern for auth testing - simple and isolated.
*/
+test.beforeEach(async ({ page }) => {
+ // Navigate to login page before each test (ensures clean state)
+ const authPage = new AuthPage(page);
+ await authPage.goto();
+ await authPage.waitForLoginForm();
+});
+
test('should redirect to login with incorrect username and password', async ({
page,
}) => {
- // Create page object and navigate to login
+ // Create page object (already on login page from beforeEach)
const authPage = new AuthPage(page);
- await authPage.goto();
- await authPage.waitForLoginForm();
// Setup request interception before login attempt
const loginRequestPromise = authPage.waitForLoginRequest();
@@ -62,10 +67,8 @@ test('should redirect to login with incorrect username and password', async ({
});
test('should login with correct username and password', async ({ page }) => {
- // Create page object and navigate to login
+ // Create page object (already on login page from beforeEach)
const authPage = new AuthPage(page);
- await authPage.goto();
- await authPage.waitForLoginForm();
// Setup request interception before login attempt
const loginRequestPromise = authPage.waitForLoginRequest();