1- import { beforeEach , describe , expect , it , vi } from 'vitest'
1+ import { afterAll , beforeAll , beforeEach , describe , expect , it , vi } from 'vitest'
22import { BROWSER_SOURCES , type BrowserSource } from '@/main/browser-import/browser-sources'
33import type { BrowserProfile } from '@/main/browser-import/types'
44import { emptySkipCounts } from '@/main/browser-import/types'
@@ -35,9 +35,33 @@ vi.mock('@/main/browser-import/chromium-crypto', async (importOriginal) => ({
3535const { openInBrowserProfile } = await import ( '@/main/browser-import/browser-launch' )
3636const { listAllBrowserProfiles } = await import ( '@/main/browser-import/chromium-profiles' )
3737const { readBrowserCookies } = await import ( '@/main/browser-import/chromium-cookies' )
38- const { bringSignInBack, cancelSignIn, continueSignIn, getPendingSignIn } = await import (
39- '@/main/browser-import'
40- )
38+ const {
39+ bringSignInBack,
40+ cancelSignIn,
41+ clearSignIns,
42+ continueSignIn,
43+ getPendingSignIn,
44+ migrateSignIn,
45+ } = await import ( '@/main/browser-import' )
46+
47+ /** The importer is macOS-only; pin the platform so the suite means the same on every runner. */
48+ const realPlatform = Object . getOwnPropertyDescriptor ( process , 'platform' )
49+ beforeAll ( ( ) => Object . defineProperty ( process , 'platform' , { value : 'darwin' } ) )
50+ afterAll ( ( ) => {
51+ if ( realPlatform ) Object . defineProperty ( process , 'platform' , realPlatform )
52+ } )
53+
54+ /** Holds the next browser launch open until the test releases it. */
55+ function holdLaunch ( ) : ( ) => void {
56+ let release : ( ( ) => void ) | undefined
57+ vi . mocked ( openInBrowserProfile ) . mockImplementationOnce (
58+ ( ) =>
59+ new Promise < void > ( ( resolve ) => {
60+ release = resolve
61+ } )
62+ )
63+ return ( ) => release ?.( )
64+ }
4165
4266const ARC = BROWSER_SOURCES . find ( ( { id } ) => id === 'arc' ) as BrowserSource
4367const PROFILE : BrowserProfile = {
@@ -71,12 +95,10 @@ function readsCookies(count: number) {
7195}
7296
7397beforeEach ( ( ) => {
74- vi . clearAllMocks ( )
7598 vi . mocked ( listAllBrowserProfiles ) . mockResolvedValue ( [ PROFILE ] )
7699 vi . mocked ( openInBrowserProfile ) . mockResolvedValue ( )
77100 readsCookies ( 2 )
78- cancelSignIn ( 'chat-a' )
79- cancelSignIn ( 'chat-b' )
101+ clearSignIns ( )
80102} )
81103
82104describe ( 'continueSignIn' , ( ) => {
@@ -132,6 +154,7 @@ describe('bringSignInBack', () => {
132154 await expect ( bringSignInBack ( 'chat-a' ) ) . resolves . toEqual ( {
133155 result : { cookiesImported : 2 , cookiesSkipped : 0 } ,
134156 handoff : expect . objectContaining ( { tabId : 'tab-1' , url : SIGN_IN_URL } ) ,
157+ current : true ,
135158 } )
136159 expect ( readBrowserCookies ) . toHaveBeenCalledWith ( '/arc/Profile 2/Cookies' , expect . any ( Buffer ) , {
137160 scope : { domain : 'amazon.com' , exact : false } ,
@@ -167,7 +190,10 @@ describe('bringSignInBack', () => {
167190 await vi . waitFor ( ( ) => expect ( finishRead ) . toBeTypeOf ( 'function' ) )
168191 await continueSignIn ( 'chat-a' , request ( 'https://accounts.google.com/signin' ) )
169192 finishRead ?.( )
170- await expect ( broughtBack ) . resolves . toMatchObject ( { result : { cookiesImported : 2 } } )
193+ await expect ( broughtBack ) . resolves . toMatchObject ( {
194+ result : { cookiesImported : 2 } ,
195+ current : false ,
196+ } )
171197
172198 expect ( getPendingSignIn ( 'chat-a' ) ) . toEqual ( { site : 'google.com' , browserLabel : 'Arc' } )
173199 } )
@@ -189,3 +215,56 @@ describe('bringSignInBack', () => {
189215 expect ( readBrowserCookies ) . not . toHaveBeenCalled ( )
190216 } )
191217} )
218+
219+ describe ( 'a handoff retired or moved while its browser launches' , ( ) => {
220+ it ( 'records nothing once a cancel lands mid-launch' , async ( ) => {
221+ const release = holdLaunch ( )
222+ const continuing = continueSignIn ( 'chat-a' , request ( ) )
223+ await vi . waitFor ( ( ) => expect ( openInBrowserProfile ) . toHaveBeenCalled ( ) )
224+ cancelSignIn ( 'chat-a' )
225+ release ( )
226+
227+ await expect ( continuing ) . resolves . toEqual ( { } )
228+ expect ( getPendingSignIn ( 'chat-a' ) ) . toBeNull ( )
229+ } )
230+
231+ it ( 'lets a newer continue win over an older launch that finishes later' , async ( ) => {
232+ const release = holdLaunch ( )
233+ const older = continueSignIn ( 'chat-a' , request ( ) )
234+ await vi . waitFor ( ( ) => expect ( openInBrowserProfile ) . toHaveBeenCalled ( ) )
235+ await continueSignIn ( 'chat-a' , request ( 'https://accounts.google.com/signin' ) )
236+ release ( )
237+
238+ await expect ( older ) . resolves . toEqual ( { } )
239+ expect ( getPendingSignIn ( 'chat-a' ) ) . toEqual ( { site : 'google.com' , browserLabel : 'Arc' } )
240+ } )
241+
242+ it ( 'follows a provisional chat to its saved id, mid-launch or after' , async ( ) => {
243+ const release = holdLaunch ( )
244+ const continuing = continueSignIn ( 'pending:new-chat' , request ( ) )
245+ await vi . waitFor ( ( ) => expect ( openInBrowserProfile ) . toHaveBeenCalled ( ) )
246+ migrateSignIn ( 'pending:new-chat' , 'chat-a' )
247+ release ( )
248+ await continuing
249+
250+ expect ( getPendingSignIn ( 'chat-a' ) ) . toEqual ( { site : 'amazon.com' , browserLabel : 'Arc' } )
251+ expect ( getPendingSignIn ( 'pending:new-chat' ) ) . toBeNull ( )
252+ migrateSignIn ( 'chat-a' , 'chat-b' )
253+ await expect ( bringSignInBack ( 'chat-b' ) ) . resolves . toMatchObject ( {
254+ result : { cookiesImported : 2 } ,
255+ } )
256+ } )
257+
258+ it ( 'forgets every handoff on account teardown, including one still launching' , async ( ) => {
259+ await continueSignIn ( 'chat-a' , request ( ) )
260+ const release = holdLaunch ( )
261+ const continuing = continueSignIn ( 'chat-b' , request ( ) )
262+ await vi . waitFor ( ( ) => expect ( openInBrowserProfile ) . toHaveBeenCalledTimes ( 2 ) )
263+ clearSignIns ( )
264+ release ( )
265+
266+ await expect ( continuing ) . resolves . toEqual ( { } )
267+ expect ( getPendingSignIn ( 'chat-a' ) ) . toBeNull ( )
268+ expect ( getPendingSignIn ( 'chat-b' ) ) . toBeNull ( )
269+ } )
270+ } )
0 commit comments