Skip to content

Commit a7e07d6

Browse files
committed
fix(playwright): inject access token via addInitScript to bypass silent refresh
Use page.addInitScript to set __pw_access_token before React runs on every navigation. auth-context reads it in getInitialState() and calls setAccessToken() directly, so no refresh cookie is needed. Also fix strict mode violation in workflow.spec.ts (3 matching spans).
1 parent 52a97fc commit a7e07d6

3 files changed

Lines changed: 19 additions & 11 deletions

File tree

packages/frontend/context/auth-context.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,24 @@ function getInitialState(): AuthStateWithInit {
6767
return defaultState; // SSR — isInitialized: false
6868
}
6969

70+
// Playwright test injection: addInitScript sets __pw_access_token before
71+
// any page scripts run so we can inject the token directly, bypassing the
72+
// silent-refresh flow that depends on the refresh cookie.
73+
const win = window as Record<string, unknown>;
74+
const pwToken = typeof win['__pw_access_token'] === 'string'
75+
? (win['__pw_access_token'] as string)
76+
: null;
77+
if (pwToken) {
78+
setAccessToken(pwToken);
79+
}
80+
7081
const userId = sessionStorage.getItem(SESSION_KEY_USER_ID);
7182
const role = sessionStorage.getItem(SESSION_KEY_ROLE) as UserRole | null;
7283
const email = sessionStorage.getItem(SESSION_KEY_EMAIL);
7384

7485
if (userId && role) {
7586
return {
76-
accessToken: null, // se renueva vía silent refresh en la primera petición
87+
accessToken: pwToken, // direct token injection in tests; null in production (silent refresh)
7788
userId,
7889
role,
7990
email,

packages/frontend/e2e/helpers/auth.helper.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,16 @@ export async function injectAuth(
8080
loginResult: LoginResult,
8181
targetPath = '/dashboard',
8282
): Promise<void> {
83-
// First visit — page needs to load at least once so JS is running
84-
await page.goto('/login', { waitUntil: 'domcontentloaded' });
85-
86-
await page.evaluate(
83+
// Register an init script that runs BEFORE any page scripts on every
84+
// navigation in this page (including subsequent test gotos).
85+
// This ensures sessionStorage auth metadata and __pw_access_token are
86+
// available when auth-context.tsx's getInitialState() executes, so the
87+
// access token is injected directly — no silent refresh needed.
88+
await page.addInitScript(
8789
({ userId, role, email, accessToken }) => {
8890
sessionStorage.setItem('auth:userId', userId);
8991
sessionStorage.setItem('auth:role', role);
9092
sessionStorage.setItem('auth:email', email);
91-
// Store token so the axios interceptor picks it up on the
92-
// first authenticated request (silent-refresh path).
93-
// We expose it via a well-known window property; the interceptor
94-
// in api.ts will read it before the first 401 is thrown.
9593
(window as Record<string, unknown>)['__pw_access_token'] = accessToken;
9694
},
9795
{
@@ -102,7 +100,6 @@ export async function injectAuth(
102100
},
103101
);
104102

105-
// Navigate to the actual target page
106103
await page.goto(targetPath, { waitUntil: 'load' });
107104
}
108105

packages/frontend/e2e/workflow.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ test.describe('Workflow — send to validation', () => {
105105

106106
// Status badge should update to READY_FOR_VALIDATION
107107
await expect(
108-
page.getByText(/needs validation|ready.for.validation/i),
108+
page.getByText(/needs validation|ready.for.validation/i).first(),
109109
).toBeVisible({ timeout: 10_000 });
110110
});
111111
});

0 commit comments

Comments
 (0)