test

const APIComponent = () => { const { instance, accounts } = useMsal(); useEffect(() => { if (accounts.length > 0) { setupAxiosInterceptors(instance, accounts); // Set up the interceptor when logged in } }, [instance, accounts]); const callApi = async () => { try { const response = await apiClient.get(‘https://your-api-endpoint.com’); console.log(“API Response:”, response.data); } catch (error) { console.error(“Error calling API:”, error); } }; return ( <div> <button onClick={callApi}>Call API</button> </div> ); };

 

import { render, screen, fireEvent, waitFor } from ‘@testing-library/react’;
import APIComponent from ‘./APIComponent’; // The component we want to test
import { useMsal } from ‘@azure/msal-react’;
import { rest } from ‘msw’;
import { setupServer } from ‘msw/node’;
import axios from ‘axios’;

// Mock MSAL’s useMsal and the acquireTokenSilent and acquireTokenRedirect methods
jest.mock(‘@azure/msal-react’, () => ({
useMsal: jest.fn(),
}));

const mockAcquireTokenSilent = jest.fn();
const mockAcquireTokenRedirect = jest.fn();

// MSW server to mock API responses
const server = setupServer(
// Initial 401 Unauthorized response to simulate expired token
rest.get(‘https://your-api-endpoint.com’, (req, res, ctx) => {
return res(ctx.status(401));
}),
// Successful response on retry
rest.get(‘https://your-api-endpoint.com’, (req, res, ctx) => {
return res(ctx.status(200), ctx.json({ data: ‘success’ }));
})
);

// Setup server before tests
beforeAll(() => server.listen());
afterEach(() => {
server.resetHandlers();
jest.clearAllMocks(); // Clear mock call history between tests
});
afterAll(() => server.close());

describe(‘APIComponent’, () => {
beforeEach(() => {
// Mock MSAL useMsal hook return
useMsal.mockReturnValue({
instance: {
acquireTokenSilent: mockAcquireTokenSilent,
acquireTokenRedirect: mockAcquireTokenRedirect,
},
accounts: [{ username: ‘testuser’ }],
});
});

test(‘handles token expiration by retrying with a refreshed token’, async () => {
// Mock acquireTokenSilent to return a token initially, then throw an error to simulate expiration
mockAcquireTokenSilent
.mockResolvedValueOnce({ accessToken: ‘initial-token’ }) // First call (for the initial request)
.mockResolvedValueOnce({ accessToken: ‘refreshed-token’ }); // Second call (for retry)

render(<APIComponent />);

// Trigger the API call
fireEvent.click(screen.getByText(‘Call API’));

// Wait for the interceptor to retry and make a successful request
await waitFor(() => expect(screen.getByText(‘API Response: success’)).toBeInTheDocument());

// Check if acquireTokenSilent was called twice
expect(mockAcquireTokenSilent).toHaveBeenCalledTimes(2);
expect(mockAcquireTokenRedirect).not.toHaveBeenCalled(); // Ensure no redirection occurred

// Verify the Authorization header for each call
const calls = axios.interceptors.request.handlers[0].fulfilled.mock.calls;
expect(calls[0][0].headers.Authorization).toBe(‘Bearer initial-token’);
expect(calls[1][0].headers.Authorization).toBe(‘Bearer refreshed-token’);
});
});