@@ -16,12 +16,49 @@ export interface TestContext {
1616// Auth helpers
1717// ──────────────────────────────────────────────────
1818
19- async function getApiHeaders ( page : Page ) : Promise < Record < string , string > > {
20- const cookies = await page . context ( ) . cookies ( ) ;
21- const xsrfCookie = cookies . find ( ( c ) => c . name === 'XSRF-TOKEN' ) ;
19+ /**
20+ * Create a Passport API token by calling the token endpoint from the browser.
21+ *
22+ * The browser's native fetch includes the laravel_token cookie (set by
23+ * CreateFreshApiToken during the dashboard page load), so authentication
24+ * is handled by the browser's own cookie jar — no Playwright cookie sync
25+ * issues. The returned Bearer token is then used for all subsequent API
26+ * calls, making them completely independent of cookie state.
27+ */
28+ async function createApiToken ( page : Page ) : Promise < string > {
29+ const result = await page . evaluate ( async ( baseUrl ) => {
30+ const xsrfCookie = document . cookie
31+ . split ( '; ' )
32+ . find ( ( c ) => c . startsWith ( 'XSRF-TOKEN=' ) ) ;
33+ const xsrfToken = xsrfCookie
34+ ? decodeURIComponent ( xsrfCookie . split ( '=' ) . slice ( 1 ) . join ( '=' ) )
35+ : '' ;
36+
37+ const res = await fetch ( `${ baseUrl } /api/v1/users/me/api-tokens` , {
38+ method : 'POST' ,
39+ headers : {
40+ 'Content-Type' : 'application/json' ,
41+ Accept : 'application/json' ,
42+ 'X-XSRF-TOKEN' : xsrfToken ,
43+ } ,
44+ body : JSON . stringify ( { name : 'playwright-test' } ) ,
45+ } ) ;
46+
47+ if ( ! res . ok ) {
48+ throw new Error ( `Failed to create API token: ${ res . status } ${ await res . text ( ) } ` ) ;
49+ }
50+
51+ const body = await res . json ( ) ;
52+ return body . data . access_token as string ;
53+ } , PLAYWRIGHT_BASE_URL ) ;
54+
55+ return result ;
56+ }
57+
58+ function bearerHeaders ( token : string ) : Record < string , string > {
2259 return {
2360 Accept : 'application/json' ,
24- ... ( xsrfCookie ? { 'X-XSRF-TOKEN' : decodeURIComponent ( xsrfCookie . value ) } : { } ) ,
61+ Authorization : `Bearer ${ token } ` ,
2562 } ;
2663}
2764
@@ -30,8 +67,10 @@ async function getApiHeaders(page: Page): Promise<Record<string, string>> {
3067// ──────────────────────────────────────────────────
3168
3269export async function setupTestContext ( page : Page ) : Promise < TestContext > {
70+ const token = await createApiToken ( page ) ;
3371 const request = page . request ;
34- const headers = await getApiHeaders ( page ) ;
72+ const headers = bearerHeaders ( token ) ;
73+
3574 const orgId = await getOrganizationId ( request , headers ) ;
3675 const memberId = await getCurrentMemberId ( request , orgId , headers ) ;
3776 return { request : createAuthenticatedRequest ( request , headers ) , orgId, memberId } ;
0 commit comments