Skip to content

Commit b992652

Browse files
authored
feat(web): seed demo data (#1466)
* feat(storage): add demo data seed migration and related tests - Introduced a new migration for seeding demo data for first-time users, including events and tasks with sensible defaults. - Updated storage migration tests to accommodate new localStorage keys and ensure proper handling of migration flags. - Added comprehensive tests for the demo data seed migration to verify correct data population and behavior under various conditions. - Refactored existing migration tests to improve clarity and maintainability. * refactor(event): remove default somedays creation from EventService - Eliminated the createDefaultSomedays method from EventService to streamline event management. - Updated UserService to remove calls to createDefaultSomedays during user initialization, focusing on priority creation instead. - Adjusted related tests to reflect the removal of default someday events, ensuring consistency in user data setup. * feat(tests): implement prepareEmptyStorageForTests utility for test setup - Added a new utility function, prepareEmptyStorageForTests, to streamline the test setup process by clearing localStorage and IndexedDB, and setting a migration flag to prevent demo data seeding. - Updated multiple test files to utilize this new utility, enhancing consistency and reducing redundancy in test initialization. - Refactored existing tests to ensure they correctly prepare the storage state before each test, improving reliability and maintainability. * feat(demo-data): update demo data seed to include all-day event and adjust event counts - Added an all-day event titled "Deep work day" to the demo data seed, enhancing the variety of events generated for testing. - Updated the expected event count in tests to reflect the addition of the new all-day event, ensuring accurate verification of event creation. - Adjusted documentation to clarify the changes in the demo data structure, including the new all-day event and updated counts for today’s events. * refactor(demo-data): simplify demo data seed documentation - Removed detailed descriptions of demo data contents from the migration documentation to streamline the information presented. - Updated the demo data seed migration to maintain clarity while focusing on essential details for first-time users. * feat(tests): enhance storage tests with mock adapter and migration flag updates - Introduced a new utility function, createMockStorageAdapter, to streamline the creation of mock storage adapters for testing. - Updated existing tests to utilize the new mock adapter, improving consistency and reducing redundancy in test setup. - Refactored migration tests to replace hardcoded migration flag keys with the new DEMO_DATA_SEED_FLAG_KEY, ensuring clarity and maintainability. - Enhanced the demo data seed migration to utilize the updated flag key, aligning with recent changes in the storage architecture. * feat(demo-data): add timed events with RFC3339 offset format to demo data seed - Introduced a new test case to verify the creation of timed events with 15-minute-aligned times in RFC3339 offset format, ensuring no seconds or milliseconds are included. - Updated the demo data generation logic to align with the new event format, enhancing the consistency and accuracy of the demo data for testing purposes. - Adjusted existing event creation functions to ensure proper handling of time formatting, improving overall data integrity. * feat(demo-data): enhance demo data seed with additional event properties - Added `isAllDay` and `isSomeday` properties to multiple events in the demo data seed, ensuring more accurate representation of event types. - Renamed an event from "Catch up with a friend" to "Call a friend" and added a description for clarity. - Updated the demo data generation logic to improve the variety and detail of events for testing purposes. * feat(demo-data): enhance demo data seed with grid position data for timed events - Added a new test case to verify that default grid position data is correctly added to seeded timed events, ensuring proper layout handling. - Updated the demo data generation logic to include grid event assembly for timed events, improving the accuracy of event positioning in the demo data. - Enhanced existing event descriptions to provide more context for testing scenarios. * feat(demo-data): enhance demo data seed with event schema validation - Added a new test case to ensure seeded events conform to their respective schemas, validating both grid and core event structures. - Updated the demo data generation logic to include position data for timed events, improving layout accuracy in the demo data. - Enhanced event descriptions for clarity in testing scenarios, ensuring better context for validation checks.
1 parent 502b7ac commit b992652

15 files changed

Lines changed: 580 additions & 176 deletions

File tree

packages/backend/src/event/services/event.service.ts

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import type { GaxiosError } from "gaxios";
22
import { ClientSession, Document, Filter, ObjectId, WithId } from "mongodb";
33
import {
4-
Origin,
5-
Priorities,
6-
RRULE,
7-
RRULE_COUNT_MONTHS,
8-
RRULE_COUNT_WEEKS,
94
SOMEDAY_MONTHLY_LIMIT,
105
SOMEDAY_WEEKLY_LIMIT,
116
} from "@core/constants/core.constants";
@@ -14,22 +9,18 @@ import { Status } from "@core/errors/status.codes";
149
import { MapEvent } from "@core/mappers/map.event";
1510
import {
1611
CalendarProvider,
17-
CompassEventStatus,
18-
CompassThisEvent,
1912
EventUpdatePayload,
2013
EventUpdateSchema,
2114
Params_DeleteMany,
2215
Payload_Order,
2316
Query_Event,
24-
RecurringEventUpdateScope,
2517
Result_DeleteMany,
2618
Schema_Event,
2719
Schema_Event_Core,
2820
WithCompassId,
2921
} from "@core/types/event.types";
3022
import { gSchema$Event } from "@core/types/gcal";
3123
import { IDSchema } from "@core/types/type.utils";
32-
import { getCurrentRangeDates } from "@core/util/date/date.util";
3324
import { CompassEventRRule } from "@core/util/event/compass.event.rrule";
3425
import { isInstance, parseCompassEventDate } from "@core/util/event/event.util";
3526
import { getGcalClient } from "@backend/auth/services/google.auth.service";
@@ -41,78 +32,8 @@ import gcalService from "@backend/common/services/gcal/gcal.service";
4132
import mongoService from "@backend/common/services/mongo.service";
4233
import { reorderEvents } from "@backend/event/queries/event.queries";
4334
import { getReadAllFilter } from "@backend/event/services/event.service.util";
44-
import { CompassSyncProcessor } from "@backend/sync/services/sync/compass.sync.processor";
4535

4636
class EventService {
47-
createDefaultSomedays = async (userId: string, session?: ClientSession) => {
48-
const { week, month } = getCurrentRangeDates();
49-
50-
const defaultWeekly: Schema_Event_Core = {
51-
title: "⭐ That one thing...",
52-
isAllDay: false,
53-
isSomeday: true,
54-
startDate: week.startDate,
55-
endDate: week.endDate,
56-
priority: Priorities.UNASSIGNED,
57-
origin: Origin.COMPASS,
58-
description: `... that you wanna do this week, but aren't sure when.\
59-
\nKeep it here for safekeeping, then drag it over to the calendar once you're ready to commit times.\
60-
\n\nThese sidebar events are:\
61-
\n-filtered by the calendar week you're on\
62-
\n-limited to ${SOMEDAY_WEEKLY_LIMIT} per week`,
63-
user: userId,
64-
};
65-
66-
const weeklyRepeat: Schema_Event_Core = {
67-
title: "🪴 Water plants",
68-
isAllDay: false,
69-
isSomeday: true,
70-
startDate: week.startDate,
71-
endDate: week.endDate,
72-
origin: Origin.COMPASS,
73-
priority: Priorities.SELF,
74-
description: `This event happens every week.\
75-
\n\nRather than repeating forever, however, it'll stop after ${
76-
RRULE_COUNT_WEEKS / RRULE_COUNT_MONTHS
77-
} months.\
78-
\n\nThis encourages frequent re-prioritizing, rather than running on autopilot indefinitely.`,
79-
recurrence: {
80-
rule: [RRULE.WEEK],
81-
},
82-
user: userId,
83-
};
84-
85-
const monthlyRepeat: Schema_Event_Core = {
86-
isAllDay: false,
87-
isSomeday: true,
88-
origin: Origin.COMPASS,
89-
priority: Priorities.RELATIONS,
90-
startDate: month.startDate,
91-
endDate: month.endDate,
92-
title: "🎲 Schedule game night",
93-
recurrence: {
94-
rule: [RRULE.MONTH],
95-
},
96-
description: `This one repeats once a month for ${RRULE_COUNT_MONTHS} months`,
97-
user: userId,
98-
};
99-
100-
return CompassSyncProcessor.processEvents(
101-
[weeklyRepeat, monthlyRepeat, defaultWeekly].map((e) => {
102-
const eventId = new ObjectId().toString();
103-
104-
return {
105-
eventId,
106-
userId,
107-
payload: { ...e, _id: eventId } as CompassThisEvent["payload"],
108-
status: CompassEventStatus.CONFIRMED,
109-
applyTo: RecurringEventUpdateScope.THIS_EVENT,
110-
};
111-
}),
112-
session,
113-
);
114-
};
115-
11637
/*
11738
Deletes all of a user's events
11839
REMINDER: this should only delete a user's *Compass* events --

packages/backend/src/user/services/user.service.test.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import calendarService from "@backend/calendar/services/calendar.service";
1414
import { UserError } from "@backend/common/errors/user/user.errors";
1515
import { initSupertokens } from "@backend/common/middleware/supertokens.middleware";
1616
import mongoService from "@backend/common/services/mongo.service";
17-
import eventService from "@backend/event/services/event.service";
1817
import priorityService from "@backend/priority/services/priority.service";
1918
import userMetadataService from "@backend/user/services/user-metadata.service";
2019
import userService from "@backend/user/services/user.service";
@@ -85,7 +84,6 @@ describe("UserService", () => {
8584
expect(storedUser).not.toBeNull();
8685

8786
await priorityService.createDefaultPriorities(userId);
88-
await eventService.createDefaultSomedays(userId);
8987
await SyncDriver.createSync(storedUser!, true);
9088
await userService.startGoogleCalendarSync(userId);
9189

@@ -121,7 +119,7 @@ describe("UserService", () => {
121119
});
122120

123121
describe("initUserData", () => {
124-
it("creates the compass user with default resources", async () => {
122+
it("creates the compass user with default priorities", async () => {
125123
const gUser = UserDriver.generateGoogleUser();
126124

127125
EmailDriver.mockEmailServiceResponse();
@@ -141,11 +139,6 @@ describe("UserService", () => {
141139
.find({ user: userId })
142140
.toArray();
143141
expect(priorities.length).toBeGreaterThan(0);
144-
145-
const somedayEvents = await mongoService.event
146-
.find({ user: userId, isSomeday: true })
147-
.toArray();
148-
expect(somedayEvents.length).toBeGreaterThan(0);
149142
});
150143
});
151144

packages/backend/src/user/services/user.service.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,6 @@ class UserService {
155155

156156
await priorityService.createDefaultPriorities(cUser.userId, session);
157157

158-
await eventService.createDefaultSomedays(cUser.userId, session);
159-
160158
return cUser;
161159
};
162160

packages/web/src/__tests__/utils/storage/indexeddb.test.util.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { DEMO_DATA_SEED_FLAG_KEY } from "@web/common/storage/migrations/external/demo-data-seed";
2+
13
const COMPASS_LOCAL_DB_NAME = "compass-local";
24

35
export async function clearCompassLocalDb(): Promise<void> {
@@ -8,3 +10,14 @@ export async function clearCompassLocalDb(): Promise<void> {
810
request.onblocked = () => resolve();
911
});
1012
}
13+
14+
/**
15+
* Prepares empty storage for tests that expect no data.
16+
* Clears localStorage and IndexedDB, then sets the demo-data-seed migration
17+
* flag so it won't seed when storage initializes.
18+
*/
19+
export async function prepareEmptyStorageForTests(): Promise<void> {
20+
localStorage.clear();
21+
await clearCompassLocalDb();
22+
localStorage.setItem(DEMO_DATA_SEED_FLAG_KEY, "completed");
23+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { StorageAdapter } from "@web/common/storage/adapter/storage.adapter";
2+
3+
/**
4+
* Creates a mock StorageAdapter for tests.
5+
*
6+
* All methods default to empty results or no-op implementations.
7+
* Override specific methods (e.g., getAllEvents, getAllTasks) as needed per test.
8+
*/
9+
export function createMockStorageAdapter(): jest.Mocked<StorageAdapter> {
10+
return {
11+
initialize: jest.fn().mockResolvedValue(undefined),
12+
isReady: jest.fn().mockReturnValue(true),
13+
getTasks: jest.fn().mockResolvedValue([]),
14+
getAllTasks: jest.fn().mockResolvedValue([]),
15+
putTasks: jest.fn().mockResolvedValue(undefined),
16+
putTask: jest.fn().mockResolvedValue(undefined),
17+
deleteTask: jest.fn().mockResolvedValue(undefined),
18+
moveTask: jest.fn().mockResolvedValue(undefined),
19+
clearAllTasks: jest.fn().mockResolvedValue(undefined),
20+
getEvents: jest.fn().mockResolvedValue([]),
21+
getAllEvents: jest.fn().mockResolvedValue([]),
22+
putEvent: jest.fn().mockResolvedValue(undefined),
23+
putEvents: jest.fn().mockResolvedValue(undefined),
24+
deleteEvent: jest.fn().mockResolvedValue(undefined),
25+
clearAllEvents: jest.fn().mockResolvedValue(undefined),
26+
getMigrationRecords: jest.fn().mockResolvedValue([]),
27+
setMigrationRecord: jest.fn().mockResolvedValue(undefined),
28+
};
29+
}

0 commit comments

Comments
 (0)