2
2
APIRequestContext ,
3
3
test as base /* eslint-disable-line no-restricted-imports -- We need this here to extend it */ ,
4
4
} from "@playwright/test"
5
- import { readFile , writeFile } from "node:fs/promises"
6
- import { fileURLToPath , URL } from "node:url"
7
5
8
6
/**
9
7
* Authentication token returned by the OAuth flow.
@@ -13,78 +11,77 @@ export type Token = {
13
11
// Omitted additional properties that are not needed for tests
14
12
}
15
13
16
- export type AuthorizationHeader = { Authorization : string }
14
+ let savedToken : Token
15
+
16
+ async function getToken (
17
+ username : string ,
18
+ password : string ,
19
+ request : APIRequestContext ,
20
+ ) : Promise < Token > {
21
+ if ( ! savedToken ) {
22
+ const tokenRequest = await request . post (
23
+ "http://localhost:8443/realms/ris/protocol/openid-connect/token" ,
24
+ {
25
+ form : {
26
+ grant_type : "password" ,
27
+ client_id : "ris-norms-local" ,
28
+ client_secret : "ris-norms-local" ,
29
+ username,
30
+ password,
31
+ } ,
32
+ } ,
33
+ )
34
+
35
+ if ( ! tokenRequest . ok ) {
36
+ throw new Error ( "Failed to fetch a token for the E2E tests" , {
37
+ cause : tokenRequest ,
38
+ } )
39
+ }
40
+
41
+ savedToken = await tokenRequest . json ( )
42
+ }
43
+
44
+ return savedToken
45
+ }
17
46
18
47
/**
19
48
* Drop-in replacement for Playwright's regular test method that also handles
20
49
* the authorization token. This should be used for all tests in order to
21
50
* guarantee that the token is always up to date.
22
51
*/
23
52
export const test = base . extend < {
24
- /**
25
- * Hooks into the requests made by the page. If one of them contains a new token,
26
- * the token will automatically be saved to a shared location, so it can be used
27
- * by other tests.
28
- *
29
- * This behavior is managed by Playwright automatically. The method should not be
30
- * called manually.
31
- */
32
- updateToken : void
33
-
34
53
/**
35
54
* Provides an API context that can be used to make requests just like `page.request`,
36
55
* except that those requests will be authenticated with a previously saved token.
37
56
*/
38
57
authenticatedRequest : APIRequestContext
39
- } > ( {
40
- updateToken : [
41
- async ( { page } , use ) => {
42
- await page . route ( / t o k e n $ / , async ( route ) => {
43
- const response = await page . request . fetch ( route . request ( ) )
44
- if ( response . ok ( ) ) await saveToken ( await response . json ( ) )
45
- await route . fulfill ( { response } )
46
- } )
47
58
48
- await use ( )
49
- } ,
50
- { auto : true } ,
59
+ /**
60
+ * Username and password of the example user that should be used in E2E tests.
61
+ */
62
+ appCredentials : { username : string ; password : string }
63
+ } > ( {
64
+ appCredentials : [
65
+ { username : "jane.doe" , password : "test" } ,
66
+ { option : true } ,
51
67
] ,
52
68
53
- authenticatedRequest : async ( { playwright } , use ) => {
54
- const token = await restoreToken ( )
69
+ authenticatedRequest : async (
70
+ { playwright, request, appCredentials } ,
71
+ use ,
72
+ ) => {
73
+ const token = await getToken (
74
+ appCredentials . username ,
75
+ appCredentials . password ,
76
+ request ,
77
+ )
55
78
56
- const request = await playwright . request . newContext ( {
79
+ const authenticatedRequest = await playwright . request . newContext ( {
57
80
extraHTTPHeaders : {
58
81
Authorization : `Bearer ${ token . access_token } ` ,
59
82
} ,
60
83
} )
61
84
62
- await use ( request )
85
+ await use ( authenticatedRequest )
63
86
} ,
64
87
} )
65
-
66
- const storagePath = fileURLToPath (
67
- new URL ( "../storage/token.json" , import . meta. url ) ,
68
- )
69
-
70
- /**
71
- * Takes a token and saves it to a shared location that can be used across tests.
72
- *
73
- * @param token Token to save
74
- */
75
- export function saveToken ( token : Token ) : Promise < void > {
76
- return writeFile ( storagePath , JSON . stringify ( token , undefined , 2 ) , {
77
- encoding : "utf-8" ,
78
- } )
79
- }
80
-
81
- /**
82
- * Loads a previously saved token from the shared location. This will throw if
83
- * no token has been saved.
84
- *
85
- * @returns Saved token
86
- */
87
- export async function restoreToken ( ) : Promise < Token > {
88
- const raw = await readFile ( storagePath , { encoding : "utf-8" } )
89
- return JSON . parse ( raw )
90
- }
0 commit comments