Skip to content

Commit a1a0ff7

Browse files
committed
test(api): cover trait-history write semantics and cascade delete
1 parent fa73e81 commit a1a0ff7

1 file changed

Lines changed: 67 additions & 0 deletions

File tree

apps/api/src/integration/profile-handlers.test.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import {
55
profiles,
66
profileTraitChanges,
77
} from "@databuddy/db/schema";
8+
import { eq } from "@databuddy/db";
89
import { appRouter, type Context } from "@databuddy/rpc";
10+
import { splitTraits, upsertProfile } from "@databuddy/services/identity";
911
import {
1012
addToOrganization,
1113
cleanup,
@@ -179,3 +181,68 @@ describe("profiles.getHistory", () => {
179181
);
180182
});
181183
});
184+
185+
describe("upsertProfile trait history", () => {
186+
iit("records baseline on first identify, diff on the next", async () => {
187+
const org = await insertOrganization();
188+
const website = await insertWebsite({ organizationId: org.id });
189+
190+
await upsertProfile(website.id, "user_1", splitTraits({ plan: "free" }));
191+
await upsertProfile(
192+
website.id,
193+
"user_1",
194+
splitTraits({ plan: "pro" }),
195+
"billing"
196+
);
197+
198+
const rows = await db()
199+
.select()
200+
.from(profileTraitChanges)
201+
.where(eq(profileTraitChanges.profileId, "user_1"))
202+
.orderBy(profileTraitChanges.createdAt);
203+
204+
expect(rows).toHaveLength(2);
205+
expect(rows[0]?.changes).toEqual({ plan: { old: null, new: "free" } });
206+
expect(rows[0]?.source).toBe("identify");
207+
expect(rows[1]?.changes).toEqual({ plan: { old: "free", new: "pro" } });
208+
expect(rows[1]?.source).toBe("billing");
209+
expect(rows[1]?.traits).toEqual({ plan: "pro" });
210+
});
211+
212+
iit("writes no history row when traits are unchanged", async () => {
213+
const org = await insertOrganization();
214+
const website = await insertWebsite({ organizationId: org.id });
215+
216+
await upsertProfile(website.id, "user_1", splitTraits({ plan: "pro" }));
217+
await upsertProfile(website.id, "user_1", splitTraits({ plan: "pro" }));
218+
219+
const rows = await db()
220+
.select()
221+
.from(profileTraitChanges)
222+
.where(eq(profileTraitChanges.profileId, "user_1"));
223+
224+
expect(rows).toHaveLength(1);
225+
});
226+
227+
iit("cascades history deletion when the profile is deleted", async () => {
228+
const org = await insertOrganization();
229+
const website = await insertWebsite({ organizationId: org.id });
230+
231+
await upsertProfile(website.id, "user_1", splitTraits({ plan: "pro" }));
232+
expect(
233+
await db()
234+
.select()
235+
.from(profileTraitChanges)
236+
.where(eq(profileTraitChanges.profileId, "user_1"))
237+
).toHaveLength(1);
238+
239+
await db().delete(profiles).where(eq(profiles.profileId, "user_1"));
240+
241+
expect(
242+
await db()
243+
.select()
244+
.from(profileTraitChanges)
245+
.where(eq(profileTraitChanges.profileId, "user_1"))
246+
).toHaveLength(0);
247+
});
248+
});

0 commit comments

Comments
 (0)