// Integration smoke test for the poller's ADF assembly. // // We can't (and shouldn't) fire the whole `pollNewTickets` from a unit // test — it needs Jira credentials, the AI classifier, and Webex. So // we test the two composed pieces the plan says matter: (1) the new // `buildAdfComment` shape, and (2) end-to-end that a Meraki `[..](..)` // link the renderer emits actually survives the markdown → ADF trip // and lands as a `link` mark in the poster body. // // `buildAdfComment` was extracted to utils/adfComment.js — a pure // module with no side-effect imports — precisely so tests can pull it // in without needing to satisfy Jira/Webex/Grok env vars at load time. import test from 'node:test'; import assert from 'node:assert/strict'; import { buildAdfComment } from '../utils/adfComment.js'; import { markdownToAdfContent } from '../utils/markdownToAdf.js'; import { renderPhoneStatusMarkdown } from '../services/renderers/phoneStatusRenderer.js'; test('buildAdfComment shape: italic header + spliced body nodes', () => { const body = markdownToAdfContent('hello **bold** world'); const doc = buildAdfComment({ headerLine: 'Auto-enriched by CollabFinder — sample', bodyNodes: body, }); assert.equal(doc.version, 1); assert.equal(doc.type, 'doc'); assert.equal(doc.content.length, 2); const header = doc.content[0]; assert.equal(header.type, 'paragraph'); assert.equal(header.content[0].marks[0].type, 'em'); assert.equal(header.content[0].text, 'Auto-enriched by CollabFinder — sample'); assert.equal(doc.content[1].type, 'paragraph'); const strong = doc.content[1].content.find((n) => n.marks?.[0]?.type === 'strong'); assert.ok(strong, 'expected a strong-marked text node in body'); assert.equal(strong.text, 'bold'); }); test('buildAdfComment tolerates empty bodyNodes', () => { const doc = buildAdfComment({ headerLine: 'header only' }); assert.equal(doc.content.length, 1); assert.equal(doc.content[0].content[0].text, 'header only'); }); test('end-to-end: Meraki [Meraki↗](url) survives to a link mark in ADF', () => { const threeHrAgo = new Date(Date.now() - 3 * 60 * 60 * 1000).toISOString(); const data = { phones: { data: [{ displayName: 'PHONE 782-1', status: 'connected', lastSeen: threeHrAgo, meraki: { switchName: 'STORE-782-SW1', status: 'Online', port: '17', vlan: '20', ip: '10.1.1.5', lastSeen: threeHrAgo, clientUrl: 'https://n123.meraki.com/example/manage/clients/abc/overview', }, }], }, }; const markdown = renderPhoneStatusMarkdown(data, { storeNum: '782', detailed: true, footer: false, }); const bodyNodes = markdownToAdfContent(markdown); const doc = buildAdfComment({ headerLine: 'test', bodyNodes }); const allTextNodes = collectTextNodes(doc); const linkNodes = allTextNodes.filter((n) => n.marks?.some((m) => m.type === 'link')); assert.ok(linkNodes.length > 0, 'expected at least one link mark in the ADF output'); const merakiLink = linkNodes.find((n) => n.marks.some((m) => m.type === 'link' && m.attrs?.href === 'https://n123.meraki.com/example/manage/clients/abc/overview', ), ); assert.ok(merakiLink, 'expected the Meraki↗ URL to be preserved as a link mark'); assert.equal(merakiLink.text, 'Meraki↗'); }); test('end-to-end: bold device names survive to strong marks in ADF', () => { const data = { phones: { data: [{ displayName: 'PHONE 782-99', status: 'connected', lastSeen: new Date(Date.now() - 60 * 60 * 1000).toISOString(), }], }, }; const markdown = renderPhoneStatusMarkdown(data, { storeNum: '782', footer: false }); const nodes = markdownToAdfContent(markdown); const all = collectTextNodes({ content: nodes }); const strongNames = all.filter((n) => n.marks?.some((m) => m.type === 'strong')); assert.ok( strongNames.some((n) => n.text === 'PHONE 782-99'), 'expected device name to appear as strong-marked text', ); }); // Walk an ADF doc (or partial fragment) and return every leaf text node. function collectTextNodes(node, acc = []) { if (!node) return acc; if (node.type === 'text') { acc.push(node); return acc; } const children = Array.isArray(node.content) ? node.content : []; for (const child of children) collectTextNodes(child, acc); return acc; }