Files
opportunities-extension/tests/spaSessionReload.test.cjs

88 lines
4.2 KiB
JavaScript

const assert = require("node:assert/strict");
const { test } = require("node:test");
const { loadBackground, response } = require("./support/characterization.cjs");
const currentUser = "opportunitiesExtension.requestCurrentUser";
const consumer = "opportunitiesExtension.requestConsumerTokenService";
const identity = { user: { id: "test@example.invalid", name: "Test User", roles: [] }, token: "synthetic-token" };
const tokens = [
{ tokenService: "ACCP-TS", uiaasHeader: { value: "synthetic-account" } },
{ tokenService: "OCICONS-TS", uiaasHeader: { value: "synthetic-consumption" } }
];
const html = () => new Response("<html>Sign in</html>");
function navigation(app, overrides = {}) {
const observer = app.responseHeaderListeners.find(item => item.filter.types.includes("main_frame"));
assert.ok(observer);
observer.listener({ tabId: 91, type: "main_frame", statusCode: 401,
url: "https://spa.oracle.com/cloudgate/v1/oauth2/callback?code=do-not-replay", ...overrides });
}
for (const family of ["chrome", "firefox"]) {
for (const type of [currentUser, consumer]) {
test(`${family}: ${type} restarts a rejected callback at SPA home in the same inactive tab`, async () => {
let calls = 0;
const app = loadBackground({ family, fetch: async () => {
calls++;
if (calls === 1) return html();
if (calls === 2) { navigation(app); return html(); }
assert.deepEqual(app.updatedTabs, [{ id: 91, details: { url: "https://spa.oracle.com/", active: false } }]);
return response(type === currentUser ? identity : tokens);
} });
const result = await app.dispatch({ type });
assert.equal(result.ok, true);
assert.equal(app.tabs.length, 1);
assert.deepEqual(app.removedTabs, [91]);
assert.equal(result.debugRequests[1].metadata.sessionBootstrapReloadState, "restarted-at-spa-home");
assert.match(result.debugRequests[1].metadata.sessionBootstrapReloadReason, /401/);
assert.doesNotMatch(JSON.stringify(result.debugRequests), /do-not-replay/);
assert.equal(app.responseHeaderListeners.filter(item => item.filter.types.includes("main_frame")).length, 0);
});
}
test(`${family}: failed navigation is recorded and retried after the cooldown without opening another tab`, async () => {
let calls = 0;
const app = loadBackground({ family, updateTabError: true, fetch: async () => {
calls++;
if (calls === 2) navigation(app, { statusCode: 403 });
return calls < 5 ? html() : response(identity);
} });
const result = await app.dispatch({ type: currentUser });
assert.equal(result.ok, false);
assert.equal(calls, 2, "failed navigation must never release another identity probe");
assert.equal(app.updatedTabs.length, 3, "at most three restart attempts per session wait");
assert.equal(app.tabs.length, 1);
assert.match(result.debugRequests[1].metadata.sessionBootstrapReloadState, /restart-failed/);
assert.equal(result.debugRequests[1].metadata.sessionBootstrapReloadCount, "3");
assert.deepEqual(app.removedTabs, [91]);
});
}
test("only errors in the owned SPA document trigger navigation, never other tabs, frames or hosts", async () => {
let calls = 0;
const app = loadBackground({ fetch: async () => {
if (++calls === 1) return html();
if (calls === 2) {
navigation(app, { tabId: 7 });
navigation(app, { type: "sub_frame" });
navigation(app, { type: "xmlhttprequest" });
navigation(app, { url: "https://other.example.invalid/callback" });
navigation(app, { statusCode: 302 });
assert.equal(app.updatedTabs.length, 0);
}
return response(identity);
} });
assert.equal((await app.dispatch({ type: currentUser })).ok, true);
});
test("a successful SPA navigation clears an earlier failure before it can be restarted", async () => {
let calls = 0;
const app = loadBackground({ fetch: async () => {
if (++calls === 1) return html();
if (calls === 2) {
navigation(app);
navigation(app, { url: "https://spa.oracle.com/", statusCode: 200 });
assert.equal(app.updatedTabs.length, 0);
}
return response(identity);
} });
assert.equal((await app.dispatch({ type: currentUser })).ok, true);
});