111 lines
6.1 KiB
JavaScript
111 lines
6.1 KiB
JavaScript
const assert = require("node:assert/strict");
|
|
const { test } = require("node:test");
|
|
const { loadBackground, response } = require("./support/characterization.cjs");
|
|
const lookups = () => Object.fromEntries(["ROLE", "NAME", "TEAM", "STATUS", "COMPLEXITY"].map(key => [
|
|
`WWB_ACTION_${key}`, [{ code: `${key}_CODE`, name: `${key} label` }]
|
|
]));
|
|
const teamType = "opportunitiesExtension.requestActionTeamMembers";
|
|
const lookupType = "opportunitiesExtension.requestActionFindLookup";
|
|
|
|
test("Save sends the WWB POST, accepts empty success and never retries errors", async () => {
|
|
const payload = { parentType: "WORKLOAD", parentId: "123", action: {
|
|
ownerEmail: "owner@example.invalid", role: "CA", name: "REVIEW", team: "TEAM", tags: "",
|
|
startDate: "2026-09-14T00:00:00.000Z", endDate: "2026-09-15T00:00:00.000Z",
|
|
status: "COMPLETE", complexity: "LOW", notes: [], objective: "",
|
|
createdBy: "creator@example.invalid", updatedBy: "creator@example.invalid"
|
|
} };
|
|
for (const status of [200, 201, 204, 403, 500]) {
|
|
const calls = [];
|
|
const h = loadBackground({ family: "chrome", fetch: async (url, options) => {
|
|
calls.push({ url, options });
|
|
return status === 204 ? new Response(null, { status }) : response({ id: 123 }, status);
|
|
} });
|
|
const result = await h.dispatch({ type: "opportunitiesExtension.requestMgmtAction", payload, authorization: { value: "secret-wwb" } });
|
|
assert.equal(result.ok, status < 300, `${status}: ${result.error}`);
|
|
assert.equal(calls.length, 1);
|
|
assert.ok(calls[0].url.endsWith("/wwb/mgmt/actions"));
|
|
assert.equal(calls[0].options.method, "POST");
|
|
assert.equal(calls[0].options.headers["Wwb-Provider-Authorization"], "secret-wwb");
|
|
assert.deepEqual(JSON.parse(calls[0].options.body), payload);
|
|
assert.ok(!JSON.stringify(result).includes("secret-wwb"));
|
|
}
|
|
});
|
|
|
|
for (const family of ["chrome", "firefox"]) {
|
|
test(`${family}: Action options use dynamic RevnId, WWB-TS and masked GET diagnostics`, 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-token" } },
|
|
{ tokenService: "OCICONS-TS", uiaasHeader: { value: "wrong-token" } },
|
|
{ tokenService: "WWB-TS", uiaasHeader: { value: "synthetic-wwb" } }
|
|
]);
|
|
return response(url.includes("teamMembers") ? [{ email: "owner@example.invalid" }] : lookups());
|
|
} });
|
|
const auth = await h.dispatch({ type: "opportunitiesExtension.requestConsumerTokenService" });
|
|
const authorization = auth.authorizations.workloadActions;
|
|
const team = await h.dispatch({ type: teamType, workloadId: "987654", authorization, url: "https://example.invalid" });
|
|
const lookup = await h.dispatch({ type: lookupType, authorization });
|
|
assert.equal(team.ok, true);
|
|
assert.deepEqual(team.members, [{ email: "owner@example.invalid" }]);
|
|
assert.deepEqual(lookup.lookups, lookups());
|
|
const base = "https://spa.oracle.com/oalcrm/web/api/provider-proxy/wwb-provider/service/workbench-proxy/wwb/mgmt/workloads";
|
|
assert.equal(calls[1].url, `${base}/987654/teamMembers?includeLeads=true`);
|
|
assert.equal(calls[2].url, `${base}/fndLookup`);
|
|
for (const call of calls.slice(1)) {
|
|
assert.equal(call.options.method, "GET");
|
|
assert.equal(call.options.credentials, "include");
|
|
assert.deepEqual({ ...call.options.headers }, { Accept: "application/json", "Wwb-Provider-Authorization": "synthetic-wwb" });
|
|
}
|
|
for (const [result, name] of [[team, "requestActionTeamMembers"], [lookup, "requestActionFindLookup"]]) {
|
|
const log = result.debugRequests[0];
|
|
assert.equal(log.name, name);
|
|
assert.equal(log.status, "success");
|
|
assert.equal(log.httpStatus, 200);
|
|
assert.ok(log.durationMs >= 0);
|
|
assert.equal(log.requestHeaders["Wwb-Provider-Authorization"], "(present)");
|
|
assert.doesNotMatch(JSON.stringify(result), /synthetic-wwb|wrong-token/);
|
|
}
|
|
});
|
|
}
|
|
|
|
test("invalid workload IDs and missing authorization never fetch or accept an arbitrary target", async () => {
|
|
const h = loadBackground({ fetch: () => assert.fail("No network expected") });
|
|
for (const workloadId of [undefined, "", "abc", "12/../fndLookup", "12?other=1"]) {
|
|
assert.equal((await h.dispatch({ type: teamType, workloadId, authorization: { value: "synthetic" } })).ok, false);
|
|
}
|
|
for (const type of [teamType, lookupType]) {
|
|
assert.equal((await h.dispatch({ type, workloadId: "123" })).ok, false);
|
|
}
|
|
});
|
|
|
|
test("Action options require exactly HTTP 200 and valid collections and preserve failed debug entries", async () => {
|
|
for (const type of [teamType, lookupType]) {
|
|
const valid = type === teamType ? [{ email: "owner@example.invalid" }] : lookups();
|
|
for (const fetch of [
|
|
async () => response(valid, 201), async () => response({}, 401), async () => response({}, 403),
|
|
async () => { throw new Error("Synthetic network failure"); },
|
|
async () => new Response("<html>Unexpected session page</html>"),
|
|
async () => response(type === teamType ? [{ name: "Missing email" }] : { ...lookups(), WWB_ACTION_NAME: null })
|
|
]) {
|
|
const h = loadBackground({ fetch });
|
|
const result = await h.dispatch({ type, workloadId: "123", authorization: { value: "synthetic-secret" } });
|
|
assert.equal(result.ok, false);
|
|
assert.equal(result.debugRequests.length, 1);
|
|
assert.equal(result.debugRequests[0].status, "failed");
|
|
assert.ok(result.error);
|
|
assert.doesNotMatch(JSON.stringify(result), /synthetic-secret/);
|
|
}
|
|
}
|
|
});
|
|
|
|
test("empty option lists are valid responses, not invented defaults", async () => {
|
|
const empty = Object.fromEntries(Object.keys(lookups()).map(key => [key, []]));
|
|
const h = loadBackground({ fetch: async url => response(url.includes("teamMembers") ? [] : empty) });
|
|
const members = await h.dispatch({ type: teamType, workloadId: "123", authorization: { value: "synthetic" } });
|
|
const lookup = await h.dispatch({ type: lookupType, authorization: { value: "synthetic" } });
|
|
assert.deepEqual(members.members, []);
|
|
assert.deepEqual(lookup.lookups, empty);
|
|
});
|