connecton satus mobil profile
This commit is contained in:
@@ -133,6 +133,22 @@ try {
|
||||
})()`);
|
||||
console.log("PASS decoder diagnostics update without resetting settings draft");
|
||||
await runOverlaySmoke({ evaluate });
|
||||
const mobileState = await savedState();
|
||||
const mobileToken = "browser-mobile-profile-token-1234567890";
|
||||
mobileState.training ||= {};
|
||||
mobileState.training.shares = [{ driverId: mobileState.drivers[0].id, token: mobileToken, enabled: true }];
|
||||
const mobileSave = await fetch(base + "/api/state", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(mobileState) });
|
||||
assert.ok(mobileSave.ok);
|
||||
await send("Page.navigate", { url: base + "/public-training/" + mobileToken + "?lang=sv" });
|
||||
await waitFor(async () => await evaluate('document.getElementById("publicTrainingConnection")?.dataset.state === "current"'), "mobile profile loaded");
|
||||
await evaluate('window.mobileContentBeforeFailure = document.getElementById("publicTrainingRoot").firstElementChild');
|
||||
await send("Network.emulateNetworkConditions", { offline: true, latency: 0, downloadThroughput: -1, uploadThroughput: -1 });
|
||||
await waitFor(async () => await evaluate('document.getElementById("publicTrainingConnection")?.dataset.state === "failed"'), "mobile connection warning");
|
||||
assert.ok(await evaluate('window.mobileContentBeforeFailure === document.getElementById("publicTrainingRoot").firstElementChild'));
|
||||
await send("Network.emulateNetworkConditions", { offline: false, latency: 0, downloadThroughput: -1, uploadThroughput: -1 });
|
||||
await evaluate('document.getElementById("publicTrainingRetry").click()');
|
||||
await waitFor(async () => await evaluate('document.getElementById("publicTrainingConnection")?.dataset.state === "current"'), "mobile retry recovered");
|
||||
console.log("PASS mobile offline status preserves profile nodes and retry recovers");
|
||||
assert.deepEqual(errors, []);
|
||||
console.log("PASS offline save failure, local draft retention, retry and confirmed saved status");
|
||||
} finally {
|
||||
|
||||
@@ -13,8 +13,8 @@ function profileHarness() {
|
||||
set innerHTML(value) { ui.html = value; },
|
||||
};
|
||||
const context = vm.createContext({
|
||||
URL, URLSearchParams,
|
||||
document: { getElementById: () => root, activeElement: { matches: () => true } },
|
||||
URL, URLSearchParams, AbortController, setTimeout, clearTimeout,
|
||||
document: { getElementById: (id) => id === "publicTrainingRoot" ? root : null, activeElement: { matches: () => true } },
|
||||
window: { location: { pathname: "/public-training/test", search: "?lang=sv", origin: "http://localhost" } },
|
||||
fetch: async () => { ui.requests++; return { ok: true, json: async () => ({}) }; },
|
||||
onRender: () => { ui.renders++; },
|
||||
@@ -60,3 +60,68 @@ test("an initial mobile load failure still displays the error", async () => {
|
||||
await refresh();
|
||||
assert.match(ui.html, /public-training-error/);
|
||||
});
|
||||
|
||||
test("mobile status detects stale data and recovery after failure", async () => {
|
||||
const { context, refresh } = profileHarness();
|
||||
await refresh();
|
||||
assert.equal(vm.runInContext('getProfileConnectionState()', context), "current");
|
||||
assert.equal(vm.runInContext('getProfileConnectionState(profileConnection.lastSuccessAt + 30000)', context), "stale");
|
||||
context.fetch = async () => { throw new Error("offline"); };
|
||||
await refresh();
|
||||
assert.equal(vm.runInContext('getProfileConnectionState()', context), "failed");
|
||||
context.fetch = async () => ({ ok: true, json: async () => ({}) });
|
||||
await refresh();
|
||||
assert.equal(vm.runInContext('getProfileConnectionState()', context), "current");
|
||||
});
|
||||
|
||||
test("mobile requests cannot overlap and a skipped edit never refreshes the timestamp", async () => {
|
||||
const { context, ui, refresh } = profileHarness();
|
||||
let resolve;
|
||||
context.fetch = () => { ui.requests++; return new Promise(done => { resolve = done; }); };
|
||||
const pending = refresh();
|
||||
await refresh();
|
||||
assert.equal(ui.requests, 1);
|
||||
ui.editing = true;
|
||||
resolve({ ok: true, json: async () => ({}) });
|
||||
await pending;
|
||||
assert.equal(vm.runInContext('profileConnection.lastSuccessAt', context), null);
|
||||
assert.equal(vm.runInContext('profileConnection.loading', context), false);
|
||||
});
|
||||
|
||||
test("mobile status updates its own nodes without replacing loaded profile", async () => {
|
||||
const { context, ui, refresh } = profileHarness();
|
||||
const nodes = {
|
||||
publicTrainingConnection: { dataset: {} },
|
||||
publicTrainingConnectionText: { textContent: "" },
|
||||
publicTrainingRetry: {},
|
||||
};
|
||||
context.document.getElementById = id => nodes[id] || null;
|
||||
await refresh();
|
||||
assert.equal(nodes.publicTrainingConnection.dataset.state, "current");
|
||||
assert.equal(nodes.publicTrainingRetry.hidden, true);
|
||||
context.fetch = async () => { throw new Error("offline"); };
|
||||
await refresh();
|
||||
assert.equal(nodes.publicTrainingConnection.dataset.state, "failed");
|
||||
assert.equal(nodes.publicTrainingRetry.hidden, false);
|
||||
assert.equal(nodes.publicTrainingRetry.disabled, false);
|
||||
assert.equal(ui.html, "existing profile");
|
||||
assert.equal(ui.renders, 1);
|
||||
});
|
||||
|
||||
test("a timed-out mobile fetch releases its lock and allows retry", async () => {
|
||||
const { context, refresh } = profileHarness();
|
||||
let expire;
|
||||
context.setTimeout = callback => { expire = callback; return 1; };
|
||||
context.clearTimeout = () => {};
|
||||
context.fetch = (_, { signal }) => new Promise((resolve, reject) => {
|
||||
signal.addEventListener("abort", () => reject(new Error("aborted")));
|
||||
});
|
||||
const pending = refresh();
|
||||
expire();
|
||||
await pending;
|
||||
assert.equal(vm.runInContext('profileConnection.loading', context), false);
|
||||
assert.equal(vm.runInContext('getProfileConnectionState()', context), "failed");
|
||||
context.fetch = async () => ({ ok: true, json: async () => ({}) });
|
||||
await refresh();
|
||||
assert.equal(vm.runInContext('getProfileConnectionState()', context), "current");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user