Skip to content

Commit 3ffdffd

Browse files
committed
add tests
1 parent 9fa37a6 commit 3ffdffd

5 files changed

Lines changed: 283 additions & 86 deletions

File tree

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { Auth0Client, RedirectConnectAccountOptions } from '../../src';
2+
3+
(<any>global).crypto = {
4+
subtle: {
5+
digest: () => ''
6+
},
7+
getRandomValues: () => ''
8+
};
9+
10+
describe('Auth0Client', () => {
11+
let client: Auth0Client;
12+
let mockMyAccountApi: any;
13+
let mockConnectAccountTransactionManager: any;
14+
const oldLocation = window.location;
15+
16+
beforeEach(() => {
17+
delete window.location;
18+
window.location = {
19+
...oldLocation,
20+
assign: jest.fn()
21+
} as Location;
22+
mockMyAccountApi = {
23+
connectAccount: jest.fn().mockResolvedValue({
24+
connect_uri: 'https://connect.example.com',
25+
connect_params: { ticket: 'test-ticket' },
26+
auth_session: 'test-session'
27+
})
28+
};
29+
mockConnectAccountTransactionManager = {
30+
create: jest.fn()
31+
};
32+
client = new Auth0Client({
33+
domain: 'test',
34+
clientId: 'abc',
35+
authorizationParams: {}
36+
} as any);
37+
// @ts-ignore
38+
client.myAccountApi = mockMyAccountApi;
39+
// @ts-ignore
40+
client.connectAccountTransactionManager =
41+
mockConnectAccountTransactionManager;
42+
});
43+
44+
afterEach(() => {
45+
window.location = oldLocation;
46+
});
47+
48+
describe('connectAccountWithRedirect', () => {
49+
it('should call myAccountApi.connectAccount with correct params', async () => {
50+
const options: RedirectConnectAccountOptions<any> = {
51+
connection: 'google-oauth2',
52+
authorization_params: { scope: 'profile email' }
53+
};
54+
55+
await client.connectAccountWithRedirect(options);
56+
57+
expect(mockMyAccountApi.connectAccount).toHaveBeenCalledWith(
58+
expect.objectContaining({
59+
connection: 'google-oauth2',
60+
authorization_params: { scope: 'profile email' }
61+
})
62+
);
63+
});
64+
65+
it('should create a transaction with correct state and code_verifier', async () => {
66+
const options: RedirectConnectAccountOptions<any> = {
67+
connection: 'github'
68+
};
69+
70+
await client.connectAccountWithRedirect(options);
71+
72+
expect(mockConnectAccountTransactionManager.create).toHaveBeenCalledWith(
73+
expect.objectContaining({
74+
state: expect.any(String),
75+
code_verifier: expect.any(String),
76+
auth_session: 'test-session',
77+
redirect_uri: expect.any(String)
78+
})
79+
);
80+
});
81+
82+
it('should use openUrl if provided', async () => {
83+
const openUrl = jest.fn();
84+
const options: RedirectConnectAccountOptions<any> = {
85+
connection: 'github',
86+
openUrl
87+
};
88+
89+
await client.connectAccountWithRedirect(options);
90+
91+
expect(openUrl).toHaveBeenCalledWith(
92+
'https://connect.example.com/?ticket=test-ticket'
93+
);
94+
});
95+
96+
it('should fallback to window.location.assign if openUrl is not provided', async () => {
97+
const options: RedirectConnectAccountOptions<any> = {
98+
connection: 'github'
99+
};
100+
101+
await client.connectAccountWithRedirect(options);
102+
103+
expect(window.location.assign).toHaveBeenCalledWith(
104+
expect.objectContaining({ href: 'https://connect.example.com/?ticket=test-ticket' })
105+
);
106+
});
107+
});
108+
});

__tests__/Auth0Client/handleRedirectCallback.test.ts

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ import {
3030
} from '../constants';
3131

3232
import { DEFAULT_AUTH0_CLIENT } from '../../src/constants';
33-
import { GenericError } from '../../src';
33+
import { Auth0Client, GenericError } from '../../src';
34+
import { CompleteResponse } from '../../src/MyAccountApiClient';
3435

3536
jest.mock('es-cookie');
3637
jest.mock('../../src/jwt');
@@ -522,4 +523,94 @@ describe('Auth0Client', () => {
522523
);
523524
});
524525
});
526+
527+
describe('handleRedirectCallback with connect_code', () => {
528+
let client: Auth0Client;
529+
let myAccountApi: any;
530+
let url: URL;
531+
let completeResponse: CompleteResponse;
532+
let transaction: any;
533+
534+
beforeEach(() => {
535+
url = new URL('https://example.com/callback');
536+
client = new Auth0Client({ domain: 'test', clientId: 'abc', authorizationParams: {} });
537+
transaction = {
538+
state: 'state123',
539+
code_verifier: 'verifier',
540+
auth_session: 'session',
541+
redirect_uri: 'uri',
542+
appState: { foo: 'bar' }
543+
};
544+
completeResponse = {
545+
id: 'account_123',
546+
connection: 'google-oauth2',
547+
access_type: 'offline',
548+
scopes: ['email', 'profile'],
549+
created_at: '2024-06-01T12:00:00Z',
550+
expires_at: '2025-06-01T12:00:00Z'
551+
};
552+
myAccountApi = {
553+
completeAccount: jest.fn().mockResolvedValue(completeResponse)
554+
};
555+
(client as any).myAccountApi = myAccountApi;
556+
(client as any).connectAccountTransactionManager = {
557+
get: jest.fn(),
558+
remove: jest.fn()
559+
};
560+
});
561+
562+
it('returns appState and data on success', async () => {
563+
(client as any).connectAccountTransactionManager.get.mockReturnValue(transaction);
564+
565+
url.searchParams.set('state', 'state123');
566+
url.searchParams.set('connect_code', 'code');
567+
568+
const result = await client.handleRedirectCallback(url.toString());
569+
570+
expect(myAccountApi.completeAccount).toHaveBeenCalledWith({
571+
auth_session: 'session',
572+
connect_code: 'code',
573+
redirect_uri: 'uri',
574+
code_verifier: 'verifier'
575+
});
576+
expect(result).toEqual({ appState: { foo: 'bar' }, ...completeResponse });
577+
expect((client as any).connectAccountTransactionManager.remove).toHaveBeenCalled();
578+
});
579+
580+
it('throws GenericError if transaction is missing', async () => {
581+
(client as any).connectAccountTransactionManager.get.mockReturnValue(undefined);
582+
url.searchParams.set('state', 'state123');
583+
url.searchParams.set('connect_code', 'code');
584+
await expect(client.handleRedirectCallback(url.toString())).rejects.toThrow(GenericError);
585+
});
586+
587+
it('throws GenericError if error is present', async () => {
588+
(client as any).connectAccountTransactionManager.get.mockReturnValue(transaction);
589+
590+
url.searchParams.set('error', 'err');
591+
url.searchParams.set('error_description', 'desc');
592+
url.searchParams.set('state', 'state123');
593+
await expect(client.handleRedirectCallback(url.toString())).rejects.toThrow(GenericError);
594+
expect((client as any).connectAccountTransactionManager.remove).toHaveBeenCalled();
595+
});
596+
597+
it('throws GenericError on state mismatch', async () => {
598+
(client as any).connectAccountTransactionManager.get.mockReturnValue(transaction);
599+
600+
url.searchParams.set('state', 'wrong-state');
601+
url.searchParams.set('connect_code', 'code');
602+
await expect(client.handleRedirectCallback(url.toString())).rejects.toThrow(GenericError);
603+
});
604+
605+
it('throws MyAccountApiError if completeAccount fails', async () => {
606+
(client as any).connectAccountTransactionManager.get.mockReturnValue(transaction);
607+
const apiError = new Error('API error');
608+
myAccountApi.completeAccount.mockRejectedValue(apiError);
609+
610+
url.searchParams.set('state', 'state123');
611+
url.searchParams.set('connect_code', 'code');
612+
await expect(client.handleRedirectCallback(url.toString())).rejects.toThrow('API error');
613+
expect((client as any).connectAccountTransactionManager.remove).toHaveBeenCalled();
614+
});
615+
});
525616
});

0 commit comments

Comments
 (0)