11import { OAUTH_SCOPE_VERSION } from "@shared/constants/oauth" ;
22import { afterEach , beforeEach , describe , expect , it , vi } from "vitest" ;
3+ import { createMockAuthPreferenceRepository } from "../../db/repositories/auth-preference-repository.mock" ;
34import { createMockAuthSessionRepository } from "../../db/repositories/auth-session-repository.mock" ;
45import { decrypt , encrypt } from "../../utils/encryption" ;
56import type { ConnectivityService } from "../connectivity/service" ;
@@ -18,6 +19,7 @@ vi.mock("../../utils/logger.js", () => ({
1819} ) ) ;
1920
2021describe ( "AuthService" , ( ) => {
22+ const preferenceRepository = createMockAuthPreferenceRepository ( ) ;
2123 const repository = createMockAuthSessionRepository ( ) ;
2224 const oauthService = {
2325 refreshToken : vi . fn ( ) ,
@@ -31,16 +33,43 @@ describe("AuthService", () => {
3133 let service : AuthService ;
3234
3335 beforeEach ( ( ) => {
36+ preferenceRepository . _preferences = [ ] ;
3437 repository . clearCurrent ( ) ;
3538 vi . clearAllMocks ( ) ;
36- service = new AuthService ( repository , oauthService , connectivityService ) ;
39+ service = new AuthService (
40+ preferenceRepository ,
41+ repository ,
42+ oauthService ,
43+ connectivityService ,
44+ ) ;
3745 } ) ;
3846
3947 afterEach ( async ( ) => {
4048 vi . unstubAllGlobals ( ) ;
4149 await service . logout ( ) ;
4250 } ) ;
4351
52+ const stubAuthFetch = ( accountKey = "user-1" ) => {
53+ vi . stubGlobal (
54+ "fetch" ,
55+ vi . fn ( async ( input : string | Request ) => {
56+ const url = typeof input === "string" ? input : input . url ;
57+
58+ if ( url . includes ( "/api/users/@me/" ) ) {
59+ return {
60+ ok : true ,
61+ json : vi . fn ( ) . mockResolvedValue ( { uuid : accountKey } ) ,
62+ } as unknown as Response ;
63+ }
64+
65+ return {
66+ ok : true ,
67+ json : vi . fn ( ) . mockResolvedValue ( { has_access : true } ) ,
68+ } as unknown as Response ;
69+ } ) as typeof fetch ,
70+ ) ;
71+ } ;
72+
4473 it ( "bootstraps to anonymous when there is no stored session" , async ( ) => {
4574 await service . initialize ( ) ;
4675
@@ -99,12 +128,7 @@ describe("AuthService", () => {
99128 } ,
100129 } ) ;
101130
102- vi . stubGlobal (
103- "fetch" ,
104- vi . fn ( ) . mockResolvedValue ( {
105- json : vi . fn ( ) . mockResolvedValue ( { has_access : true } ) ,
106- } ) as unknown as typeof fetch ,
107- ) ;
131+ stubAuthFetch ( ) ;
108132
109133 await service . initialize ( ) ;
110134
@@ -151,12 +175,7 @@ describe("AuthService", () => {
151175 scoped_organizations : [ "org-1" ] ,
152176 } ,
153177 } ) ;
154- vi . stubGlobal (
155- "fetch" ,
156- vi . fn ( ) . mockResolvedValue ( {
157- json : vi . fn ( ) . mockResolvedValue ( { has_access : true } ) ,
158- } ) as unknown as typeof fetch ,
159- ) ;
178+ stubAuthFetch ( ) ;
160179
161180 await service . login ( "us" ) ;
162181
@@ -211,12 +230,7 @@ describe("AuthService", () => {
211230 } ,
212231 } ) ;
213232
214- vi . stubGlobal (
215- "fetch" ,
216- vi . fn ( ) . mockResolvedValue ( {
217- json : vi . fn ( ) . mockResolvedValue ( { has_access : true } ) ,
218- } ) as unknown as typeof fetch ,
219- ) ;
233+ stubAuthFetch ( ) ;
220234
221235 await service . login ( "us" ) ;
222236 await service . selectProject ( 84 ) ;
@@ -237,4 +251,66 @@ describe("AuthService", () => {
237251 availableProjectIds : [ 42 , 84 ] ,
238252 } ) ;
239253 } ) ;
254+
255+ it ( "restores the selected project after app restart while logged out" , async ( ) => {
256+ vi . mocked ( oauthService . startFlow )
257+ . mockResolvedValueOnce ( {
258+ success : true ,
259+ data : {
260+ access_token : "initial-access-token" ,
261+ refresh_token : "initial-refresh-token" ,
262+ expires_in : 3600 ,
263+ token_type : "Bearer" ,
264+ scope : "" ,
265+ scoped_teams : [ 42 , 84 ] ,
266+ scoped_organizations : [ "org-1" ] ,
267+ } ,
268+ } )
269+ . mockResolvedValueOnce ( {
270+ success : true ,
271+ data : {
272+ access_token : "second-access-token" ,
273+ refresh_token : "second-refresh-token" ,
274+ expires_in : 3600 ,
275+ token_type : "Bearer" ,
276+ scope : "" ,
277+ scoped_teams : [ 42 , 84 ] ,
278+ scoped_organizations : [ "org-1" ] ,
279+ } ,
280+ } ) ;
281+ vi . mocked ( oauthService . refreshToken ) . mockResolvedValue ( {
282+ success : true ,
283+ data : {
284+ access_token : "refreshed-access-token" ,
285+ refresh_token : "refreshed-refresh-token" ,
286+ expires_in : 3600 ,
287+ token_type : "Bearer" ,
288+ scope : "" ,
289+ scoped_teams : [ 42 , 84 ] ,
290+ scoped_organizations : [ "org-1" ] ,
291+ } ,
292+ } ) ;
293+
294+ stubAuthFetch ( ) ;
295+
296+ await service . login ( "us" ) ;
297+ await service . selectProject ( 84 ) ;
298+ await service . logout ( ) ;
299+
300+ service = new AuthService (
301+ preferenceRepository ,
302+ repository ,
303+ oauthService ,
304+ connectivityService ,
305+ ) ;
306+
307+ await service . login ( "us" ) ;
308+
309+ expect ( service . getState ( ) ) . toMatchObject ( {
310+ status : "authenticated" ,
311+ cloudRegion : "us" ,
312+ projectId : 84 ,
313+ availableProjectIds : [ 42 , 84 ] ,
314+ } ) ;
315+ } ) ;
240316} ) ;
0 commit comments