11/* eslint-disable @typescript-eslint/no-unsafe-member-access */
2- import { setupServer , superRequest } from '../../jest.utils' ;
2+ import {
3+ setupServer ,
4+ superRequest ,
5+ createSuperRequest
6+ } from '../../jest.utils' ;
37import { AUTH0_DOMAIN } from '../utils/env' ;
48
9+ const mockedFetch = jest . fn ( ) ;
10+ jest . spyOn ( globalThis , 'fetch' ) . mockImplementation ( mockedFetch ) ;
11+
12+ const newUserEmail = '[email protected] ' ; 13+
14+ const mockAuth0NotOk = ( ) => ( {
15+ ok : false
16+ } ) ;
17+
18+ const mockAuth0InvalidEmail = ( ) => ( {
19+ ok : true ,
20+ json : ( ) => ( { email : 'invalid-email' } )
21+ } ) ;
22+
23+ const mockAuth0ValidEmail = ( ) => ( {
24+ ok : true ,
25+ json : ( ) => ( { email : newUserEmail } )
26+ } ) ;
27+
528jest . mock ( '../utils/env' , ( ) => {
629 // eslint-disable-next-line @typescript-eslint/no-unsafe-return
730 return {
@@ -23,4 +46,107 @@ describe('auth0 routes', () => {
2346 expect ( redirectUrl . pathname ) . toBe ( '/authorize' ) ;
2447 } ) ;
2548 } ) ;
49+
50+ describe ( 'GET /mobile-login' , ( ) => {
51+ let superGet : ReturnType < typeof createSuperRequest > ;
52+
53+ beforeAll ( ( ) => {
54+ superGet = createSuperRequest ( { method : 'GET' } ) ;
55+ } ) ;
56+ beforeEach ( async ( ) => {
57+ await fastifyTestInstance . prisma . userRateLimit . deleteMany ( { } ) ;
58+ await fastifyTestInstance . prisma . user . deleteMany ( {
59+ where : { email : newUserEmail }
60+ } ) ;
61+ } ) ;
62+
63+ it ( 'should be rate-limited' , async ( ) => {
64+ await Promise . all (
65+ [ ...Array ( 10 ) . keys ( ) ] . map ( ( ) => superGet ( '/mobile-login' ) )
66+ ) ;
67+
68+ const res = await superGet ( '/mobile-login' ) ;
69+ expect ( res . status ) . toBe ( 429 ) ;
70+ } ) ;
71+
72+ it ( 'should return 401 if the authorization header is invalid' , async ( ) => {
73+ mockedFetch . mockResolvedValueOnce ( mockAuth0NotOk ( ) ) ;
74+ const res = await superGet ( '/mobile-login' ) . set (
75+ 'Authorization' ,
76+ 'Bearer invalid-token'
77+ ) ;
78+
79+ expect ( res . body ) . toStrictEqual ( {
80+ type : 'danger' ,
81+ message : 'We could not log you in, please try again in a moment.'
82+ } ) ;
83+ expect ( res . status ) . toBe ( 401 ) ;
84+ } ) ;
85+
86+ it ( 'should return 400 if the email is not valid' , async ( ) => {
87+ mockedFetch . mockResolvedValueOnce ( mockAuth0InvalidEmail ( ) ) ;
88+ const res = await superGet ( '/mobile-login' ) . set (
89+ 'Authorization' ,
90+ 'Bearer valid-token'
91+ ) ;
92+
93+ expect ( res . body ) . toStrictEqual ( {
94+ type : 'danger' ,
95+ message : 'The email is incorrectly formatted'
96+ } ) ;
97+ expect ( res . status ) . toBe ( 400 ) ;
98+ } ) ;
99+
100+ it ( 'should set the jwt_access_token cookie if the authorization header is valid' , async ( ) => {
101+ mockedFetch . mockResolvedValueOnce ( mockAuth0ValidEmail ( ) ) ;
102+ const res = await superGet ( '/mobile-login' ) . set (
103+ 'Authorization' ,
104+ 'Bearer valid-token'
105+ ) ;
106+
107+ expect ( res . status ) . toBe ( 200 ) ;
108+ expect ( res . get ( 'Set-Cookie' ) ) . toEqual (
109+ expect . arrayContaining ( [ expect . stringMatching ( / j w t _ a c c e s s _ t o k e n = / ) ] )
110+ ) ;
111+ } ) ;
112+
113+ it ( 'should create a user if they do not exist' , async ( ) => {
114+ mockedFetch . mockResolvedValueOnce ( mockAuth0ValidEmail ( ) ) ;
115+ const existingUserCount = await fastifyTestInstance . prisma . user . count ( ) ;
116+
117+ const res = await superGet ( '/mobile-login' ) . set (
118+ 'Authorization' ,
119+ 'Bearer valid-token'
120+ ) ;
121+
122+ const newUserCount = await fastifyTestInstance . prisma . user . count ( ) ;
123+
124+ expect ( existingUserCount ) . toBe ( 0 ) ;
125+ expect ( newUserCount ) . toBe ( 1 ) ;
126+ expect ( res . status ) . toBe ( 200 ) ;
127+ } ) ;
128+
129+ it ( 'should redirect to returnTo if already logged in' , async ( ) => {
130+ mockedFetch . mockResolvedValueOnce ( mockAuth0ValidEmail ( ) ) ;
131+ const firstRes = await superGet ( '/mobile-login' ) . set (
132+ 'Authorization' ,
133+ 'Bearer valid-token'
134+ ) ;
135+
136+ expect ( firstRes . status ) . toBe ( 200 ) ;
137+
138+ const res = await superRequest ( '/mobile-login' , {
139+ method : 'GET' ,
140+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
141+ setCookies : firstRes . get ( 'Set-Cookie' )
142+ } )
143+ . set ( 'Authorization' , 'Bearer does-not-matter' )
144+ . set ( 'Referer' , 'https://www.freecodecamp.org/back-home' ) ;
145+
146+ expect ( res . status ) . toBe ( 302 ) ;
147+ expect ( res . headers . location ) . toBe (
148+ 'https://www.freecodecamp.org/back-home'
149+ ) ;
150+ } ) ;
151+ } ) ;
26152} ) ;
0 commit comments