Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/web/src/__tests__/utils/event.util/test.event.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { faker } from "@faker-js/faker";
import { Origin, Priorities } from "@core/constants/core.constants";
import dayjs from "@core/util/date/dayjs";
import { Schema_DraftEvent } from "@web/common/schemas/events/draft.event.schemas";
import { Schema_WebEvent } from "@web/common/schemas/events/web.event.schemas";

/**
* These utils focus on generating web-specific schemas.
* For generating API-compatible events, see utils in `@core`
*/

export const createWebEvent = (
overrides: Partial<Schema_WebEvent> = {},
): Schema_WebEvent => {
const start = faker.date.future();
const end = dayjs(start).add(1, "hour");

return {
_id: faker.string.uuid(),
origin: Origin.COMPASS,
title: faker.lorem.sentence(),
description: faker.lorem.paragraph(),
startDate: start.toISOString(),
endDate: end.toISOString(),
priority: faker.helpers.arrayElement(Object.values(Priorities)),
recurrence: undefined,
user: faker.string.uuid(),
...overrides,
};
};
259 changes: 259 additions & 0 deletions packages/web/src/common/parsers/event.parser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
import { faker } from "@faker-js/faker";
import { Priorities } from "@core/constants/core.constants";
import { createWebEvent } from "../../__tests__/utils/event.util/test.event.util";
import { WebEventParser, isEventDirty } from "./event.parser";

describe("WebEventParser", () => {
it("should return false when draft and original events are identical", () => {
const originalEvent = createWebEvent();
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: originalEvent.recurrence,
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(false);
});

it("should return true when title has changed", () => {
const originalEvent = createWebEvent();
const draftEvent = createWebEvent({
title: "Different Title",
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: originalEvent.recurrence,
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(true);
});

it("should return true when description has changed", () => {
const originalEvent = createWebEvent();
const draftEvent = createWebEvent({
title: originalEvent.title,
description: "Different Description",
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: originalEvent.recurrence,
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(true);
});

it("should return true when startDate has changed", () => {
const originalEvent = createWebEvent();
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: faker.date.future().toISOString(),
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: originalEvent.recurrence,
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(true);
});

it("should return true when endDate has changed", () => {
const originalEvent = createWebEvent();
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: faker.date.future().toISOString(),
priority: originalEvent.priority,
recurrence: originalEvent.recurrence,
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(true);
});

it("should return true when priority has changed", () => {
const originalEvent = createWebEvent({ priority: Priorities.WORK });
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: Priorities.SELF,
recurrence: originalEvent.recurrence,
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(true);
});

it("should return true when recurrence is added to non-recurring event", () => {
const originalEvent = createWebEvent({ recurrence: undefined });
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: { rule: ["RRULE:FREQ=WEEKLY"] },
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(true);
});

it("should return true when recurrence is removed from recurring event", () => {
const originalEvent = createWebEvent({
recurrence: { rule: ["RRULE:FREQ=WEEKLY"] },
});
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: undefined,
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(true);
});

it("should return true when recurrence rules have changed", () => {
const originalEvent = createWebEvent({
recurrence: { rule: ["RRULE:FREQ=WEEKLY"] },
});
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: { rule: ["RRULE:FREQ=DAILY"] },
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(true);
});

it("should return true when recurrence rules array length has changed", () => {
const originalEvent = createWebEvent({
recurrence: { rule: ["RRULE:FREQ=WEEKLY"] },
});
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: { rule: ["RRULE:FREQ=WEEKLY", "RRULE:BYDAY=MO"] },
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(true);
});

it("should return true when dates change in recurring event", () => {
const originalEvent = createWebEvent({
recurrence: { rule: ["RRULE:FREQ=WEEKLY"] },
startDate: "2024-01-01T10:00:00Z",
endDate: "2024-01-01T11:00:00Z",
});
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: "2024-01-01T11:00:00Z", // Different start time
endDate: "2024-01-01T12:00:00Z", // Different end time
priority: originalEvent.priority,
recurrence: { rule: ["RRULE:FREQ=WEEKLY"] }, // Same recurrence
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(true);
});

it("should return false when only non-tracked fields change", () => {
const originalEvent = createWebEvent();
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: originalEvent.recurrence,
user: "different-user", // This field is not tracked
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(false);
});

it("should handle undefined recurrence gracefully", () => {
const originalEvent = createWebEvent({ recurrence: undefined });
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: undefined,
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(false);
});

it("should handle empty recurrence rules", () => {
const originalEvent = createWebEvent({
recurrence: { rule: [] },
});
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: { rule: [] },
});

const parser = new WebEventParser(draftEvent, originalEvent);
expect(parser.isDirty()).toBe(false);
});
});

describe("isDraftDirty", () => {
it("should work as a standalone function", () => {
const originalEvent = createWebEvent();
const draftEvent = createWebEvent({
title: "Different Title",
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: originalEvent.recurrence,
});

expect(isEventDirty(draftEvent, originalEvent)).toBe(true);
});

it("should return false for identical events", () => {
const originalEvent = createWebEvent();
const draftEvent = createWebEvent({
title: originalEvent.title,
description: originalEvent.description,
startDate: originalEvent.startDate,
endDate: originalEvent.endDate,
priority: originalEvent.priority,
recurrence: originalEvent.recurrence,
});

expect(isEventDirty(draftEvent, originalEvent)).toBe(false);
});
});
Loading