Implemented the Create Internal Service Request functionality

This commit is contained in:
2026-10-09 18:41:39 -03:00
parent c9de750261
commit 8b4d88b226
34 changed files with 1690 additions and 480 deletions

View File

@@ -1,8 +1,141 @@
const assert = require("node:assert/strict");
const { test } = require("node:test");
const { loadBackground, response } = require("./support/characterization.cjs");
const { loadApplication } = require("./support/application.cjs");
function assertDebugVisibility(result, secret) {
const app = loadApplication("content");
const entries = result.debugRequests || [];
const render = () => entries.map(entry => app.debugContentLog.formatHeaderBlock(entry.requestHeaders)
+ app.debugContentLog.formatDebugBody(entry.responseBody, entry.name)).join("\n");
assert.ok(!render().includes(secret));
app.debugState.debugSecretsVisible = true;
assert.equal(render().includes(secret), JSON.stringify(entries).includes(secret));
}
const type = "opportunitiesExtension.requestPostServiceRequest";
const emailAddress = "signed.in+sr@example.invalid";
const internalType = "opportunitiesExtension.requestPostInternalServiceRequest";
const internalInput = () => ({ Title: "Internal request title", ServiceNew_Id_c: "404", ProblemDescription: "Form description",
CustomerDeadline_c: "2026-11-29", TechPlatformLookUp_c: "DATABASE", InternalDeadline_c: "2027-01-31",
ServiceRequest_Id_SRToInternalSR: "505" });
const parentInfo = () => ({ SrId: 505, SrNumber: "SR505", AccountPartyId: 100000693906507, OpportunityName_c: "A8YPN8",
OpportunityName_Id_c: 302959906052470, RegionText_c: "LAD", SvcHealth_c: "SVC_HEALTH_YELLOW", Language_c: "PORTUGUESE",
CountryText_c: "BR", PrimaryPillarNew_c: "Tech_Cloud_Platform", SecondaryPillarNew_c: "Tech_Cloud_Infrastructure", ServiceNew_Id_c: 300010753841648 });
for (const family of ["chrome", "firefox"]) {
test(`${family}: internal SR reads parent SRInfo, resolves user and posts form values with Session and observed client ID`, async () => {
const calls = [];
const h = loadBackground({ family, fetch: async (url, options) => {
calls.push({ url, options });
if (options.method === "GET" && url.includes("/serviceRequests?")) return withClientId({ items: [parentInfo()] }, 200, "internal-client");
if (url.includes("/resourceUsers?")) return response({ resourcePartyId: 303 });
assert.ok(!url.includes("Catalogue_c"), "Internal SR must not use catalog signing");
return response({ SrNumber: "ISR1" }, 201);
} });
const input = { ...internalInput(), AccountPartyId: 1, OpportunityName_c: "STALE", OpportunityName_Id_c: 2, RegionText_c: "APAC",
SvcHealth_c: "SVC_HEALTH_GREEN", Language_c: "ENGLISH", CountryText_c: "US", PrimaryPillarNew_c: "STALE", SecondaryPillarNew_c: null, ReportedByPartyId: 999 };
const result = await h.dispatch({ type: internalType, emailAddress, payload: input });
assert.equal(result.ok, true);
assert.equal(calls.length, 3);
const info = new URL(calls[0].url);
assert.match(info.pathname, /SeaaS_SR_management.*\/oalsetCRMRestAPI\/.*resources\/latest\/serviceRequests$/);
assert.equal(info.searchParams.get("q"), "SrId=505");
assert.equal(info.searchParams.get("onlyData"), "true");
assert.equal(info.searchParams.get("orderBy"), "LastUpdateDate:desc");
assert.equal(info.searchParams.get("fields"), "PrimaryPillarNew_c,SecondaryPillarNew_c,SvcHealth_c,SrNumber,AccountPartyId,CountryText_c,Language_c,OpportunityName_Id_c,OpportunityName_c,RegionText_c,ServiceNew_Id_c");
const post = calls[2];
assert.equal(new URL(calls[1].url).searchParams.get("emailAddress"), emailAddress);
assert.match(post.url, /SeaaS_SR_management.*oalsetCRMRestAPICloudAccount.*resources\/latest\/serviceRequests$/);
assert.equal(post.options.method, "POST");
const { SrId, SrNumber, ...parent } = parentInfo();
assert.deepEqual(JSON.parse(post.options.body), { ...parent, ...internalInput(),
ServiceRequest_Id_SRToInternalSR: "505", ServiceNew_Id_c: 404,
InternalDeadline_c: "2027-01-31T00:00:00.000Z", ReportedByPartyId: 303, SvcQuestionsCollection_c: [] });
assert.ok(calls.every(call => call.options.headers.Authorization === "Session" && call.options.credentials === "include"));
const origin = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com";
assert.deepEqual({ ...post.options.headers }, { Accept: "application/json", "Content-Type": "application/json",
Authorization: "Session", Origin: origin, "x-appbuilder-client-id": "internal-client" });
assertDebugVisibility(result, "internal-client");
assert.equal(calls[0].options.headers.Origin, undefined);
assert.equal(result.debugRequests[2].requestHeaders.Origin, origin);
assert.equal(h.headerRules.length, 1);
const { removeRuleIds, addRules } = h.headerRules[0];
assert.deepEqual(removeRuleIds, [7203]);
assert.equal(addRules.length, 1);
const rule = addRules[0];
assert.deepEqual(rule.action, { type: "modifyHeaders", requestHeaders: [{ header: "Origin", operation: "set", value: origin }] });
assert.deepEqual(rule.condition.initiatorDomains, ["synthetic-extension"]);
assert.deepEqual(rule.condition.requestMethods, ["post"]);
assert.deepEqual(rule.condition.resourceTypes, ["xmlhttprequest"]);
const pattern = new RegExp(rule.condition.regexFilter);
assert.ok(pattern.test(post.url));
assert.ok(!pattern.test(calls[0].url));
assert.ok(!pattern.test(post.url + "/other"));
assert.ok(!pattern.test(post.url + "?other=1"));
assert.deepEqual(result.debugRequests.map(entry => entry.name), ["requestSRInfo", "requestResourceUser", "requestPostInternalServiceRequest"]);
});
}
test("internal SR queries the current parent on every Save and reuses captured client ID after worker restart", async () => {
const sessionStorage = {};
const queries = [], posts = [];
const fetch = async (url, options) => {
if (url.includes("/serviceRequests?")) {
const id = Number(new URL(url).searchParams.get("q").slice("SrId=".length));
queries.push(id);
const parent = { ...parentInfo(), SrId: id, SecondaryPillarNew_c: null, ServiceNew_Id_c: id + 1000 };
if (id === 606) delete parent.ServiceNew_Id_c;
return id === 505 ? withClientId({ items: [parent] }, 200, "saved-internal-client") : response({ items: [parent] });
}
if (url.includes("/resourceUsers?")) return response({ resourcePartyId: 303 });
posts.push(options);
return response({ SrNumber: "ISR1" }, 201);
};
const h = loadBackground({ fetch, sessionStorage });
assert.equal((await h.dispatch({ type: internalType, emailAddress, payload: internalInput() })).ok, true);
const restarted = loadBackground({ fetch, sessionStorage });
assert.equal((await restarted.dispatch({ type: internalType, emailAddress,
payload: { ...internalInput(), ServiceRequest_Id_SRToInternalSR: "606" } })).ok, true);
assert.deepEqual(queries, [505, 606]);
assert.equal(posts[1].headers["x-appbuilder-client-id"], "saved-internal-client");
assert.equal(JSON.parse(posts[1].body).ServiceRequest_Id_SRToInternalSR, "606", "links to parent SrId, independently of the parent's service ID");
assert.equal(JSON.parse(posts[1].body).SecondaryPillarNew_c, null);
});
test("internal SR save validates form fields and parent ID before requesting SRInfo", async () => {
let calls = 0;
const h = loadBackground({ fetch: async () => { calls++; return response({}, 403); } });
for (const change of [{ Title: "" }, { ProblemDescription: "" }, { TechPlatformLookUp_c: "" }, { InternalDeadline_c: "2026-02-30" },
{ CustomerDeadline_c: "2026-02-30" }, { ServiceNew_Id_c: "bad" }, { ServiceRequest_Id_SRToInternalSR: "bad" }]) {
assert.equal((await h.dispatch({ type: internalType, emailAddress, payload: { ...internalInput(), ...change } })).ok, false);
}
assert.equal(calls, 0);
assert.equal((await h.dispatch({ type: internalType, emailAddress, payload: internalInput() })).ok, false);
assert.equal(calls, 1);
});
test("internal SR stops after missing or rejected parent data, failed user lookup or POST and never retries creation", async () => {
for (const mode of ["info-401", "info-500", "empty", "multiple", "wrong-parent", "missing-country", "user", "post-403", "post-500", "network"]) {
const calls = [];
const h = loadBackground({ fetch: async (url, options) => {
calls.push({ url, options });
if (url.includes("/serviceRequests?")) {
const parent = parentInfo();
if (mode === "wrong-parent") parent.SrId = 999;
if (mode === "missing-country") delete parent.CountryText_c;
return response({ items: mode === "empty" ? [] : mode === "multiple" ? [parent, parent] : [parent] }, mode === "info-401" ? 401 : mode === "info-500" ? 500 : 200);
}
if (url.includes("/resourceUsers?")) return response({ resourcePartyId: 303 }, mode === "user" ? 403 : 200);
if (mode === "network") throw new Error("Synthetic network failure");
return response({}, mode === "post-403" ? 403 : 500);
} });
const result = await h.dispatch({ type: internalType, emailAddress, payload: internalInput() });
assert.equal(result.ok, false, mode);
const hasPost = ["post-403", "post-500", "network"].includes(mode);
assert.equal(calls.length, hasPost ? 3 : mode === "user" ? 2 : 1, mode);
assert.equal(calls.filter(call => call.options.method === "POST").length, hasPost ? 1 : 0);
assert.equal(result.debugRequests.at(-1).status, ["empty", "multiple", "wrong-parent", "missing-country"].includes(mode) ? "success" : "failed");
}
});
const payload = () => ({ AccountPartyId: 100000000000101, OpportunityName_Id_c: 202,
ServiceNew_Id_c: 404, Title: "Service-OP1-Customer", RegionText_c: "LAD", CountryText_c: "BR",
ProblemDescription: "Test description", Language_c: "ENGLISH", CustomerDeadline_c: "2027-01-31",
@@ -80,7 +213,7 @@ test("token 403 retries once only with a newly returned client ID; SR POST is ne
if (["recovered", "save-failure"].includes(mode)) {
assert.deepEqual({ ...calls.at(-1).options.headers }, { ...tokenCalls.at(-1).options.headers, "vb-proxy-header-x-oracle-ectoken": "retry-token" });
}
assert.ok(!JSON.stringify(result).includes("retry-token"));
assertDebugVisibility(result, "retry-token");
}
});
@@ -137,7 +270,7 @@ for (const family of ["chrome", "firefox"]) {
assert.deepEqual(JSON.parse(calls[3].options.body), { ...payload(), ReportedByPartyId: 303, SvcQuestionsCollection_c: [],
SourceCd: "SVC_OPPORTUNITY_SCREEN", SeverityCd: "ORA_SVC_SEV2", ChannelTypeCd: "ORA_SVC_WEB" });
assert.equal(calls[3].options.body, JSON.stringify(prepared.payload));
assert.ok(!JSON.stringify(result).includes("synthetic-secret-token"));
assertDebugVisibility(result, "synthetic-secret-token");
assert.equal(h.tabs.length, 0);
});
}
@@ -209,6 +342,20 @@ test("Origin rule failure blocks token acquisition and SR creation", async () =>
assert.match(result.error, /Rule permission denied/);
});
test("Origin rule failure prevents the Internal SR POST", async () => {
const calls = [];
const h = loadBackground({ ruleError: true, fetch: async url => {
calls.push(url);
if (url.includes("/serviceRequests?")) return response({ items: [parentInfo()] });
assert.match(url, /\/resourceUsers\?/);
return response({ resourcePartyId: 303 });
} });
const result = await h.dispatch({ type: internalType, emailAddress, payload: internalInput() });
assert.equal(result.ok, false);
assert.match(result.error, /Rule permission denied/);
assert.equal(calls.length, 2);
});
test("resource lookup failures or invalid resourcePartyId never obtain a token or create SR", async () => {
for (const body of [{ resourcePartyId: null }, { resourceProfileId: 999 }, { resourcePartyId: "9007199254740993" }, { resourcePartyId: 0 }, "unauthorized"]) {
let calls = 0;
@@ -238,7 +385,7 @@ test("token rejection never creates SR; creation failures are never automaticall
const result = await h.dispatch({ type, phase: "confirm", catalogId: 505, payload: prepared.payload });
assert.equal(result.ok, false);
assert.equal(calls, failure === "token" || failure === "empty-token" ? 2 : 3);
assert.ok(!JSON.stringify(result).includes("secret-token"));
assertDebugVisibility(result, "secret-token");
assert.equal(h.tabs.length, 0);
}
});