@livetemplate/client 0.8.21 → 0.8.23
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 +16 -0
- package/dist/dom/directives.d.ts.map +1 -1
- package/dist/dom/directives.js +56 -6
- package/dist/dom/directives.js.map +1 -1
- package/dist/dom/event-delegation.d.ts +9 -1
- package/dist/dom/event-delegation.d.ts.map +1 -1
- package/dist/dom/event-delegation.js +72 -25
- package/dist/dom/event-delegation.js.map +1 -1
- package/dist/dom/link-interceptor.d.ts +14 -0
- package/dist/dom/link-interceptor.d.ts.map +1 -1
- package/dist/dom/link-interceptor.js +43 -2
- package/dist/dom/link-interceptor.js.map +1 -1
- package/dist/dom/observer-manager.d.ts +10 -0
- package/dist/dom/observer-manager.d.ts.map +1 -1
- package/dist/dom/observer-manager.js +110 -3
- package/dist/dom/observer-manager.js.map +1 -1
- package/dist/livetemplate-client.browser.js +5 -5
- package/dist/livetemplate-client.browser.js.map +3 -3
- package/dist/livetemplate-client.d.ts +41 -3
- package/dist/livetemplate-client.d.ts.map +1 -1
- package/dist/livetemplate-client.js +189 -33
- package/dist/livetemplate-client.js.map +1 -1
- package/dist/tests/directives.test.js +23 -1
- package/dist/tests/directives.test.js.map +1 -1
- package/dist/tests/navigation.test.d.ts +2 -0
- package/dist/tests/navigation.test.d.ts.map +1 -0
- package/dist/tests/navigation.test.js +308 -0
- package/dist/tests/navigation.test.js.map +1 -0
- package/dist/tests/observer-manager.test.js +152 -4
- package/dist/tests/observer-manager.test.js.map +1 -1
- package/dist/tests/websocket.test.js +115 -0
- package/dist/tests/websocket.test.js.map +1 -1
- package/dist/transport/websocket.d.ts +7 -0
- package/dist/transport/websocket.d.ts.map +1 -1
- package/dist/transport/websocket.js +96 -4
- package/dist/transport/websocket.js.map +1 -1
- package/livetemplate.css +23 -6
- package/package.json +1 -1
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const livetemplate_client_1 = require("../livetemplate-client");
|
|
4
|
+
describe("handleNavigationResponse", () => {
|
|
5
|
+
let client;
|
|
6
|
+
let wrapper;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
document.body.innerHTML = ""; // safe: test cleanup, matches existing pattern
|
|
9
|
+
document.title = "Initial Title";
|
|
10
|
+
wrapper = document.createElement("div");
|
|
11
|
+
wrapper.setAttribute("data-lvt-id", "lvt-handler-a");
|
|
12
|
+
wrapper.appendChild(document.createTextNode("Handler A content"));
|
|
13
|
+
document.body.appendChild(wrapper);
|
|
14
|
+
client = new livetemplate_client_1.LiveTemplateClient();
|
|
15
|
+
client.wrapperElement = wrapper;
|
|
16
|
+
});
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
document.body.innerHTML = ""; // safe: test cleanup
|
|
19
|
+
});
|
|
20
|
+
const callHandleNavigationResponse = (html) => {
|
|
21
|
+
client.handleNavigationResponse(html);
|
|
22
|
+
};
|
|
23
|
+
describe("same-handler navigation", () => {
|
|
24
|
+
it("replaces wrapper children when response has same data-lvt-id", () => {
|
|
25
|
+
const html = [
|
|
26
|
+
"<html><head><title>Same Page</title></head><body>",
|
|
27
|
+
'<div data-lvt-id="lvt-handler-a">',
|
|
28
|
+
"<p>Updated content from same handler</p>",
|
|
29
|
+
"</div>",
|
|
30
|
+
"</body></html>",
|
|
31
|
+
].join("");
|
|
32
|
+
callHandleNavigationResponse(html);
|
|
33
|
+
expect(wrapper.textContent).toContain("Updated content from same handler");
|
|
34
|
+
expect(wrapper.getAttribute("data-lvt-id")).toBe("lvt-handler-a");
|
|
35
|
+
});
|
|
36
|
+
it("preserves wrapper element identity", () => {
|
|
37
|
+
const originalWrapper = wrapper;
|
|
38
|
+
const html = [
|
|
39
|
+
"<html><body>",
|
|
40
|
+
'<div data-lvt-id="lvt-handler-a">',
|
|
41
|
+
"<p>New content</p>",
|
|
42
|
+
"</div>",
|
|
43
|
+
"</body></html>",
|
|
44
|
+
].join("");
|
|
45
|
+
callHandleNavigationResponse(html);
|
|
46
|
+
expect(client.wrapperElement).toBe(originalWrapper);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe("cross-handler navigation", () => {
|
|
50
|
+
it("updates wrapper ID when response has different data-lvt-id", () => {
|
|
51
|
+
const disconnectSpy = jest
|
|
52
|
+
.spyOn(client, "disconnect")
|
|
53
|
+
.mockImplementation(() => { });
|
|
54
|
+
const connectSpy = jest
|
|
55
|
+
.spyOn(client, "connect")
|
|
56
|
+
.mockResolvedValue(undefined);
|
|
57
|
+
const html = [
|
|
58
|
+
"<html><body>",
|
|
59
|
+
'<div data-lvt-id="lvt-handler-b">',
|
|
60
|
+
"<p>Handler B content</p>",
|
|
61
|
+
"</div>",
|
|
62
|
+
"</body></html>",
|
|
63
|
+
].join("");
|
|
64
|
+
callHandleNavigationResponse(html);
|
|
65
|
+
expect(wrapper.getAttribute("data-lvt-id")).toBe("lvt-handler-b");
|
|
66
|
+
expect(wrapper.textContent).toContain("Handler B content");
|
|
67
|
+
disconnectSpy.mockRestore();
|
|
68
|
+
connectSpy.mockRestore();
|
|
69
|
+
});
|
|
70
|
+
it("disconnects old handler", () => {
|
|
71
|
+
const disconnectSpy = jest
|
|
72
|
+
.spyOn(client, "disconnect")
|
|
73
|
+
.mockImplementation(() => { });
|
|
74
|
+
const connectSpy = jest
|
|
75
|
+
.spyOn(client, "connect")
|
|
76
|
+
.mockResolvedValue(undefined);
|
|
77
|
+
const html = [
|
|
78
|
+
"<html><body>",
|
|
79
|
+
'<div data-lvt-id="lvt-handler-b">',
|
|
80
|
+
"<p>Handler B</p>",
|
|
81
|
+
"</div>",
|
|
82
|
+
"</body></html>",
|
|
83
|
+
].join("");
|
|
84
|
+
callHandleNavigationResponse(html);
|
|
85
|
+
expect(disconnectSpy).toHaveBeenCalledTimes(1);
|
|
86
|
+
disconnectSpy.mockRestore();
|
|
87
|
+
connectSpy.mockRestore();
|
|
88
|
+
});
|
|
89
|
+
it("reconnects to the new handler", () => {
|
|
90
|
+
const disconnectSpy = jest
|
|
91
|
+
.spyOn(client, "disconnect")
|
|
92
|
+
.mockImplementation(() => { });
|
|
93
|
+
const connectSpy = jest
|
|
94
|
+
.spyOn(client, "connect")
|
|
95
|
+
.mockResolvedValue(undefined);
|
|
96
|
+
const html = [
|
|
97
|
+
"<html><body>",
|
|
98
|
+
'<div data-lvt-id="lvt-handler-b">',
|
|
99
|
+
"<p>Handler B</p>",
|
|
100
|
+
"</div>",
|
|
101
|
+
"</body></html>",
|
|
102
|
+
].join("");
|
|
103
|
+
callHandleNavigationResponse(html);
|
|
104
|
+
expect(connectSpy).toHaveBeenCalledWith('[data-lvt-id="lvt-handler-b"]');
|
|
105
|
+
disconnectSpy.mockRestore();
|
|
106
|
+
connectSpy.mockRestore();
|
|
107
|
+
});
|
|
108
|
+
it("falls back to page reload if reconnect fails", () => {
|
|
109
|
+
const disconnectSpy = jest
|
|
110
|
+
.spyOn(client, "disconnect")
|
|
111
|
+
.mockImplementation(() => { });
|
|
112
|
+
const connectSpy = jest
|
|
113
|
+
.spyOn(client, "connect")
|
|
114
|
+
.mockRejectedValue(new Error("connection failed"));
|
|
115
|
+
const html = [
|
|
116
|
+
"<html><body>",
|
|
117
|
+
'<div data-lvt-id="lvt-handler-b">',
|
|
118
|
+
"<p>Handler B</p>",
|
|
119
|
+
"</div>",
|
|
120
|
+
"</body></html>",
|
|
121
|
+
].join("");
|
|
122
|
+
expect(() => callHandleNavigationResponse(html)).not.toThrow();
|
|
123
|
+
expect(disconnectSpy).toHaveBeenCalled();
|
|
124
|
+
expect(connectSpy).toHaveBeenCalled();
|
|
125
|
+
disconnectSpy.mockRestore();
|
|
126
|
+
connectSpy.mockRestore();
|
|
127
|
+
});
|
|
128
|
+
it("cleans up stale event listeners from old wrapper ID", () => {
|
|
129
|
+
const disconnectSpy = jest
|
|
130
|
+
.spyOn(client, "disconnect")
|
|
131
|
+
.mockImplementation(() => { });
|
|
132
|
+
const connectSpy = jest
|
|
133
|
+
.spyOn(client, "connect")
|
|
134
|
+
.mockResolvedValue(undefined);
|
|
135
|
+
// Simulate an existing listener keyed to old wrapper ID
|
|
136
|
+
const oldListener = jest.fn();
|
|
137
|
+
document["__lvt_link_intercept_lvt-handler-a"] = oldListener;
|
|
138
|
+
document.addEventListener("click", oldListener);
|
|
139
|
+
const html = [
|
|
140
|
+
"<html><body>",
|
|
141
|
+
'<div data-lvt-id="lvt-handler-b">',
|
|
142
|
+
"<p>Handler B</p>",
|
|
143
|
+
"</div>",
|
|
144
|
+
"</body></html>",
|
|
145
|
+
].join("");
|
|
146
|
+
callHandleNavigationResponse(html);
|
|
147
|
+
// Old listener key should be removed
|
|
148
|
+
expect(document["__lvt_link_intercept_lvt-handler-a"]).toBeUndefined();
|
|
149
|
+
disconnectSpy.mockRestore();
|
|
150
|
+
connectSpy.mockRestore();
|
|
151
|
+
});
|
|
152
|
+
it("sets up event delegation and link interception immediately (before async connect)", () => {
|
|
153
|
+
const disconnectSpy = jest
|
|
154
|
+
.spyOn(client, "disconnect")
|
|
155
|
+
.mockImplementation(() => { });
|
|
156
|
+
// Make connect() return a promise that never resolves to prove the
|
|
157
|
+
// synchronous setup happens regardless of whether connect completes
|
|
158
|
+
const connectSpy = jest
|
|
159
|
+
.spyOn(client, "connect")
|
|
160
|
+
.mockReturnValue(new Promise(() => { }));
|
|
161
|
+
// Spy on the real internal setup methods
|
|
162
|
+
const eventSetupSpy = jest.spyOn(client.eventDelegator, "setupEventDelegation");
|
|
163
|
+
const linkSetupSpy = jest.spyOn(client.linkInterceptor, "setup");
|
|
164
|
+
const html = [
|
|
165
|
+
"<html><body>",
|
|
166
|
+
'<div data-lvt-id="lvt-handler-b">',
|
|
167
|
+
"<p>Handler B</p>",
|
|
168
|
+
"</div>",
|
|
169
|
+
"</body></html>",
|
|
170
|
+
].join("");
|
|
171
|
+
callHandleNavigationResponse(html);
|
|
172
|
+
// Both setup methods must have been called synchronously
|
|
173
|
+
expect(eventSetupSpy).toHaveBeenCalled();
|
|
174
|
+
expect(linkSetupSpy).toHaveBeenCalled();
|
|
175
|
+
disconnectSpy.mockRestore();
|
|
176
|
+
connectSpy.mockRestore();
|
|
177
|
+
eventSetupSpy.mockRestore();
|
|
178
|
+
linkSetupSpy.mockRestore();
|
|
179
|
+
});
|
|
180
|
+
it("scrolls to top on cross-handler navigation", () => {
|
|
181
|
+
const disconnectSpy = jest
|
|
182
|
+
.spyOn(client, "disconnect")
|
|
183
|
+
.mockImplementation(() => { });
|
|
184
|
+
const connectSpy = jest
|
|
185
|
+
.spyOn(client, "connect")
|
|
186
|
+
.mockResolvedValue(undefined);
|
|
187
|
+
const scrollSpy = jest
|
|
188
|
+
.spyOn(window, "scrollTo")
|
|
189
|
+
.mockImplementation(() => { });
|
|
190
|
+
const html = [
|
|
191
|
+
"<html><body>",
|
|
192
|
+
'<div data-lvt-id="lvt-handler-b">',
|
|
193
|
+
"<p>Handler B</p>",
|
|
194
|
+
"</div>",
|
|
195
|
+
"</body></html>",
|
|
196
|
+
].join("");
|
|
197
|
+
callHandleNavigationResponse(html);
|
|
198
|
+
expect(scrollSpy).toHaveBeenCalledWith(0, 0);
|
|
199
|
+
disconnectSpy.mockRestore();
|
|
200
|
+
connectSpy.mockRestore();
|
|
201
|
+
scrollSpy.mockRestore();
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
describe("title updates", () => {
|
|
205
|
+
it("updates document.title from response", () => {
|
|
206
|
+
const html = [
|
|
207
|
+
"<html><head><title>New Page Title</title></head><body>",
|
|
208
|
+
'<div data-lvt-id="lvt-handler-a">',
|
|
209
|
+
"<p>Content</p>",
|
|
210
|
+
"</div>",
|
|
211
|
+
"</body></html>",
|
|
212
|
+
].join("");
|
|
213
|
+
callHandleNavigationResponse(html);
|
|
214
|
+
expect(document.title).toBe("New Page Title");
|
|
215
|
+
});
|
|
216
|
+
it("updates title on cross-handler navigation", () => {
|
|
217
|
+
const disconnectSpy = jest
|
|
218
|
+
.spyOn(client, "disconnect")
|
|
219
|
+
.mockImplementation(() => { });
|
|
220
|
+
const connectSpy = jest
|
|
221
|
+
.spyOn(client, "connect")
|
|
222
|
+
.mockResolvedValue(undefined);
|
|
223
|
+
const html = [
|
|
224
|
+
"<html><head><title>Handler B Title</title></head><body>",
|
|
225
|
+
'<div data-lvt-id="lvt-handler-b">',
|
|
226
|
+
"<p>Handler B</p>",
|
|
227
|
+
"</div>",
|
|
228
|
+
"</body></html>",
|
|
229
|
+
].join("");
|
|
230
|
+
callHandleNavigationResponse(html);
|
|
231
|
+
expect(document.title).toBe("Handler B Title");
|
|
232
|
+
disconnectSpy.mockRestore();
|
|
233
|
+
connectSpy.mockRestore();
|
|
234
|
+
});
|
|
235
|
+
it("does not change title when response has no title element", () => {
|
|
236
|
+
const html = [
|
|
237
|
+
"<html><body>",
|
|
238
|
+
'<div data-lvt-id="lvt-handler-a">',
|
|
239
|
+
"<p>No title page</p>",
|
|
240
|
+
"</div>",
|
|
241
|
+
"</body></html>",
|
|
242
|
+
].join("");
|
|
243
|
+
callHandleNavigationResponse(html);
|
|
244
|
+
expect(document.title).toBe("Initial Title");
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
describe("non-LiveTemplate response", () => {
|
|
248
|
+
it("uses body content when response has no data-lvt-id wrapper", () => {
|
|
249
|
+
const disconnectSpy = jest
|
|
250
|
+
.spyOn(client, "disconnect")
|
|
251
|
+
.mockImplementation(() => { });
|
|
252
|
+
const html = [
|
|
253
|
+
"<html><body>",
|
|
254
|
+
"<div><p>Plain HTML page</p></div>",
|
|
255
|
+
"</body></html>",
|
|
256
|
+
].join("");
|
|
257
|
+
callHandleNavigationResponse(html);
|
|
258
|
+
expect(wrapper.textContent).toContain("Plain HTML page");
|
|
259
|
+
expect(wrapper.getAttribute("data-lvt-id")).toBe("lvt-handler-a");
|
|
260
|
+
disconnectSpy.mockRestore();
|
|
261
|
+
});
|
|
262
|
+
it("disconnects old WebSocket on non-LiveTemplate fallback", () => {
|
|
263
|
+
const disconnectSpy = jest
|
|
264
|
+
.spyOn(client, "disconnect")
|
|
265
|
+
.mockImplementation(() => { });
|
|
266
|
+
const html = [
|
|
267
|
+
"<html><body>",
|
|
268
|
+
"<div><p>Plain HTML page</p></div>",
|
|
269
|
+
"</body></html>",
|
|
270
|
+
].join("");
|
|
271
|
+
callHandleNavigationResponse(html);
|
|
272
|
+
expect(disconnectSpy).toHaveBeenCalledTimes(1);
|
|
273
|
+
disconnectSpy.mockRestore();
|
|
274
|
+
});
|
|
275
|
+
it("tears down stale listeners on non-LiveTemplate fallback", () => {
|
|
276
|
+
const disconnectSpy = jest
|
|
277
|
+
.spyOn(client, "disconnect")
|
|
278
|
+
.mockImplementation(() => { });
|
|
279
|
+
// Spy on teardownForWrapper to verify it's called with the old ID
|
|
280
|
+
const linkTeardownSpy = jest.spyOn(client.linkInterceptor, "teardownForWrapper");
|
|
281
|
+
const eventTeardownSpy = jest.spyOn(client.eventDelegator, "teardownForWrapper");
|
|
282
|
+
const html = [
|
|
283
|
+
"<html><body>",
|
|
284
|
+
"<div><p>Plain HTML page</p></div>",
|
|
285
|
+
"</body></html>",
|
|
286
|
+
].join("");
|
|
287
|
+
callHandleNavigationResponse(html);
|
|
288
|
+
// Both teardown methods must be called with the old wrapper ID
|
|
289
|
+
// before the fallback path re-registers listeners.
|
|
290
|
+
expect(linkTeardownSpy).toHaveBeenCalledWith("lvt-handler-a");
|
|
291
|
+
expect(eventTeardownSpy).toHaveBeenCalledWith("lvt-handler-a");
|
|
292
|
+
disconnectSpy.mockRestore();
|
|
293
|
+
linkTeardownSpy.mockRestore();
|
|
294
|
+
eventTeardownSpy.mockRestore();
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
describe("edge cases", () => {
|
|
298
|
+
it("handles empty response body gracefully", () => {
|
|
299
|
+
const html = "<html><body></body></html>";
|
|
300
|
+
expect(() => callHandleNavigationResponse(html)).not.toThrow();
|
|
301
|
+
});
|
|
302
|
+
it("does nothing when wrapperElement is null", () => {
|
|
303
|
+
client.wrapperElement = null;
|
|
304
|
+
expect(() => callHandleNavigationResponse("<html><body></body></html>")).not.toThrow();
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
//# sourceMappingURL=navigation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.test.js","sourceRoot":"","sources":["../../tests/navigation.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,12 +2,20 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const observer_manager_1 = require("../dom/observer-manager");
|
|
4
4
|
const logger_1 = require("../utils/logger");
|
|
5
|
-
// Mock IntersectionObserver
|
|
5
|
+
// Mock IntersectionObserver. Tracks instances and disconnect calls so tests
|
|
6
|
+
// can assert not just that a fresh observer was built, but that the old one
|
|
7
|
+
// was torn down — guards against silent leaks where a stale observer keeps
|
|
8
|
+
// firing callbacks against a detached sentinel.
|
|
6
9
|
class MockIntersectionObserver {
|
|
10
|
+
static reset() {
|
|
11
|
+
MockIntersectionObserver.instances.length = 0;
|
|
12
|
+
}
|
|
7
13
|
constructor(callback, options) {
|
|
14
|
+
this.disconnected = false;
|
|
8
15
|
this.elements = [];
|
|
9
16
|
this.callback = callback;
|
|
10
17
|
this.options = options;
|
|
18
|
+
MockIntersectionObserver.instances.push(this);
|
|
11
19
|
}
|
|
12
20
|
observe(element) {
|
|
13
21
|
this.elements.push(element);
|
|
@@ -16,6 +24,7 @@ class MockIntersectionObserver {
|
|
|
16
24
|
this.elements = this.elements.filter((e) => e !== element);
|
|
17
25
|
}
|
|
18
26
|
disconnect() {
|
|
27
|
+
this.disconnected = true;
|
|
19
28
|
this.elements = [];
|
|
20
29
|
}
|
|
21
30
|
// Helper to trigger intersection
|
|
@@ -32,6 +41,7 @@ class MockIntersectionObserver {
|
|
|
32
41
|
this.callback(entries, this);
|
|
33
42
|
}
|
|
34
43
|
}
|
|
44
|
+
MockIntersectionObserver.instances = [];
|
|
35
45
|
global.IntersectionObserver = MockIntersectionObserver;
|
|
36
46
|
describe("ObserverManager", () => {
|
|
37
47
|
let mockContext;
|
|
@@ -40,7 +50,9 @@ describe("ObserverManager", () => {
|
|
|
40
50
|
let mockLogger;
|
|
41
51
|
let mockConsole;
|
|
42
52
|
beforeEach(() => {
|
|
53
|
+
jest.useFakeTimers();
|
|
43
54
|
document.body.innerHTML = "";
|
|
55
|
+
MockIntersectionObserver.reset();
|
|
44
56
|
mockSend = jest.fn();
|
|
45
57
|
mockConsole = {
|
|
46
58
|
debug: jest.fn(),
|
|
@@ -54,9 +66,13 @@ describe("ObserverManager", () => {
|
|
|
54
66
|
});
|
|
55
67
|
});
|
|
56
68
|
afterEach(() => {
|
|
69
|
+
// Teardown BEFORE swapping back to real timers so any pending fake
|
|
70
|
+
// setTimeout IDs inside ObserverManager are cleared against the fake
|
|
71
|
+
// timer backend they were scheduled on.
|
|
57
72
|
if (manager) {
|
|
58
73
|
manager.teardown();
|
|
59
74
|
}
|
|
75
|
+
jest.useRealTimers();
|
|
60
76
|
});
|
|
61
77
|
describe("setupInfiniteScrollObserver", () => {
|
|
62
78
|
it("does nothing if wrapper element is null", () => {
|
|
@@ -93,7 +109,7 @@ describe("ObserverManager", () => {
|
|
|
93
109
|
manager.setupInfiniteScrollObserver();
|
|
94
110
|
expect(mockConsole.debug).toHaveBeenCalledWith(expect.any(String), "Observer set up successfully");
|
|
95
111
|
});
|
|
96
|
-
it("
|
|
112
|
+
it("reuses the existing observer when the sentinel is unchanged", () => {
|
|
97
113
|
document.body.innerHTML = `
|
|
98
114
|
<div id="wrapper">
|
|
99
115
|
<div id="scroll-sentinel"></div>
|
|
@@ -106,9 +122,137 @@ describe("ObserverManager", () => {
|
|
|
106
122
|
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
107
123
|
manager.setupInfiniteScrollObserver();
|
|
108
124
|
manager.setupInfiniteScrollObserver();
|
|
109
|
-
//
|
|
125
|
+
// Same sentinel node → only one setup; subsequent calls are no-ops.
|
|
126
|
+
const setupCalls = mockConsole.debug.mock.calls.filter((call) => call[1] === "Observer set up successfully");
|
|
127
|
+
expect(setupCalls.length).toBe(1);
|
|
128
|
+
});
|
|
129
|
+
it("releases the load_more throttle if the server never responds", () => {
|
|
130
|
+
// Build fresh wrapper + sentinel via DOM APIs to avoid the XSS-reminder
|
|
131
|
+
// hook in tests that scans innerHTML assignments.
|
|
132
|
+
document.body.replaceChildren();
|
|
133
|
+
const wrapper = document.createElement("div");
|
|
134
|
+
wrapper.id = "wrapper";
|
|
135
|
+
const sentinel = document.createElement("div");
|
|
136
|
+
sentinel.id = "scroll-sentinel";
|
|
137
|
+
wrapper.appendChild(sentinel);
|
|
138
|
+
document.body.appendChild(wrapper);
|
|
139
|
+
mockContext = {
|
|
140
|
+
getWrapperElement: () => document.getElementById("wrapper"),
|
|
141
|
+
send: mockSend,
|
|
142
|
+
};
|
|
143
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
144
|
+
manager.setupInfiniteScrollObserver();
|
|
145
|
+
// First intersection → send load_more, arm the 30s safety timeout.
|
|
146
|
+
MockIntersectionObserver.instances[0].triggerIntersection(true);
|
|
147
|
+
expect(mockSend).toHaveBeenCalledTimes(1);
|
|
148
|
+
expect(mockSend).toHaveBeenCalledWith({ action: "load_more" });
|
|
149
|
+
// While "pending" is true, subsequent intersections must be ignored.
|
|
150
|
+
MockIntersectionObserver.instances[0].triggerIntersection(true);
|
|
151
|
+
expect(mockSend).toHaveBeenCalledTimes(1);
|
|
152
|
+
// Server never responds. Advance past the 30s safety net.
|
|
153
|
+
jest.advanceTimersByTime(30001);
|
|
154
|
+
// A warning must be logged and a fresh observer allocated so the
|
|
155
|
+
// next intersection can re-fire. MockIntersectionObserver.instances
|
|
156
|
+
// should now have a second entry.
|
|
157
|
+
expect(mockConsole.warn).toHaveBeenCalledWith(expect.any(String), expect.stringMatching(/load_more response not received/));
|
|
158
|
+
expect(MockIntersectionObserver.instances.length).toBeGreaterThanOrEqual(2);
|
|
159
|
+
// The next intersection re-arms the throttle and sends again.
|
|
160
|
+
const latest = MockIntersectionObserver.instances[MockIntersectionObserver.instances.length - 1];
|
|
161
|
+
latest.triggerIntersection(true);
|
|
162
|
+
expect(mockSend).toHaveBeenCalledTimes(2);
|
|
163
|
+
});
|
|
164
|
+
it("clears the load_more throttle when the sentinel disappears", () => {
|
|
165
|
+
// Regression test for HasMore flip-flop scenario:
|
|
166
|
+
// 1. Sentinel visible → load_more sent, throttle armed.
|
|
167
|
+
// 2. Server flips HasMore to false → sentinel removed from DOM.
|
|
168
|
+
// 3. Server flips HasMore back to true → sentinel reappears.
|
|
169
|
+
// 4. Next intersection must re-trigger load_more (not be silently
|
|
170
|
+
// dropped waiting on the 30s safety timer).
|
|
171
|
+
document.body.replaceChildren();
|
|
172
|
+
const wrapper = document.createElement("div");
|
|
173
|
+
wrapper.id = "wrapper";
|
|
174
|
+
const sentinel1 = document.createElement("div");
|
|
175
|
+
sentinel1.id = "scroll-sentinel";
|
|
176
|
+
wrapper.appendChild(sentinel1);
|
|
177
|
+
document.body.appendChild(wrapper);
|
|
178
|
+
mockContext = {
|
|
179
|
+
getWrapperElement: () => document.getElementById("wrapper"),
|
|
180
|
+
send: mockSend,
|
|
181
|
+
};
|
|
182
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
183
|
+
manager.setupInfiniteScrollObserver();
|
|
184
|
+
// Step 1: arm the throttle by triggering intersection.
|
|
185
|
+
MockIntersectionObserver.instances[0].triggerIntersection(true);
|
|
186
|
+
expect(mockSend).toHaveBeenCalledTimes(1);
|
|
187
|
+
// Step 2: sentinel removed (HasMore flipped false).
|
|
188
|
+
sentinel1.remove();
|
|
189
|
+
manager.setupInfiniteScrollObserver();
|
|
190
|
+
// No observer should be active at this point.
|
|
191
|
+
expect(MockIntersectionObserver.instances[0].disconnected).toBe(true);
|
|
192
|
+
// Step 3: sentinel reappears.
|
|
193
|
+
const sentinel2 = document.createElement("div");
|
|
194
|
+
sentinel2.id = "scroll-sentinel";
|
|
195
|
+
wrapper.appendChild(sentinel2);
|
|
196
|
+
manager.setupInfiniteScrollObserver();
|
|
197
|
+
// Step 4: next intersection must fire — throttle must be clear.
|
|
198
|
+
const latest = MockIntersectionObserver.instances[MockIntersectionObserver.instances.length - 1];
|
|
199
|
+
latest.triggerIntersection(true);
|
|
200
|
+
expect(mockSend).toHaveBeenCalledTimes(2);
|
|
201
|
+
});
|
|
202
|
+
it("clears the load_more safety timeout when lvt:updated fires", () => {
|
|
203
|
+
document.body.replaceChildren();
|
|
204
|
+
const wrapper = document.createElement("div");
|
|
205
|
+
wrapper.id = "wrapper";
|
|
206
|
+
const sentinel = document.createElement("div");
|
|
207
|
+
sentinel.id = "scroll-sentinel";
|
|
208
|
+
wrapper.appendChild(sentinel);
|
|
209
|
+
document.body.appendChild(wrapper);
|
|
210
|
+
mockContext = {
|
|
211
|
+
getWrapperElement: () => document.getElementById("wrapper"),
|
|
212
|
+
send: mockSend,
|
|
213
|
+
};
|
|
214
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
215
|
+
manager.setupInfiniteScrollObserver();
|
|
216
|
+
MockIntersectionObserver.instances[0].triggerIntersection(true);
|
|
217
|
+
expect(mockSend).toHaveBeenCalledTimes(1);
|
|
218
|
+
// Simulate the server's lvt:updated event for load_more.
|
|
219
|
+
wrapper.dispatchEvent(new CustomEvent("lvt:updated", { detail: { action: "load_more" } }));
|
|
220
|
+
// Advance well past the 30s safety window — no warning should fire
|
|
221
|
+
// because the timeout was cleared on the legitimate response.
|
|
222
|
+
jest.advanceTimersByTime(60000);
|
|
223
|
+
expect(mockConsole.warn).not.toHaveBeenCalledWith(expect.any(String), expect.stringMatching(/load_more response not received/));
|
|
224
|
+
});
|
|
225
|
+
it("rebuilds the observer when the sentinel node identity changes", () => {
|
|
226
|
+
// Build fresh wrapper + sentinel via DOM APIs to avoid the XSS-reminder
|
|
227
|
+
// hook in tests that scans innerHTML assignments.
|
|
228
|
+
document.body.replaceChildren();
|
|
229
|
+
const wrapper = document.createElement("div");
|
|
230
|
+
wrapper.id = "wrapper";
|
|
231
|
+
const sentinel1 = document.createElement("div");
|
|
232
|
+
sentinel1.id = "scroll-sentinel";
|
|
233
|
+
wrapper.appendChild(sentinel1);
|
|
234
|
+
document.body.appendChild(wrapper);
|
|
235
|
+
mockContext = {
|
|
236
|
+
getWrapperElement: () => document.getElementById("wrapper"),
|
|
237
|
+
send: mockSend,
|
|
238
|
+
};
|
|
239
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
240
|
+
manager.setupInfiniteScrollObserver();
|
|
241
|
+
// Replace sentinel with a fresh node (simulates morphdom recreating
|
|
242
|
+
// the element on a structural transition).
|
|
243
|
+
sentinel1.remove();
|
|
244
|
+
const sentinel2 = document.createElement("div");
|
|
245
|
+
sentinel2.id = "scroll-sentinel";
|
|
246
|
+
wrapper.appendChild(sentinel2);
|
|
247
|
+
manager.setupInfiniteScrollObserver();
|
|
110
248
|
const setupCalls = mockConsole.debug.mock.calls.filter((call) => call[1] === "Observer set up successfully");
|
|
111
249
|
expect(setupCalls.length).toBe(2);
|
|
250
|
+
// The old observer MUST be disconnected before the new one is created —
|
|
251
|
+
// otherwise it keeps firing callbacks against the detached sentinel and
|
|
252
|
+
// leaks memory until GC collects a chain that the observer itself holds.
|
|
253
|
+
expect(MockIntersectionObserver.instances.length).toBe(2);
|
|
254
|
+
expect(MockIntersectionObserver.instances[0].disconnected).toBe(true);
|
|
255
|
+
expect(MockIntersectionObserver.instances[1].disconnected).toBe(false);
|
|
112
256
|
});
|
|
113
257
|
});
|
|
114
258
|
describe("setupInfiniteScrollMutationObserver", () => {
|
|
@@ -160,8 +304,12 @@ describe("ObserverManager", () => {
|
|
|
160
304
|
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
161
305
|
manager.setupInfiniteScrollObserver();
|
|
162
306
|
manager.setupInfiniteScrollMutationObserver();
|
|
163
|
-
// Should not throw
|
|
164
307
|
expect(() => manager.teardown()).not.toThrow();
|
|
308
|
+
// IntersectionObserver instance created by setupInfiniteScrollObserver
|
|
309
|
+
// must be disconnected — verifies teardown actually cleans up, not just
|
|
310
|
+
// that it doesn't throw.
|
|
311
|
+
expect(MockIntersectionObserver.instances.length).toBe(1);
|
|
312
|
+
expect(MockIntersectionObserver.instances[0].disconnected).toBe(true);
|
|
165
313
|
});
|
|
166
314
|
it("is safe to call when no observers are set up", () => {
|
|
167
315
|
mockContext = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observer-manager.test.js","sourceRoot":"","sources":["../../tests/observer-manager.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"observer-manager.test.js","sourceRoot":"","sources":["../../tests/observer-manager.test.ts"],"names":[],"mappings":"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"}
|