@@ -21,6 +21,11 @@ vi.mock('@/lib/credential-groups/provider-registry', () => ({
2121 getCredentialGroupProviderAdapter : ( ) => adapter ,
2222} ) )
2323
24+ vi . mock ( '@/lib/credentials/managed-oauth' , ( ) => ( {
25+ decryptManagedOAuthTokenSet : vi . fn ( ) ,
26+ encryptManagedOAuthTokenSet : vi . fn ( ) . mockResolvedValue ( 'encrypted-token-set' ) ,
27+ } ) )
28+
2429import { completeCredentialGroupOAuth } from '@/lib/credential-groups/oauth'
2530
2631const POLICY = {
@@ -97,4 +102,44 @@ describe('credential group OAuth persistence', () => {
97102 expect ( dbChainMockFns . update ) . not . toHaveBeenCalled ( )
98103 expect ( dbChainMockFns . insert ) . not . toHaveBeenCalled ( )
99104 } )
105+
106+ it ( 'preserves completed enrollment state when an account reconnects' , async ( ) => {
107+ dbChainMockFns . limit . mockResolvedValueOnce ( [ { status : 'completed' } ] ) . mockResolvedValueOnce ( [
108+ {
109+ id : 'credential-1' ,
110+ providerSubjectId : 'google-subject-1' ,
111+ encryptedOauthTokenSet : null ,
112+ refreshTokenExpiresAt : null ,
113+ } ,
114+ ] )
115+ dbChainMockFns . returning
116+ . mockResolvedValueOnce ( [ { id : 'credential-1' } ] )
117+ . mockResolvedValueOnce ( [ { id : CONTEXT . enrollmentId } ] )
118+
119+ await completeCredentialGroupOAuth (
120+ { ...CONTEXT , enrollmentStatus : 'completed' } ,
121+ {
122+ state : 'state-1' ,
123+ provider : 'gmail' ,
124+ nonceHash : 'nonce-hash' ,
125+ enrollmentId : CONTEXT . enrollmentId ,
126+ credentialGroupId : CONTEXT . credentialGroupId ,
127+ optionId : CONTEXT . option . id ,
128+ authorizationAppId : POLICY . authorizationAppId ,
129+ scopeVersion : POLICY . scopeVersion ,
130+ requiredScopes : POLICY . requiredScopes ,
131+ redirectUri : 'https://sim.ai/api/credential-groups/oauth/gmail/callback' ,
132+ codeVerifier : 'verifier' ,
133+ invitationToken : 'invitation-token' ,
134+ createdAt : Date . now ( ) ,
135+ } ,
136+ 'authorization-code'
137+ )
138+
139+ const enrollmentUpdate = dbChainMockFns . set . mock . calls [ 1 ] ?. [ 0 ]
140+ expect ( enrollmentUpdate ) . toEqual (
141+ expect . objectContaining ( { status : 'completed' , updatedAt : expect . any ( Date ) } )
142+ )
143+ expect ( enrollmentUpdate ) . not . toHaveProperty ( 'completedAt' )
144+ } )
100145} )
0 commit comments