import assert from "node:assert/strict"; import { before, after, test } from "node:test"; import { createServer } from "vite"; let server; let observeProvisioningRequest; let networkProvisionFailureMessage; let ApiError; before(async () => { server = await createServer({ appType: "custom", logLevel: "silent", server: { middlewareMode: true } }); ({ observeProvisioningRequest, networkProvisionFailureMessage } = await server.ssrLoadModule("@xgrids-k1/frontend/networkProvisioning.ts")); ({ ApiError } = await server.ssrLoadModule("@xgrids-k1/frontend/api.ts")); }); after(async () => { await server?.close(); }); test("reviewed station errors explain Wi-Fi recovery without claiming a Bluetooth failure", () => { for (const [code, pattern] of [ ["k1-wifi-network-not-found", /указанная сеть не найдена/], ["k1-wifi-credentials-required", /устройство запросило учётные данные сети/], ]) { const message = networkProvisionFailureMessage({ status: "failed", error: { code } }); assert.match(message, pattern); assert.match(message, /Проверьте название сети и пароль/); assert.doesNotMatch(message, /INVALID_PDU|ошибкой Bluetooth|Переподключиться/); } assert.match(networkProvisionFailureMessage({ status: "failed", error: { code: "BleakGATTProtocolError", ble_att_error_code: 4, ble_att_error_name: "INVALID_PDU", } }), /INVALID_PDU/); assert.match(networkProvisionFailureMessage({ status: "failed", error: { code: "network-not-found", } }), /macOS/); }); const request = { device_id: "synthetic-k1", connection_mode: "bridge", idempotency_key: "explicit-one" }; function snapshot(status, revision = 2) { return { snapshot_runtime_id: "runtime-one", snapshot_runtime_started_at_utc: "2026-09-06T00:00:00Z", snapshot_revision: revision, operations: status ? [{ operation_id: "op-one", action: "network.provision", idempotency_key: request.idempotency_key, status, error: status === "failed" ? { code: "BleakGATTProtocolError", ble_att_error_code: 4, ble_att_error_name: "INVALID_PDU", device_write_attempted: true, device_write_confirmed: false, safe_to_retry: false, side_effect_status: "unknown", } : null, }] : [], }; } function context(overrides = {}) { let current = snapshot(null, 1); const calls = []; return { calls, initialState: current, send: async (input) => { calls.push(["send", input]); throw new ApiError("transport", 502); }, readState: async () => { calls.push(["read"]); return snapshot("failed"); }, acceptState: (incoming) => { if (incoming.snapshot_revision >= current.snapshot_revision) current = incoming; }, currentState: () => current, assertCurrent() {}, ...overrides, }; } test("HTTP 502 retains the exact failed snapshot and ATT facts after one submission", async () => { const ctx = context(); const result = await observeProvisioningRequest(request, ctx); assert.deepEqual(ctx.calls.map(([kind]) => kind), ["send", "read"]); assert.equal(ctx.calls[0][1], request); assert.equal(result.operation.operation_id, "op-one"); assert.equal(result.operation.error.ble_att_error_name, "INVALID_PDU"); assert.equal(result.state.operations[0], result.operation); assert.equal(result.transportError.status, 502); }); test("an existing failed or successful intent is never resubmitted", async () => { for (const status of ["failed", "succeeded"]) { const ctx = context({ initialState: snapshot(status) }); const result = await observeProvisioningRequest(request, ctx); assert.equal(result.operation.status, status); assert.equal(ctx.calls.length, 0); } }); test("lost HTTP response can observe journal success without another command", async () => { const ctx = context({ readState: async () => snapshot("succeeded") }); const result = await observeProvisioningRequest(request, ctx); assert.equal(result.operation.status, "succeeded"); assert.equal(ctx.calls.filter(([kind]) => kind === "send").length, 1); }); test("an admitted pending intent is followed only by bounded local state reads", async () => { let now = 0; const ctx = context({ initialState: snapshot("running"), settlementOptions: { now: () => now, wait: async (ms) => { now += ms; } }, }); const result = await observeProvisioningRequest(request, ctx); assert.equal(result.operation.status, "failed"); assert.deepEqual(ctx.calls.map(([kind]) => kind), ["read"]); }); test("newer WebSocket failure outranks a stale running REST result", async () => { const newer = snapshot("failed", 7); const ctx = context({ send: async () => snapshot("running", 5), currentState: () => newer, }); const result = await observeProvisioningRequest(request, ctx); assert.equal(result.state, newer); assert.equal(result.operation.status, "failed"); assert.equal(ctx.calls.length, 0); }); test("superseding an intent after dispatch stops continuation without replay", async () => { let active = true; const ctx = context({ send: async () => { active = false; throw new ApiError("lost", 502); }, assertCurrent: () => { if (!active) throw new Error("superseded"); }, }); await assert.rejects(observeProvisioningRequest(request, ctx), /superseded/); assert.equal(ctx.calls.length, 0); }); test("an unrelated journal row cannot confirm the current command", async () => { const unrelated = snapshot("succeeded"); unrelated.operations[0].idempotency_key = "another-intent"; const ctx = context({ readState: async () => unrelated }); const result = await observeProvisioningRequest(request, ctx); assert.equal(result.operation, null); assert.equal(result.transportError.status, 502); assert.equal(ctx.calls.length, 1); });