@snehal96/unimail
Version:
Unified email fetching & document extraction layer for modern web apps
130 lines (129 loc) • 5.61 kB
JavaScript
import { OutlookOAuthProvider } from '../../../src/auth/providers/OutlookOAuthProvider.js';
import { mockData } from '../../setup.js';
import { ConfidentialClientApplication } from '@azure/msal-node';
// Mock the @azure/msal-node package
jest.mock('@azure/msal-node', () => {
return {
ConfidentialClientApplication: jest.fn().mockImplementation(() => ({
getAuthCodeUrl: jest.fn().mockResolvedValue('https://login.microsoftonline.com/oauth2/authorize'),
acquireTokenByCode: jest.fn().mockResolvedValue({
accessToken: 'test-access-token',
refreshToken: 'test-refresh-token',
expiresOn: new Date(Date.now() + 3600000),
tokenType: 'Bearer',
idToken: 'test-id-token',
scopes: ['Mail.Read']
}),
acquireTokenByRefreshToken: jest.fn().mockResolvedValue({
accessToken: 'refreshed-access-token',
expiresOn: new Date(Date.now() + 3600000),
tokenType: 'Bearer',
idToken: 'refreshed-id-token',
scopes: ['Mail.Read']
// Note: acquireTokenByRefreshToken does not return a new refresh token
})
}))
};
});
const mockOAuth2 = ConfidentialClientApplication;
describe('OutlookOAuthProvider', () => {
let provider;
let options;
beforeEach(() => {
jest.clearAllMocks();
provider = new OutlookOAuthProvider();
options = {
...mockData.oauthOptions,
scopes: ['Mail.Read']
};
});
describe('initializeOAuthFlow', () => {
test('should initialize OAuth flow with correct parameters', async () => {
const result = await provider.initializeOAuthFlow(options);
expect(ConfidentialClientApplication).toHaveBeenCalledWith({
auth: {
clientId: options.clientId,
clientSecret: options.clientSecret,
authority: 'https://login.microsoftonline.com/common'
}
});
const mockMsalApp = mockOAuth2.mock.results[0].value;
expect(mockMsalApp.getAuthCodeUrl).toHaveBeenCalledWith({
scopes: ['Mail.Read'],
redirectUri: options.redirectUri,
prompt: "consent",
state: "test-state"
});
expect(result).toEqual({
authUrl: 'https://login.microsoftonline.com/oauth2/authorize',
state: "test-state"
});
});
test('should pass additional options correctly', async () => {
const extendedOptions = {
...options,
prompt: 'consent',
forceConsent: true
};
await provider.initializeOAuthFlow(extendedOptions);
expect(ConfidentialClientApplication).toHaveBeenCalledWith({
auth: {
clientId: options.clientId,
clientSecret: options.clientSecret,
authority: 'https://login.microsoftonline.com/common'
}
});
const mockMsalApp = mockOAuth2.mock.results[0].value;
expect(mockMsalApp.getAuthCodeUrl).toHaveBeenCalledWith({
scopes: ['Mail.Read'],
redirectUri: options.redirectUri,
prompt: 'consent',
state: "test-state"
});
});
});
describe('handleCallback', () => {
test('should exchange code for tokens', async () => {
const result = await provider.handleCallback('auth-code', options);
const mockMsalApp = mockOAuth2.mock.results[0].value;
expect(mockMsalApp.acquireTokenByCode).toHaveBeenCalledWith({
code: 'auth-code',
scopes: ['Mail.Read'],
redirectUri: options.redirectUri
});
expect(result).toEqual({
accessToken: 'test-access-token',
refreshToken: 'test-refresh-token',
expiresAt: expect.any(Number),
tokenType: 'Bearer',
idToken: 'test-id-token',
scope: 'Mail.Read'
});
});
});
describe('refreshToken', () => {
test('should refresh access token', async () => {
const result = await provider.refreshToken('refresh-token', options);
const mockMsalApp = mockOAuth2.mock.results[0].value;
expect(mockMsalApp.acquireTokenByRefreshToken).toHaveBeenCalledWith({
refreshToken: 'refresh-token',
scopes: ['Mail.Read']
});
expect(result).toEqual({
accessToken: 'refreshed-access-token',
expiresAt: expect.any(Number),
tokenType: 'Bearer',
idToken: 'refreshed-id-token',
scope: 'Mail.Read',
refreshToken: 'refresh-token' // Preserving the original refresh token
// Note: no refreshToken as MSAL doesn't return it on refresh
});
});
test('should preserve the original refresh token', async () => {
const result = await provider.refreshToken('original-refresh-token', options);
// The result should include the original refresh token even though
// MSAL doesn't return one during the refresh operation
expect(result.refreshToken).toBe('original-refresh-token');
});
});
});