Files
runicgateway.com/test/footer.test.mjs
Claude 12c416f5fc
All checks were successful
PR checks / checks (pull_request) Successful in 9m38s
fix(footer): send each documentation link to the section its label names
All three links under "Documentation" pointed at /docs/. Three labels — Getting
started, Administration, Building a module — and one destination, which is the
docs home and also what the header's Docs link already opens.

They now land inside the section they name:

  Getting started     /docs/getting-started/requirements/
  Administration      /docs/administration/configuration/
  Building a module   /docs/modules/building-a-module/

The docs home stays the header's link rather than becoming a fourth route to the
same page.

Eleven checks and two suites could not see this, and the reason is worth keeping:
the bug is not a broken link. checkLinks resolves every internal href against the
build and /docs/ resolves — three links to a page that exists are three valid
links. checkSidebar compares the docs tree to the planned tree and never looks at
the footer. checkA11y checks structure, and three correctly marked-up anchors are
correct markup. Nothing asserted that a link goes where its label says.

So the columns move to src/data/footer.mjs, beside legal.mjs and collection.mjs,
and test/footer.test.mjs asserts it: every destination in a column distinct, no
destination repeated across columns, each documentation link inside its own
section prefix, none of them the docs home, and the two Project links still read
from the brand. A column list inside an .astro component cannot be imported by a
test, which is the whole reason for the move.

Verified by reintroducing the bug: the suite fails with "Administration points at
/docs/, which is not inside /docs/administration/". Restored, npm run verify is
green — 42 tests, eleven checks, and the built index.html renders three distinct
hrefs.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-27 00:30:15 -05:00

98 lines
4.2 KiB
JavaScript

/**
* The footer's links, tested where a mistake is invisible to every other check.
*
* ---------------------------------------------------------------------------------------
* WHY THIS FILE EXISTS
* ---------------------------------------------------------------------------------------
* The footer shipped with all three "Documentation" links pointing at `/docs/`. Three
* labels — Getting started, Administration, Building a module — and one destination. It
* reached production and stayed there through eleven checks and two test suites, because
* none of them could see it:
*
* - `checkLinks.mjs` resolves every internal link against the build. `/docs/` resolves.
* Three links to a page that exists are three valid links.
* - `checkSidebar.mjs` compares the docs tree to the planned tree. The footer is not the
* sidebar and was never in scope.
* - `checkA11y.mjs` checks structure. Three correctly-marked-up links are correct markup.
*
* The bug is not a broken link. It is a link that goes somewhere other than where its label
* says, which is the one property nothing was asserting. So that is what this file asserts,
* and the reason `src/data/footer.mjs` exists at all — a column list inside an `.astro`
* component cannot be imported by a test.
*/
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { footerColumns, docsEntryPoints } from '../src/data/footer.mjs';
/** A stand-in for the rendered brand; only the two Project links read it. */
const brand = {
giteaOrg: 'https://gitea.example.com/Org',
discordInvite: 'https://discord.gg/example',
};
const columns = footerColumns(brand);
const documentation = columns.find((c) => c.heading === 'Documentation');
test('every link in a column has its own destination', () => {
for (const column of columns) {
const hrefs = column.links.map((l) => l.href);
assert.equal(
new Set(hrefs).size,
hrefs.length,
`the ${column.heading} column has two links pointing at the same page: ${hrefs.join(', ')}`,
);
}
});
test('no two columns offer the same destination twice', () => {
const all = columns.flatMap((c) => c.links.map((l) => l.href));
assert.equal(new Set(all).size, all.length, `a footer destination is repeated: ${all.join(', ')}`);
});
test('each documentation link lands inside the section its label names', () => {
// The exact failure that shipped: `/docs/` under all three labels satisfies "starts with
// /docs/" but names no section, so the prefixes below are section prefixes, not `/docs/`.
const expected = [
['Getting started', '/docs/getting-started/'],
['Administration', '/docs/administration/'],
['Building a module', '/docs/modules/'],
];
for (const [label, prefix] of expected) {
const link = documentation.links.find((l) => l.label === label);
assert.ok(link, `the Documentation column no longer has a "${label}" link`);
assert.ok(
link.href.startsWith(prefix),
`"${label}" points at ${link.href}, which is not inside ${prefix}`,
);
}
});
test('no documentation link is the docs home, which the header already carries', () => {
for (const link of documentation.links) {
assert.notEqual(
link.href,
'/docs/',
`"${link.label}" points at the docs home; the header's Docs link is that page`,
);
}
});
test('every documentation entry point is a directory URL', () => {
// Astro builds these as directories with an index.html; a missing trailing slash costs a
// redirect on every click and reads as a broken path in the status bar.
for (const [section, href] of Object.entries(docsEntryPoints)) {
assert.ok(href.endsWith('/'), `the ${section} entry point (${href}) needs a trailing slash`);
assert.ok(href.startsWith('/docs/'), `the ${section} entry point (${href}) is not under /docs/`);
}
});
test('the brand supplies the two Project links rather than the code', () => {
const project = columns.find((c) => c.heading === 'Project');
const hrefs = project.links.map((l) => l.href);
assert.ok(hrefs.includes(brand.giteaOrg), 'the Source link no longer reads brand.giteaOrg');
assert.ok(hrefs.includes(brand.discordInvite), 'the Discord link no longer reads brand.discordInvite');
});