// tests/kb-update/test-url-normalize.test.mjs // Unit tests for scripts/kb-update/lib/url-normalize.mjs. // Pins the canonical-URL contract that build-registry ↔ poll-sitemaps matching // depends on, AND the Fase 1a registry-herding extension: schema-less citations // (learn.microsoft.com/... without the https:// prefix) must be extracted and // canonicalised to https://, while bare-domain prose mentions (no path) and // JSON example strings must NOT be captured. import { test } from 'node:test'; import assert from 'node:assert/strict'; import { normalizeUrl, extractUrls } from '../../scripts/kb-update/lib/url-normalize.mjs'; // --- normalizeUrl: existing contract (regression guard) --- test('normalizeUrl — strips locale, fragment, query, trailing slash; lowercases', () => { assert.equal( normalizeUrl('https://learn.microsoft.com/en-us/azure/AI-Foundry/Overview/?view=x#sec'), 'https://learn.microsoft.com/azure/ai-foundry/overview' ); }); test('normalizeUrl — strips trailing markdown punctuation', () => { assert.equal( normalizeUrl('https://learn.microsoft.com/azure/foo).'), 'https://learn.microsoft.com/azure/foo' ); }); test('normalizeUrl — non-learn URL returns null', () => { assert.equal(normalizeUrl('https://example.com/azure/foo'), null); assert.equal(normalizeUrl(''), null); assert.equal(normalizeUrl(null), null); }); // --- normalizeUrl: Fase 1a — schema-less canonicalisation --- test('normalizeUrl — schema-less citation gets https:// prepended', () => { assert.equal( normalizeUrl('learn.microsoft.com/azure/api-management/genai-gateway-capabilities'), 'https://learn.microsoft.com/azure/api-management/genai-gateway-capabilities' ); }); test('normalizeUrl — schema-less with en-us locale is also canonicalised', () => { assert.equal( normalizeUrl('learn.microsoft.com/en-us/compliance/assurance/assurance-artificial-intelligence'), 'https://learn.microsoft.com/compliance/assurance/assurance-artificial-intelligence' ); }); test('normalizeUrl — idempotent on schema-less input', () => { const once = normalizeUrl('learn.microsoft.com/azure/foo'); assert.equal(normalizeUrl(once), once); }); // --- extractUrls: existing contract (regression guard) --- test('extractUrls — extracts https markdown-link URL', () => { assert.deepEqual( extractUrls('See [docs](https://learn.microsoft.com/azure/foo) here.'), ['https://learn.microsoft.com/azure/foo'] ); }); test('extractUrls — dedups same URL across forms', () => { const out = extractUrls( 'https://learn.microsoft.com/azure/foo and learn.microsoft.com/azure/foo' ); assert.deepEqual(out, ['https://learn.microsoft.com/azure/foo']); }); // --- extractUrls: Fase 1a — schema-less table-cell citations (the 2 named files) --- test('extractUrls — captures schema-less table-cell citation', () => { const row = '| **GenAI Gateway** | desc | learn.microsoft.com/azure/api-management/genai-gateway-capabilities |'; assert.deepEqual( extractUrls(row), ['https://learn.microsoft.com/azure/api-management/genai-gateway-capabilities'] ); }); test('extractUrls — captures multiple schema-less rows', () => { const text = [ '| A | learn.microsoft.com/en-us/compliance/assurance/assurance-artificial-intelligence |', '| B | learn.microsoft.com/en-us/azure/cloud-adoption-framework/scenarios/ai/govern |', ].join('\n'); assert.deepEqual(extractUrls(text), [ 'https://learn.microsoft.com/compliance/assurance/assurance-artificial-intelligence', 'https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/ai/govern', ]); }); // --- extractUrls: must NOT capture bare-domain prose / JSON examples --- test('extractUrls — ignores bare-domain prose mention (no path)', () => { assert.deepEqual( extractUrls('All info fra offisiell dokumentasjon (learn.microsoft.com, blogs.microsoft.com).'), [] ); }); test('extractUrls — ignores JSON example string with no path', () => { assert.deepEqual(extractUrls('{"url": "learn.microsoft.com"}'), []); }); test('extractUrls — strips wrapping backticks from inline-code citation', () => { // `learn.microsoft.com/agent-framework/` inside prose backticks must not leak // the backtick into the URL (would never match a sitemap entry). assert.deepEqual( extractUrls('verifisert mot `learn.microsoft.com/agent-framework/`).'), ['https://learn.microsoft.com/agent-framework'] ); }); test('normalizeUrl — strips trailing backtick', () => { assert.equal( normalizeUrl('https://learn.microsoft.com/azure/foo`'), 'https://learn.microsoft.com/azure/foo' ); });