Coming back to the app after a few minutes in the background replaced the Frasier series page with "Failed to load item". Android cuts a backgrounded app's network, the app declares the server offline, and on resume the reconnect and offline-filter reloads refresh the page. Every backend call in that refresh answered from the cache, yet something in it threw, and: - any throw replaced the whole page with an error, although it was a refresh of content already on screen; - no later successful reload of the same item cleared that error, so it stayed until the viewer navigated away; - the catch logged nothing and turned every non-Error value (backend errors arrive as plain strings) into the generic text, so neither logcat nor the screen said what failed. A failed refresh now keeps the page and logs the value actually thrown; every successful load clears the error; failing to open an item still shows one, with the backend's own message. The decision lives in detailLoadError.ts so it is unit-tested. The throw itself is not yet identified - the next occurrence names itself in the log. DR-297, UT-267.
44 lines
1.7 KiB
TypeScript
44 lines
1.7 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { errorAfterLoad, loadErrorMessage } from "./detailLoadError";
|
|
|
|
/**
|
|
* TRACES: UR-062 | DR-297 | UT-267
|
|
*
|
|
* Resuming the app after a few minutes in the background replaced a series page
|
|
* that was on screen with "Failed to load item". The resume reload is a refresh
|
|
* of content the cache had already answered, yet any throw in it blanked the
|
|
* page — and no later successful reload of the same item ever cleared it.
|
|
*/
|
|
describe("errorAfterLoad", () => {
|
|
it("clears the error when a load succeeds", () => {
|
|
expect(errorAfterLoad({ ok: true }, { refreshing: true })).toBeNull();
|
|
expect(errorAfterLoad({ ok: true }, { refreshing: false })).toBeNull();
|
|
});
|
|
|
|
it("keeps a page on screen when a refresh of it fails", () => {
|
|
expect(errorAfterLoad({ ok: false, error: "boom" }, { refreshing: true })).toBeNull();
|
|
});
|
|
|
|
it("reports a failure to open an item that is not on screen yet", () => {
|
|
expect(errorAfterLoad({ ok: false, error: new Error("Offline") }, { refreshing: false })).toBe(
|
|
"Offline",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("loadErrorMessage", () => {
|
|
it("shows the text of a backend error, which arrives as a plain string", () => {
|
|
expect(loadErrorMessage("Repository not found")).toBe("Repository not found");
|
|
});
|
|
|
|
it("shows an Error's message", () => {
|
|
expect(loadErrorMessage(new TypeError("x is undefined"))).toBe("x is undefined");
|
|
});
|
|
|
|
it("falls back to a generic message for anything else", () => {
|
|
expect(loadErrorMessage(undefined)).toBe("Failed to load item");
|
|
expect(loadErrorMessage({})).toBe("Failed to load item");
|
|
expect(loadErrorMessage("")).toBe("Failed to load item");
|
|
});
|
|
});
|