const test = require("node:test"); const assert = require("node:assert/strict"); const fs = require("node:fs"); const path = require("node:path"); const vm = require("node:vm"); const { root, plain, response, loadContent, loadBackground } = require("./support/characterization.cjs"); const { composeScript } = require("./support/application.cjs"); const PREFIX = "opportunitiesExtension."; const FILTER_KEY = "opportunities-extension-filter-preferences"; const TYPE_KEY = "opportunities-extension-opportunity-type-preferences"; const CACHE_KEY = "opportunitiesExtension.opptyProductsCache.v1"; const DAY = 86400000; const range = { startCloseDate: "2026-06-01T00:00:00.000Z", endCloseDate: "2026-08-31T00:00:00.000Z" }; const drain = () => new Promise(resolve => setImmediate(resolve)); const productRequest = (requestId, optyNumbers = ["SYNTH-1"]) => ({ type: PREFIX + "requestOpptyProducts", requestId, optyNumbers, accessToken: "synthetic-products-token" }); test("content bootstrap ignores other origins and preserves the existing tile/listener on reinjection", () => { const source = composeScript("content"); const script = new vm.Script(source); assert.doesNotThrow(() => script.runInNewContext({ window: { location: { hostname: "unrelated.example", pathname: "/" } }, document: { getElementById() { assert.fail("DOM touched on unrelated origin"); } } })); let listeners = 0; const context = vm.createContext({ window: { location: { hostname: "eeho.fa.us2.oraclecloud.com", pathname: "/fscmUI/faces/FuseWelcome" } }, document: { getElementById: () => ({}) }, chrome: { runtime: { onMessage: { addListener() { listeners++; } } } }, MutationObserver: class { constructor() { assert.fail("Observer unnecessary when tile already exists"); } } }); script.runInContext(context); script.runInContext(context); assert.equal(listeners, 1); }); test("distribution contracts: manifests, execution boundaries and deterministic composition", () => { const base = { manifest_version: 3, name: "Opportunities Extension", description: "Adiciona um atalho de Opportunities Extension nas paginas Oracle Fusion permitidas.", version: "1.0.1", permissions: ["cookies", "storage"], host_permissions: ["https://eeho.fa.us2.oraclecloud.com/*", "https://spa.oracle.com/*"], content_scripts: [{ matches: ["https://eeho.fa.us2.oraclecloud.com/hcmUI/faces/FuseWelcome*", "https://eeho.fa.us2.oraclecloud.com/fscmUI/faces/FuseWelcome*"], js: ["content.js"], all_frames: true, run_at: "document_idle" }] }; for (const target of ["chromium", "firefox"]) { const expected = target === "chromium" ? { ...base, background: { service_worker: "background.js" } } : { ...base, background: { scripts: ["background.js"] }, browser_specific_settings: { gecko: { id: "opportunities-extension@local.dev" } } }; assert.deepEqual(JSON.parse(fs.readFileSync(path.join(root, "dist", target, "manifest.json"))), expected); for (const file of ["content.js", "background.js"]) { const output = fs.readFileSync(path.join(root, "dist", target, file), "utf8"); assert.equal(output, composeScript(file.replace(".js", ""))); assert.doesNotThrow(() => new vm.Script(output, { filename: `${target}/${file}` })); } } }); test("fiscal dates preserve quarter/year boundaries, leap year and unsupported renewals", () => { const h = loadContent(); const cases = [ ["Current Quarter", [2026, 5, 1], "2026-06-01", "2026-08-31"], ["Current Quarter", [2026, 7, 31], "2026-06-01", "2026-08-31"], ["Current Quarter", [2026, 8, 1], "2026-09-01", "2026-11-30"], ["Current Quarter", [2028, 1, 29], "2027-12-01", "2028-02-29"], ["Next Quarter", [2026, 10, 30], "2026-12-01", "2027-02-28"], ["Previous Quarter", [2026, 7, 24], "2026-03-01", "2026-05-31"], ["Current Fiscal Year", [2026, 4, 31], "2025-06-01", "2026-05-31"], ["Current Fiscal Year", [2026, 5, 1], "2026-06-01", "2027-05-31"], ["Current Fiscal Year", [2027, 0, 1], "2026-06-01", "2027-05-31"], ["4 Rolling Quarters (CQ + 3)", [2026, 8, 16], "2026-09-01", "2027-08-31"] ]; for (const [period, date, start, end] of cases) { assert.deepEqual(plain(h.getFiscalPeriodRange(period, new Date(...date))), { startCloseDate: start + "T00:00:00.000Z", endCloseDate: end + "T00:00:00.000Z" }); } assert.equal(h.getFiscalPeriodRange("RENEWALS (Current + Past Due)", new Date()), null); }); test("opportunity query preserves fields, record-set OR, date AND, and pagination payload", () => { const h = loadContent(); const types = ["ORA_MYSALESTEAMOPTIES", "ORA_MYASSGTERROPTIES", "ORA_CREDITRECEIVER_ISME"]; h.setTypes(types); const fields = ["Name", "OptyNumber", "PrimaryRevenue.WinProb", "CustomerAccount", "PrimaryRevenue.RevnAmount", "EffectiveDate", "StatusCode", "DealRisk_c", "Owner", "ForecastGroup_c", "LastUpdateDate", "PrimaryRevenue.RevnAmountCurcyCode", "OptyId"]; assert.deepEqual(plain(h.createOpportunitiesQueryPayload(range, 15)), { aggregationResults: false, applications: ["ORACLE-ISS-APP"], onlyData: true, entity: "Opportunity", q: { op: "$and", criteria: [ { op: "$or", criteria: types.map(value => ({ op: "$eq", attribute: "RecordSet", value })) }, { op: "$wi", attribute: "EffectiveDate", value1: range.startCloseDate, value2: range.endCloseDate, dynamicDate: false } ] }, keywords: null, keywordsFields: fields, fields: [...fields, "CustomerAccount.PartyUniqueName", "CustomerAccount.PartyId", "CustomerAccount.PartyNumber"], sort: [], language: "en", skipInValidFields: true, skipHiddenFromUIFields: true, copiedFrom: "queries/d5dbcd01-9ff3-40be-9b5b-64744cbf7162", limit: 15, offset: 15 }); }); test("opportunity pagination uses response offsets/count, ignores stale versions and detects stalled pages", async () => { const calls = []; const h = loadContent({ fetch: async (url, options) => { calls.push({ url, options }); return response(calls.length === 1 ? { items: [{ OptyNumber: "S1" }], offset: 0, count: 1, hasMore: true } : { items: [{ OptyNumber: "S2" }], offset: 1, count: 1, hasMore: false }); } }); const items = await h.requestOpportunitiesPage("synthetic-token", "Current Quarter", range, 0, [], 0, 1); assert.deepEqual(plain(items), [{ OptyNumber: "S1" }, { OptyNumber: "S2" }]); assert.deepEqual(calls.map(call => JSON.parse(call.options.body).offset), [0, 1]); assert.equal(calls[0].url, "https://eeho.fa.us2.oraclecloud.com/crmRestApi/searchResources/11.13.18.05/custom-actions/queries"); assert.deepEqual(plain(calls[0].options.headers), { Accept: "application/json", Authorization: "Bearer synthetic-token", "Content-Type": "application/json", Origin: "https://eeho.fa.us2.oraclecloud.com", Preference: "transient" }); assert.equal(calls[0].options.method, "POST"); assert.equal(calls[0].options.credentials, "include"); h.setVersion(1); assert.equal(await h.requestOpportunitiesPage("unused", "Current Quarter", range, 0, [], 0, 1), null); assert.equal(calls.length, 2); const stalled = loadContent({ fetch: async () => response({ items: [], count: 0, hasMore: true }) }); await assert.rejects(stalled.requestOpportunitiesPage("synthetic", "Current Quarter", range, 0, [], 0, 1), /without additional results/); }); const opportunity = (number, status, amount) => ({ Name: `Synthetic cloud ${number}`, OptyNumber: number, StatusCode: status, ForecastGroup_c: "PIPELINE", CustomerAccount: { PartyId: "customer-1", PartyUniqueName: "Synthetic Customer", PartyNumber: "party-1" }, Owner: { PartyId: "owner-1", PersonFirstName: "Test", PersonLastName: "Owner", PartyName: "Long Test Owner Name" }, PrimaryRevenue: { RevnAmount: amount, RevnAmountCurcyCode: "USD", WinProb: 60 }, EffectiveDate: "2026-08-28", LastUpdateDate: "2026-08-28T13:40:00" }); test("filter storage round-trip, WON_PENDING membership, search, sorting and reference resets", () => { const preferences = { period: "Next Quarter", stages: ["PIPELINE"], statuses: ["WON"], customerKeys: ["party:customer-1"], ownerKeys: ["party:owner-1"], customerSearch: "Synthetic", ownerSearch: "Test", tableSearch: "cloud" }; const storage = new Map([[FILTER_KEY, JSON.stringify(preferences)]]); const h = loadContent({ storage }); const select = { value: "Current Quarter" }; h.restoreFilterPreferences(select); assert.equal(select.value, "Next Quarter"); const items = [opportunity("S1", "WON", "100"), opportunity("S2", "WON_PENDING", "20"), opportunity("S3", "OPEN", "5")]; h.setTable(items, "revenue"); assert.deepEqual(plain(h.getSortedOpportunities()).map(item => item.OptyNumber), ["S2", "S1"]); assert.equal(h.getSortedOpportunities()[0].StatusCode, "WON_PENDING"); assert.equal(h.getOwnerName(items[0]), "Test Owner"); assert.equal(h.matchesTableSearch(items[0], "28/08/2026"), true); assert.equal(h.matchesTableSearch(items[0], "test owner"), true); h.saveFilterPreferences(select.value); assert.deepEqual(JSON.parse(storage.get(FILTER_KEY)), preferences); const reopened = loadContent({ storage }); reopened.restoreFilterPreferences({ value: "Current Quarter" }); assert.equal(reopened.filters().tableSearch, "cloud"); reopened.resetCustomerAndOwnerFiltersForPeriod(); const nextItems = [...items, { ...opportunity("S4", "WON", "30"), CustomerAccount: { PartyId: "customer-2", PartyUniqueName: "Another Customer" }, Owner: { PartyId: "owner-2", PartyName: "Another Owner" } }]; reopened.setTable(nextItems); assert.deepEqual(plain(reopened.filters().customerKeys).sort(), ["party:customer-1", "party:customer-2"]); assert.deepEqual(plain(reopened.filters().ownerKeys).sort(), ["party:owner-1", "party:owner-2"]); assert.equal(reopened.filters().tableSearch, "cloud"); assert.equal(reopened.filters().customerSearch, ""); assert.equal(reopened.filters().ownerSearch, ""); }); test("malformed preferences fall back, while theme/type/cache keys retain their schema", () => { const storage = new Map([[FILTER_KEY, "not JSON"], ["opportunities-extension-theme", "dark"], [TYPE_KEY, JSON.stringify({ opportunityTypeValues: ["ORA_MYOPTIES", "UNKNOWN"], opptyProductsCacheHours: 24 })]]); const h = loadContent({ storage }); assert.doesNotThrow(() => h.restoreFilterPreferences({ value: "Current Quarter" })); assert.equal(h.getSavedTheme(), "dark"); assert.deepEqual(plain(h.getSavedOpportunityTypeValues()), ["ORA_MYOPTIES"]); assert.equal(h.getSavedOpptyProductsCacheHours(), 24); assert.equal(h.filters().tableSearch, ""); }); test("tokenrelay missing-cookie recovery and HTTP failure do not change the request contract", async () => { let reads = 0; const calls = []; const h = loadContent({ xsrf: async () => ({ token: ++reads === 1 ? "" : "synthetic-xsrf", cookieName: "XSRF-TOKEN-SYNTHETIC" }), fetch: async (url, options) => { calls.push({ url, options }); return response({ access_token: "synthetic-access" }); } }); assert.equal(await h.requestTokenRelay(), "synthetic-access"); assert.equal(h.refreshes.length, 1); assert.equal(calls.length, 1); assert.equal(calls[0].options.headers["x-xsrf-token"], "synthetic-xsrf"); assert.equal(calls[0].options.method, "GET"); for (const status of [400, 401, 403]) { let attempts = 0; const rejected = loadContent({ xsrf: async () => ({ token: "synthetic-xsrf" }), fetch: async () => { attempts++; return response({}, status); } }); await assert.rejects(rejected.requestTokenRelay(), /failed with status/); assert.equal(attempts, 2); assert.equal(rejected.refreshes.length, 1); } }); for (const family of ["chrome", "firefox"]) { test(`${family}: products paginate, route progress to sender frame and reuse persisted cache after restart`, async () => { const calls = []; const storage = {}; const h = loadBackground({ family, storage, fetch: async (url, options) => { calls.push({ url, options }); const offset = Number(new URL(url).searchParams.get("offset")); return response({ items: [{ RevnNumber: `SYNTH-${offset}` }], count: 1, offset, hasMore: offset === 0 }); } }); const result = await h.dispatch(productRequest("job-1", ["SYNTH-1", "SYNTH-1"])); assert.deepEqual(result, { ok: true, requestId: "job-1", completed: 1, total: 1, failed: 0, cacheHits: 0 }); assert.equal(calls.length, 2); assert.equal(new URL(calls[0].url).pathname, "/crmRestApi/rest/rv:be91c002-2e5d-4ed2-a37e-e0c837bf141f/en/11.13.18.05:9/opportunities/SYNTH-1/child/ChildRevenue"); assert.equal(new URL(calls[0].url).searchParams.get("q"), "(SplitTypeCode!='DETAILCHILDSPLIT') AND (RecurTypeCode!='CHILDRECUR')"); assert.equal(new URL(calls[0].url).searchParams.get("limit"), "15"); assert.equal(new URL(calls[1].url).searchParams.get("offset"), "1"); assert.equal(calls[0].options.headers.Authorization, "Bearer synthetic-products-token"); assert.ok(h.progress.every(event => event.tabId === 7 && event.options.frameId === 2)); assert.equal(h.progress[0].message.type, PREFIX + "opptyProductsProgress"); assert.equal(h.progress[0].message.items.length, 2); assert.equal(h.progress.at(-1).message.state, "complete"); assert.deepEqual(Object.keys(storage[CACHE_KEY]["SYNTH-1"]).sort(), ["fetchedAt", "items"]); const restarted = loadBackground({ family, storage }); assert.equal((await restarted.dispatch(productRequest("job-2"))).cacheHits, 1); h.advance(DAY); await h.dispatch(productRequest("job-3")); assert.equal(calls.length, 4, "default TTL expires at 24 hours"); }); test(`${family}: product queue has four workers, shares in-flight results and reports partial failures`, async () => { const calls = []; const h = loadBackground({ family, fetch: (url) => new Promise(resolve => calls.push({ url, resolve })) }); const first = h.dispatch(productRequest("concurrent-1", ["S1", "S2", "S3", "S4", "S5"])); await drain(); assert.equal(calls.length, 4); const duplicate = h.dispatch(productRequest("concurrent-2", ["S1"])); await drain(); assert.equal(calls.length, 4); calls[0].resolve(response({ items: [{ RevnNumber: "R1" }], hasMore: false })); await drain(); assert.equal(calls.length, 5); calls[1].resolve(response({}, 500)); for (const call of calls.slice(2)) call.resolve(response({ items: [], hasMore: false })); assert.equal((await duplicate).ok, true); const result = await first; assert.equal(result.failed, 1); assert.equal(result.completed, 5); assert.equal(h.progress.filter(event => event.message.requestId === "concurrent-1").at(-1).message.state, "complete-with-errors"); }); test(`${family}: custom product TTL and zero-count pagination failures`, async () => { let calls = 0; const h = loadBackground({ family, fetch: async () => { calls++; return response({ items: [], hasMore: false }); } }); const message = { ...productRequest("custom-ttl"), cacheMaxAgeMs: 1000 }; await h.dispatch(message); h.advance(999); assert.equal((await h.dispatch(message)).cacheHits, 1); assert.equal(calls, 1); h.advance(1); assert.equal((await h.dispatch(message)).cacheHits, 0); assert.equal(calls, 2); const stalled = loadBackground({ family, fetch: async () => response({ items: [], count: 0, hasMore: true }) }); assert.equal((await stalled.dispatch(productRequest("stalled"))).failed, 1); assert.match(stalled.progress[0].message.error, /without additional results/); }); test(`${family}: dynamic XSRF cookie lookup, missing-cookie result and temporary-tab cleanup`, async () => { const cookie = { name: "XSRF-TOKEN-SYNTHETIC", value: "synthetic-xsrf", domain: "eeho.fa.us2.oraclecloud.com", path: "/", storeId: "test-store" }; const h = loadBackground({ family, cookies: () => [cookie] }); const result = await h.dispatch({ type: PREFIX + "getXsrfToken" }); assert.equal(result.ok, true); assert.equal(result.cookieName, cookie.name); assert.equal(result.token, cookie.value); assert.ok(h.cookieQueries.some(query => query.storeId === "test-store")); const missing = loadBackground({ family }); assert.equal((await missing.dispatch({ type: PREFIX + "getXsrfToken" })).token, ""); const refresh = await missing.dispatch({ type: PREFIX + "refreshXsrfCookie" }); assert.equal(refresh.refreshed, false); assert.equal(refresh.durationMs, 15000); assert.deepEqual(missing.removedTabs, [91]); assert.equal(missing.tabs[0].active, false); assert.equal(missing.tabs[0].windowId, 3); assert.equal(missing.tabs[0].cookieStoreId, family === "firefox" ? "test-store" : undefined); let refreshHarness; refreshHarness = loadBackground({ family, cookies: () => refreshHarness.tabs.length ? [cookie] : [] }); assert.equal((await refreshHarness.dispatch({ type: PREFIX + "refreshXsrfCookie" })).refreshed, true); assert.deepEqual(refreshHarness.removedTabs, [91]); }); test(`${family}: SPA token selection, account POST contracts and debug envelope`, async () => { const calls = []; const h = loadBackground({ family, fetch: async (url, options) => { calls.push({ url, options }); if (calls.length === 1) return response([ { tokenService: "UNRELATED", uiaasHeader: { value: "synthetic-unused" } }, { tokenService: "ACCP-TS", uiaasHeader: { value: "synthetic-account" } }, { tokenService: "OCICONS-TS", uiaasHeader: { value: "synthetic-consumption" } } ]); if (calls.length === 2) return response({ items: [{ id: "synthetic/id" }] }); return response({ items: [{ planType: "Synthetic", subPlanNum: "plan-1" }] }); } }); const tokens = await h.dispatch({ type: PREFIX + "requestConsumerTokenService" }); const plans = await h.dispatch({ type: PREFIX + "requestAccountPlans", partyNumber: "synthetic-party", authorizations: tokens.authorizations }); assert.equal(plans.ok, true); assert.equal(plans.accountPlanId, "synthetic/id"); assert.deepEqual(plans.plans, [{ planType: "Synthetic", subPlanNum: "plan-1" }]); assert.equal(calls[1].url, "https://spa.oracle.com/oalcrm/web/api/provider-proxy/g2m-account/service/accountsummary"); assert.deepEqual(JSON.parse(calls[1].options.body), [{ key: "regId", value: "synthetic-party" }]); assert.equal(calls[1].options.headers["account-ti-authorization"], "synthetic-account"); assert.equal(calls[2].options.headers["g2m-authorization"], "synthetic-consumption"); assert.equal(calls[2].url, "https://spa.oracle.com/oalcrm/web/api/provider-proxy/g2m-consumption/service/v1/account/accountPlans/synthetic%2Fid"); assert.deepEqual(JSON.parse(calls[2].options.body), { hierarchy: "single", products: "all", language: "english", planStatus: ["active", "awaiting_provisioning", "awaiting_provisioning_error", "draft", "expired", "final_billing", "onhold", "provisioned", "signed", "superseded", "superseded_pending_final_billing", "suspended", "terminated", "terminated_pending_final_billing"] }); assert.ok(calls.slice(1).every(call => call.options.method === "POST" && call.options.credentials === "include")); assert.deepEqual(plans.debugRequests.map(entry => entry.name), ["requestAccountSummary", "requestAccountPlans"]); assert.ok(plans.debugRequests.every(entry => entry.httpStatus === 200 && entry.status === "success" && entry.durationMs >= 0)); }); test(`${family}: unknown/invalid messages fail without network; storage failure does not discard fetched products`, async () => { const h = loadBackground({ family }); assert.equal(h.listener({ type: "unknown" }, {}, () => assert.fail("Unexpected reply")), false); assert.equal((await h.dispatch({ type: PREFIX + "requestOpptyProducts" })).ok, false); assert.equal((await h.dispatch({ type: PREFIX + "requestAccountPlans" })).ok, false); assert.equal((await h.dispatch({ type: PREFIX + "requestConsumptionTrend", subPlanNum: "S1", period: "unsupported" })).ok, false); const noStorage = loadBackground({ family, storageError: true, fetch: async () => response({ items: [{ RevnNumber: "R1" }], hasMore: false }) }); assert.equal((await noStorage.dispatch(productRequest("no-storage"))).ok, true); assert.equal(noStorage.progress[0].message.items.length, 1); }); test(`${family}: consumption network/HTTP/JSON failures retain the response and debug contracts`, async () => { for (const failure of ["network", "http", "json"]) { const h = loadBackground({ family, fetch: async () => { if (failure === "network") throw new Error("Synthetic network error"); return failure === "http" ? response({}, 401) : new Response("Synthetic fallback"); } }); const result = await h.dispatch({ type: PREFIX + "requestConsumptionTrend", subPlanNum: "synthetic-plan", period: "weekly", authorization: { name: "g2m-authorization", value: "synthetic-token" } }); assert.equal(result.ok, false); assert.equal(result.debugRequests.length, 1); assert.equal(result.debugRequests[0].name, "requestConsumptionServiceWeekly"); assert.equal(result.debugRequests[0].status, "failed"); assert.equal(result.debugRequests[0].httpStatus, failure === "network" ? null : failure === "http" ? 401 : 200); assert.match(result.error, failure === "network" ? /Synthetic network error/ : failure === "http" ? /status 401/ : /invalid JSON/); } }); }