This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
// ヘルプの「飛び先の見出し」検証が本当に効くことを守るテスト (#1274)。
|
||||
//
|
||||
// 守る対象は「いま何本壊れているか」ではなく、**壊したら赤くなる経路が残って
|
||||
// いること**。`#` から後ろを見ない作りに戻したら、ここが緑のままになる——それを
|
||||
// 防ぐために、同じ本文で「合っている / 合っていない」を撮り比べる。
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const script = join(repoRoot, 'scripts', 'validate-help-docs.mjs');
|
||||
|
||||
let dir: string;
|
||||
|
||||
function write(name: string, body: string) {
|
||||
writeFileSync(join(dir, name), body);
|
||||
}
|
||||
|
||||
function run() {
|
||||
const r = spawnSync(process.execPath, [script, dir], { encoding: 'utf8' });
|
||||
return { code: r.status, out: (r.stdout ?? '') + (r.stderr ?? '') };
|
||||
}
|
||||
|
||||
/** 飛び先になるページ。見出しの深さは 2 と 4 を混ぜてある(後述)。 */
|
||||
const TARGET = `---
|
||||
id: target
|
||||
title: 飛び先
|
||||
category: basic
|
||||
order: 1
|
||||
---
|
||||
|
||||
## 接続を切ったとき、置き場の側はどうなるか
|
||||
|
||||
本文。
|
||||
|
||||
#### 深い見出しにも id は付きます
|
||||
|
||||
本文。
|
||||
`;
|
||||
|
||||
/** 同じページの中だけで完結する本文。見出しとそこへのリンクを 1 本ずつ持つ。 */
|
||||
function selfPage(link: string) {
|
||||
return `---
|
||||
id: self
|
||||
title: 同じページ
|
||||
category: basic
|
||||
order: 3
|
||||
---
|
||||
|
||||
## 書き換わったら、押さなくても切り替わります
|
||||
|
||||
続きは [上の節](${link}) を参照。
|
||||
`;
|
||||
}
|
||||
|
||||
function source(link: string) {
|
||||
return `---
|
||||
id: source
|
||||
title: 出どころ
|
||||
category: basic
|
||||
order: 2
|
||||
---
|
||||
|
||||
案内は [こちら](${link}) にあります。
|
||||
`;
|
||||
}
|
||||
|
||||
describe('validate-help-docs.mjs の飛び先検証', () => {
|
||||
beforeEach(() => { dir = mkdtempSync(join(tmpdir(), 'help-docs-')); });
|
||||
afterEach(() => { rmSync(dir, { recursive: true, force: true }); });
|
||||
|
||||
it('見出しと合っているリンクは通す', () => {
|
||||
write('01-target.md', TARGET);
|
||||
write('02-source.md', source('./01-target.md#接続を切ったとき-置き場の側はどうなるか'));
|
||||
const { code, out } = run();
|
||||
expect(out).toContain('help-docs validation OK');
|
||||
expect(code).toBe(0);
|
||||
});
|
||||
|
||||
it('見出しと合っていないリンクを、ファイル名・行番号・リンクの文字列つきで落とす', () => {
|
||||
write('01-target.md', TARGET);
|
||||
// 見出しの文言が変わったのにリンクが追いついていない、という壊れ方。
|
||||
write('02-source.md', source('./01-target.md#接続を切ったとき置き場の側はどうなるか'));
|
||||
const { code, out } = run();
|
||||
expect(code).toBe(1);
|
||||
expect(out).toContain('02-source.md:8:');
|
||||
expect(out).toContain('](./01-target.md#接続を切ったとき置き場の側はどうなるか)');
|
||||
expect(out).toContain("no heading '#接続を切ったとき置き場の側はどうなるか' in 01-target.md");
|
||||
});
|
||||
|
||||
it('h2/h3 以外の見出しへのリンクも通す(画面は深さによらず id を付けるため)', () => {
|
||||
write('01-target.md', TARGET);
|
||||
write('02-source.md', source('./01-target.md#深い見出しにも-id-は付きます'));
|
||||
const { code } = run();
|
||||
expect(code).toBe(0);
|
||||
});
|
||||
|
||||
it('同じページの中のリンクも、見出しと合っていれば通す', () => {
|
||||
write('03-self.md', selfPage('#書き換わったら-押さなくても切り替わります'));
|
||||
const { code, out } = run();
|
||||
expect(out).toContain('help-docs validation OK');
|
||||
expect(code).toBe(0);
|
||||
});
|
||||
|
||||
it('同じページの中のリンクも、合っていなければ名指しして落とす', () => {
|
||||
write('03-self.md', selfPage('#書き換わったら押さなくても切り替わります'));
|
||||
const { code, out } = run();
|
||||
expect(code).toBe(1);
|
||||
expect(out).toContain('03-self.md:10:');
|
||||
expect(out).toContain('](#書き換わったら押さなくても切り替わります)');
|
||||
expect(out).toContain("no heading '#書き換わったら押さなくても切り替わります' in 03-self.md");
|
||||
});
|
||||
|
||||
it('リンク先のファイルが無いときは、これまでどおり落とす', () => {
|
||||
write('01-target.md', TARGET);
|
||||
write('02-source.md', source('./99-missing.md#どこか'));
|
||||
const { code, out } = run();
|
||||
expect(code).toBe(1);
|
||||
expect(out).toContain('target file not found');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user