const assert = require("node:assert/strict");
const { test } = require("node:test");
const { loadBackground, response } = require("./support/characterization.cjs");
const { loadApplication } = require("./support/application.cjs");
const flush = () => new Promise(resolve => setImmediate(resolve));
for (const family of ["chrome", "firefox"]) {
test(`${family}: WWB-TS selection, fixed workload header, first-page GET and masked debug`, async () => {
const calls = [];
const h = loadBackground({ family, fetch: async (url, options) => {
calls.push({ url, options });
if (url.endsWith("consumerTokenService")) return response([
{ tokenService: "ACCP-TS", uiaasHeader: { value: "summary" } },
{ tokenService: "OCICONS-TS", uiaasHeader: { value: "consumption" } },
{ tokenService: "WWB-TS", uiaasHeader: { label: "ignored-label", value: "synthetic-wwb" } }
]);
return response({ actions: [{ id: 1, name: "TEST" }], totalCount: 20, hasNext: true });
} });
const auth = await h.dispatch({ type: "opportunitiesExtension.requestConsumerTokenService" });
assert.equal(auth.authorizations.workloadActions.value, "synthetic-wwb");
const result = await h.dispatch({ type: "opportunitiesExtension.requestWlActions", revnId: "12345", authorization: auth.authorizations.workloadActions });
assert.equal(result.ok, true);
assert.equal(result.hasNext, true);
assert.equal(result.actions.length, 1);
assert.equal(calls.length, 2, "no pagination");
assert.equal(calls[1].url, "https://spa.oracle.com/oalcrm/web/api/provider-proxy/wwb-provider/service/workbench-proxy/wwb/mgmt/actions?parentType=WORKLOAD&parentId=12345");
assert.equal(calls[1].options.method, "GET");
assert.equal(calls[1].options.headers["Wwb-Provider-Authorization"], "synthetic-wwb");
assert.equal(calls[1].options.headers.Authorization, undefined);
assert.equal(result.debugRequests[0].name, "requestWlActions");
assert.equal(result.debugRequests[0].requestHeaders["Wwb-Provider-Authorization"], "(present)");
});
}
test("workload actions reject missing credentials, invalid ids, HTTP/network/JSON failures", async () => {
for (const fetch of [
async () => { throw new Error("Synthetic network failure"); },
async () => new Response("Denied", { status: 401 }),
async () => new Response("Denied", { status: 403 }),
async () => new Response("Login"),
async () => response({ actions: null, hasNext: false })
]) {
const h = loadBackground({ fetch });
const result = await h.dispatch({ type: "opportunitiesExtension.requestWlActions", revnId: "123", authorization: { value: "synthetic" } });
assert.equal(result.ok, false);
assert.equal(result.debugRequests.length, 1);
}
const h = loadBackground({ fetch: () => assert.fail("Unexpected network") });
for (const fields of [{ revnId: "123" }, { revnId: "bad&id=2", authorization: { value: "synthetic" } }]) {
assert.equal((await h.dispatch({ type: "opportunitiesExtension.requestWlActions", ...fields })).ok, false);
}
});
function contentFixture(send) {
const app = loadApplication("content", { document: { createElement: () => ({ attributes: {}, setAttribute(k, v) { this.attributes[k] = v; } }) } });
app.currentUser.allowsCrmActivities = () => true;
app.authContentSession.requestConsumerTokenServiceOnce = async () => ({ workloadActions: { value: "synthetic-wwb" } });
app.authSessionState.principal = "test@example.invalid";
app.platformContentMessages.sendRuntimeMessage = send;
app.debugContentView.renderDebugPanel = () => {};
app.productsContentJobs.queueProductsTableRender = () => {};
return app;
}
test("Actions completion includes queued calls, shared pending records, failures and cache writes", async () => {
const pending = [];
let finishWrite;
const app = contentFixture(() => new Promise(resolve => pending.push(resolve)));
app.activityCache.read = async () => null;
app.activityCache.write = () => new Promise(resolve => { finishWrite = resolve; });
const products = { items: Array.from({ length: 5 }, (_, i) => ({ RevnId: String(i + 1) })) };
let complete = false, sharedComplete = false;
const batch = app.opportunityWorkloadActions.loadProducts(products, true, { cachedAt: 200 }).then(() => { complete = true; });
const shared = app.opportunityWorkloadActions.loadProducts(products).then(() => { sharedComplete = true; });
await flush();
assert.equal(pending.length, 4);
pending.slice(0, 4).forEach(resolve => resolve({ ok: false, error: "Synthetic" }));
await flush();
assert.equal(pending.length, 5);
assert.equal(complete, false);
assert.equal(sharedComplete, false);
pending[4]({ ok: true, actions: [], hasNext: false });
await flush();
assert.equal(complete, false, "cache write still pending");
finishWrite();
await batch;
await shared;
assert.equal(complete, true);
assert.equal(sharedComplete, true);
});
test("Actions reset settles discarded queue entries without waiting for unstarted requests", async () => {
const pending = [];
const app = contentFixture(() => new Promise(resolve => pending.push(resolve)));
const batch = app.opportunityWorkloadActions.loadProducts({ items: Array.from({ length: 8 }, (_, i) => ({ RevnId: String(i) })) });
await flush();
app.opportunityWorkloadActions.reset(false);
pending.forEach(resolve => resolve({ ok: true, actions: [], hasNext: false }));
await batch;
assert.equal(pending.length, 4);
});
test("actions aggregate all products, share RevnId queries across Reference changes and restart on reopen", async () => {
const calls = [];
const app = contentFixture(async message => {
calls.push(message);
return { ok: true, hasNext: false, actions: message.revnId === "1" ? [{ id: 1, owner: "test@example.invalid", name: "" }] : [] };
});
const products = { items: [{ RevnId: "1" }, { RevnId: 2 }, { RevnId: "1" }] };
app.productsContentState.opptyProductsByNumber.set("A", products);
app.opportunityWorkloadActions.loadProducts(products);
assert.equal(app.opportunityWorkloadActions.createBadge("A").textContent, "Act ...");
await flush();
assert.equal(calls.length, 2);
assert.equal(calls[0].authorization.value, "synthetic-wwb");
const badge = app.opportunityWorkloadActions.createBadge("A");
assert.equal(badge.textContent, "\u2705 Act");
assert.match(badge.title, /