const assert = require("node:assert/strict"); const { test } = require("node:test"); const { loadBackground, response } = require("./support/characterization.cjs"); const type = "opportunitiesExtension.requestInternalServiceRequest"; test("preparation reuses an existing unexpired cookie pair without navigation or API calls", async () => { const domain = "comcipapic-oalprod.integration.ocp.oraclecloud.com"; const h = loadBackground({ fetch: async () => assert.fail("No API calls during preparation"), cookies: () => [1, 2].map(part => ({ name: `ORA_OCIS_CG_SESSION_idcs-existing_${domain}_${part}`, value: `secret-${part}`, domain })) }); const result = await h.dispatch({ type: "opportunitiesExtension.prepareSrSession" }); assert.equal(result.ok, true); assert.equal(h.tabs.length, 0); assert.equal(h.removedTabs.length, 0); }); test("preparation closes immediately on the second cookie event even while getAll is pending", { timeout: 2000 }, async () => { const fs = require("node:fs"), vm = require("node:vm"), path = require("node:path"); const factory = vm.runInNewContext(`${fs.readFileSync(path.join(__dirname, "../src/services/fusion/sr-details.js"), "utf8")}\ncreateFusionSrDetails`); const listeners = new Set(); let reads = 0, closed = 0; const domain = "comcipapic-oalprod.integration.ocp.oraclecloud.com"; const cookie = part => ({ name: `ORA_OCIS_CG_SESSION_idcs-new_${domain}_${part}`, value: `secret-${part}`, domain, storeId: "store" }); const emit = change => { for (const listener of listeners) listener(change); }; const api = factory({ fetchJson: async () => assert.fail("No API calls during preparation"), cookieChanges: { addListener: fn => listeners.add(fn), removeListener: fn => listeners.delete(fn) }, cookiesGetAll: () => ++reads === 1 ? Promise.resolve([]) : new Promise(() => {}), tabsCreate: async () => { setImmediate(() => { emit({ cookie: cookie(1) }); emit({ cookie: { ...cookie(2), storeId: "other" } }); assert.equal(closed, 0); emit({ cookie: cookie(2), removed: true }); assert.equal(closed, 0); emit({ cookie: cookie(2) }); }); return { id: 7 }; }, tabsRemove: async id => { assert.equal(id, 7); closed += 1; }, supportsFirefoxCookieStoreTabs: () => false, wait: () => new Promise(() => {}) }); assert.equal((await api.prepareSession({ tab: { cookieStoreId: "store" } })).ok, true); assert.equal(closed, 1); assert.equal(listeners.size, 0); }); test("explicit preparation opens SeaaS initiation and observes cookies without any API requests", async () => { let calls = 0; let reads = 0; const domain = "comcipapic-oalprod.integration.ocp.oraclecloud.com"; const pair = [1, 2].map(part => ({ name: `ORA_OCIS_CG_SESSION_idcs-new_${domain}_${part}`, value: `secret-${part}`, domain })); const h = loadBackground({ fetch: async () => { calls += 1; assert.fail("Opening the main modal must not trigger any session-dependent API request"); }, cookies: () => { reads += 1; if (reads === 1) return []; assert.equal(h.tabs.length, 1); if (reads === 2) return pair.slice(0, 1); if (reads === 3) return pair.map(cookie => ({ ...cookie, expirationDate: 1 })); return pair; } }); const result = await h.dispatch({ type: "opportunitiesExtension.prepareSrSession" }); assert.equal(result.ok, true); assert.equal(calls, 0); assert.equal(reads, 4); assert.deepEqual(result.debugRequests, []); assert.ok(!JSON.stringify(result).includes("secret")); assert.equal(h.tabs[0].active, false); assert.equal(h.tabs[0].url, "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live/webApps/external/"); assert.deepEqual(h.removedTabs, [91]); }); test("proactive preparation times out without issuing lookup probes", async () => { let calls = 0; const h = loadBackground({ messageTimeout: 10000, fetch: async () => { calls += 1; assert.fail("No probes allowed"); } }); const result = await h.dispatch({ type: "opportunitiesExtension.prepareSrSession" }); assert.equal(result.ok, false); assert.equal(calls, 0); assert.match(result.error, /session could not be established/); assert.deepEqual(h.removedTabs, [91]); }); test("cookie change wakes recovery without waiting for a polling timer and removes its listener", { timeout: 2000 }, async () => { const fs = require("node:fs"); const vm = require("node:vm"); const path = require("node:path"); const factory = vm.runInNewContext(`${fs.readFileSync(path.join(__dirname, "../src/services/fusion/sr-details.js"), "utf8")}\ncreateFusionSrDetails`); const listeners = new Set(); let ready = false; let calls = 0; let closed = 0; const domain = "comcipapic-oalprod.integration.ocp.oraclecloud.com"; const cookies = [1, 2].map(part => ({ name: `ORA_OCIS_CG_SESSION_idcs-new_${domain}_${part}`, value: `secret-${part}`, domain, storeId: "store" })); const api = factory({ cookieChanges: { addListener: fn => listeners.add(fn), removeListener: fn => listeners.delete(fn) }, cookiesGetAll: async () => ready ? cookies : [], tabsCreate: async () => { setImmediate(() => { ready = true; for (const listener of listeners) listener({ cookie: cookies[1] }); }); return { id: 7 }; }, tabsRemove: async () => { closed += 1; }, supportsFirefoxCookieStoreTabs: () => false, wait: () => new Promise(() => {}) }); const result = await api.requestLookupWithSession(async () => { calls += 1; if (!ready) { const error = new Error("Unauthorized"); error.httpStatus = 401; throw error; } return { ok: true, items: [] }; }, {}, { tab: { cookieStoreId: "store" } }); assert.equal(result.ok, true); assert.equal(calls, 2); assert.equal(closed, 1); assert.equal(listeners.size, 0); }); test("renewed matching cookie fragments trigger an early retry without leaking session values", async () => { let reads = 0; let calls = 0; const domain = "comcipapic-oalprod.integration.ocp.oraclecloud.com"; const cookie = (id, part, value) => ({ name: `ORA_OCIS_CG_SESSION_idcs-${id}_${domain}_${part}`, value, domain, path: "/", session: true }); const h = loadBackground({ cookies: () => { reads += 1; if (reads < 3) return [cookie("old", 1, "old-secret-1"), cookie("old", 2, "old-secret-2")]; if (reads === 3) return [cookie("new", 1, "new-secret-1"), cookie("other", 2, "wrong-pair")]; return [cookie("new", 1, "new-secret-1"), cookie("new", 2, "new-secret-2")]; }, fetch: async (_, options) => { calls += 1; assert.equal(options.credentials, "include"); assert.equal(options.headers.Cookie, undefined); if (calls === 1) return response({}, 401); assert.equal(reads, 4, "retry immediately when both renewed parts match, not on a partial pair"); return response({ items: [] }); } }); const result = await h.dispatch({ type: "opportunitiesExtension.requestSrLookupLanguage" }); assert.equal(result.ok, true); assert.equal(calls, 2); assert.ok(!JSON.stringify(result).includes("secret")); assert.ok(h.cookieQueries.every(query => query.domain === domain && query.storeId === "test-store")); assert.deepEqual(h.removedTabs, [91]); }); for (const family of ["chrome", "firefox"]) { test(`${family}: simultaneous lookup 401s share an inactive session tab and close it after successful retries`, async () => { const counts = new Map(); const h = loadBackground({ family, fetch: async url => { const count = (counts.get(url) || 0) + 1; counts.set(url, count); return count < 3 ? response({}, 401) : response({ items: [] }); } }); const results = await Promise.all(["PrimaryPillar", "Language", "TechPlatform", "OpportunityBusiness"].map(name => h.dispatch({ type: `opportunitiesExtension.requestSrLookup${name}`, emailAddress: "test@example.invalid" }))); assert.ok(results.every(result => result.ok)); assert.ok(results.every(result => result.debugRequests.length === 3)); assert.equal(h.tabs.length, 1); assert.equal(h.tabs[0].active, false); assert.equal(h.tabs[0].windowId, 3); assert.equal(h.tabs[0].url, "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_initiation/live/webApps/external/"); assert.equal(h.tabs[0].cookieStoreId, family === "firefox" ? "test-store" : undefined); assert.deepEqual(h.removedTabs, [91]); }); } test("lookup authentication timeout closes the temporary tab and returns a clear error", async () => { const h = loadBackground({ messageTimeout: 10000, fetch: async () => response({}, 401) }); const result = await h.dispatch({ type: "opportunitiesExtension.requestSrLookupLanguage" }); assert.equal(result.ok, false); assert.match(result.error, /session could not be established/); assert.equal(h.tabs.length, 1); assert.deepEqual(h.removedTabs, [91]); }); test("SR language, platform and services use fixed Session endpoints and dynamic email", async () => { const calls = []; const h = loadBackground({ fetch: async (url, options) => { calls.push({ url, options }); return response({ items: url.includes("/services?") ? [{ Id: 123, RecordName: "Consumption", Abstract_c: "Service summary" }] : [{ code: "CODE", name: "Label", enabledFlag: "Y", displaySequence: 1 }] }); } }); for (const [name, lookup] of [["requestSrLookupLanguage", "SENGG_LANGUAGE"], ["requestSrLookupTechPlatform", "SENGG_TECH_PLATFORM"]]) { const result = await h.dispatch({ type: `opportunitiesExtension.${name}` }); assert.deepEqual(result.items, [{ code: "CODE", name: "Label" }]); assert.equal(new URL(calls.at(-1).url).searchParams.get("lookupType"), lookup); assert.equal(result.debugRequests[0].name, name); } const result = await h.dispatch({ type: "opportunitiesExtension.requestSrLookupOpportunityBusiness", emailAddress: "user+test@example.invalid" }); assert.deepEqual(result.items, [{ Id: "123", RecordName: "Consumption", Abstract_c: "Service summary" }]); const url = new URL(calls.at(-1).url); assert.equal(url.searchParams.get("emailAddress"), "user+test@example.invalid"); assert.equal(url.searchParams.get("salesObject"), "OPPORTUNITY"); assert.equal(url.searchParams.get("serviceType"), "BUSINESS"); assert.ok(calls.every(call => call.options.headers.Authorization === "Session" && call.options.method === "GET")); assert.equal((await h.dispatch({ type: "opportunitiesExtension.requestSrLookupOpportunityBusiness" })).ok, false); assert.equal(calls.length, 3); }); test("Primary pillar lookup uses Session, orders enabled name/code options and rejects invalid data", async () => { const calls = []; const h = loadBackground({ fetch: async (url, options) => { calls.push({ url, options }); return response({ items: [ { code: "B", name: "Second", displaySequence: 20, enabledFlag: "Y" }, { code: "N", name: "Disabled", displaySequence: 1, enabledFlag: "N" }, { code: "A", name: "First", displaySequence: 10, enabledFlag: "Y" } ] }); } }); const result = await h.dispatch({ type: "opportunitiesExtension.requestSrLookupPrimaryPillar" }); assert.equal(result.ok, true); assert.deepEqual(result.items, [{ code: "A", name: "First" }, { code: "B", name: "Second" }]); assert.ok(calls[0].url.includes("SeaaS_initiation/live;profile=PROD")); assert.ok(calls[0].url.endsWith("lookupType=SENGG_PRIMARY_PILLAR&type=STANDARD")); assert.equal(calls[0].options.headers.Authorization, "Session"); assert.equal(calls[0].options.method, "GET"); for (const fetch of [async () => response({ items: [{}] }), async () => response({}, 401)]) { assert.equal((await loadBackground({ fetch, messageTimeout: 10000 }).dispatch({ type: "opportunitiesExtension.requestSrLookupPrimaryPillar" })).ok, false); } }); for (const family of ["chrome", "firefox"]) { test(`${family}: 401 is returned to the caller without opening tabs`, async () => { let count = 0; const h = loadBackground({ family, fetch: async () => ++count < 3 ? response({}, 401) : response({ items: [] }) }); const result = await h.dispatch({ type, srId: "123" }); assert.equal(result.ok, false); assert.equal(result.httpStatus, 401); assert.equal(count, 1); assert.equal(h.tabs.length, 0); assert.deepEqual(h.removedTabs, []); assert.deepEqual(result.debugRequests.map(entry => entry.httpStatus), [401]); }); } test("concurrent 401 responses do not cause background tab recovery", async () => { let calls = 0; const h = loadBackground({ fetch: async url => { if (++calls <= 2) return response({}, 401); const id = new URL(url).searchParams.get("q"); return response({ items: [{ ServiceRequest_SRToInternalSR_Tgt: [{ Title: id }] }] }); } }); const results = await Promise.all([h.dispatch({ type, srId: "1" }), h.dispatch({ type, srId: "2" })]); assert.equal(h.tabs.length, 0); assert.deepEqual(h.removedTabs, []); assert.ok(results.every(result => result.httpStatus === 401)); }); test("background never creates recovery tabs after an error", async () => { for (const status of [401, 500]) { let count = 0; const h = loadBackground({ fetch: async () => response({}, ++count === 1 ? 401 : status) }); const result = await h.dispatch({ type, srId: "1" }); assert.equal(result.ok, false); assert.equal(count, 1); assert.deepEqual(h.removedTabs, []); } const h = loadBackground({ fetch: async () => response({}, 403) }); assert.equal((await h.dispatch({ type, srId: "1" })).ok, false); assert.equal(h.tabs.length, 0); }); for (const family of ["chrome", "firefox"]) { test(`${family}: SR detail GET uses exact scope and Session authentication`, async () => { const calls = []; const children = [{ SrId: 123, SrNumber: "SR123", Title: "Synthetic" }]; const h = loadBackground({ family, fetch: async (url, options) => { calls.push({ url, options }); return response({ items: [{ ServiceRequest_SRToInternalSR_Tgt: children }] }); } }); const result = await h.dispatch({ type, srId: "987", token: "secret-test" }); assert.equal(result.ok, true); assert.deepEqual(result.items, children); const url = new URL(calls[0].url); assert.equal(url.hostname, "comcipapic-oalprod.integration.ocp.oraclecloud.com"); assert.equal(url.searchParams.get("q"), "SrId=987"); assert.equal(url.searchParams.get("onlyData"), "true"); assert.ok(url.searchParams.get("fields").includes("ServiceRequest_SRToInternalSR_Tgt:ReportedHours_c")); assert.equal(calls[0].options.method, "GET"); assert.equal(calls[0].options.headers.Authorization, "Session"); assert.equal(calls[0].options.credentials, "include"); assert.equal(result.debugRequests[0].requestHeaders.Authorization, "Session"); assert.ok(!JSON.stringify(result).includes("secret-test")); assert.equal(result.debugRequests[0].name, "requestInternalServiceRequest"); }); } test("SR details distinguish empty collections from errors and validate inputs", async () => { for (const body of [{ items: [] }, { items: [{}] }, { items: [{ ServiceRequest_SRToInternalSR_Tgt: [] }] }]) { const h = loadBackground({ fetch: async () => response(body) }); assert.deepEqual((await h.dispatch({ type, srId: "1" })).items, []); } for (const fetch of [async () => response({}, 403), async () => response({}), async () => response({ items: [{ ServiceRequest_SRToInternalSR_Tgt: {} }] })]) { const h = loadBackground({ fetch }); assert.equal((await h.dispatch({ type, srId: "1", token: "test" })).ok, false); } const h = loadBackground({ fetch: () => assert.fail("Invalid input must not fetch") }); assert.equal((await h.dispatch({ type, srId: "1 OR 1=1", token: "test" })).ok, false); assert.equal((await h.dispatch({ type })).ok, false); });