Implemented filters for Service Requests and Actions

This commit is contained in:
2026-09-25 16:37:29 -03:00
parent cc567c8ff1
commit de4da0eec6
26 changed files with 1001 additions and 99 deletions

View File

@@ -4,12 +4,14 @@ const { loadApplication } = require("./support/application.cjs");
const flush = () => new Promise(resolve => setImmediate(resolve));
function setup(family, saved = {}, principal = "user@example.invalid") {
const local = {
get: async key => ({ [key]: saved[key] }),
set: async values => Object.assign(saved, JSON.parse(JSON.stringify(values)))
get: async key => key === null ? { ...saved } : ({ [key]: saved[key] }),
set: async values => Object.assign(saved, JSON.parse(JSON.stringify(values))),
remove: async keys => keys.forEach(key => delete saved[key])
};
const api = family === "firefox" ? { browser: { storage: { local } } } : {
chrome: { runtime: {}, storage: { local: {
get: (key, done) => local.get(key).then(done), set: (values, done) => local.set(values).then(done)
get: (key, done) => local.get(key).then(done), set: (values, done) => local.set(values).then(done),
remove: (keys, done) => local.remove(keys).then(done)
} } }
};
const app = loadApplication("content", { ...api, document: { createElement: () => ({ setAttribute() {}, addEventListener() {} }) } });
@@ -41,6 +43,34 @@ function setup(family, saved = {}, principal = "user@example.invalid") {
return { app, calls, load, saved, local };
}
for (const family of ["chrome", "firefox"]) {
test(`${family}: Current Quarter -> Next Quarter -> Current Quarter restores SR hours and filters without requests`, async () => {
const h = setup(family);
const currentStamp = Date.now() - 2000;
const nextStamp = currentStamp + 1000;
let hours = 2;
h.app.fusionCrmServiceRequests.requestCrmServiceRequest = async () => {
h.calls.push("sr");
return [{ SrNumber: "SR1", ReportedHours_c: hours, OpportunityName_Id_c: { OptyNumber: "OP1" } }];
};
await h.load(currentStamp, false);
hours = 8;
await h.load(nextStamp, false);
assert.equal(h.app.opportunityCrmServiceRequests.getSummary("OP1").reportedHours, 8);
const count = h.calls.length;
await h.load(currentStamp, true);
assert.equal(h.calls.length, count);
assert.equal(h.app.opportunityCrmServiceRequests.createBadge("OP1").textContent, "\u2705 SR (2h)");
h.app.opportunitiesTable.renderOpportunitiesTable = () => {};
h.app.activityFilters.toggle("sr", "under4");
assert.equal(h.app.activityFilters.matches({ OptyNumber: "OP1" }), true);
await h.load(nextStamp, true);
assert.equal(h.calls.length, count);
assert.equal(h.app.activityFilters.matches({ OptyNumber: "OP1" }), false);
const reopened = setup(family, h.saved);
await reopened.load(currentStamp, true);
assert.deepEqual(reopened.calls, []);
assert.equal(reopened.app.opportunityCrmServiceRequests.getSummary("OP1").reportedHours, 2);
});
test(`${family}: activities persist across instances with product timestamps and no credential storage`, async () => {
const h = setup(family);
const stamp = Date.now() - 1000;
@@ -78,6 +108,26 @@ test("TTL follows product preferences, rejects stale/mismatched cache and stores
await h.load(stamp + 1, true);
assert.deepEqual(h.calls, []);
});
test("versioned SR cache reads matching legacy entries and prunes expired snapshots only", async () => {
const h = setup("firefox");
const legacyKey = `opportunitiesExtension.activities.v1:${JSON.stringify(["user@example.invalid", "sr", "all"])}`;
const stamp = Date.now() - 1000;
h.saved[legacyKey] = { fetchedAt: stamp, items: [], hasNext: false };
assert.ok(await h.app.activityCache.read("sr", "all", stamp));
assert.equal(await h.app.activityCache.read("sr", "all", stamp + 1), null);
const expiredStamp = Date.now() - 25 * 3600000;
const expiredKey = `opportunitiesExtension.activities.v1:${JSON.stringify(["user@example.invalid", "sr", "all", expiredStamp])}`;
h.saved[expiredKey] = { fetchedAt: expiredStamp, items: [], hasNext: false };
h.saved.preferences = { keep: true };
await h.app.activityCache.write("sr", "all", stamp + 1, []);
assert.equal(h.saved[expiredKey], undefined);
assert.ok(h.saved[legacyKey]);
assert.equal(h.saved.preferences.keep, true);
await h.app.activityCache.invalidate();
assert.equal(await h.app.activityCache.read("sr", "all", stamp + 1), null);
assert.equal(h.saved.preferences.keep, true);
});
test("storage failure does not lose live activity results and failures are never cached", async () => {
const h = setup("firefox");
h.local.get = async () => { throw new Error("Synthetic storage read failure"); };