@@ -185,7 +185,7 @@ describe('SlicknodeLink', () => {
185185 } ) ;
186186 } ) ;
187187
188- it ( 'executes refreshToken request in subsequent links' , ( done ) => {
188+ it ( 'executes refreshToken request in subsequent links and adds auth headers ' , ( done ) => {
189189 const data = {
190190 test : true ,
191191 } ;
@@ -195,22 +195,177 @@ describe('SlicknodeLink', () => {
195195 refreshToken : 'refresh1' ,
196196 refreshTokenLifetime : 100 ,
197197 } ;
198+ const refreshedAuthTokenSet : IAuthTokenSet = {
199+ accessToken : 'accessToken2' ,
200+ accessTokenLifetime : 20 ,
201+ refreshToken : 'refresh2' ,
202+ refreshTokenLifetime : 200 ,
203+ } ;
198204 const slicknodeLink = new SlicknodeLink ( ) ;
199205 slicknodeLink . setAuthTokenSet ( authTokenSet ) ;
200206
207+ let refreshTokenExecuted = false ;
208+ const query = gql `{test}` ;
201209 const link = ApolloLink . from ( [
202210 slicknodeLink ,
203211 new ApolloLink ( ( operation ) => {
204- expect ( operation . query ) . to . deep . equal ( gql `${ REFRESH_TOKEN_MUTATION } ` ) ;
205- expect ( operation . variables ) . to . deep . equal ( {
206- token : authTokenSet . refreshToken ,
212+ if ( ! refreshTokenExecuted ) {
213+ // First request refreshes auth tokens
214+ expect ( operation . query ) . to . deep . equal ( gql `${ REFRESH_TOKEN_MUTATION } ` ) ;
215+ expect ( operation . variables ) . to . deep . equal ( {
216+ token : authTokenSet . refreshToken ,
217+ } ) ;
218+ expect ( operation . getContext ( ) ) . to . deep . equal ( { } ) ;
219+ refreshTokenExecuted = true ;
220+ return new Observable < FetchResult > ( ( observer ) => {
221+ observer . next ( {
222+ data : {
223+ refreshAuthToken : refreshedAuthTokenSet ,
224+ } ,
225+ } ) ;
226+ } ) ;
227+ }
228+ // Second request returns actual results and should contain auth headers
229+ expect ( operation . query ) . to . deep . equal ( query ) ;
230+ expect ( operation . variables ) . to . deep . equal ( { } ) ;
231+ expect ( operation . getContext ( ) ) . to . deep . equal ( {
232+ headers : {
233+ Authorization : `Bearer ${ refreshedAuthTokenSet . accessToken } ` ,
234+ } ,
207235 } ) ;
208- expect ( operation . getContext ( ) ) . to . deep . equal ( { } ) ;
236+ return new Observable < FetchResult > ( ( observer ) => {
237+ observer . next ( { data} ) ;
238+ } ) ;
239+ } ) ,
240+ ] ) ;
241+ const request : GraphQLRequest = {
242+ query,
243+ variables : { } ,
244+ } ;
245+ const observable = execute ( link , request ) ;
246+ observable . subscribe ( {
247+ next ( result : FetchResult ) {
248+ expect ( result . data ) . to . equal ( data ) ;
209249 done ( ) ;
210- return null ;
250+ } ,
251+ error : done ,
252+ } ) ;
253+ } ) ;
254+
255+ it ( 'ignores invalid refreshToken' , ( done ) => {
256+ const data = {
257+ test : true ,
258+ } ;
259+ const authTokenSet : IAuthTokenSet = {
260+ accessToken : 'accessToken1' ,
261+ accessTokenLifetime : - 20 ,
262+ refreshToken : 'refresh1' ,
263+ refreshTokenLifetime : 100 ,
264+ } ;
265+ const refreshedAuthTokenSet = {
266+ accessToken : 'accessToken2' ,
267+ accessTokenLifetime : 'invalid' ,
268+ refreshToken : 'refresh2' ,
269+ refreshTokenLifetime : 200 ,
270+ } ;
271+ const slicknodeLink = new SlicknodeLink ( ) ;
272+ slicknodeLink . setAuthTokenSet ( authTokenSet ) ;
273+
274+ let refreshTokenExecuted = false ;
275+ const query = gql `{test}` ;
276+ const link = ApolloLink . from ( [
277+ slicknodeLink ,
278+ new ApolloLink ( ( operation ) => {
279+ if ( ! refreshTokenExecuted ) {
280+ // First request refreshes auth tokens
281+ expect ( operation . query ) . to . deep . equal ( gql `${ REFRESH_TOKEN_MUTATION } ` ) ;
282+ expect ( operation . variables ) . to . deep . equal ( {
283+ token : authTokenSet . refreshToken ,
284+ } ) ;
285+ expect ( operation . getContext ( ) ) . to . deep . equal ( { } ) ;
286+ refreshTokenExecuted = true ;
287+ return new Observable < FetchResult > ( ( observer ) => {
288+ observer . next ( {
289+ data : {
290+ refreshAuthToken : refreshedAuthTokenSet ,
291+ } ,
292+ } ) ;
293+ } ) ;
294+ }
295+ // Second request returns actual results and should contain auth headers
296+ expect ( operation . query ) . to . deep . equal ( query ) ;
297+ expect ( operation . variables ) . to . deep . equal ( { } ) ;
298+ expect ( operation . getContext ( ) ) . to . deep . equal ( { headers : { } } ) ;
299+ expect ( slicknodeLink . getRefreshToken ( ) ) . to . be . null ;
300+ return new Observable < FetchResult > ( ( observer ) => {
301+ observer . next ( { data} ) ;
302+ } ) ;
211303 } ) ,
212304 ] ) ;
305+ const request : GraphQLRequest = {
306+ query,
307+ variables : { } ,
308+ } ;
309+ const observable = execute ( link , request ) ;
310+ observable . subscribe ( {
311+ next ( result : FetchResult ) {
312+ expect ( result . data ) . to . equal ( data ) ;
313+ done ( ) ;
314+ } ,
315+ error : done ,
316+ } ) ;
317+ } ) ;
318+
319+ it ( 'ignores expired accessToken from automatic refresh' , ( done ) => {
320+ const data = {
321+ test : true ,
322+ } ;
323+ const authTokenSet : IAuthTokenSet = {
324+ accessToken : 'accessToken1' ,
325+ accessTokenLifetime : - 20 ,
326+ refreshToken : 'refresh1' ,
327+ refreshTokenLifetime : 100 ,
328+ } ;
329+ const refreshedAuthTokenSet = {
330+ accessToken : 'accessToken2' ,
331+ accessTokenLifetime : - 20 ,
332+ refreshToken : 'refresh2' ,
333+ refreshTokenLifetime : 200 ,
334+ } ;
335+ const slicknodeLink = new SlicknodeLink ( ) ;
336+ slicknodeLink . setAuthTokenSet ( authTokenSet ) ;
337+
338+ let refreshTokenExecuted = false ;
213339 const query = gql `{test}` ;
340+ const link = ApolloLink . from ( [
341+ slicknodeLink ,
342+ new ApolloLink ( ( operation ) => {
343+ if ( ! refreshTokenExecuted ) {
344+ // First request refreshes auth tokens
345+ expect ( operation . query ) . to . deep . equal ( gql `${ REFRESH_TOKEN_MUTATION } ` ) ;
346+ expect ( operation . variables ) . to . deep . equal ( {
347+ token : authTokenSet . refreshToken ,
348+ } ) ;
349+ expect ( operation . getContext ( ) ) . to . deep . equal ( { } ) ;
350+ refreshTokenExecuted = true ;
351+ return new Observable < FetchResult > ( ( observer ) => {
352+ observer . next ( {
353+ data : {
354+ refreshAuthToken : refreshedAuthTokenSet ,
355+ } ,
356+ } ) ;
357+ } ) ;
358+ }
359+ // Second request returns actual results and should contain auth headers
360+ expect ( operation . query ) . to . deep . equal ( query ) ;
361+ expect ( operation . variables ) . to . deep . equal ( { } ) ;
362+ expect ( operation . getContext ( ) ) . to . deep . equal ( { headers : { } } ) ;
363+ expect ( slicknodeLink . hasAccessToken ( ) ) . to . be . false ;
364+ return new Observable < FetchResult > ( ( observer ) => {
365+ observer . next ( { data} ) ;
366+ } ) ;
367+ } ) ,
368+ ] ) ;
214369 const request : GraphQLRequest = {
215370 query,
216371 variables : { } ,
@@ -219,6 +374,7 @@ describe('SlicknodeLink', () => {
219374 observable . subscribe ( {
220375 next ( result : FetchResult ) {
221376 expect ( result . data ) . to . equal ( data ) ;
377+ done ( ) ;
222378 } ,
223379 error : done ,
224380 } ) ;
0 commit comments