ms-ai-architect/tests/kb-update/test-url-normalize.test.mjs
Kjell Tore Guttormsen e74646d395 fix(ms-ai-architect): registry-herding Fase 1a — +5 sitemap-prefiks + skjemaløs URL-ekstraksjon
Update-mekanismen lot siterte URL-er stå som not_in_sitemap fordi deres docset
aldri ble pollet, og skjemaløse citater (tabellceller: bare learn.microsoft.com/...
uten https://) ble aldri ekstrahert.

- Taxonomy: +5 docsets (graph, ai-builder, power-apps, power-automate,
  microsoftsearch) — hver ett child-sitemap, verifisert live mot indeksen.
  Bevist: 21/24 not_in_sitemap-URL-er i disse docsetene blir nå tracked.
- url-normalize: extractUrls fanger skjemaløse citater-med-sti (krever /path
  etter domenet → avviser bare-domene-prosa og JSON-eksempler); normalizeUrl
  kanonikaliserer scheme til https. Bevist: +19 nye URL-er ekstraherbare.
- Bugfix: backtick fra inline-kode-citat (`learn.microsoft.com/...`) lekket inn
  i URL-en — ekskludert i regex + trailing-strip.

TDD: tests/kb-update/test-url-normalize.test.mjs (ny, 14) + test-taxonomy
prefiks-count 18→23 + Fase 1a-assertion. Full suite 338/338, 0 regresjon.
Registry-refresh (build-registry --merge + poll) bevisst utsatt — unngår
552KB re-order-churn; effekten er empirisk verifisert read-only.
2026-06-26 10:15:46 +02:00

115 lines
4.6 KiB
JavaScript

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