|
| 1 | +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. |
| 2 | + |
| 3 | +/** |
| 4 | + * Pin for the category-overview card grid — WHICH pages |
| 5 | + * `content/docs/references/<cat>/index.mdx` cards (#11260). |
| 6 | + * |
| 7 | + * THE DEFECT THIS PINS. `build-docs.ts` wrote a category's `meta.json` from the |
| 8 | + * pages it had just emitted, and that category's card grid from a second, |
| 9 | + * independently derived list: the `.zod.ts` files on disk. The `misc` catch-all |
| 10 | + * — where a published schema that no `.zod.ts` accounts for lands — has no |
| 11 | + * `.zod.ts` behind it by definition, so it was structurally absent from the |
| 12 | + * second list. Measured on `origin/main`: `security/meta.json` declared five |
| 13 | + * pages, the grid carded four, and `misc.mdx` was generated, routed in the |
| 14 | + * sidebar, and unreachable from the category overview. The card loop's own |
| 15 | + * comment claimed "This aligns the index with `meta.json`" — true only for the |
| 16 | + * 13 categories where the two enumerations happened to agree. |
| 17 | + * |
| 18 | + * WHY A UNIT TEST, rather than the regenerated `.mdx` alone. Two reasons, and |
| 19 | + * the second is the load-bearing one: |
| 20 | + * |
| 21 | + * - the defect's output is an ABSENT card. `check:docs` compares generated |
| 22 | + * output to committed output, so a card that was never emitted is green |
| 23 | + * forever — which is how this survived until someone diffed the grid against |
| 24 | + * the `meta.json` beside it; |
| 25 | + * - the edge the card asked to verify — a category whose pages are ALL `misc` |
| 26 | + * — HAS NO INSTANCE in the repo, so no emitted file can pin it in either |
| 27 | + * direction. Under the old loop it would have rendered an EMPTY `<Cards>` |
| 28 | + * grid: every zod-derived slug filtered out by `wasEmitted`, and `misc` |
| 29 | + * never considered. Asserting on a category that does not exist requires the |
| 30 | + * rule to be out of the side-effecting script (the move #7658 and #4912 made |
| 31 | + * for `schema-section.ts` and `format-type.ts`). |
| 32 | + */ |
| 33 | + |
| 34 | +import { describe, expect, it } from 'vitest'; |
| 35 | + |
| 36 | +import { categoryGrid } from './lib/category-index'; |
| 37 | + |
| 38 | +/** Every page emitted — the healthy case, where `meta.json` cannot over-declare. */ |
| 39 | +const allEmitted = () => true; |
| 40 | + |
| 41 | +describe('categoryGrid — the pages a category overview cards (#11260)', () => { |
| 42 | + it('cards `misc`, the page with no `.zod.ts` behind it', () => { |
| 43 | + // The exact shape measured on `origin/main`: security/ declares five pages, |
| 44 | + // one of which (`misc`) no source-derived enumeration can contain. |
| 45 | + const declared = ['explain', 'misc', 'permission', 'rls', 'sharing']; |
| 46 | + |
| 47 | + const { cards, undelivered } = categoryGrid(declared, allEmitted); |
| 48 | + |
| 49 | + expect(cards).toEqual(['explain', 'misc', 'permission', 'rls', 'sharing']); |
| 50 | + expect(undelivered).toEqual([]); |
| 51 | + }); |
| 52 | + |
| 53 | + it('cards every page `meta.json` declares, so the grid and the sidebar cannot disagree', () => { |
| 54 | + const declared = ['---Section One---', 'beta', 'alpha', '---Section Two---', 'gamma']; |
| 55 | + |
| 56 | + const { cards } = categoryGrid(declared, allEmitted); |
| 57 | + |
| 58 | + // Separators are sidebar headings, not pages — never carded. |
| 59 | + expect(cards).toEqual(['alpha', 'beta', 'gamma']); |
| 60 | + }); |
| 61 | + |
| 62 | + it('orders cards alphabetically, not in `meta.json` section order', () => { |
| 63 | + // The grid's order is the one the pre-fix `Array.from(zodFiles).sort()` |
| 64 | + // produced. Pinned because taking `meta.json`'s order instead would reshuffle |
| 65 | + // all 13 grids that were already correct — a fix to WHICH pages are carded |
| 66 | + // must not also churn the ones it is not fixing. |
| 67 | + const declared = ['---Grouped---', 'zebra', 'alpha', '---More---', 'middle']; |
| 68 | + |
| 69 | + expect(categoryGrid(declared, allEmitted).cards).toEqual(['alpha', 'middle', 'zebra']); |
| 70 | + }); |
| 71 | + |
| 72 | + it('does not card a page this run did not emit — it reports it', () => { |
| 73 | + // The `wasEmitted` guard is KEPT: a `.zod.ts` whose schemas are all |
| 74 | + // unrepresentable in JSON Schema generates no page, and carding it would be |
| 75 | + // a dangling 404. What changed is that dropping a declared page is now |
| 76 | + // reported rather than silent — silence is what shipped the `misc` bug. |
| 77 | + const declared = ['delivered', 'unrepresentable']; |
| 78 | + |
| 79 | + const { cards, undelivered } = categoryGrid(declared, page => page !== 'unrepresentable'); |
| 80 | + |
| 81 | + expect(cards).toEqual(['delivered']); |
| 82 | + expect(undelivered).toEqual(['unrepresentable']); |
| 83 | + }); |
| 84 | + |
| 85 | + describe('the all-`misc` category — no instance in the repo, so only assertable here', () => { |
| 86 | + it('cards `misc` rather than rendering an empty grid', () => { |
| 87 | + // A category whose every published schema falls to the catch-all. The old |
| 88 | + // loop iterated the `.zod.ts` slugs, all of which produced no page, and |
| 89 | + // emitted `<Cards>\n</Cards>` — an overview linking nowhere, for a folder |
| 90 | + // whose one page is routed in the sidebar. |
| 91 | + const { cards, undelivered } = categoryGrid(['misc'], allEmitted); |
| 92 | + |
| 93 | + expect(cards).toEqual(['misc']); |
| 94 | + expect(cards).not.toHaveLength(0); |
| 95 | + expect(undelivered).toEqual([]); |
| 96 | + }); |
| 97 | + |
| 98 | + it('cannot produce an empty grid from a non-empty declaration without saying so', () => { |
| 99 | + // The invariant the caller enforces: declared pages in, at least one card |
| 100 | + // out — or `undelivered` names what went missing and the build stops. |
| 101 | + // Every way of reaching an empty grid passes through this list. |
| 102 | + const { cards, undelivered } = categoryGrid(['misc'], () => false); |
| 103 | + |
| 104 | + expect(cards).toEqual([]); |
| 105 | + expect(undelivered).toEqual(['misc']); |
| 106 | + }); |
| 107 | + }); |
| 108 | + |
| 109 | + it('declares nothing for a category with no pages', () => { |
| 110 | + // §2 writes no `meta.json` for a category that published no page, so §2.5 |
| 111 | + // writes no `index.mdx` — the overview exists exactly when the pages do. |
| 112 | + expect(categoryGrid([], allEmitted)).toEqual({ cards: [], undelivered: [] }); |
| 113 | + expect(categoryGrid(['---Empty Section---'], allEmitted).cards).toEqual([]); |
| 114 | + }); |
| 115 | +}); |
0 commit comments