lively 0.2.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,354 @@
1
+ import {describe, before, after, it} from 'node:test';
2
+ import {ok, strict, strictEqual, deepStrictEqual} from 'node:assert';
3
+
4
+ import {WebSocket} from 'ws';
5
+ import {JSDOM} from 'jsdom';
6
+ import {Live} from '../Live.js';
7
+
8
+ describe('Live', function () {
9
+ let dom;
10
+ let webSocketServer;
11
+
12
+ const webSocketServerConfig = {port: 3000};
13
+ const webSocketServerURL = `ws://localhost:${webSocketServerConfig.port}/live`;
14
+
15
+ before(async function () {
16
+ const listening = new Promise((resolve, reject) => {
17
+ webSocketServer = new WebSocket.Server(webSocketServerConfig, resolve);
18
+ webSocketServer.on('error', reject);
19
+ });
20
+
21
+ dom = new JSDOM('<!DOCTYPE html><html><body><div id="my"><p>Hello World</p></div></body></html>');
22
+ // Ensure the WebSocket class is available:
23
+ dom.window.WebSocket = WebSocket;
24
+
25
+ await new Promise(resolve => dom.window.addEventListener('load', resolve));
26
+
27
+ await listening;
28
+ });
29
+
30
+ after(function () {
31
+ webSocketServer.close();
32
+ });
33
+
34
+ it('should start the live connection', function () {
35
+ const live = Live.start({window: dom.window, base: 'http://localhost/'});
36
+ ok(live);
37
+
38
+ strictEqual(live.window, dom.window);
39
+ strictEqual(live.document, dom.window.document);
40
+ strictEqual(live.url.href, 'ws://localhost/live');
41
+ });
42
+
43
+ it('should connect to the WebSocket server', function () {
44
+ const live = new Live(dom.window, webSocketServerURL);
45
+
46
+ const server = live.connect();
47
+ ok(server);
48
+
49
+ live.disconnect();
50
+ });
51
+
52
+ it('should handle visibility changes', function () {
53
+ const live = new Live(dom.window, webSocketServerURL);
54
+
55
+ var hidden = false;
56
+ Object.defineProperty(dom.window.document, "hidden", {
57
+ get() {return hidden},
58
+ });
59
+
60
+ live.handleVisibilityChange();
61
+
62
+ ok(live.server);
63
+
64
+ hidden = true;
65
+
66
+ live.handleVisibilityChange();
67
+
68
+ ok(!live.server);
69
+ });
70
+
71
+ it('should handle updates', async function () {
72
+ const live = new Live(dom.window, webSocketServerURL);
73
+
74
+ live.connect();
75
+
76
+ const connected = new Promise(resolve => {
77
+ webSocketServer.on('connection', resolve);
78
+ });
79
+
80
+ let socket = await connected;
81
+
82
+ const reply = new Promise((resolve, reject) => {
83
+ socket.on('message', message => {
84
+ let payload = JSON.parse(message);
85
+ if (payload[0] == 'reply') resolve(payload);
86
+ });
87
+ });
88
+
89
+ socket.send(
90
+ JSON.stringify(['update', 'my', '<div id="my"><p>Goodbye World!</p></div>', {reply: true}])
91
+ );
92
+
93
+ await reply;
94
+
95
+ strictEqual(dom.window.document.getElementById('my').innerHTML, '<p>Goodbye World!</p>');
96
+
97
+ live.disconnect();
98
+ });
99
+
100
+ it('should handle updates with child live elements', async function () {
101
+ const live = new Live(dom.window, webSocketServerURL);
102
+
103
+ live.connect();
104
+
105
+ const connected = new Promise(resolve => {
106
+ webSocketServer.on('connection', resolve);
107
+ });
108
+
109
+ let socket = await connected;
110
+
111
+ const reply = new Promise((resolve, reject) => {
112
+ socket.on('message', message => {
113
+ let payload = JSON.parse(message);
114
+ console.log("message", payload);
115
+ if (payload[0] == 'bind') resolve(payload);
116
+ else console.log("ignoring", payload);
117
+ });
118
+ });
119
+
120
+ socket.send(
121
+ JSON.stringify(['update', 'my', '<div id="my"><div id="mychild" class="live"></div></div>'])
122
+ );
123
+
124
+ let payload = await reply;
125
+
126
+ deepStrictEqual(payload, ['bind', 'mychild', {}]);
127
+
128
+ live.disconnect();
129
+ });
130
+
131
+ it('can unbind removed elements', async function () {
132
+ dom.window.document.body.innerHTML = '<div id="my" class="live"><p>Hello World</p></div>';
133
+
134
+ const live = new Live(dom.window, webSocketServerURL);
135
+
136
+ live.connect();
137
+
138
+ const connected = new Promise(resolve => {
139
+ webSocketServer.on('connection', resolve);
140
+ });
141
+
142
+ let socket = await connected;
143
+
144
+ const reply = new Promise((resolve, reject) => {
145
+ socket.on('message', message => {
146
+ let payload = JSON.parse(message);
147
+ if (payload[0] == 'unbind') resolve(payload);
148
+ else console.log("ignoring", payload);
149
+ });
150
+ });
151
+
152
+ live.attach();
153
+
154
+ dom.window.document.getElementById('my').remove();
155
+
156
+ let payload = await reply;
157
+
158
+ deepStrictEqual(payload, ['unbind', 'my']);
159
+
160
+ live.disconnect();
161
+ });
162
+
163
+ it('should handle replacements', async function () {
164
+ dom.window.document.body.innerHTML = '<div id="my"><p>Hello World</p></div>';
165
+
166
+ const live = new Live(dom.window, webSocketServerURL);
167
+
168
+ live.connect();
169
+
170
+ const connected = new Promise(resolve => {
171
+ webSocketServer.on('connection', resolve);
172
+ });
173
+
174
+ let socket = await connected;
175
+
176
+ const reply = new Promise((resolve, reject) => {
177
+ socket.on('message', message => {
178
+ let payload = JSON.parse(message);
179
+ if (payload[0] == 'reply') resolve(payload);
180
+ else console.log("ignoring", payload);
181
+ });
182
+ });
183
+
184
+ socket.send(
185
+ JSON.stringify(['replace', '#my p', '<p>Replaced!</p>', {reply: true}])
186
+ );
187
+
188
+ await reply;
189
+
190
+ strictEqual(dom.window.document.getElementById('my').innerHTML, '<p>Replaced!</p>');
191
+
192
+ live.disconnect();
193
+ });
194
+
195
+ it('should handle prepends', async function () {
196
+ const live = new Live(dom.window, webSocketServerURL);
197
+
198
+ live.connect();
199
+
200
+ const connected = new Promise(resolve => {
201
+ webSocketServer.on('connection', resolve);
202
+ });
203
+
204
+ let socket = await connected;
205
+
206
+ socket.send(
207
+ JSON.stringify(['update', 'my', '<div id="my"><p>Middle</p></div>'])
208
+ );
209
+
210
+ const reply = new Promise((resolve, reject) => {
211
+ socket.on('message', message => {
212
+ let payload = JSON.parse(message);
213
+ if (payload[0] == 'reply') resolve(payload);
214
+ else console.log("ignoring", payload);
215
+ });
216
+ });
217
+
218
+ socket.send(
219
+ JSON.stringify(['prepend', '#my', '<p>Prepended!</p>', {reply: true}])
220
+ );
221
+
222
+ await reply;
223
+
224
+ strictEqual(dom.window.document.getElementById('my').innerHTML, '<p>Prepended!</p><p>Middle</p>');
225
+
226
+ live.disconnect();
227
+ });
228
+
229
+ it('should handle appends', async function () {
230
+ const live = new Live(dom.window, webSocketServerURL);
231
+
232
+ live.connect();
233
+
234
+ const connected = new Promise(resolve => {
235
+ webSocketServer.on('connection', resolve);
236
+ });
237
+
238
+ let socket = await connected;
239
+
240
+ socket.send(
241
+ JSON.stringify(['update', 'my', '<div id="my"><p>Middle</p></div>'])
242
+ );
243
+
244
+ const reply = new Promise((resolve, reject) => {
245
+ socket.on('message', message => {
246
+ let payload = JSON.parse(message);
247
+ if (payload[0] == 'reply') resolve(payload);
248
+ else console.log("ignoring", payload);
249
+ });
250
+ });
251
+
252
+ socket.send(
253
+ JSON.stringify(['append', '#my', '<p>Appended!</p>', {reply: true}])
254
+ );
255
+
256
+ await reply;
257
+
258
+ strictEqual(dom.window.document.getElementById('my').innerHTML, '<p>Middle</p><p>Appended!</p>');
259
+
260
+ live.disconnect();
261
+ });
262
+
263
+ it ('should handle removals', async function () {
264
+ const live = new Live(dom.window, webSocketServerURL);
265
+
266
+ live.connect();
267
+
268
+ const connected = new Promise(resolve => {
269
+ webSocketServer.on('connection', resolve);
270
+ });
271
+
272
+ let socket = await connected;
273
+
274
+ socket.send(
275
+ JSON.stringify(['update', 'my', '<div id="my"><p>Middle</p></div>'])
276
+ );
277
+
278
+ const reply = new Promise((resolve, reject) => {
279
+ socket.on('message', message => {
280
+ let payload = JSON.parse(message);
281
+ if (payload[0] == 'reply') resolve(payload);
282
+ });
283
+ });
284
+
285
+ socket.send(
286
+ JSON.stringify(['remove', '#my p', {reply: true}])
287
+ );
288
+
289
+ await reply;
290
+
291
+ strictEqual(dom.window.document.getElementById('my').innerHTML, '');
292
+
293
+ live.disconnect();
294
+ });
295
+
296
+ it ('can dispatch custom events', async function () {
297
+ const live = new Live(dom.window, webSocketServerURL);
298
+
299
+ live.connect();
300
+
301
+ const connected = new Promise(resolve => {
302
+ webSocketServer.on('connection', resolve);
303
+ });
304
+
305
+ let socket = await connected;
306
+
307
+ const reply = new Promise((resolve, reject) => {
308
+ socket.on('message', message => {
309
+ let payload = JSON.parse(message);
310
+ if (payload[0] == 'reply') resolve(payload);
311
+ });
312
+ });
313
+
314
+ socket.send(
315
+ JSON.stringify(['dispatchEvent', '#my', 'click', {reply: true}])
316
+ );
317
+
318
+ await reply;
319
+
320
+ live.disconnect();
321
+ });
322
+
323
+ it ('can forward events', async function () {
324
+ const live = new Live(dom.window, webSocketServerURL);
325
+
326
+ live.connect();
327
+
328
+ const connected = new Promise(resolve => {
329
+ webSocketServer.on('connection', resolve);
330
+ });
331
+
332
+ let socket = await connected;
333
+
334
+ const reply = new Promise((resolve, reject) => {
335
+ socket.on('message', message => {
336
+ let payload = JSON.parse(message);
337
+ if (payload[0] == 'event') resolve(payload);
338
+ });
339
+ });
340
+
341
+ dom.window.document.getElementById('my').addEventListener('click', event => {
342
+ live.forwardEvent('my', event);
343
+ });
344
+
345
+ dom.window.document.getElementById('my').click();
346
+
347
+ let payload = await reply;
348
+
349
+ strictEqual(payload[1], 'my');
350
+ strictEqual(payload[2].type, 'click');
351
+
352
+ live.disconnect();
353
+ });
354
+ });