-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsessions.test.ts
More file actions
103 lines (92 loc) · 3.21 KB
/
Copy pathsessions.test.ts
File metadata and controls
103 lines (92 loc) · 3.21 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
import { describe, expect, it } from "vitest";
import type { AuthClient } from "./authClient.js";
import type { ApiResponse } from "./http.js";
import {
listSessions,
revokeAllSessions,
revokeSessionById,
} from "./sessions.js";
function response<T>(status: number, data: T | null): ApiResponse<T> {
return { ok: status >= 200 && status < 300, status, data, headers: new Headers() };
}
function fakeClient(
handler: (method: string, path: string) => ApiResponse<unknown>,
): AuthClient {
return {
profile: { name: "default", instanceUrl: "https://auth.example.com" },
get: async (path) => handler("GET", path) as never,
post: async (path) => handler("POST", path) as never,
request: async (path, init) =>
handler((init?.method ?? "GET").toUpperCase(), path) as never,
};
}
describe("listSessions", () => {
it("maps the session list and the current marker", async () => {
const client = fakeClient((method, path) => {
expect(`${method} ${path}`).toBe("GET /sessions");
return response(200, {
total: 2,
sessions: [
{
id: "s1",
deviceName: "MacBook",
ipAddress: "203.0.113.4",
userAgent: "curl/8",
lastUsedAt: "2026-07-13T10:00:00.000Z",
expiresAt: "2026-07-20T10:00:00.000Z",
current: true,
},
{ id: "s2", current: false },
],
});
});
const sessions = await listSessions(client);
expect(sessions).toHaveLength(2);
expect(sessions[0]).toMatchObject({
id: "s1",
deviceName: "MacBook",
ipAddress: "203.0.113.4",
current: true,
});
expect(sessions[1]).toEqual({ id: "s2", current: false });
});
it("drops malformed entries and throws on a non-ok response", async () => {
const withJunk = fakeClient(() =>
response(200, { sessions: [{ id: "ok", current: false }, {}, 42, null] }),
);
expect(await listSessions(withJunk)).toEqual([{ id: "ok", current: false }]);
const bad = fakeClient(() => response(500, null));
await expect(listSessions(bad)).rejects.toThrow(/could not list/i);
});
});
describe("revokeSessionById", () => {
it("deletes by id and URL-encodes it", async () => {
const seen: string[] = [];
const client = fakeClient((method, path) => {
seen.push(`${method} ${path}`);
return response(200, { message: "ok" });
});
const res = await revokeSessionById(client, "a b/c");
expect(res).toEqual({ ok: true, status: 200 });
expect(seen).toEqual(["DELETE /sessions/a%20b%2Fc"]);
});
it("surfaces a 404 for an unknown session", async () => {
const client = fakeClient(() => response(404, { error: "Session not found" }));
expect(await revokeSessionById(client, "gone")).toEqual({
ok: false,
status: 404,
});
});
});
describe("revokeAllSessions", () => {
it("deletes the collection", async () => {
const seen: string[] = [];
const client = fakeClient((method, path) => {
seen.push(`${method} ${path}`);
return response(200, { message: "ok" });
});
const res = await revokeAllSessions(client);
expect(res).toEqual({ ok: true, status: 200 });
expect(seen).toEqual(["DELETE /sessions"]);
});
});