Skip to content
File

Blob: tests/client/lib/doc-sync-session.test.ts

typescript130 lines
1import { describe, expect, it } from "vitest";
2import {
3 decideDocSyncRefresh,
4 deriveDocSyncPhase,
5 type DocSyncPhaseInputs,
6 type DocSyncRefreshDecisionInput,
7} from "@/client/lib/doc-sync-session";
8 
9const base: DocSyncPhaseInputs = {
10 hasLocalBodyState: false,
11 wantsConnection: true,
12 workspaceId: "ws-1",
13 bootstrapStatus: "pending",
14};
15 
16describe("doc-sync cold bootstrap phase", () => {
17 it("exposes local state when offline or unauthed without connecting", () => {
18 expect(deriveDocSyncPhase({ ...base, wantsConnection: false })).toEqual({
19 ready: true,
20 shouldConnect: false,
21 snapshotFetch: null,
22 error: false,
23 });
24 });
25 
26 it("mounts and connects immediately when a local body is cached", () => {
27 expect(deriveDocSyncPhase({ ...base, hasLocalBodyState: true })).toEqual({
28 ready: true,
29 shouldConnect: true,
30 snapshotFetch: null,
31 error: false,
32 });
33 });
34 
35 it("stays loading without a workspace id since the snapshot route is unreachable", () => {
36 expect(deriveDocSyncPhase({ ...base, workspaceId: undefined })).toEqual({
37 ready: false,
38 shouldConnect: false,
39 snapshotFetch: null,
40 error: false,
41 });
42 });
43 
44 it("fetches a snapshot before mounting on a cold uncached live doc", () => {
45 expect(deriveDocSyncPhase(base)).toEqual({
46 ready: false,
47 shouldConnect: false,
48 snapshotFetch: { workspaceId: "ws-1" },
49 error: false,
50 });
51 });
52 
53 it("mounts and connects once the snapshot has resolved (applied or absent)", () => {
54 expect(deriveDocSyncPhase({ ...base, bootstrapStatus: "resolved" })).toEqual({
55 ready: true,
56 shouldConnect: true,
57 snapshotFetch: null,
58 error: false,
59 });
60 });
61 
62 it("surfaces an error state on snapshot failure and keeps the provider parked", () => {
63 expect(deriveDocSyncPhase({ ...base, bootstrapStatus: "error" })).toEqual({
64 ready: false,
65 shouldConnect: false,
66 snapshotFetch: null,
67 error: true,
68 });
69 });
70});
71 
72describe("decideDocSyncRefresh", () => {
73 const baseInput: DocSyncRefreshDecisionInput = {
74 isOnline: true,
75 isProviderActive: true,
76 hasShareToken: false,
77 currentAccessToken: "T1",
78 lastRefreshAttemptedFor: null,
79 };
80 
81 it("skips when offline so a parked provider does not burn refresh budget", () => {
82 expect(decideDocSyncRefresh({ ...baseInput, isOnline: false })).toEqual({
83 kind: "skip",
84 reason: "offline",
85 });
86 });
87 
88 it("skips when the session is no longer active (cleanup or disabled)", () => {
89 expect(decideDocSyncRefresh({ ...baseInput, isProviderActive: false })).toEqual({
90 kind: "skip",
91 reason: "inactive",
92 });
93 });
94 
95 it("skips share-token sessions even when an authenticated bearer is present", () => {
96 expect(decideDocSyncRefresh({ ...baseInput, hasShareToken: true })).toEqual({
97 kind: "skip",
98 reason: "share",
99 });
100 });
101 
102 it("skips when there is no access token to refresh against", () => {
103 expect(decideDocSyncRefresh({ ...baseInput, currentAccessToken: null })).toEqual({
104 kind: "skip",
105 reason: "no_token",
106 });
107 });
108 
109 it("skips when refresh has already been attempted for this token value", () => {
110 expect(decideDocSyncRefresh({ ...baseInput, lastRefreshAttemptedFor: "T1" })).toEqual({
111 kind: "skip",
112 reason: "already_attempted",
113 });
114 });
115 
116 it("triggers a refresh on first close for an authenticated session", () => {
117 expect(decideDocSyncRefresh(baseInput)).toEqual({
118 kind: "refresh",
119 tokenAtAttempt: "T1",
120 });
121 });
122 
123 it("allows a refresh against a freshly rotated token when the prior attempt was for the old token", () => {
124 expect(decideDocSyncRefresh({ ...baseInput, currentAccessToken: "T2", lastRefreshAttemptedFor: "T1" })).toEqual({
125 kind: "refresh",
126 tokenAtAttempt: "T2",
127 });
128 });
129});