refactor: move broken fixtures into skill directory, remove global fixtures/

fixture: paths now resolve relative to skill's cases/ dir, not global.
Each validate skill keeps its broken fixtures locally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-03-28 13:31:34 +03:00
parent 671be7c6b5
commit 74b3f76a32
4 changed files with 9 additions and 9 deletions
+3 -4
View File
@@ -52,7 +52,7 @@ Exit code: 0 = все прошли, 1 = есть падения.
| Поле | Описание |
|---|---|
| `script` | Путь от `.claude/skills/`, без расширения. Раннер добавит `.ps1` (по умолчанию) или `.py` |
| `setup` | Фикстура: `"empty-config"`, `"base-config"`, `"none"`, `"fixture:<name>"` |
| `setup` | Фикстура: `"empty-config"`, `"base-config"`, `"none"`, `"fixture:<name>"` (из `fixtures/` папки навыка) |
| `args` | Маппинг параметров навыка (см. ниже) |
| `snapshot` | Настройки сравнения: `root` (`"workDir"` или `"outputPath"`) и `normalizeUuids` |
@@ -184,13 +184,12 @@ tests/skills/
runner.mjs # тест-раннер
README.md # этот файл
.cache/ # кэш фикстур (в .gitignore)
fixtures/ # broken-фикстуры для тестов валидаторов
broken/
<имя>/ # сломанный XML для негативных тестов validate-навыков
cases/
<навык>/
_skill.json # конфиг навыка
<кейс>.json # тестовый случай
snapshots/
<кейс>/ # эталон
fixtures/ # broken-фикстуры (для validate-навыков)
<имя>/ # сломанный XML, ссылка: "setup": "fixture:<имя>"
```
@@ -1,6 +1,6 @@
{
"name": "Валидатор находит ошибку: неверный корневой элемент",
"setup": "fixture:broken/catalog-bad-root",
"setup": "fixture:catalog-bad-root",
"params": { "objectPath": "Catalogs/Bad.xml" },
"expectError": true
}
+5 -4
View File
@@ -15,7 +15,6 @@ const REPO_ROOT = resolve(ROOT, '../..');
const SKILLS = resolve(REPO_ROOT, '.claude/skills');
const CASES = resolve(ROOT, 'cases');
const CACHE = resolve(ROOT, '.cache');
const FIXTURES = resolve(ROOT, 'fixtures');
// ─── CLI args ───────────────────────────────────────────────────────────────
@@ -80,11 +79,12 @@ function discoverCases(filter) {
// ─── Setup / Fixtures ───────────────────────────────────────────────────────
function ensureSetup(setupName, runtime) {
function ensureSetup(setupName, runtime, skillCasesDir) {
if (setupName === 'none' || !setupName) return null;
if (setupName.startsWith('fixture:')) {
const fixturePath = join(FIXTURES, setupName.slice('fixture:'.length));
// Resolve relative to skill's cases directory (e.g. cases/meta-validate/fixtures/...)
const fixturePath = join(skillCasesDir, 'fixtures', setupName.slice('fixture:'.length));
if (!existsSync(fixturePath)) throw new Error(`Fixture not found: ${fixturePath}`);
return fixturePath;
}
@@ -331,7 +331,8 @@ function runCase(testCase, opts) {
try {
// 1. Setup workspace
const fixturePath = ensureSetup(setupName, opts.runtime);
const skillCasesDir = join(CASES, testCase.skillDir);
const fixturePath = ensureSetup(setupName, opts.runtime, skillCasesDir);
workDir = createWorkspace(fixturePath);
// 2. Pre-run steps (setup prerequisites like creating objects)