WIP! A BB-style forum, on the ATmosphere!
We're still working... we'll be back soon when we have something to show off!
node
typescript
hono
htmx
atproto
1import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
2import { CookieSessionStore, type CookieSession } from "../cookie-session-store.js";
3
4describe("CookieSessionStore", () => {
5 let store: CookieSessionStore;
6
7 beforeEach(() => {
8 store = new CookieSessionStore();
9 vi.useFakeTimers();
10 });
11
12 afterEach(() => {
13 store.destroy();
14 vi.useRealTimers();
15 });
16
17 it("stores and retrieves cookie sessions", () => {
18 const session: CookieSession = {
19 did: "did:plc:test123",
20 handle: "testuser.test",
21 expiresAt: new Date(Date.now() + 7 * 24 * 3600 * 1000), // 7 days from now
22 createdAt: new Date(),
23 };
24
25 store.set("cookie-token-1", session);
26 const retrieved = store.get("cookie-token-1");
27
28 expect(retrieved).toEqual(session);
29 });
30
31 it("returns null for non-existent tokens", () => {
32 const result = store.get("nonexistent-token");
33 expect(result).toBeNull();
34 });
35
36 it("enforces expiresAt boundary correctly", () => {
37 const now = Date.now();
38 const session: CookieSession = {
39 did: "did:plc:test123",
40 handle: "testuser.test",
41 expiresAt: new Date(now + 3600 * 1000), // Expires in 1 hour
42 createdAt: new Date(now),
43 };
44
45 store.set("cookie-token-1", session);
46
47 // Before expiration - session available
48 vi.advanceTimersByTime(3599 * 1000); // 59 minutes 59 seconds
49 expect(store.get("cookie-token-1")).toEqual(session);
50
51 // After expiration - session should be evicted
52 vi.advanceTimersByTime(2 * 1000); // Total: 1 hour 1 second
53 expect(store.get("cookie-token-1")).toBeNull();
54 });
55
56 it("handles sessions without handle field", () => {
57 const session: CookieSession = {
58 did: "did:plc:test123",
59 // No handle field
60 expiresAt: new Date(Date.now() + 7 * 24 * 3600 * 1000),
61 createdAt: new Date(),
62 };
63
64 store.set("cookie-token-1", session);
65 const retrieved = store.get("cookie-token-1");
66
67 expect(retrieved).toEqual(session);
68 expect(retrieved?.handle).toBeUndefined();
69 });
70
71 it("deletes sessions immediately", () => {
72 const session: CookieSession = {
73 did: "did:plc:test123",
74 handle: "testuser.test",
75 expiresAt: new Date(Date.now() + 7 * 24 * 3600 * 1000),
76 createdAt: new Date(),
77 };
78
79 store.set("cookie-token-1", session);
80 expect(store.get("cookie-token-1")).toEqual(session);
81
82 store.delete("cookie-token-1");
83 expect(store.get("cookie-token-1")).toBeNull();
84 });
85
86 it("handles multiple sessions independently", () => {
87 const session1: CookieSession = {
88 did: "did:plc:user1",
89 handle: "user1.test",
90 expiresAt: new Date(Date.now() + 7 * 24 * 3600 * 1000),
91 createdAt: new Date(),
92 };
93
94 const session2: CookieSession = {
95 did: "did:plc:user2",
96 handle: "user2.test",
97 expiresAt: new Date(Date.now() + 14 * 24 * 3600 * 1000), // Different expiration
98 createdAt: new Date(),
99 };
100
101 store.set("token1", session1);
102 store.set("token2", session2);
103
104 expect(store.get("token1")).toEqual(session1);
105 expect(store.get("token2")).toEqual(session2);
106
107 store.delete("token1");
108 expect(store.get("token1")).toBeNull();
109 expect(store.get("token2")).toEqual(session2);
110 });
111
112 it("correctly compares Date objects for expiration", () => {
113 // Test the Date comparison logic works correctly
114 const now = new Date();
115 const past = new Date(now.getTime() - 1000); // 1 second ago
116 const future = new Date(now.getTime() + 1000); // 1 second from now
117
118 const expiredSession: CookieSession = {
119 did: "did:plc:expired",
120 expiresAt: past,
121 createdAt: new Date(past.getTime() - 3600 * 1000),
122 };
123
124 const validSession: CookieSession = {
125 did: "did:plc:valid",
126 expiresAt: future,
127 createdAt: now,
128 };
129
130 store.set("expired", expiredSession);
131 store.set("valid", validSession);
132
133 // Expired session should return null
134 expect(store.get("expired")).toBeNull();
135
136 // Valid session should be available
137 expect(store.get("valid")).toEqual(validSession);
138 });
139
140 it("maps undefined to null for missing entries", () => {
141 // The adapter should return null (not undefined) for missing entries
142 // to match the public API contract
143 const result = store.get("missing-key");
144 expect(result).toBeNull();
145 expect(result).not.toBeUndefined();
146 });
147});