// __tests__/auth.test.ts import { Auth, Callback, clientConfig, getClientConfig, Logout, } from "@/features/User/oidcAuth"; import * as apiUtils from "@/utils/apiUtils"; import * as client from "openid-client"; clientConfig.url = "https://example.com"; const localAdress = "https://local.exemple.com"; describe("OpenID Client Auth Module", () => { beforeEach(() => { jest.clearAllMocks(); jest.spyOn(apiUtils, "getLocation").mockImplementation(() => localAdress); }); describe("getClientConfig", () => { it("should call discovery with clientConfig.url", async () => { const discoveryMock = client.discovery as jest.Mock; discoveryMock.mockResolvedValue("discoveredClient"); const result = await getClientConfig(); expect(discoveryMock).toHaveBeenCalledWith( new URL(clientConfig.url), clientConfig.client_id ); expect(result).toBe("discoveredClient"); }); }); describe("Auth", () => { it("should generate PKCE and build authorization URL with PKCE", async () => { (client.randomPKCECodeVerifier as jest.Mock).mockReturnValue( "verifier123" ); (client.calculatePKCECodeChallenge as jest.Mock).mockResolvedValue( "challenge123" ); // Mock discovery returning an object with serverMetadata() const discoveredClient = { serverMetadata: jest.fn(() => ({ supportsPKCE: () => true, })), }; (client.discovery as jest.Mock).mockResolvedValue(discoveredClient); (client.buildAuthorizationUrl as jest.Mock).mockReturnValue( "https://auth.url" ); const result = await Auth(); expect(client.randomPKCECodeVerifier).toHaveBeenCalled(); expect(client.calculatePKCECodeChallenge).toHaveBeenCalledWith( "verifier123" ); expect(client.buildAuthorizationUrl).toHaveBeenCalledWith( discoveredClient, expect.objectContaining({ code_challenge: "challenge123", code_challenge_method: clientConfig.code_challenge_method, redirect_uri: clientConfig.redirect_uri, scope: clientConfig.scope, }) ); expect(result).toEqual({ redirectTo: "https://auth.url", code_verifier: "verifier123", state: undefined, }); }); it("should generate state when PKCE not supported", async () => { (client.randomPKCECodeVerifier as jest.Mock).mockReturnValue( "verifier123" ); (client.calculatePKCECodeChallenge as jest.Mock).mockResolvedValue( "challenge123" ); const discoveredClient = { serverMetadata: jest.fn(() => ({ supportsPKCE: () => false, })), }; (client.discovery as jest.Mock).mockResolvedValue(discoveredClient); (client.randomState as jest.Mock).mockReturnValue("state123"); (client.buildAuthorizationUrl as jest.Mock).mockReturnValue( "https://auth.url" ); const result = await Auth(); expect(client.randomState).toHaveBeenCalled(); expect(result.state).toBe("state123"); expect(result.redirectTo).toBe("https://auth.url"); }); }); describe("Logout", () => { it("should build end session URL", async () => { const discoveredClient = {}; (client.discovery as jest.Mock).mockResolvedValue(discoveredClient); (client.buildEndSessionUrl as jest.Mock).mockReturnValue( "https://logout.url" ); const result = await Logout(); expect(client.buildEndSessionUrl).toHaveBeenCalledWith(discoveredClient, { post_logout_redirect_uri: clientConfig.post_logout_redirect_uri, }); expect(result).toBe("https://logout.url"); }); }); describe("Callback", () => { it("should perform authorization code grant and fetch user info", async () => { const discoveredClient = {}; (client.discovery as jest.Mock).mockResolvedValue(discoveredClient); const mockTokenSet = { access_token: "access123", claims: jest.fn(() => ({ sub: "user123" })), }; (client.authorizationCodeGrant as jest.Mock).mockResolvedValue( mockTokenSet ); (client.fetchUserInfo as jest.Mock).mockResolvedValue({ name: "User" }); const result = await Callback("verifier123", "state123"); expect(client.authorizationCodeGrant).toHaveBeenCalledWith( discoveredClient, new URL(localAdress), { pkceCodeVerifier: "verifier123", expectedState: "state123" } ); expect(client.fetchUserInfo).toHaveBeenCalledWith( discoveredClient, "access123", "user123" ); expect(result).toEqual({ tokenSet: mockTokenSet, userinfo: { name: "User" }, }); }); it("should catch and log errors", async () => { const error = new Error("fail"); (client.discovery as jest.Mock).mockResolvedValue({}); (client.authorizationCodeGrant as jest.Mock).mockRejectedValue(error); const consoleErrorSpy = jest .spyOn(console, "error") .mockImplementation(() => {}); const result = await Callback("verifier", "state"); expect(consoleErrorSpy).toHaveBeenCalledWith("Token grant error:", error); expect(result).toBeUndefined(); consoleErrorSpy.mockRestore(); }); }); });