test: fix timezone issues in EventDisplay tests
- Set explicit UTC timezone globally in jest.config.ts and setupTests.ts - Mock Intl.DateTimeFormat to use UTC by default while preserving prototype - Replace regex patterns with exact values for declarative assertions - Remove complex date formatting computations in tests - Use fixed dates (2025-01-15T10:00:00.000Z) for consistent test results - Fix EventDisplay.test.tsx to use exact time values instead of regex
This commit is contained in:
committed by
Benoit TELLIER
parent
59e7992cfe
commit
192ab17789
@@ -17,8 +17,7 @@ import {
|
|||||||
|
|
||||||
describe("Event Preview Display", () => {
|
describe("Event Preview Display", () => {
|
||||||
const mockOnClose = jest.fn();
|
const mockOnClose = jest.fn();
|
||||||
const day = new Date();
|
const day = new Date("2025-01-15T10:00:00.000Z"); // Fixed date in UTC: Jan 15, 2025 10:00 AM UTC
|
||||||
const RealDateToLocaleString = Date.prototype.toLocaleString;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
@@ -102,13 +101,6 @@ describe("Event Preview Display", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it("renders correctly event data", () => {
|
it("renders correctly event data", () => {
|
||||||
jest.spyOn(Date.prototype, "toLocaleString").mockImplementation(function (
|
|
||||||
this: Date,
|
|
||||||
locales?: Intl.LocalesArgument,
|
|
||||||
options?: Intl.DateTimeFormatOptions | undefined
|
|
||||||
): string {
|
|
||||||
return RealDateToLocaleString.call(this, "en-UK", options);
|
|
||||||
});
|
|
||||||
renderWithProviders(
|
renderWithProviders(
|
||||||
<EventPreviewModal
|
<EventPreviewModal
|
||||||
open={true}
|
open={true}
|
||||||
@@ -118,19 +110,20 @@ describe("Event Preview Display", () => {
|
|||||||
/>,
|
/>,
|
||||||
preloadedState
|
preloadedState
|
||||||
);
|
);
|
||||||
const weekday = day.toLocaleString("en-UK", { weekday: "long" });
|
|
||||||
const month = day.toLocaleString("en-UK", { month: "long" });
|
|
||||||
const dayOfMonth = day.getDate().toString();
|
|
||||||
|
|
||||||
|
// With UTC timezone, we can assert exact values
|
||||||
|
// Date: January 15, 2025 10:00 AM UTC
|
||||||
expect(screen.getByText("Test Event")).toBeInTheDocument();
|
expect(screen.getByText("Test Event")).toBeInTheDocument();
|
||||||
expect(screen.getByText(new RegExp(weekday, "i"))).toBeInTheDocument();
|
expect(screen.getByText(/Wednesday/i)).toBeInTheDocument();
|
||||||
expect(
|
expect(screen.getByText(/January/i)).toBeInTheDocument();
|
||||||
screen.getByText(new RegExp(`\\b${dayOfMonth}\\b ${month}`))
|
expect(screen.getByText(/15/)).toBeInTheDocument();
|
||||||
).toBeInTheDocument();
|
|
||||||
|
|
||||||
// Check time range is displayed (format may vary by locale/implementation)
|
// Check time is displayed with exact values
|
||||||
// Use regex to match time pattern since exact format depends on component implementation
|
// Format: "Wednesday, January 15, 2025 at 10:00 AM" and " – 10:00 AM" are in separate elements
|
||||||
expect(screen.getByText(/\d{2}:\d{2} – \d{2}:\d{2}/)).toBeInTheDocument();
|
expect(
|
||||||
|
screen.getByText(/Wednesday, January 15, 2025 at 10:00 AM/)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(screen.getByText(/– 10:00 AM/)).toBeInTheDocument();
|
||||||
|
|
||||||
expect(screen.getByText("Calendar")).toBeInTheDocument();
|
expect(screen.getByText("Calendar")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
@@ -569,7 +562,7 @@ describe("Event Preview Display", () => {
|
|||||||
|
|
||||||
describe("Event Full Display", () => {
|
describe("Event Full Display", () => {
|
||||||
const mockOnClose = jest.fn();
|
const mockOnClose = jest.fn();
|
||||||
const day = new Date();
|
const day = new Date("2025-01-15T10:00:00.000Z"); // Fixed date in UTC: Jan 15, 2025 10:00 AM UTC
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
@@ -645,20 +638,12 @@ describe("Event Full Display", () => {
|
|||||||
|
|
||||||
it("renders correctly event data with fixed timezone", () => {
|
it("renders correctly event data with fixed timezone", () => {
|
||||||
// Use fixed timezone UTC for consistent test results across all environments
|
// Use fixed timezone UTC for consistent test results across all environments
|
||||||
// Calculate expected local time from UTC time for exact value matching
|
|
||||||
const fixedDate = new Date("2025-01-15T10:00:00.000Z"); // 10AM UTC
|
const fixedDate = new Date("2025-01-15T10:00:00.000Z"); // 10AM UTC
|
||||||
const endDate = new Date(fixedDate.getTime() + 3600000); // 11AM UTC
|
const endDate = new Date(fixedDate.getTime() + 3600000); // 11AM UTC
|
||||||
|
|
||||||
// Format expected values in local timezone (what formatLocalDateTime produces)
|
// With UTC timezone set, formatLocalDateTime produces predictable values
|
||||||
const pad = (n: number) => n.toString().padStart(2, "0");
|
const expectedStart = "2025-01-15T10:00"; // 10:00 AM UTC
|
||||||
const formatLocal = (date: Date) => {
|
const expectedEnd = "2025-01-15T11:00"; // 11:00 AM UTC
|
||||||
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(
|
|
||||||
date.getDate()
|
|
||||||
)}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const expectedStart = formatLocal(fixedDate);
|
|
||||||
const expectedEnd = formatLocal(endDate);
|
|
||||||
|
|
||||||
const stateWithFixedDate = {
|
const stateWithFixedDate = {
|
||||||
...preloadedState,
|
...preloadedState,
|
||||||
@@ -693,11 +678,10 @@ describe("Event Full Display", () => {
|
|||||||
|
|
||||||
expect(screen.getByDisplayValue("Test Event")).toBeInTheDocument();
|
expect(screen.getByDisplayValue("Test Event")).toBeInTheDocument();
|
||||||
|
|
||||||
// Use exact equality assertions with calculated local time values
|
// Exact value assertions with declarative expected values
|
||||||
const startInput = screen.getByLabelText("Start");
|
const startInput = screen.getByLabelText("Start");
|
||||||
expect(startInput).toBeInTheDocument();
|
expect(startInput).toBeInTheDocument();
|
||||||
expect(startInput).toHaveAttribute("type", "datetime-local");
|
expect(startInput).toHaveAttribute("type", "datetime-local");
|
||||||
// Exact value assertion - formatLocalDateTime converts UTC to local time
|
|
||||||
expect(startInput.getAttribute("value")).toBe(expectedStart);
|
expect(startInput.getAttribute("value")).toBe(expectedStart);
|
||||||
|
|
||||||
const endInput = screen.getByLabelText("End");
|
const endInput = screen.getByLabelText("End");
|
||||||
@@ -1161,7 +1145,7 @@ describe("Event Full Display", () => {
|
|||||||
.mockImplementation((payload) => () => Promise.resolve(payload) as any);
|
.mockImplementation((payload) => () => Promise.resolve(payload) as any);
|
||||||
const spyRemove = jest.spyOn(eventThunks, "removeEvent");
|
const spyRemove = jest.spyOn(eventThunks, "removeEvent");
|
||||||
|
|
||||||
const day = new Date();
|
const testDate = new Date("2025-01-15T10:00:00.000Z");
|
||||||
const preloadedTwoCals = {
|
const preloadedTwoCals = {
|
||||||
...preloadedState,
|
...preloadedState,
|
||||||
calendars: {
|
calendars: {
|
||||||
@@ -1176,8 +1160,8 @@ describe("Event Full Display", () => {
|
|||||||
id: "event1",
|
id: "event1",
|
||||||
title: "Test Event",
|
title: "Test Event",
|
||||||
calId: "667037022b752d0026472254/cal1",
|
calId: "667037022b752d0026472254/cal1",
|
||||||
start: day.toISOString(),
|
start: testDate.toISOString(),
|
||||||
end: day.toISOString(),
|
end: testDate.toISOString(),
|
||||||
organizer: { cn: "test", cal_address: "test@test.com" },
|
organizer: { cn: "test", cal_address: "test@test.com" },
|
||||||
attendee: [{ cn: "test", cal_address: "test@test.com" }],
|
attendee: [{ cn: "test", cal_address: "test@test.com" }],
|
||||||
},
|
},
|
||||||
@@ -1229,16 +1213,15 @@ describe("Event Full Display", () => {
|
|||||||
|
|
||||||
// Mock getEvent API call to avoid API errors in test
|
// Mock getEvent API call to avoid API errors in test
|
||||||
const EventApi = require("../../../src/features/Events/EventApi");
|
const EventApi = require("../../../src/features/Events/EventApi");
|
||||||
|
const testDate = new Date("2025-01-15T10:00:00.000Z");
|
||||||
jest.spyOn(EventApi, "getEvent").mockResolvedValue({
|
jest.spyOn(EventApi, "getEvent").mockResolvedValue({
|
||||||
uid: "base",
|
uid: "base",
|
||||||
title: "Recurring event",
|
title: "Recurring event",
|
||||||
calId: "667037022b752d0026472254/cal1",
|
calId: "667037022b752d0026472254/cal1",
|
||||||
start: new Date().toISOString(),
|
start: testDate.toISOString(),
|
||||||
end: new Date().toISOString(),
|
end: testDate.toISOString(),
|
||||||
repetition: { freq: "daily", interval: 1 },
|
repetition: { freq: "daily", interval: 1 },
|
||||||
});
|
});
|
||||||
|
|
||||||
const day = new Date();
|
|
||||||
const preloadedRecurrence = {
|
const preloadedRecurrence = {
|
||||||
...preloadedState,
|
...preloadedState,
|
||||||
calendars: {
|
calendars: {
|
||||||
@@ -1252,8 +1235,8 @@ describe("Event Full Display", () => {
|
|||||||
uid: "base",
|
uid: "base",
|
||||||
calId: "667037022b752d0026472254/cal1",
|
calId: "667037022b752d0026472254/cal1",
|
||||||
title: "Recurring event",
|
title: "Recurring event",
|
||||||
start: day.toISOString(),
|
start: testDate.toISOString(),
|
||||||
end: day.toISOString(),
|
end: testDate.toISOString(),
|
||||||
organizer: { cal_address: "test@test.com" },
|
organizer: { cal_address: "test@test.com" },
|
||||||
attendee: [{ cal_address: "test@test.com", cn: "Test" }],
|
attendee: [{ cal_address: "test@test.com", cn: "Test" }],
|
||||||
repetition: { freq: "daily", interval: 1 },
|
repetition: { freq: "daily", interval: 1 },
|
||||||
@@ -1262,8 +1245,8 @@ describe("Event Full Display", () => {
|
|||||||
uid: "base/20250101",
|
uid: "base/20250101",
|
||||||
calId: "667037022b752d0026472254/cal1",
|
calId: "667037022b752d0026472254/cal1",
|
||||||
title: "Recurring event",
|
title: "Recurring event",
|
||||||
start: day.toISOString(),
|
start: testDate.toISOString(),
|
||||||
end: day.toISOString(),
|
end: testDate.toISOString(),
|
||||||
organizer: { cal_address: "test@test.com" },
|
organizer: { cal_address: "test@test.com" },
|
||||||
attendee: [{ cal_address: "test@test.com", cn: "Test" }],
|
attendee: [{ cal_address: "test@test.com", cn: "Test" }],
|
||||||
},
|
},
|
||||||
@@ -1271,8 +1254,8 @@ describe("Event Full Display", () => {
|
|||||||
uid: "base/20250201",
|
uid: "base/20250201",
|
||||||
calId: "667037022b752d0026472254/cal1",
|
calId: "667037022b752d0026472254/cal1",
|
||||||
title: "Recurring event",
|
title: "Recurring event",
|
||||||
start: day.toISOString(),
|
start: testDate.toISOString(),
|
||||||
end: day.toISOString(),
|
end: testDate.toISOString(),
|
||||||
organizer: { cal_address: "test@test.com" },
|
organizer: { cal_address: "test@test.com" },
|
||||||
attendee: [{ cal_address: "test@test.com", cn: "Test" }],
|
attendee: [{ cal_address: "test@test.com", cn: "Test" }],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import type { Config } from "jest";
|
import type { Config } from "jest";
|
||||||
|
|
||||||
|
// Set timezone to UTC for consistent test results across all environments
|
||||||
|
process.env.TZ = "UTC";
|
||||||
|
|
||||||
const config: Config = {
|
const config: Config = {
|
||||||
collectCoverage: true,
|
collectCoverage: true,
|
||||||
coverageDirectory: "coverage",
|
coverageDirectory: "coverage",
|
||||||
|
|||||||
@@ -4,6 +4,33 @@ import { TextEncoder } from "util";
|
|||||||
|
|
||||||
global.TextEncoder = TextEncoder;
|
global.TextEncoder = TextEncoder;
|
||||||
|
|
||||||
|
// Set timezone to UTC for consistent test results across all environments
|
||||||
|
process.env.TZ = "UTC";
|
||||||
|
|
||||||
|
// Mock Intl.DateTimeFormat to use UTC timezone by default
|
||||||
|
const OriginalDateTimeFormat = Intl.DateTimeFormat;
|
||||||
|
|
||||||
|
// Create a constructor function that preserves prototype
|
||||||
|
const MockedDateTimeFormat: any = function (
|
||||||
|
this: any,
|
||||||
|
locales?: string | string[],
|
||||||
|
options?: Intl.DateTimeFormatOptions
|
||||||
|
) {
|
||||||
|
// Only set timeZone to UTC if not explicitly specified
|
||||||
|
const modifiedOptions = options
|
||||||
|
? { timeZone: "UTC", ...options } // timeZone comes first so options can override it
|
||||||
|
: { timeZone: "UTC" };
|
||||||
|
return new OriginalDateTimeFormat(locales, modifiedOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Preserve the prototype so jest.spyOn works on methods
|
||||||
|
MockedDateTimeFormat.prototype = OriginalDateTimeFormat.prototype;
|
||||||
|
|
||||||
|
// Preserve static methods
|
||||||
|
Object.setPrototypeOf(MockedDateTimeFormat, OriginalDateTimeFormat);
|
||||||
|
|
||||||
|
global.Intl.DateTimeFormat = MockedDateTimeFormat;
|
||||||
|
|
||||||
jest.mock("openid-client", () => ({
|
jest.mock("openid-client", () => ({
|
||||||
discovery: jest.fn(),
|
discovery: jest.fn(),
|
||||||
randomPKCECodeVerifier: jest.fn(),
|
randomPKCECodeVerifier: jest.fn(),
|
||||||
|
|||||||
Reference in New Issue
Block a user