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;/); });