Fixed the SPA authentication flow
This commit is contained in:
87
tests/spaSessionReload.test.cjs
Normal file
87
tests/spaSessionReload.test.cjs
Normal file
@@ -0,0 +1,87 @@
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user