db.test.js
4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// RED/GREEN check for the SQLite-backed users/sessions store (dev-plan-3.md
// T18). Run: node --test db.test.js
const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");
const { openDb, createUsersStore, createSessionsStore } = require("./db.js");
function tmpDbPath() {
return path.join(fs.mkdtempSync(path.join(os.tmpdir(), "dressup-db-test-")), "data.sqlite");
}
test("users: create/get/findByEmail round-trip, defaults filled in", () => {
const db = openDb(tmpDbPath());
const users = createUsersStore(db);
const user = users.create({ email: "a@example.com", passwordHash: "hash1" });
assert.ok(user.id);
assert.equal(user.email, "a@example.com");
assert.equal(user.emailVerified, false);
assert.equal(user.role, "viewer");
assert.deepEqual(user.oauthProviders, []);
assert.equal(user.creditBalance, 0);
assert.deepEqual(users.get(user.id), user);
assert.deepEqual(users.findByEmail("a@example.com"), user);
assert.equal(users.findByEmail("nope@example.com"), null);
assert.equal(users.get("nonexistent-id"), null);
});
test("users: duplicate email is rejected as a conflict, not a second row", () => {
const db = openDb(tmpDbPath());
const users = createUsersStore(db);
users.create({ email: "dup@example.com", passwordHash: "hash1" });
assert.throws(() => users.create({ email: "dup@example.com", passwordHash: "hash2" }), (err) => err.code === "EMAIL_TAKEN");
});
test("users: update() patches only whitelisted fields, ignores the rest", () => {
const db = openDb(tmpDbPath());
const users = createUsersStore(db);
const user = users.create({ email: "b@example.com", passwordHash: "hash1" });
const updated = users.update(user.id, { emailVerified: true, nickname: "小美", id: "should-be-ignored", email: "should-be-ignored@example.com" });
assert.equal(updated.emailVerified, true);
assert.equal(updated.nickname, "小美");
assert.equal(updated.id, user.id);
assert.equal(updated.email, "b@example.com"); // unchanged original email, patch ignored
});
test("users: legacyUid/ageConfirmed carry over from an existing anonymous cookie (T21's use case)", () => {
const db = openDb(tmpDbPath());
const users = createUsersStore(db);
const ts = Date.now();
const user = users.create({
email: "c@example.com",
passwordHash: "hash1",
nickname: "老观众",
legacyUid: "viewer-uid-123",
ageConfirmed: true,
ageConfirmedAt: ts,
});
assert.equal(user.legacyUid, "viewer-uid-123");
assert.equal(user.ageConfirmed, true);
assert.equal(user.ageConfirmedAt, ts);
});
test("data survives reopening the same file path (simulated process restart)", () => {
const dbPath = tmpDbPath();
const db1 = openDb(dbPath);
const users1 = createUsersStore(db1);
const created = users1.create({ email: "restart@example.com", passwordHash: "hash1" });
db1.close();
const db2 = openDb(dbPath);
const users2 = createUsersStore(db2);
assert.deepEqual(users2.get(created.id), created);
});
test("sessions: create/findByToken round-trip", () => {
const db = openDb(tmpDbPath());
const users = createUsersStore(db);
const sessions = createSessionsStore(db);
const user = users.create({ email: "d@example.com", passwordHash: "hash1" });
const session = sessions.create({ userId: user.id, kind: "session", expiresAt: Date.now() + 100000 });
assert.ok(session.token);
assert.equal(sessions.findByToken(session.token).id, session.id);
assert.equal(sessions.findByToken("nonexistent-token"), null);
});
test("sessions: an expired token is treated as absent and reaped", () => {
const db = openDb(tmpDbPath());
const users = createUsersStore(db);
const sessions = createSessionsStore(db);
const user = users.create({ email: "e@example.com", passwordHash: "hash1" });
const session = sessions.create({ userId: user.id, kind: "email_verify", expiresAt: Date.now() - 1000 });
assert.equal(sessions.findByToken(session.token), null);
// reaped, not just filtered — a second lookup finds nothing to delete either
assert.equal(sessions.findByToken(session.token), null);
});
test("sessions: revoke() logs a session out immediately", () => {
const db = openDb(tmpDbPath());
const users = createUsersStore(db);
const sessions = createSessionsStore(db);
const user = users.create({ email: "f@example.com", passwordHash: "hash1" });
const session = sessions.create({ userId: user.id, kind: "session", expiresAt: Date.now() + 100000 });
assert.ok(sessions.findByToken(session.token));
sessions.revoke(session.token);
assert.equal(sessions.findByToken(session.token), null);
});