[#38] Adding several missing tests and correct CI setup
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
// __test__/features/calendars/calendarApi.test.ts
|
||||
|
||||
import {
|
||||
getCalendar,
|
||||
getCalendars,
|
||||
} from "../../../src/features/Calendars/CalendarApi";
|
||||
import { clientConfig } from "../../../src/features/User/oidcAuth";
|
||||
import { api } from "../../../src/utils/apiUtils";
|
||||
clientConfig.url = "https://example.com";
|
||||
|
||||
jest.mock("../../../src/utils/apiUtils");
|
||||
|
||||
describe("Calendar API", () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("getCalendars", () => {
|
||||
it("fetches calendar list for a user", async () => {
|
||||
const mockUserId = "user123";
|
||||
const mockResponse = [{ id: "calendar1" }, { id: "calendar2" }];
|
||||
|
||||
(api.get as jest.Mock).mockReturnValue({
|
||||
json: jest.fn().mockResolvedValue(mockResponse),
|
||||
});
|
||||
|
||||
const calendars = await getCalendars(mockUserId);
|
||||
|
||||
expect(api.get).toHaveBeenCalledWith(
|
||||
`dav/calendars/${mockUserId}.json?personal=true&sharedDelegationStatus=accepted&sharedPublicSubscription=true&withRights=true`,
|
||||
{
|
||||
headers: { Accept: "application/calendar+json" },
|
||||
}
|
||||
);
|
||||
expect(calendars).toEqual(mockResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getCalendar", () => {
|
||||
it("fetches calendar events for a given ID and match window", async () => {
|
||||
const calendarId = "calendar1";
|
||||
const match = { start: "2025-07-01", end: "2025-07-31" };
|
||||
const mockCalendarData = { events: ["event1", "event2"] };
|
||||
|
||||
(api as unknown as jest.Mock).mockReturnValue({
|
||||
json: jest.fn().mockResolvedValue(mockCalendarData),
|
||||
});
|
||||
|
||||
const result = await getCalendar(calendarId, match);
|
||||
|
||||
expect(api).toHaveBeenCalledWith(`dav/calendars/${calendarId}.json`, {
|
||||
method: "REPORT",
|
||||
headers: {
|
||||
Accept: "application/json, text/plain, */*",
|
||||
},
|
||||
body: JSON.stringify({ match }),
|
||||
});
|
||||
|
||||
expect(result).toEqual(mockCalendarData);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
import { screen, waitFor } from "@testing-library/react";
|
||||
import thunk from "redux-thunk";
|
||||
import HandleLogin from "../../../src/features/User/HandleLogin";
|
||||
import * as oidcAuth from "../../../src/features/User/oidcAuth";
|
||||
import { renderWithProviders } from "../../utils/Renderwithproviders";
|
||||
import { clientConfig } from "../../../src/features/User/oidcAuth";
|
||||
import * as apiUtils from "../../../src/utils/apiUtils";
|
||||
clientConfig.url = "https://example.com";
|
||||
|
||||
|
||||
describe("HandleLogin", () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(apiUtils, "redirectTo").mockImplementation(() => {});
|
||||
|
||||
jest.clearAllMocks();
|
||||
sessionStorage.clear();
|
||||
});
|
||||
|
||||
test("redirects and sets sessionStorage when no userData", async () => {
|
||||
const loginUrlMock = {
|
||||
code_verifier: "verifier123",
|
||||
state: "state123",
|
||||
redirectTo: new URL("http://login.url"),
|
||||
};
|
||||
|
||||
jest.spyOn(oidcAuth, "Auth").mockResolvedValue(loginUrlMock);
|
||||
|
||||
renderWithProviders(<HandleLogin />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(oidcAuth.Auth).toHaveBeenCalled();
|
||||
expect(sessionStorage.getItem("redirectState")).toEqual(
|
||||
JSON.stringify({
|
||||
code_verifier: "verifier123",
|
||||
state: "state123",
|
||||
})
|
||||
);
|
||||
expect(apiUtils.redirectTo).toHaveBeenCalledWith(loginUrlMock.redirectTo);
|
||||
});
|
||||
|
||||
expect(screen.getByText(/error/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("shows Loading when userData exists and calendars pending is true", () => {
|
||||
const preloadedState = {
|
||||
user: {
|
||||
userData: {
|
||||
sub: "cmoussu",
|
||||
email: "cmoussu@linagora.com",
|
||||
sid: "aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro",
|
||||
openpaasId: "667037022b752d0026472254",
|
||||
},
|
||||
},
|
||||
calendars: { list: {}, pending: true },
|
||||
};
|
||||
|
||||
renderWithProviders(<HandleLogin />, preloadedState);
|
||||
expect(screen.getByAltText(/loading/i)).toBeInTheDocument();
|
||||
});
|
||||
test("shows Loading when userData exists and calendars pending is false", () => {
|
||||
const preloadedState = {
|
||||
user: {
|
||||
userData: {
|
||||
sub: "cmoussu",
|
||||
email: "cmoussu@linagora.com",
|
||||
sid: "aiYbWZSk2g0F+LrQeD7Dg4QcUMR8R/zTZdZBiA7N6Ro",
|
||||
openpaasId: "667037022b752d0026472254",
|
||||
},
|
||||
},
|
||||
};
|
||||
renderWithProviders(<HandleLogin />, preloadedState);
|
||||
|
||||
expect(screen.getByAltText("loading")).toBeInTheDocument();
|
||||
});
|
||||
test("shows Error when userData doesnt exists and calendars pending is false", () => {
|
||||
renderWithProviders(<HandleLogin />);
|
||||
|
||||
expect(screen.getByText("Error")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
// __test__/features/user/CallbackResume.test.tsx
|
||||
import React from "react";
|
||||
import { render, waitFor } from "@testing-library/react";
|
||||
import { CallbackResume } from "../../../src/features/User/LoginCallback";
|
||||
import { useAppDispatch } from "../../../src/app/hooks";
|
||||
import * as oidcAuth from "../../../src/features/User/oidcAuth";
|
||||
import { push } from "redux-first-history";
|
||||
import {
|
||||
setTokens,
|
||||
setUserData,
|
||||
getOpenPaasUserIdAsync,
|
||||
} from "../../../src/features/User/userSlice";
|
||||
import { getCalendarsListAsync } from "../../../src/features/Calendars/CalendarSlice";
|
||||
import { renderWithProviders } from "../../utils/Renderwithproviders";
|
||||
|
||||
// Mocks
|
||||
jest.mock("../../../src/app/hooks", () => ({
|
||||
useAppDispatch: jest.fn(),
|
||||
useAppSelector: jest.fn(() => ({})),
|
||||
}));
|
||||
|
||||
jest.mock("../../../src/features/User/oidcAuth", () => ({
|
||||
Callback: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("../../../src/features/User/userSlice", () => ({
|
||||
setUserData: jest.fn((data) => ({ type: "SET_USER", payload: data })),
|
||||
setTokens: jest.fn((tokens) => ({ type: "SET_TOKENS", payload: tokens })),
|
||||
getOpenPaasUserIdAsync: jest.fn(() => ({ type: "GET_USER_ID" })),
|
||||
}));
|
||||
|
||||
jest.mock("../../../src/features/Calendars/CalendarSlice", () => ({
|
||||
getCalendarsListAsync: jest.fn(() => ({ type: "GET_CALENDARS" })),
|
||||
}));
|
||||
|
||||
describe("CallbackResume", () => {
|
||||
const dispatch = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(useAppDispatch as unknown as jest.Mock).mockReturnValue(dispatch);
|
||||
});
|
||||
|
||||
it("should call Callback and dispatch necessary actions", async () => {
|
||||
const mockTokenSet = { access_token: "abc" };
|
||||
const mockUserInfo = { name: "Test User" };
|
||||
|
||||
const mockData = {
|
||||
tokenSet: mockTokenSet,
|
||||
userinfo: mockUserInfo,
|
||||
};
|
||||
|
||||
(oidcAuth.Callback as jest.Mock).mockResolvedValue(mockData);
|
||||
|
||||
sessionStorage.setItem(
|
||||
"redirectState",
|
||||
JSON.stringify({ code_verifier: "verifier123", state: "state456" })
|
||||
);
|
||||
|
||||
render(<CallbackResume />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(oidcAuth.Callback).toHaveBeenCalledWith("verifier123", "state456");
|
||||
expect(dispatch).toHaveBeenCalledWith(setUserData(mockUserInfo));
|
||||
expect(dispatch).toHaveBeenCalledWith(setTokens(mockTokenSet));
|
||||
expect(dispatch).toHaveBeenCalledWith(getOpenPaasUserIdAsync());
|
||||
expect(dispatch).toHaveBeenCalledWith(getCalendarsListAsync());
|
||||
expect(dispatch).toHaveBeenCalledWith(push("/"));
|
||||
expect(sessionStorage.getItem("redirectState")).toBe(null);
|
||||
expect(sessionStorage.getItem("tokenSet")).toEqual(
|
||||
JSON.stringify(mockTokenSet)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("should handle missing redirectState gracefully", async () => {
|
||||
sessionStorage.removeItem("redirectState");
|
||||
renderWithProviders(<CallbackResume />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(dispatch).toHaveBeenCalledWith(push("/"));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,172 @@
|
||||
// __tests__/auth.test.ts
|
||||
import * as client from "openid-client";
|
||||
import {
|
||||
clientConfig,
|
||||
getClientConfig,
|
||||
Auth,
|
||||
Logout,
|
||||
Callback,
|
||||
} from "../../../src/features/User/oidcAuth";
|
||||
import * as apiUtils from "../../../src/utils/apiUtils";
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import { clientConfig } from "../../../src/features/User/oidcAuth";
|
||||
import getOpenPaasUserId from "../../../src/features/User/userAPI";
|
||||
import { api } from "../../../src/utils/apiUtils";
|
||||
|
||||
jest.mock("../../../src/utils/apiUtils");
|
||||
|
||||
clientConfig.url = "https://example.com";
|
||||
|
||||
describe("getOpenPaasUserId", () => {
|
||||
it("should fetch and return user data", async () => {
|
||||
const mockUser = { id: "123", name: "OpenPaas User" };
|
||||
|
||||
(api.get as jest.Mock).mockReturnValue({
|
||||
json: jest.fn().mockResolvedValue(mockUser),
|
||||
});
|
||||
|
||||
const result = await getOpenPaasUserId();
|
||||
|
||||
expect(api.get).toHaveBeenCalledWith("api/user");
|
||||
expect(result).toEqual(mockUser);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user