66import { http , HttpResponse } from 'msw'
77import { setupServer } from 'msw/node'
88import { beforeAll , beforeEach , describe , expect , it , vi } from 'vitest'
9- import { fetchRequestToken , getRequestToken , onRequestTokenUpdate , setRequestToken } from '../lib/requestToken.ts'
9+ import { fetchRequestToken , getRequestToken , setRequestToken } from '../lib/requestToken.ts'
1010
1111const eventbus = vi . hoisted ( ( ) => ( { emit : vi . fn ( ) , subscribe : vi . fn ( ) } ) )
1212vi . mock ( '@nextcloud/event-bus' , ( ) => eventbus )
@@ -15,14 +15,24 @@ const server = setupServer()
1515
1616describe ( 'getRequestToken' , ( ) => {
1717 it ( 'can read the token from DOM' , ( ) => {
18- mockToken ( 'tokenmock-123' )
18+ mockToken ( 'tokenmock-123' , undefined )
1919 expect ( getRequestToken ( ) ) . toBe ( 'tokenmock-123' )
2020 } )
2121
2222 it ( 'can handle missing token' , ( ) => {
2323 mockToken ( undefined )
2424 expect ( getRequestToken ( ) ) . toBeNull ( )
2525 } )
26+
27+ it ( 'can handle cache token' , ( ) => {
28+ mockToken ( 'cached-token' )
29+ expect ( getRequestToken ( ) ) . toBe ( 'cached-token' )
30+ } )
31+
32+ it ( 'prioritizes cached token' , ( ) => {
33+ mockToken ( 'dom-token' , 'cached-token' )
34+ expect ( getRequestToken ( ) ) . toBe ( 'cached-token' )
35+ } )
2636} )
2737
2838describe ( 'setRequestToken' , ( ) => {
@@ -33,7 +43,7 @@ describe('setRequestToken', () => {
3343 it ( 'does emit an event on change' , ( ) => {
3444 setRequestToken ( 'new-token' )
3545 expect ( eventbus . emit ) . toBeCalledTimes ( 1 )
36- expect ( eventbus . emit ) . toBeCalledWith ( 'csrf-token-update' , { token : 'new-token' } )
46+ expect ( eventbus . emit ) . toBeCalledWith ( 'csrf-token-update' , expect . objectContaining ( { token : 'new-token' } ) )
3747 } )
3848
3949 it ( 'does set the new token to the DOM' , ( ) => {
@@ -62,50 +72,6 @@ describe('setRequestToken', () => {
6272 } )
6373} )
6474
65- describe ( 'request token observers' , ( ) => {
66- beforeEach ( ( ) => {
67- mockToken ( undefined )
68- } )
69-
70- it ( 'can update token by event' , async ( ) => {
71- expect ( getRequestToken ( ) ) . toBeNull ( )
72-
73- onRequestTokenUpdate ( ( ) => { } )
74- expect ( eventbus . subscribe ) . toBeCalledWith ( 'csrf-token-update' , expect . any ( Function ) )
75- eventbus . subscribe . mock . calls [ 0 ] [ 1 ] ( { token : 'token123' } )
76-
77- expect ( getRequestToken ( ) ) . toBe ( 'token123' )
78- } )
79-
80- it ( 'request token observer is called' , async ( ) => {
81- const observer = vi . fn ( ( ) => { } )
82-
83- onRequestTokenUpdate ( observer )
84- expect ( observer ) . not . toBeCalled ( )
85-
86- expect ( eventbus . subscribe ) . toBeCalledWith ( 'csrf-token-update' , expect . any ( Function ) )
87- eventbus . subscribe . mock . calls [ 0 ] [ 1 ] ( { token : 'token123' } )
88-
89- expect ( observer ) . toBeCalledTimes ( 1 )
90- } )
91-
92- it ( 'handle exception in observer' , async ( ) => {
93- const spy = vi . spyOn ( window . console , 'error' )
94- const observer = vi . fn ( ( ) => {
95- throw new Error ( '!Error!' )
96- } )
97- // silence the console
98- spy . mockImplementationOnce ( ( ) => { } )
99-
100- onRequestTokenUpdate ( observer )
101- expect ( eventbus . subscribe ) . toBeCalledWith ( 'csrf-token-update' , expect . any ( Function ) )
102- eventbus . subscribe . mock . calls [ 0 ] [ 1 ] ( { token : 'token123' } )
103-
104- expect ( observer ) . toBeCalledTimes ( 1 )
105- expect ( spy ) . toHaveBeenCalledOnce ( )
106- } )
107- } )
108-
10975describe ( 'fetchRequestToken' , ( ) => {
11076 const successfullCsrf = http . get ( '/index.php/csrftoken' , ( ) => {
11177 return HttpResponse . json ( { token : 'new-token' } )
@@ -127,20 +93,19 @@ describe('fetchRequestToken', () => {
12793
12894 beforeEach ( ( ) => {
12995 vi . resetAllMocks ( )
96+ mockToken ( 'oldToken' )
13097 } )
13198
13299 it ( 'correctly parses response' , async ( ) => {
133100 server . use ( successfullCsrf )
134101
135- mockToken ( 'oldToken' )
136102 const token = await fetchRequestToken ( )
137103 expect ( token ) . toBe ( 'new-token' )
138104 } )
139105
140106 it ( 'sets the token' , async ( ) => {
141107 server . use ( successfullCsrf )
142108
143- mockToken ( 'oldToken' )
144109 await fetchRequestToken ( )
145110 expect ( getRequestToken ( ) ) . toBe ( 'new-token' )
146111 } )
@@ -150,7 +115,7 @@ describe('fetchRequestToken', () => {
150115
151116 await fetchRequestToken ( )
152117 expect ( eventbus . emit ) . toHaveBeenCalledOnce ( )
153- expect ( eventbus . emit ) . toBeCalledWith ( 'csrf-token-update' , { token : 'new-token' } )
118+ expect ( eventbus . emit ) . toBeCalledWith ( 'csrf-token-update' , expect . objectContaining ( { token : 'new-token' } ) )
154119 } )
155120
156121 it ( 'handles 403 error due to invalid cookies' , async ( ) => {
@@ -182,11 +147,18 @@ describe('fetchRequestToken', () => {
182147 * Mock the request token directly so we can it reading it.
183148 *
184149 * @param token - The CSRF token to mock
150+ * @param internalToken - The internal (cached version of the DOM token) token to mock, if null the `token` will be used as internal token
185151 */
186- function mockToken ( token ?: string ) {
152+ function mockToken ( token ?: string , internalToken : string | undefined | null = null ) {
187153 if ( token === undefined ) {
188154 delete document . head . dataset . requesttoken
189155 } else {
190156 document . head . dataset . requesttoken = token
191157 }
158+
159+ if ( internalToken === null ) {
160+ globalThis . _nc_auth_requestToken = token
161+ } else {
162+ globalThis . _nc_auth_requestToken = internalToken
163+ }
192164}
0 commit comments