import { describe, expect, it } from 'vitest' import { createHelpFixture } from '@/test/helpFixtures' describe ('Help file catalogue', () => { it.each ([['Éclair', 'eclair'], ['home', 'HOME'], ['e\u0301clair', 'Éclair']]) ( 'compares title %s and %s equally at primary strength', (a, b) => { const { api } = createHelpFixture () expect (api.compareHelpTitles (a, b)).toBe (0) }) it ('orders distinct Latin titles in both directions', () => { const { api } = createHelpFixture () expect (api.compareHelpTitles ('Apple', 'Zebra')).toBeLessThan (0) expect (api.compareHelpTitles ('Zebra', 'Apple')).toBeGreaterThan (0) }) it.each ([['ほーむ', 'ホーム'], ['ホーム', 'ほーむ'], ['ホーム', 'ホーム'], ['ABC', 'abc'], ['ガイド', 'がいど']]) ( 'normalises search text %s and %s identically', (query, text) => { const { api } = createHelpFixture () expect (api.normaliseHelpSearchText (query)).toBe (api.normaliseHelpSearchText (text)) }) it.each ([['2026-10-02', null], ['2026-10-02.2', 2], ['2026-10-02.3', 3], ['2026-10-02.10', 10]] as const) ( 'separates the date and revision of %s', (edition, revision) => { const { api } = createHelpFixture () expect (api.parseHelpEdition (edition)).toEqual ({ date: '2026-10-02', revision }) const date = api.helpEditionDate (edition)! expect ([date.getFullYear (), date.getMonth (), date.getDate ()]).toEqual ([2026, 9, 2]) }) it.each (['missing', '2026-02-30', '2026-10-02.0', '2026-10-02.2.extra', '2026-10-02.9007199254740992']) ('rejects invalid edition %s', edition => { const { api } = createHelpFixture () expect (api.parseHelpEdition (edition)).toBeNull () expect (api.helpEditionDate (edition)).toBeNull () }) it ('compares numeric revision suffixes without losing the edition identifiers', () => { const { api } = createHelpFixture () expect (['2026-10-02.10', '2026-10-02.3', '2026-10-02', '2026-10-02.2'] .sort (api.compareHelpEditions)).toEqual ([ '2026-10-02', '2026-10-02.2', '2026-10-02.3', '2026-10-02.10']) }) it ('uses current_edition rather than the newest file, without YAML titles', async () => { const { api } = createHelpFixture () expect ((await api.getHelpArticle ('guide'))?.languages.ja.currentEdition) .toBe ('2026-10-02.10') expect (await api.getHelpSearchEntries ('ja')).toEqual ([ { identifier: 'guide', edition: '2026-10-02.10', title: 'ホーム第十版', body: '\nタグを検索する 第十版本文' }, { identifier: '設定 手順', edition: '2026-10-03', title: '設定', body: '\nタグを設定する' }]) }) it ('orders published editions numerically and separates languages', async () => { const { api } = createHelpFixture () expect (await api.getHelpEditions ('guide', 'ja')).toEqual ([ '2026-10-01', '2026-10-02', '2026-10-02.2', '2026-10-02.3', '2026-10-02.10']) expect (await api.getHelpEditions ('guide', 'en')).toEqual (['2026-10-02']) expect (await api.getHelpPublishedEditions ('guide', 'ja')) .not.toContain ('2026-10-02.11') }) it ('uses generated edition titles without reparsing raw sources', async () => { const { api, raw } = createHelpFixture () expect (await api.getHelpEditionText ('guide', 'ja', '2026-10-01')) .toEqual ({ title: '旧ホーム', body: '\n過去限定本文' }) raw['../../help/guide/editions/ja/2026-10-02.mdx'] .mockResolvedValue ('\uFEFF# 改題\r\n\r\n本文\r\n# 別見出し') expect (await api.getHelpEditionText ('guide', 'ja', '2026-10-02')) .toEqual ({ title: 'ホーム', body: '\nタグを検索する' }) expect (raw['../../help/guide/editions/ja/2026-10-02.mdx']).not.toHaveBeenCalled () expect ((await api.getHelpEditionSource ('guide', 'ja', '2026-10-02'))?.source) .toBe ('\uFEFF# 改題\r\n\r\n本文\r\n# 別見出し') }) it ('returns missing resources without substituting another edition', async () => { const { api } = createHelpFixture () expect (await api.getHelpArticle ('absent')).toBeNull () expect (await api.getHelpEditions ('absent', 'ja')).toEqual ([]) expect (await api.getHelpEdition ('guide', 'ja', 'missing')).toBeNull () expect (await api.getHelpEditionText ('guide', 'fr', '2026-10-02')).toBeNull () }) it ('reports generated search asset failures instead of hiding articles', async () => { const { api, loads } = createHelpFixture () loads.search.mockImplementationOnce (() => { throw new Error ('asset failure') }) await expect (api.getHelpSearchEntries ('ja')).rejects.toThrow ('asset failure') }) it ('reports raw loading failures and excludes unpublished editions', async () => { const { api, raw } = createHelpFixture () const loader = raw['../../help/guide/editions/ja/2026-10-02.mdx'] loader.mockRejectedValueOnce (new Error ('fixture failure')) await expect (api.getHelpEditionSource ('guide', 'ja', '2026-10-02')) .rejects.toThrow ('fixture failure') expect (await api.getHelpEdition ('guide', 'ja', '2026-10-02.11')).toBeNull () expect (await api.getHelpEditionSource ('guide', 'ja', '2026-10-02.11')).toBeNull () }) it ('compares raw H1 and body lines in the requested direction', async () => { const { api } = createHelpFixture () const forward = await api.getHelpDiff ('guide', 'ja', '2026-10-01', '2026-10-02.10') expect (forward?.from.title).toBe ('旧ホーム') expect (forward?.to.title).toBe ('ホーム第十版') expect (forward?.lines).toEqual (expect.arrayContaining ([ { type: 'removed', content: '# 旧ホーム\n' }, { type: 'added', content: '# ホーム第十版\n' }, { type: 'unchanged', content: '\n' }])) const reverse = await api.getHelpDiff ('guide', 'ja', '2026-10-02.10', '2026-10-01') expect (reverse?.lines).toEqual (expect.arrayContaining ([ { type: 'added', content: '# 旧ホーム\n' }, { type: 'removed', content: '# ホーム第十版\n' }])) }) it.each ([['missing', 'ja', '2026-10-01', '2026-10-02.10'], ['guide', 'ja', '2026-10-01', '2026-10-02.11'], ['guide', 'en', '2026-10-01', '2026-10-02']]) ( 'rejects invalid diff editions for %s/%s without reading sources', async (id, language, from, to) => { const { api, raw } = createHelpFixture () expect (await api.getHelpDiff (id, language, from, to)).toBeNull () Object.values (raw).forEach (load => expect (load).not.toHaveBeenCalled ()) }) })