@livetemplate/client 0.8.33 → 0.8.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dom/directives.d.ts.map +1 -1
- package/dist/dom/directives.js +12 -4
- package/dist/dom/directives.js.map +1 -1
- package/dist/dom/scroll-away.d.ts +3 -0
- package/dist/dom/scroll-away.d.ts.map +1 -0
- package/dist/dom/scroll-away.js +89 -0
- package/dist/dom/scroll-away.js.map +1 -0
- package/dist/livetemplate-client.browser.js +4 -4
- package/dist/livetemplate-client.browser.js.map +4 -4
- package/dist/livetemplate-client.d.ts +10 -0
- package/dist/livetemplate-client.d.ts.map +1 -1
- package/dist/livetemplate-client.js +140 -0
- package/dist/livetemplate-client.js.map +1 -1
- package/dist/tests/directives.test.js +63 -8
- package/dist/tests/directives.test.js.map +1 -1
- package/dist/tests/scroll-away.test.d.ts +2 -0
- package/dist/tests/scroll-away.test.d.ts.map +1 -0
- package/dist/tests/scroll-away.test.js +189 -0
- package/dist/tests/scroll-away.test.js.map +1 -0
- package/dist/tests/visibility-reconnect.test.d.ts +2 -0
- package/dist/tests/visibility-reconnect.test.d.ts.map +1 -0
- package/dist/tests/visibility-reconnect.test.js +351 -0
- package/dist/tests/visibility-reconnect.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const scroll_away_1 = require("../dom/scroll-away");
|
|
4
|
+
function mockScrollableElement(id, props) {
|
|
5
|
+
const el = document.createElement("div");
|
|
6
|
+
el.id = id;
|
|
7
|
+
Object.defineProperty(el, "scrollHeight", { value: props.scrollHeight, configurable: true });
|
|
8
|
+
Object.defineProperty(el, "scrollTop", { value: props.scrollTop, configurable: true, writable: true });
|
|
9
|
+
Object.defineProperty(el, "clientHeight", { value: props.clientHeight, configurable: true });
|
|
10
|
+
return el;
|
|
11
|
+
}
|
|
12
|
+
describe("setupScrollAway", () => {
|
|
13
|
+
let rafCallbacks;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
document.body.replaceChildren();
|
|
16
|
+
rafCallbacks = [];
|
|
17
|
+
jest.spyOn(window, "requestAnimationFrame").mockImplementation((cb) => {
|
|
18
|
+
rafCallbacks.push(cb);
|
|
19
|
+
return rafCallbacks.length;
|
|
20
|
+
});
|
|
21
|
+
jest.spyOn(console, "warn").mockImplementation(() => { });
|
|
22
|
+
});
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
(0, scroll_away_1.teardownScrollAway)();
|
|
25
|
+
jest.restoreAllMocks();
|
|
26
|
+
});
|
|
27
|
+
function flushRAF() {
|
|
28
|
+
const cbs = rafCallbacks.splice(0);
|
|
29
|
+
cbs.forEach((cb) => cb(performance.now()));
|
|
30
|
+
}
|
|
31
|
+
it("adds 'visible' class when scrolled away from bottom", () => {
|
|
32
|
+
const container = mockScrollableElement("chat-log", {
|
|
33
|
+
scrollHeight: 1000,
|
|
34
|
+
scrollTop: 0,
|
|
35
|
+
clientHeight: 400,
|
|
36
|
+
});
|
|
37
|
+
document.body.appendChild(container);
|
|
38
|
+
const button = document.createElement("button");
|
|
39
|
+
button.setAttribute("lvt-scroll-away", "bottom");
|
|
40
|
+
button.setAttribute("data-lvt-target", "#chat-log");
|
|
41
|
+
document.body.appendChild(button);
|
|
42
|
+
(0, scroll_away_1.setupScrollAway)(document.body);
|
|
43
|
+
flushRAF();
|
|
44
|
+
expect(button.classList.contains("visible")).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
it("removes 'visible' class when at bottom", () => {
|
|
47
|
+
const container = mockScrollableElement("chat-log", {
|
|
48
|
+
scrollHeight: 1000,
|
|
49
|
+
scrollTop: 600,
|
|
50
|
+
clientHeight: 400,
|
|
51
|
+
});
|
|
52
|
+
document.body.appendChild(container);
|
|
53
|
+
const button = document.createElement("button");
|
|
54
|
+
button.setAttribute("lvt-scroll-away", "bottom");
|
|
55
|
+
button.setAttribute("data-lvt-target", "#chat-log");
|
|
56
|
+
document.body.appendChild(button);
|
|
57
|
+
(0, scroll_away_1.setupScrollAway)(document.body);
|
|
58
|
+
flushRAF();
|
|
59
|
+
expect(button.classList.contains("visible")).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
it("toggles on scroll events", () => {
|
|
62
|
+
const container = mockScrollableElement("chat-log", {
|
|
63
|
+
scrollHeight: 1000,
|
|
64
|
+
scrollTop: 600,
|
|
65
|
+
clientHeight: 400,
|
|
66
|
+
});
|
|
67
|
+
document.body.appendChild(container);
|
|
68
|
+
const button = document.createElement("button");
|
|
69
|
+
button.setAttribute("lvt-scroll-away", "bottom");
|
|
70
|
+
button.setAttribute("data-lvt-target", "#chat-log");
|
|
71
|
+
document.body.appendChild(button);
|
|
72
|
+
(0, scroll_away_1.setupScrollAway)(document.body);
|
|
73
|
+
flushRAF();
|
|
74
|
+
expect(button.classList.contains("visible")).toBe(false);
|
|
75
|
+
Object.defineProperty(container, "scrollTop", { value: 0, configurable: true });
|
|
76
|
+
container.dispatchEvent(new Event("scroll"));
|
|
77
|
+
flushRAF();
|
|
78
|
+
expect(button.classList.contains("visible")).toBe(true);
|
|
79
|
+
Object.defineProperty(container, "scrollTop", { value: 600, configurable: true });
|
|
80
|
+
container.dispatchEvent(new Event("scroll"));
|
|
81
|
+
flushRAF();
|
|
82
|
+
expect(button.classList.contains("visible")).toBe(false);
|
|
83
|
+
});
|
|
84
|
+
it("uses default threshold of 200 when no CSS property set", () => {
|
|
85
|
+
const container = mockScrollableElement("chat-log", {
|
|
86
|
+
scrollHeight: 1000,
|
|
87
|
+
scrollTop: 700,
|
|
88
|
+
clientHeight: 100,
|
|
89
|
+
});
|
|
90
|
+
document.body.appendChild(container);
|
|
91
|
+
const button = document.createElement("button");
|
|
92
|
+
button.setAttribute("lvt-scroll-away", "bottom");
|
|
93
|
+
button.setAttribute("data-lvt-target", "#chat-log");
|
|
94
|
+
document.body.appendChild(button);
|
|
95
|
+
(0, scroll_away_1.setupScrollAway)(document.body);
|
|
96
|
+
flushRAF();
|
|
97
|
+
// distance = 1000 - 700 - 100 = 200, which is NOT > 200
|
|
98
|
+
expect(button.classList.contains("visible")).toBe(false);
|
|
99
|
+
});
|
|
100
|
+
it("warns and skips when no target resolves (self-target)", () => {
|
|
101
|
+
const button = document.createElement("button");
|
|
102
|
+
button.setAttribute("lvt-scroll-away", "bottom");
|
|
103
|
+
document.body.appendChild(button);
|
|
104
|
+
(0, scroll_away_1.setupScrollAway)(document.body);
|
|
105
|
+
expect(button.__lvt_scroll_away).toBeUndefined();
|
|
106
|
+
expect(console.warn).toHaveBeenCalledWith("lvt-scroll-away requires data-lvt-target pointing to a scrollable container");
|
|
107
|
+
});
|
|
108
|
+
it("warns on unknown edge value", () => {
|
|
109
|
+
const container = mockScrollableElement("chat-log", {
|
|
110
|
+
scrollHeight: 1000,
|
|
111
|
+
scrollTop: 0,
|
|
112
|
+
clientHeight: 400,
|
|
113
|
+
});
|
|
114
|
+
document.body.appendChild(container);
|
|
115
|
+
const button = document.createElement("button");
|
|
116
|
+
button.setAttribute("lvt-scroll-away", "top");
|
|
117
|
+
button.setAttribute("data-lvt-target", "#chat-log");
|
|
118
|
+
document.body.appendChild(button);
|
|
119
|
+
(0, scroll_away_1.setupScrollAway)(document.body);
|
|
120
|
+
expect(console.warn).toHaveBeenCalledWith("Unknown lvt-scroll-away edge: top");
|
|
121
|
+
});
|
|
122
|
+
it("does not duplicate listeners on re-scan with same target", () => {
|
|
123
|
+
const container = mockScrollableElement("chat-log", {
|
|
124
|
+
scrollHeight: 1000,
|
|
125
|
+
scrollTop: 0,
|
|
126
|
+
clientHeight: 400,
|
|
127
|
+
});
|
|
128
|
+
document.body.appendChild(container);
|
|
129
|
+
const button = document.createElement("button");
|
|
130
|
+
button.setAttribute("lvt-scroll-away", "bottom");
|
|
131
|
+
button.setAttribute("data-lvt-target", "#chat-log");
|
|
132
|
+
document.body.appendChild(button);
|
|
133
|
+
(0, scroll_away_1.setupScrollAway)(document.body);
|
|
134
|
+
const firstBinding = button.__lvt_scroll_away;
|
|
135
|
+
(0, scroll_away_1.setupScrollAway)(document.body);
|
|
136
|
+
const secondBinding = button.__lvt_scroll_away;
|
|
137
|
+
expect(firstBinding).toBe(secondBinding);
|
|
138
|
+
});
|
|
139
|
+
it("re-attaches listener when target element is replaced", () => {
|
|
140
|
+
const container1 = mockScrollableElement("chat-log", {
|
|
141
|
+
scrollHeight: 1000,
|
|
142
|
+
scrollTop: 0,
|
|
143
|
+
clientHeight: 400,
|
|
144
|
+
});
|
|
145
|
+
document.body.appendChild(container1);
|
|
146
|
+
const button = document.createElement("button");
|
|
147
|
+
button.setAttribute("lvt-scroll-away", "bottom");
|
|
148
|
+
button.setAttribute("data-lvt-target", "#chat-log");
|
|
149
|
+
document.body.appendChild(button);
|
|
150
|
+
(0, scroll_away_1.setupScrollAway)(document.body);
|
|
151
|
+
flushRAF();
|
|
152
|
+
expect(button.classList.contains("visible")).toBe(true);
|
|
153
|
+
// Replace the container (simulating morphdom replacement)
|
|
154
|
+
container1.remove();
|
|
155
|
+
const container2 = mockScrollableElement("chat-log", {
|
|
156
|
+
scrollHeight: 500,
|
|
157
|
+
scrollTop: 100,
|
|
158
|
+
clientHeight: 400,
|
|
159
|
+
});
|
|
160
|
+
document.body.appendChild(container2);
|
|
161
|
+
(0, scroll_away_1.setupScrollAway)(document.body);
|
|
162
|
+
flushRAF();
|
|
163
|
+
// distance = 500 - 100 - 400 = 0, not > 200
|
|
164
|
+
expect(button.classList.contains("visible")).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
it("teardown removes all listeners", () => {
|
|
167
|
+
const container = mockScrollableElement("chat-log", {
|
|
168
|
+
scrollHeight: 1000,
|
|
169
|
+
scrollTop: 0,
|
|
170
|
+
clientHeight: 400,
|
|
171
|
+
});
|
|
172
|
+
document.body.appendChild(container);
|
|
173
|
+
const button = document.createElement("button");
|
|
174
|
+
button.setAttribute("lvt-scroll-away", "bottom");
|
|
175
|
+
button.setAttribute("data-lvt-target", "#chat-log");
|
|
176
|
+
document.body.appendChild(button);
|
|
177
|
+
(0, scroll_away_1.setupScrollAway)(document.body);
|
|
178
|
+
flushRAF();
|
|
179
|
+
expect(button.classList.contains("visible")).toBe(true);
|
|
180
|
+
(0, scroll_away_1.teardownScrollAway)();
|
|
181
|
+
expect(button.__lvt_scroll_away).toBeUndefined();
|
|
182
|
+
button.classList.remove("visible");
|
|
183
|
+
container.dispatchEvent(new Event("scroll"));
|
|
184
|
+
flushRAF();
|
|
185
|
+
// Listener removed: class should stay removed
|
|
186
|
+
expect(button.classList.contains("visible")).toBe(false);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
//# sourceMappingURL=scroll-away.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-away.test.js","sourceRoot":"","sources":["../../tests/scroll-away.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visibility-reconnect.test.d.ts","sourceRoot":"","sources":["../../tests/visibility-reconnect.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const livetemplate_client_1 = require("../livetemplate-client");
|
|
4
|
+
class MockWebSocket {
|
|
5
|
+
constructor(url) {
|
|
6
|
+
this.readyState = MockWebSocket.CONNECTING;
|
|
7
|
+
this.onopen = null;
|
|
8
|
+
this.onmessage = null;
|
|
9
|
+
this.onclose = null;
|
|
10
|
+
this.onerror = null;
|
|
11
|
+
this.url = url;
|
|
12
|
+
}
|
|
13
|
+
send(_data) { }
|
|
14
|
+
close() {
|
|
15
|
+
this.readyState = MockWebSocket.CLOSED;
|
|
16
|
+
if (this.onclose) {
|
|
17
|
+
this.onclose(new CloseEvent("close", { code: 1000 }));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
simulateOpen() {
|
|
21
|
+
this.readyState = MockWebSocket.OPEN;
|
|
22
|
+
if (this.onopen) {
|
|
23
|
+
this.onopen(new Event("open"));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
simulateClose() {
|
|
27
|
+
this.readyState = MockWebSocket.CLOSED;
|
|
28
|
+
if (this.onclose) {
|
|
29
|
+
this.onclose(new CloseEvent("close", { code: 1006 }));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
MockWebSocket.CONNECTING = 0;
|
|
34
|
+
MockWebSocket.OPEN = 1;
|
|
35
|
+
MockWebSocket.CLOSING = 2;
|
|
36
|
+
MockWebSocket.CLOSED = 3;
|
|
37
|
+
let mockSockets = [];
|
|
38
|
+
function installMockWebSocket() {
|
|
39
|
+
mockSockets = [];
|
|
40
|
+
const WS = jest.fn().mockImplementation((url) => {
|
|
41
|
+
const sock = new MockWebSocket(url);
|
|
42
|
+
mockSockets.push(sock);
|
|
43
|
+
return sock;
|
|
44
|
+
});
|
|
45
|
+
WS.CONNECTING = 0;
|
|
46
|
+
WS.OPEN = 1;
|
|
47
|
+
WS.CLOSING = 2;
|
|
48
|
+
WS.CLOSED = 3;
|
|
49
|
+
global.WebSocket = WS;
|
|
50
|
+
}
|
|
51
|
+
function installFetchStub() {
|
|
52
|
+
if (typeof globalThis.fetch !== "function") {
|
|
53
|
+
globalThis.fetch = () => { };
|
|
54
|
+
}
|
|
55
|
+
jest.spyOn(globalThis, "fetch").mockImplementation((...args) => {
|
|
56
|
+
const opts = args[1];
|
|
57
|
+
if (opts?.method === "HEAD") {
|
|
58
|
+
return Promise.resolve(new Response(null, {
|
|
59
|
+
status: 200,
|
|
60
|
+
headers: { "X-LiveTemplate-WebSocket": "enabled" },
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
return Promise.resolve(new Response("{}", { status: 200 }));
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function createWrapper() {
|
|
67
|
+
const wrapper = document.createElement("div");
|
|
68
|
+
wrapper.setAttribute("data-lvt-id", "test-visibility");
|
|
69
|
+
document.body.appendChild(wrapper);
|
|
70
|
+
return wrapper;
|
|
71
|
+
}
|
|
72
|
+
function fireVisibilityChange(hidden) {
|
|
73
|
+
Object.defineProperty(document, "hidden", {
|
|
74
|
+
value: hidden,
|
|
75
|
+
writable: true,
|
|
76
|
+
configurable: true,
|
|
77
|
+
});
|
|
78
|
+
document.dispatchEvent(new Event("visibilitychange"));
|
|
79
|
+
}
|
|
80
|
+
function firePageShow(persisted) {
|
|
81
|
+
const event = new PageTransitionEvent("pageshow", { persisted });
|
|
82
|
+
window.dispatchEvent(event);
|
|
83
|
+
}
|
|
84
|
+
// Simulates a background/foreground cycle with the given elapsed time
|
|
85
|
+
function simulateBackground(ms) {
|
|
86
|
+
fireVisibilityChange(true);
|
|
87
|
+
jest.advanceTimersByTime(ms);
|
|
88
|
+
fireVisibilityChange(false);
|
|
89
|
+
}
|
|
90
|
+
describe("Visibility-based reconnection", () => {
|
|
91
|
+
let client;
|
|
92
|
+
beforeEach(() => {
|
|
93
|
+
jest.useFakeTimers();
|
|
94
|
+
document.body.replaceChildren();
|
|
95
|
+
installMockWebSocket();
|
|
96
|
+
installFetchStub();
|
|
97
|
+
history.replaceState(null, "", "/test");
|
|
98
|
+
});
|
|
99
|
+
afterEach(() => {
|
|
100
|
+
client?.disconnect();
|
|
101
|
+
jest.useRealTimers();
|
|
102
|
+
jest.restoreAllMocks();
|
|
103
|
+
});
|
|
104
|
+
async function connectClient() {
|
|
105
|
+
createWrapper();
|
|
106
|
+
client = new livetemplate_client_1.LiveTemplateClient({ logLevel: "error" });
|
|
107
|
+
const connectPromise = client.connect();
|
|
108
|
+
// Resolve the HEAD fetch
|
|
109
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
110
|
+
// Open the WebSocket
|
|
111
|
+
mockSockets[0]?.simulateOpen();
|
|
112
|
+
await connectPromise;
|
|
113
|
+
}
|
|
114
|
+
it("reconnects when page becomes visible after >3s with dead WebSocket", async () => {
|
|
115
|
+
await connectClient();
|
|
116
|
+
expect(client.isReady()).toBe(true);
|
|
117
|
+
// Simulate iOS background: WebSocket dies while hidden
|
|
118
|
+
fireVisibilityChange(true);
|
|
119
|
+
jest.advanceTimersByTime(1000);
|
|
120
|
+
mockSockets[0].simulateClose();
|
|
121
|
+
jest.advanceTimersByTime(4000);
|
|
122
|
+
fireVisibilityChange(false);
|
|
123
|
+
// Wait for the 500ms reconnect delay + resolve async connect
|
|
124
|
+
await jest.advanceTimersByTimeAsync(500);
|
|
125
|
+
// Let the HEAD fetch inside performVisibilityReconnect resolve
|
|
126
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
127
|
+
// A new WebSocket should have been created for reconnection
|
|
128
|
+
expect(mockSockets.length).toBe(2);
|
|
129
|
+
// Simulate successful reconnection
|
|
130
|
+
mockSockets[1].simulateOpen();
|
|
131
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
132
|
+
expect(client.isReady()).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
it("does not reconnect on short background (<3s)", async () => {
|
|
135
|
+
await connectClient();
|
|
136
|
+
const initialSocketCount = mockSockets.length;
|
|
137
|
+
// Background for only 2 seconds then WebSocket dies
|
|
138
|
+
fireVisibilityChange(true);
|
|
139
|
+
jest.advanceTimersByTime(500);
|
|
140
|
+
mockSockets[0].simulateClose();
|
|
141
|
+
jest.advanceTimersByTime(1500);
|
|
142
|
+
fireVisibilityChange(false);
|
|
143
|
+
// Wait well past the 500ms delay
|
|
144
|
+
await jest.advanceTimersByTimeAsync(1000);
|
|
145
|
+
// No reconnection attempt — elapsed < 3s
|
|
146
|
+
expect(mockSockets.length).toBe(initialSocketCount);
|
|
147
|
+
});
|
|
148
|
+
it("reconnects even when WebSocket reports OPEN (zombie socket defense)", async () => {
|
|
149
|
+
await connectClient();
|
|
150
|
+
expect(client.isReady()).toBe(true);
|
|
151
|
+
const initialSocketCount = mockSockets.length;
|
|
152
|
+
// Background for 5 seconds — WebSocket stays OPEN (possible zombie)
|
|
153
|
+
simulateBackground(5000);
|
|
154
|
+
// Wait for the 500ms delay + resolve async connect
|
|
155
|
+
await jest.advanceTimersByTimeAsync(500);
|
|
156
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
157
|
+
// Should reconnect regardless of readyState — iOS zombie defense
|
|
158
|
+
expect(mockSockets.length).toBe(initialSocketCount + 1);
|
|
159
|
+
// Complete the reconnection
|
|
160
|
+
mockSockets[mockSockets.length - 1].simulateOpen();
|
|
161
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
162
|
+
expect(client.isReady()).toBe(true);
|
|
163
|
+
});
|
|
164
|
+
it("does not set hiddenAt when no WebSocket transport exists", () => {
|
|
165
|
+
// Unit-level guard test: in HTTP mode (or after disconnect), there
|
|
166
|
+
// is no WebSocket transport, so getReadyState() returns undefined.
|
|
167
|
+
// The visibility handler should not set hiddenAt and therefore
|
|
168
|
+
// never schedule a reconnect. This avoids needing to stand up a
|
|
169
|
+
// full HTTP-mode client with its complex async initialization.
|
|
170
|
+
createWrapper();
|
|
171
|
+
client = new livetemplate_client_1.LiveTemplateClient({ logLevel: "error" });
|
|
172
|
+
// Client hasn't connected — no transport exists.
|
|
173
|
+
// Fire visibility events to verify the handler guards work.
|
|
174
|
+
fireVisibilityChange(true);
|
|
175
|
+
fireVisibilityChange(false);
|
|
176
|
+
// With no transport, the hidden handler's readyState check blocks
|
|
177
|
+
// hiddenAt from being set. The visible handler sees hiddenAt === 0
|
|
178
|
+
// and returns early. No setTimeout is scheduled.
|
|
179
|
+
expect(jest.getTimerCount()).toBe(0);
|
|
180
|
+
expect(mockSockets.length).toBe(0);
|
|
181
|
+
});
|
|
182
|
+
it("prevents duplicate concurrent reconnects", async () => {
|
|
183
|
+
await connectClient();
|
|
184
|
+
const initialSocketCount = mockSockets.length;
|
|
185
|
+
// WebSocket dies while connected
|
|
186
|
+
fireVisibilityChange(true);
|
|
187
|
+
jest.advanceTimersByTime(500);
|
|
188
|
+
mockSockets[0].simulateClose();
|
|
189
|
+
jest.advanceTimersByTime(4500);
|
|
190
|
+
fireVisibilityChange(false);
|
|
191
|
+
// Schedule another visibility cycle before first reconnect fires
|
|
192
|
+
// (simulates rapid pageshow + visibilitychange in quick succession)
|
|
193
|
+
firePageShow(true);
|
|
194
|
+
// Wait for both 500ms delays to fire
|
|
195
|
+
await jest.advanceTimersByTimeAsync(600);
|
|
196
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
197
|
+
// Only one reconnection attempt should have been made
|
|
198
|
+
expect(mockSockets.length).toBe(initialSocketCount + 1);
|
|
199
|
+
});
|
|
200
|
+
it("reconnects on pageshow with persisted=true", async () => {
|
|
201
|
+
await connectClient();
|
|
202
|
+
const initialSocketCount = mockSockets.length;
|
|
203
|
+
// Simulate WebSocket dying
|
|
204
|
+
mockSockets[0].simulateClose();
|
|
205
|
+
// Simulate bfcache restore
|
|
206
|
+
firePageShow(true);
|
|
207
|
+
// Wait for the 500ms delay + resolve async
|
|
208
|
+
await jest.advanceTimersByTimeAsync(500);
|
|
209
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
210
|
+
// Should attempt reconnection
|
|
211
|
+
expect(mockSockets.length).toBe(initialSocketCount + 1);
|
|
212
|
+
});
|
|
213
|
+
it("does not reconnect on pageshow with persisted=false", async () => {
|
|
214
|
+
await connectClient();
|
|
215
|
+
const initialSocketCount = mockSockets.length;
|
|
216
|
+
// Simulate WebSocket dying
|
|
217
|
+
mockSockets[0].simulateClose();
|
|
218
|
+
// Normal page load (not from bfcache)
|
|
219
|
+
firePageShow(false);
|
|
220
|
+
await jest.advanceTimersByTimeAsync(500);
|
|
221
|
+
// No reconnection
|
|
222
|
+
expect(mockSockets.length).toBe(initialSocketCount);
|
|
223
|
+
});
|
|
224
|
+
it("removes the old visibility handler on disconnect and re-registers on reconnect", async () => {
|
|
225
|
+
await connectClient();
|
|
226
|
+
const addEventSpy = jest.spyOn(document, "addEventListener");
|
|
227
|
+
const removeEventSpy = jest.spyOn(document, "removeEventListener");
|
|
228
|
+
// disconnect must remove the previously registered handler so that
|
|
229
|
+
// SPAs that build a new client per route don't accumulate listeners
|
|
230
|
+
// holding closures over destroyed instances.
|
|
231
|
+
client.disconnect();
|
|
232
|
+
const removed = removeEventSpy.mock.calls.filter(([event]) => event === "visibilitychange");
|
|
233
|
+
expect(removed.length).toBe(1);
|
|
234
|
+
// The next connect re-attaches a fresh handler — exactly one.
|
|
235
|
+
createWrapper();
|
|
236
|
+
const connectPromise = client.connect();
|
|
237
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
238
|
+
mockSockets[mockSockets.length - 1]?.simulateOpen();
|
|
239
|
+
await connectPromise;
|
|
240
|
+
const added = addEventSpy.mock.calls.filter(([event]) => event === "visibilitychange");
|
|
241
|
+
expect(added.length).toBe(1);
|
|
242
|
+
addEventSpy.mockRestore();
|
|
243
|
+
removeEventSpy.mockRestore();
|
|
244
|
+
});
|
|
245
|
+
it("dispatches lvt:reconnected event on successful reconnect", async () => {
|
|
246
|
+
await connectClient();
|
|
247
|
+
const wrapper = document.querySelector("[data-lvt-id]");
|
|
248
|
+
const reconnectedSpy = jest.fn();
|
|
249
|
+
wrapper.addEventListener("lvt:reconnected", reconnectedSpy);
|
|
250
|
+
// Simulate WebSocket dying while backgrounded
|
|
251
|
+
fireVisibilityChange(true);
|
|
252
|
+
jest.advanceTimersByTime(500);
|
|
253
|
+
mockSockets[0].simulateClose();
|
|
254
|
+
jest.advanceTimersByTime(4500);
|
|
255
|
+
fireVisibilityChange(false);
|
|
256
|
+
// Wait for 500ms delay
|
|
257
|
+
await jest.advanceTimersByTimeAsync(500);
|
|
258
|
+
// Resolve the HEAD fetch inside performVisibilityReconnect
|
|
259
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
260
|
+
// Complete the reconnection
|
|
261
|
+
mockSockets[1].simulateOpen();
|
|
262
|
+
// Flush microtasks so performVisibilityReconnect() completes
|
|
263
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
264
|
+
expect(reconnectedSpy).toHaveBeenCalledTimes(1);
|
|
265
|
+
});
|
|
266
|
+
it("does not reconnect after intentional disconnect", async () => {
|
|
267
|
+
await connectClient();
|
|
268
|
+
// hiddenAt is tracked while connected
|
|
269
|
+
fireVisibilityChange(true);
|
|
270
|
+
jest.advanceTimersByTime(1000);
|
|
271
|
+
// Intentional disconnect while hidden
|
|
272
|
+
client.disconnect();
|
|
273
|
+
jest.advanceTimersByTime(4000);
|
|
274
|
+
fireVisibilityChange(false);
|
|
275
|
+
await jest.advanceTimersByTimeAsync(500);
|
|
276
|
+
// hiddenAt was reset by disconnect(), so no reconnection
|
|
277
|
+
const socketsAfterDisconnect = mockSockets.length;
|
|
278
|
+
expect(client.isReady()).toBe(false);
|
|
279
|
+
// No new sockets created — disconnect cleared hiddenAt
|
|
280
|
+
await jest.advanceTimersByTimeAsync(100);
|
|
281
|
+
expect(mockSockets.length).toBe(socketsAfterDisconnect);
|
|
282
|
+
});
|
|
283
|
+
it("a second schedule call cancels the first timer (rapid visibility+pageshow)", async () => {
|
|
284
|
+
await connectClient();
|
|
285
|
+
const initialSocketCount = mockSockets.length;
|
|
286
|
+
// Long background — first schedule queues a 500ms timer
|
|
287
|
+
fireVisibilityChange(true);
|
|
288
|
+
jest.advanceTimersByTime(4000);
|
|
289
|
+
fireVisibilityChange(false);
|
|
290
|
+
// bfcache restore fires almost immediately after — second schedule
|
|
291
|
+
firePageShow(true);
|
|
292
|
+
// Disconnect within the 500ms window. Without rescheduling cancelling
|
|
293
|
+
// the previous timer, the first timer would not be tracked by
|
|
294
|
+
// visibilityReconnectTimer (overwritten by the second), so
|
|
295
|
+
// teardownVisibilityReconnect() would only cancel the second.
|
|
296
|
+
// The first would fire after disconnect and trigger a reconnect.
|
|
297
|
+
client.disconnect();
|
|
298
|
+
await jest.advanceTimersByTimeAsync(600);
|
|
299
|
+
// No reconnect attempted after disconnect.
|
|
300
|
+
expect(mockSockets.length).toBe(initialSocketCount);
|
|
301
|
+
});
|
|
302
|
+
it("aborts the post-await continuation if disconnect ran mid-flight", async () => {
|
|
303
|
+
await connectClient();
|
|
304
|
+
const initialSocketCount = mockSockets.length;
|
|
305
|
+
// Trigger reconnect — performVisibilityReconnect awaits webSocketManager.connect()
|
|
306
|
+
fireVisibilityChange(true);
|
|
307
|
+
jest.advanceTimersByTime(4000);
|
|
308
|
+
fireVisibilityChange(false);
|
|
309
|
+
await jest.advanceTimersByTimeAsync(500);
|
|
310
|
+
// Now mid-flight: a second WebSocket has been allocated, but
|
|
311
|
+
// performVisibilityReconnect is awaiting its connect() resolution.
|
|
312
|
+
// disconnect() resets reconnecting=false. The pending await
|
|
313
|
+
// completion must observe that and bail without mutating state.
|
|
314
|
+
client.disconnect();
|
|
315
|
+
// Resolve the pending WebSocket connection.
|
|
316
|
+
mockSockets[mockSockets.length - 1]?.simulateOpen();
|
|
317
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
318
|
+
// useHTTP should remain false (reset by disconnect), not be flipped
|
|
319
|
+
// by the bailed-out continuation.
|
|
320
|
+
expect(client.useHTTP).toBe(false);
|
|
321
|
+
// No new connection should be opened past the in-flight one.
|
|
322
|
+
expect(mockSockets.length).toBe(initialSocketCount + 1);
|
|
323
|
+
});
|
|
324
|
+
it("cancels a pending reconnect timer when disconnect runs mid-window", async () => {
|
|
325
|
+
await connectClient();
|
|
326
|
+
const initialSocketCount = mockSockets.length;
|
|
327
|
+
// Background long enough to queue a reconnect
|
|
328
|
+
fireVisibilityChange(true);
|
|
329
|
+
jest.advanceTimersByTime(4000);
|
|
330
|
+
fireVisibilityChange(false);
|
|
331
|
+
// 500ms timer is now queued but has not fired yet.
|
|
332
|
+
// disconnect → connect within the timer window. Without timer
|
|
333
|
+
// cancellation, the queued timer fires after the new connect()
|
|
334
|
+
// and triggers an unwanted performVisibilityReconnect() on the
|
|
335
|
+
// freshly connected client.
|
|
336
|
+
client.disconnect();
|
|
337
|
+
createWrapper();
|
|
338
|
+
const connectPromise = client.connect();
|
|
339
|
+
await jest.advanceTimersByTimeAsync(0);
|
|
340
|
+
mockSockets[mockSockets.length - 1]?.simulateOpen();
|
|
341
|
+
await connectPromise;
|
|
342
|
+
const socketsAfterConnect = mockSockets.length;
|
|
343
|
+
// Drain the previously queued 500ms timer — should be a no-op now.
|
|
344
|
+
await jest.advanceTimersByTimeAsync(600);
|
|
345
|
+
// No spurious second WebSocket opened by the cancelled timer.
|
|
346
|
+
expect(mockSockets.length).toBe(socketsAfterConnect);
|
|
347
|
+
// Sanity: the connect itself did open one socket past the initial.
|
|
348
|
+
expect(socketsAfterConnect).toBe(initialSocketCount + 1);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
//# sourceMappingURL=visibility-reconnect.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visibility-reconnect.test.js","sourceRoot":"","sources":["../../tests/visibility-reconnect.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED