Implemented the feature to identify and update estimates based on the ACR value, consumption start date, and ramp-up
This commit is contained in:
102
tests/workload-forecast-update.test.cjs
Normal file
102
tests/workload-forecast-update.test.cjs
Normal file
@@ -0,0 +1,102 @@
|
||||
const test = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const { loadBackground, response, plain } = require("./support/characterization.cjs");
|
||||
const { loadApplication } = require("./support/application.cjs");
|
||||
const type = "opportunitiesExtension.requestWorkloadForecastUpdate";
|
||||
const payload = [{ year: 2026, month: 11, amount: 303.03, updatedBy: "test@example.invalid" }];
|
||||
const message = { type, workloadId: "1234", authorization: { value: "synthetic-wwb" }, payload };
|
||||
|
||||
for (const family of ["chrome", "firefox"]) {
|
||||
test(`${family}: forecast PATCH uses dynamic workload, JSON, WWB authorization and invalidates cache on 204`, async () => {
|
||||
const calls = [];
|
||||
const storage = { "opportunitiesExtension.workloadsCache.v1": { old: { items: [{ id: 1234 }] } } };
|
||||
const h = loadBackground({ family, storage, fetch: async (url, options) => {
|
||||
calls.push({ url, options });
|
||||
return new Response(null, { status: 204 });
|
||||
} });
|
||||
const result = await h.dispatch(message);
|
||||
assert.equal(result.ok, true);
|
||||
assert.equal(calls.length, 1);
|
||||
assert.ok(calls[0].url.endsWith("/workloads/1234/forecast"));
|
||||
assert.equal(calls[0].options.method, "PATCH");
|
||||
assert.equal(calls[0].options.credentials, "include");
|
||||
assert.equal(calls[0].options.headers["wwb-provider-authorization"], "synthetic-wwb");
|
||||
assert.equal(calls[0].options.headers["Content-Type"], "application/json");
|
||||
assert.deepEqual(JSON.parse(calls[0].options.body), payload);
|
||||
assert.deepEqual(storage["opportunitiesExtension.workloadsCache.v1"], {});
|
||||
assert.equal(result.debugRequests[0].name, "requestWorkloadForecastUpdate");
|
||||
assert.equal(result.debugRequests[0].httpStatus, 204);
|
||||
});
|
||||
|
||||
test(`${family}: denied PATCH preserves cache, returns debug and is not automatically retried`, async () => {
|
||||
let calls = 0;
|
||||
const storage = { "opportunitiesExtension.workloadsCache.v1": { old: { items: [{ id: 1234 }] } } };
|
||||
const before = JSON.stringify(storage);
|
||||
const h = loadBackground({ family, storage, fetch: async () => { calls++; return response({ error: "Denied" }, 403); } });
|
||||
const result = await h.dispatch(message);
|
||||
assert.equal(result.ok, false);
|
||||
assert.equal(result.httpStatus, 403);
|
||||
assert.equal(calls, 1);
|
||||
assert.equal(JSON.stringify(storage), before);
|
||||
assert.equal(result.debugRequests[0].httpStatus, 403);
|
||||
});
|
||||
}
|
||||
|
||||
test("forecast update rejects invalid identity, invalid amounts and duplicate months before fetch", async () => {
|
||||
let calls = 0;
|
||||
const h = loadBackground({ fetch: async () => { calls++; return response({}); } });
|
||||
for (const change of [{ workloadId: "../other" }, { authorization: {} }, { payload: [] },
|
||||
{ payload: [{ ...payload[0], amount: -1 }] }, { payload: [{ ...payload[0], month: 13 }] },
|
||||
{ payload: [{ ...payload[0], updatedBy: "" }] }, { payload: [payload[0], payload[0]] }]) {
|
||||
assert.equal((await h.dispatch({ ...message, ...change })).ok, false);
|
||||
}
|
||||
assert.equal(calls, 0);
|
||||
});
|
||||
|
||||
function setup() {
|
||||
const app = loadApplication("content");
|
||||
const item = { RevnId: 1234, RampMonths_c: 2, workload: { id: 1234, adjustedACR: 50000,
|
||||
consumptionStartDate: "2026-11-25", forecast: [
|
||||
{ year: 2026, month: 10, adjustedConsumptionAmount: 0 },
|
||||
{ year: 2026, month: 11, adjustedConsumptionAmount: 100 },
|
||||
{ year: 2026, month: 12, adjustedConsumptionAmount: 100 }
|
||||
] } };
|
||||
app.currentUser.ensure = async () => {};
|
||||
app.currentUser.getUserId = () => "test@example.invalid";
|
||||
app.authContentSession.requestConsumerTokenServiceOnce = async () => ({ workloadActions: message.authorization });
|
||||
app.debugContentLog.appendBackgroundRequestLog = () => {};
|
||||
app.productsContentJobs.queueProductsTableRender = () => {};
|
||||
app.productsContentState.opptyProductsByNumber.set("ONE", { items: [item] });
|
||||
app.productsContentState.opptyProductsByNumber.set("TWO", { items: [{ ...item }] });
|
||||
app.productsContentState.workloadsByCustomer.set("99", { status: "ready", workloads: [item.workload], byId: new Map([["1234", item.workload]]) });
|
||||
return { app, item };
|
||||
}
|
||||
|
||||
test("content constructs calculated months and updates both joins only after successful PATCH", async () => {
|
||||
const { app, item } = setup();
|
||||
let release, sent;
|
||||
app.platformContentMessages.sendRuntimeMessage = value => { sent = value; return new Promise(resolve => { release = resolve; }); };
|
||||
const saving = app.workloadForecastUpdate.save(item);
|
||||
await new Promise(resolve => setImmediate(resolve));
|
||||
assert.equal(item.workload.forecast[1].adjustedConsumptionAmount, 100);
|
||||
assert.equal(sent.type, type);
|
||||
assert.equal(sent.workloadId, "1234");
|
||||
assert.deepEqual(plain(sent.payload), [payload[0], { year: 2026, month: 12, amount: 3030.30, updatedBy: "test@example.invalid" }]);
|
||||
await assert.rejects(app.workloadForecastUpdate.save(item), /already being updated/);
|
||||
release({ ok: true });
|
||||
await saving;
|
||||
assert.equal(app.rampProjection.compare(item).status, "matched");
|
||||
assert.equal(app.productsContentState.workloadsByCustomer.get("99").byId.get("1234").forecast[1].adjustedConsumptionAmount, 303.03);
|
||||
for (const record of app.productsContentState.opptyProductsByNumber.values()) assert.equal(app.rampProjection.compare(record.items[0]).status, "matched");
|
||||
});
|
||||
|
||||
test("failed forecast update leaves values unchanged and allows a deliberate retry", async () => {
|
||||
const { app, item } = setup();
|
||||
const before = JSON.stringify(item);
|
||||
app.platformContentMessages.sendRuntimeMessage = async () => ({ ok: false, error: "Forbidden" });
|
||||
await assert.rejects(app.workloadForecastUpdate.save(item), /Forbidden/);
|
||||
assert.equal(JSON.stringify(item), before);
|
||||
app.platformContentMessages.sendRuntimeMessage = async () => ({ ok: true });
|
||||
await app.workloadForecastUpdate.save(item);
|
||||
assert.equal(app.rampProjection.compare(item).status, "matched");
|
||||
});
|
||||
Reference in New Issue
Block a user