44import { NextRequest } from 'next/server'
55import { beforeEach , describe , expect , it , vi } from 'vitest'
66
7- const { mockConsumeAttempt , mockGetContext , mockCompleteOAuth , mockRateLimit } = vi . hoisted ( ( ) => ( {
8- mockConsumeAttempt : vi . fn ( ) ,
9- mockGetContext : vi . fn ( ) ,
10- mockCompleteOAuth : vi . fn ( ) ,
11- mockRateLimit : vi . fn ( ) ,
7+ const mocks = vi . hoisted ( ( ) => ( {
8+ authenticate : vi . fn ( ) ,
9+ completeOAuth : vi . fn ( ) ,
10+ consumeAttempt : vi . fn ( ) ,
11+ rateLimit : vi . fn ( ) ,
1212} ) )
1313
14- vi . mock ( '@/lib/credential-groups/oauth-state ' , ( ) => ( {
15- consumeCredentialGroupOAuthAttempt : mockConsumeAttempt ,
14+ vi . mock ( '@/lib/credential-groups/application/enrollment-auth ' , ( ) => ( {
15+ authenticateCredentialGroupEnrollment : mocks . authenticate ,
1616} ) )
1717
18- vi . mock ( '@/lib/credential-groups/enrollments ' , ( ) => ( {
19- getCredentialGroupOAuthContext : mockGetContext ,
18+ vi . mock ( '@/lib/credential-groups/application/public-enrollment ' , ( ) => ( {
19+ completePublicCredentialGroupOAuth : { execute : mocks . completeOAuth } ,
2020} ) )
2121
22- vi . mock ( '@/lib/credential-groups/oauth' , ( ) => ( {
23- completeCredentialGroupOAuth : mockCompleteOAuth ,
22+ vi . mock ( '@/lib/credential-groups/oauth-state ' , ( ) => ( {
23+ consumeCredentialGroupOAuthAttempt : mocks . consumeAttempt ,
2424} ) )
2525
2626vi . mock ( '@/lib/credential-groups/rate-limit' , ( ) => ( {
27- enforcePublicCredentialGroupIpRateLimit : mockRateLimit ,
27+ enforcePublicCredentialGroupIpRateLimit : mocks . rateLimit ,
2828} ) )
2929
3030import { GET } from '@/app/api/credential-groups/oauth/[provider]/callback/route'
3131
32+ const principal = {
33+ kind : 'credential_group_enrollment' ,
34+ workspaceId : 'workspace-1' ,
35+ credentialGroupId : 'group-1' ,
36+ enrollmentId : 'enrollment-1' ,
37+ email : 'alex@example.com' ,
38+ invitationTokenHash : 'hash-1' ,
39+ } as const
3240const attempt = {
3341 provider : 'gmail' ,
3442 invitationToken : 'invitation-token' ,
@@ -45,21 +53,22 @@ function request(query: string) {
4553describe ( 'credential group OAuth callback' , ( ) => {
4654 beforeEach ( ( ) => {
4755 vi . clearAllMocks ( )
48- mockRateLimit . mockResolvedValue ( null )
49- mockConsumeAttempt . mockResolvedValue ( attempt )
50- mockGetContext . mockResolvedValue ( { enrollmentId : 'enrollment-1' } )
51- mockCompleteOAuth . mockResolvedValue ( undefined )
56+ mocks . rateLimit . mockResolvedValue ( null )
57+ mocks . consumeAttempt . mockResolvedValue ( attempt )
58+ mocks . authenticate . mockResolvedValue ( principal )
59+ mocks . completeOAuth . mockResolvedValue ( { connectedOptionId : 'option-1' } )
5260 } )
5361
54- it ( 'consumes provider-bound state and returns after a successful exchange' , async ( ) => {
55- const response = await GET ( request ( 'state=state-1&code=code-1' ) , context )
62+ it ( 'consumes provider-bound state and enters the application operation' , async ( ) => {
63+ const callbackRequest = request ( 'state=state-1&code=code-1' )
64+ const response = await GET ( callbackRequest , context )
5665
57- expect ( mockConsumeAttempt ) . toHaveBeenCalledWith ( 'state-1' )
58- expect ( mockCompleteOAuth ) . toHaveBeenCalledWith (
59- { enrollmentId : 'enrollment-1' } ,
60- attempt ,
61- 'code-1'
62- )
66+ expect ( mocks . consumeAttempt ) . toHaveBeenCalledWith ( 'state-1' )
67+ expect ( mocks . completeOAuth ) . toHaveBeenCalledWith ( {
68+ principal ,
69+ input : { attempt, code : 'code-1' } ,
70+ request : callbackRequest ,
71+ } )
6372 expect ( response . status ) . toBe ( 307 )
6473 expect ( response . headers . get ( 'location' ) ) . toBe (
6574 '/credential-groups/enroll/invitation-token?connected=option-1'
@@ -73,19 +82,19 @@ describe('credential group OAuth callback', () => {
7382 expect ( response . headers . get ( 'location' ) ) . toBe (
7483 '/credential-groups/enroll/invitation-token?oauth=denied'
7584 )
76- expect ( mockGetContext ) . not . toHaveBeenCalled ( )
77- expect ( mockCompleteOAuth ) . not . toHaveBeenCalled ( )
85+ expect ( mocks . authenticate ) . not . toHaveBeenCalled ( )
86+ expect ( mocks . completeOAuth ) . not . toHaveBeenCalled ( )
7887 } )
7988
8089 it ( 'rejects replayed, expired, or cross-provider state' , async ( ) => {
81- mockConsumeAttempt . mockResolvedValue ( null )
90+ mocks . consumeAttempt . mockResolvedValue ( null )
8291
8392 const replayedResponse = await GET ( request ( 'state=state-1&code=code-1' ) , context )
8493 expect ( replayedResponse . status ) . toBe ( 400 )
8594
86- mockConsumeAttempt . mockResolvedValue ( { ...attempt , provider : 'slack' } )
95+ mocks . consumeAttempt . mockResolvedValue ( { ...attempt , provider : 'slack' } )
8796 const mismatchedResponse = await GET ( request ( 'state=state-2&code=code-2' ) , context )
8897 expect ( mismatchedResponse . status ) . toBe ( 400 )
89- expect ( mockCompleteOAuth ) . not . toHaveBeenCalled ( )
98+ expect ( mocks . completeOAuth ) . not . toHaveBeenCalled ( )
9099 } )
91100} )
0 commit comments