74 lines
3.6 KiB
JavaScript
74 lines
3.6 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { createUiConnection } from "../extension/ui-connection.js";
|
|
|
|
function harness() {
|
|
const ports = [], events = [];
|
|
const runtime = { connect() {
|
|
const messages = [], disconnects = [];
|
|
const port = { sent: [], dead: false,
|
|
onMessage: { addListener: listener => messages.push(listener) },
|
|
onDisconnect: { addListener: listener => disconnects.push(listener) },
|
|
postMessage(message) {
|
|
if (this.dead) throw new Error("Attempting to use a disconnected port object");
|
|
this.sent.push(message);
|
|
},
|
|
respond(result, index = this.sent.length - 1) { messages.forEach(listener => listener({ id: this.sent[index].id, ok: true, result })); },
|
|
emit(message) { messages.forEach(listener => listener(message)); },
|
|
disconnect() { this.dead = true; disconnects.forEach(listener => listener()); },
|
|
};
|
|
ports.push(port); return port;
|
|
} };
|
|
const connection = createUiConnection({ runtime, onEvent: event => events.push(event), onDisconnect: () => events.push({ disconnected: true }) });
|
|
return { ...connection, ports, events, runtime };
|
|
}
|
|
|
|
test("a menu reconnects after worker shutdown, without resending an in-flight operation", async () => {
|
|
const h = harness();
|
|
const pending = h.call("helper_remove");
|
|
const rejected = assert.rejects(pending, /Связь с расширением прервана/);
|
|
const old = h.ports[0]; old.disconnect(); await rejected;
|
|
const next = h.call("helper_start");
|
|
assert.equal(h.ports.length, 2); assert.equal(old.sent.length, 1);
|
|
assert.equal(h.ports[1].sent[0].action, "helper_start");
|
|
h.ports[1].respond({ ready: true }); assert.deepEqual(await next, { ready: true });
|
|
// Late events from the old worker must not change the new status.
|
|
const count = h.events.length;
|
|
old.emit({ event: "helper", helper: { status: "missing" } }); old.disconnect();
|
|
assert.equal(h.events.length, count);
|
|
h.ports[1].emit({ event: "helper", helper: { status: "running" } });
|
|
assert.equal(h.events.at(-1).helper.status, "running");
|
|
});
|
|
|
|
test("a disconnected-port exception before its callback reconnects in the same click", async () => {
|
|
const h = harness();
|
|
const initial = h.call("hello"); h.ports[0].respond({ ready: true }); await initial;
|
|
h.ports[0].dead = true;
|
|
const retry = h.call("helper_start");
|
|
assert.equal(h.ports.length, 2);
|
|
h.ports[0].disconnect();
|
|
h.ports[1].respond({ ready: true }); assert.equal((await retry).ready, true);
|
|
assert.equal(h.ports[0].sent.length, 1, "Failed post was never delivered");
|
|
});
|
|
|
|
test("repeated disconnected-port failures stop after one retry with a readable error", async () => {
|
|
let attempts = 0;
|
|
const h = createUiConnection({ runtime: { connect() {
|
|
attempts++;
|
|
return { onMessage: { addListener() {} }, onDisconnect: { addListener() {} },
|
|
postMessage() { throw new Error("Attempting to use a disconnected port object"); } };
|
|
} } });
|
|
await assert.rejects(h.call("helper_start"), /Проверить подключение/);
|
|
assert.equal(attempts, 2);
|
|
});
|
|
|
|
test("helper errors are delivered once and do not replay updates or removal", async () => {
|
|
for (const action of ["helper_update", "helper_remove", "download"]) {
|
|
const h = harness(), result = h.call(action);
|
|
const rejected = assert.rejects(result, /Дождитесь завершения/);
|
|
h.ports[0].emit({ id: h.ports[0].sent[0].id, ok: false, error: "Дождитесь завершения загрузок" });
|
|
await rejected;
|
|
assert.equal(h.ports.length, 1); assert.equal(h.ports[0].sent.length, 1);
|
|
}
|
|
});
|