114 lines
6.1 KiB
JavaScript
114 lines
6.1 KiB
JavaScript
const assert = require("node:assert/strict");
|
|
const { test } = require("node:test");
|
|
const fs = require("node:fs");
|
|
const path = require("node:path");
|
|
const { loadApplication, composeScript } = require("./support/application.cjs");
|
|
|
|
const root = path.join(__dirname, "..");
|
|
class Element {
|
|
constructor(tag) {
|
|
this.tag = tag; this.children = []; this.attributes = {}; this.listeners = {}; this.text = "";
|
|
this.classList = { toggle() {} };
|
|
}
|
|
set textContent(value) { this.text = String(value); this.children = []; }
|
|
get textContent() { return this.text + this.children.map(child => child.textContent).join(""); }
|
|
append(...children) { this.children.push(...children); }
|
|
setAttribute(key, value) { this.attributes[key] = value; }
|
|
addEventListener(key, callback) { this.listeners[key] = callback; }
|
|
}
|
|
function setup() {
|
|
const app = loadApplication("content", { document: { createElement: tag => new Element(tag), getElementById: () => null,
|
|
createElementNS: (namespace, tag) => Object.assign(new Element(tag), { namespace }) } });
|
|
app.currentUser.allowsCrmActivities = () => true;
|
|
app.productsContentJobs.queueProductsTableRender = () => {};
|
|
app.activityProgress.update = () => {};
|
|
app.authSessionState.principal = "me@example.invalid";
|
|
return app;
|
|
}
|
|
function checkIcon(badge, kind, value) {
|
|
assert.equal(badge.textContent, value);
|
|
const images = badge.children.filter(child => child.tag === "svg");
|
|
assert.equal(images.length, 1);
|
|
const icon = images[0];
|
|
assert.equal(icon.namespace, "http://www.w3.org/2000/svg");
|
|
assert.equal(icon.attributes.viewBox, "0 0 24 24");
|
|
assert.equal(icon.attributes.fill, "none");
|
|
assert.equal(icon.attributes.stroke, "currentColor");
|
|
assert.equal(icon.attributes["stroke-width"], "2.25");
|
|
assert.equal(icon.attributes["stroke-linecap"], "round");
|
|
assert.equal(icon.attributes["stroke-linejoin"], "round");
|
|
assert.equal(icon.attributes["data-badge-icon"], kind);
|
|
assert.equal(icon.attributes["aria-hidden"], "true");
|
|
assert.equal(icon.attributes.focusable, "false");
|
|
assert.equal(icon.attributes.width, "16");
|
|
assert.equal(icon.attributes.height, "16");
|
|
assert.ok(icon.children.length >= 3);
|
|
assert.ok(icon.children.every(child => ["path", "rect", "polyline"].includes(child.tag)));
|
|
assert.ok(icon.children.every(child => child.namespace === icon.namespace));
|
|
assert.equal(badge.children.some(child => child.tag === "img"), false);
|
|
}
|
|
|
|
test("consistent inline vectors replace raster icons without parentheses or lost tooltips", async () => {
|
|
const app = setup();
|
|
const products = { items: [1, 2, 3].map(RampMonths_c => ({ RampMonths_c, RevnId: "123" })) };
|
|
const count = app.productsDetails.createProductsCountButton("TEST", products);
|
|
checkIcon(count, "products", "3");
|
|
assert.equal(count.title, "3 products");
|
|
assert.equal(typeof count.listeners.click, "function");
|
|
const ramp = app.productsDetails.createProductsRampBadge(products);
|
|
checkIcon(ramp, "ramp", "1 | 2 | 3");
|
|
assert.equal(ramp.title, "Ramp Months: 1, 2, 3");
|
|
const missingRamp = app.productsDetails.createProductsRampBadge({ items: [{ RampMonths_c: null }] });
|
|
checkIcon(missingRamp, "ramp", "N/A");
|
|
assert.equal(missingRamp.attributes["data-missing"], "true");
|
|
|
|
app.fusionCrmServiceRequests.requestCrmServiceRequest = async () => [
|
|
{ SrNumber: "SR-TEST", ReportedHours_c: 4, OpportunityName_Id_c: { OptyNumber: "TEST" } }
|
|
];
|
|
await app.opportunityCrmServiceRequests.load("synthetic", app.opportunitiesQueryState.periodRequestVersion);
|
|
const sr = app.opportunityCrmServiceRequests.createBadge("TEST");
|
|
checkIcon(sr, "sr", "4h");
|
|
assert.equal(sr.title, "Whether a Service Request has been created for the opportunities.");
|
|
assert.equal(typeof sr.listeners.click, "function");
|
|
checkIcon(app.opportunityCrmServiceRequests.createBadge("OTHER"), "sr", "0h+");
|
|
|
|
app.productsContentState.opptyProductsByNumber.set("TEST", products);
|
|
app.authContentSession.requestConsumerTokenServiceOnce = async () => ({ workloadActions: { value: "synthetic" } });
|
|
app.platformContentMessages.sendRuntimeMessage = async () => ({ ok: true, hasNext: false, actions: [
|
|
{ id: 1, owner: "me@example.invalid", name: "My action" },
|
|
{ id: 2, owner: "other@example.invalid", name: "Other action" }
|
|
] });
|
|
await app.opportunityWorkloadActions.loadProducts(products);
|
|
const actions = app.opportunityWorkloadActions.createBadge("TEST");
|
|
checkIcon(actions, "actions", "2");
|
|
assert.equal(actions.attributes["data-state"], "matched");
|
|
assert.match(actions.title, /My action/);
|
|
assert.match(actions.title, /Other action/);
|
|
app.currentUser.allowsCrmActivities = () => false;
|
|
assert.equal(app.opportunityWorkloadActions.createBadge("TEST"), null);
|
|
assert.equal(app.opportunityCrmServiceRequests.createBadge("TEST"), null);
|
|
});
|
|
|
|
test("vector shapes and their license ship in both distributions without raster images or requests", () => {
|
|
const source = composeScript("content");
|
|
const module = fs.readFileSync(path.join(root, "src/features/opportunities/badge-content.js"), "utf8");
|
|
assert.ok(source.includes(module));
|
|
assert.doesNotMatch(source, /opportunityBadgeImages|data:image\/png;base64/);
|
|
for (const target of ["chromium", "firefox"]) {
|
|
const bundle = fs.readFileSync(path.join(root, "dist", target, "content.js"), "utf8");
|
|
assert.ok(bundle.includes(module));
|
|
assert.ok(bundle.includes("Copyright (c) 2026 Lucide Icons and Contributors"));
|
|
}
|
|
});
|
|
|
|
test("icon styles preserve uniform dimensions and provide light, dark and active contrast", () => {
|
|
const css = fs.readFileSync(path.join(root, "src/features/opportunities/styles.css"), "utf8");
|
|
const icon = css.match(/\.opportunities-extension-badge-icon \{([^}]+)\}/)[1];
|
|
for (const rule of ["order: -1;", "flex: 0 0 16px;", "width: 16px;", "height: 16px;", "color: inherit;", "stroke: currentColor;", "stroke-width: 2.25;"]) {
|
|
assert.ok(icon.includes(rule), rule);
|
|
}
|
|
assert.doesNotMatch(icon, /filter:|mix-blend-mode:/);
|
|
assert.match(css, /gap: 4px;\s*height: 20px;/);
|
|
assert.match(css, /cell-actions > \.opportunities-extension-crm-sr-badge \{\s*display: inline-flex;\s*align-items: center;\s*justify-content: flex-start;/);
|
|
});
|