oficina / meet Public

Clone
git clone https://amadan.net/oficina/meet

Plain git — no account needed to clone.

Download

Download this file

1// room-reconnect.test.mjs — "Reconnecting…" only for a problem that
2// lasts (spec §15.23, 2026-09-30), gated without a browser.
3//
4// node --test test/browser/room-reconnect.test.mjs
5//
6// reconnectStep and reconnectRecord lifted out of the shipped room.js by
7// name, with the constants they read, as room-screen.test.mjs does.
8import { test } from 'node:test';
9import assert from 'node:assert/strict';
10import { readFileSync } from 'node:fs';
11import { fileURLToPath } from 'node:url';
12
13const src = readFileSync(fileURLToPath(new URL('../../internal/calls/static/room.js', import.meta.url)), 'utf8');
14
15function lift(name) {
16 const start = src.indexOf('function ' + name + '(');
17 assert.notEqual(start, -1, name + ' is not in room.js any more — this test is stale, not passing');
18 let depth = 0;
19 for (let i = src.indexOf('{', start); i < src.length; i++) {
20 if (src[i] === '{') depth += 1;
21 else if (src[i] === '}') {
22 depth -= 1;
23 if (depth === 0) return src.slice(start, i + 1);
24 }
25 }
26 assert.fail('unbalanced braces reading ' + name);
27}
28function liftConst(name) {
29 const m = src.match(new RegExp('const ' + name + ' = ([0-9.]+);'));
30 assert.ok(m, name + ' is not a numeric const in room.js any more');
31 return 'const ' + name + ' = ' + m[1] + ';';
32}
33const CONSTS = ['RECONNECT_STREAM_AFTER', 'RECONNECT_CONNECTION_AFTER', 'RECONNECT_AUDIO_AFTER', 'RECONNECT_HOLD']
34 .map(liftConst).join('\n');
35// eslint-disable-next-line no-new-func
36const { reconnectRecord, reconnectStep } = new Function(CONSTS + '\n' + lift('reconnectRecord') + '\n' +
37 lift('reconnectStep') + '; return { reconnectRecord, reconnectStep };')();
38
39const fine = { connectionBad: false, audioMissing: false };
40
41// Five looks a second from `from` to `to` seconds; the times the whole
42// call's words showed, and the tiles' at each time.
43function run(rec, from, to, stream, people) {
44 const call = [];
45 const peers = new Map();
46 for (let t = from * 10; t < to * 10; t += 2) {
47 const s = t / 10;
48 reconnectStep(rec, s * 1000, stream(s), people(s));
49 if (rec.call) call.push(s);
50 if (rec.peers.size) peers.set(s, Array.from(rec.peers).sort().join());
51 }
52 return { call, peers };
53}
54
55test('a routine stream renewal, and a slow one, are never said', () => {
56 const rec = reconnectRecord();
57 const seen = run(rec, 0, 60, (t) => (t >= 10 && t < 10.6) || (t >= 30 && t < 33.5),
58 () => new Map([['sam', fine]]));
59 assert.deepEqual(seen.call, []);
60 assert.equal(seen.peers.size, 0);
61});
62
63test('a stream down four seconds is said, and held a second past recovery', () => {
64 const rec = reconnectRecord();
65 const seen = run(rec, 0, 20, (t) => t >= 5 && t < 12, () => new Map([['sam', fine]]));
66 assert.equal(seen.call[0], 9);
67 assert.equal(seen.call[seen.call.length - 1], 12.8);
68});
69
70test('short blips on one person are never said', () => {
71 const rec = reconnectRecord();
72 const seen = run(rec, 0, 30, () => false, (t) => new Map([['sam', {
73 connectionBad: t >= 5 && t < 7.5, audioMissing: t >= 15 && t < 16.5,
74 }]]));
75 assert.deepEqual(seen.call, []);
76 assert.equal(seen.peers.size, 0);
77});
78
79test('one person\'s lasting trouble is said on their tile alone', () => {
80 const rec = reconnectRecord();
81 const seen = run(rec, 0, 30, () => false,
82 (t) => new Map([['sam', { connectionBad: t >= 5 && t < 15, audioMissing: false }], ['ana', fine]]));
83 assert.deepEqual(seen.call, []);
84 const times = Array.from(seen.peers.keys());
85 assert.equal(times[0], 8);
86 assert.equal(times[times.length - 1], 15.8);
87 assert.ok(Array.from(seen.peers.values()).every((v) => v === 'sam'));
88});
89
90test('audio that stops from someone unmuted is said after two seconds', () => {
91 const rec = reconnectRecord();
92 const seen = run(rec, 0, 20, () => false,
93 (t) => new Map([['sam', { connectionBad: false, audioMissing: t >= 5 && t < 10 }], ['ana', fine]]));
94 assert.equal(Array.from(seen.peers.keys())[0], 7);
95});
96
97test('everyone\'s trouble is the whole call, not a tile each', () => {
98 const rec = reconnectRecord();
99 const seen = run(rec, 0, 20, () => false, (t) => {
100 const bad = { connectionBad: t >= 5 && t < 12, audioMissing: false };
101 return new Map([['sam', bad], ['ana', bad]]);
102 });
103 assert.equal(seen.call[0], 8);
104 assert.equal(seen.peers.size, 0);
105});
106