test(runner): expectError больше не отключает файловые ожидания

Кейс с expectError и fileContains/fileNotContains/filesEqual/preserves проходил
при любом содержимом файла — проверки лежали под !expectError вместе со снэпшотом.
Под !expectError остались только снэпшот и идемпотентность: эталон с аварийного
состояния снимать нельзя, а файлы, написанные до отказа, проверять нужно.
Заодно во втором кодовом пути раннера не было filesEqual — пути выровнены.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013MQkqXxErBepYmoUycfkbn
This commit is contained in:
Nick Shirokov
2026-09-05 19:10:58 +03:00
co-authored by Claude Opus 5
parent 06bdee3e25
commit cc0b7d3b64
+17 -2
View File
@@ -958,7 +958,11 @@ async function runCaseAsync(testCase, opts) {
} }
} }
} }
if (!caseData.expectError) { // Файловые ожидания проверяются И У НЕГАТИВНОГО кейса: навык мог отказать, но до
// отказа что-то написать — именно это и проверяется. Под `!expectError` остаются только
// снэпшот и идемпотентность: эталон с аварийного состояния снимать нельзя. Раньше
// всё лежало под `!expectError`, и кейс с expectError + fileContains молча проходил
// при любом содержимом файла (тот же класс, что когда-то был со stdout).
if (caseData.expect?.preserves) { if (caseData.expect?.preserves) {
const specs = Array.isArray(caseData.expect.preserves) const specs = Array.isArray(caseData.expect.preserves)
? caseData.expect.preserves : [caseData.expect.preserves]; ? caseData.expect.preserves : [caseData.expect.preserves];
@@ -979,6 +983,7 @@ async function runCaseAsync(testCase, opts) {
? caseData.expect.fileNotContains : [caseData.expect.fileNotContains]; ? caseData.expect.fileNotContains : [caseData.expect.fileNotContains];
for (const spec of specs) errors.push(...checkFileContains(workDir, spec, false)); for (const spec of specs) errors.push(...checkFileContains(workDir, spec, false));
} }
if (!caseData.expectError) {
if (errors.length === 0 && !caseData.expectError && !workspace.readOnly) { if (errors.length === 0 && !caseData.expectError && !workspace.readOnly) {
const snapshotConfig = { ...skillConfig.snapshot, runtime: opts.runtime }; const snapshotConfig = { ...skillConfig.snapshot, runtime: opts.runtime };
if (opts.updateSnapshots) { if (opts.updateSnapshots) {
@@ -1197,12 +1202,21 @@ function runCase(testCase, opts) {
} }
} }
if (!caseData.expectError) { // Файловые ожидания проверяются И У НЕГАТИВНОГО кейса: навык мог отказать, но до
// отказа что-то написать — именно это и проверяется. Под `!expectError` остаются только
// снэпшот и идемпотентность: эталон с аварийного состояния снимать нельзя. Раньше
// всё лежало под `!expectError`, и кейс с expectError + fileContains молча проходил
// при любом содержимом файла (тот же класс, что когда-то был со stdout).
if (caseData.expect?.preserves) { if (caseData.expect?.preserves) {
const specs = Array.isArray(caseData.expect.preserves) const specs = Array.isArray(caseData.expect.preserves)
? caseData.expect.preserves : [caseData.expect.preserves]; ? caseData.expect.preserves : [caseData.expect.preserves];
for (const spec of specs) errors.push(...checkPreserves(workDir, spec)); for (const spec of specs) errors.push(...checkPreserves(workDir, spec));
} }
if (caseData.expect?.filesEqual) {
const specs = Array.isArray(caseData.expect.filesEqual)
? caseData.expect.filesEqual : [caseData.expect.filesEqual];
for (const spec of specs) errors.push(...checkFilesEqual(workDir, spec));
}
if (caseData.expect?.fileContains) { if (caseData.expect?.fileContains) {
const specs = Array.isArray(caseData.expect.fileContains) const specs = Array.isArray(caseData.expect.fileContains)
? caseData.expect.fileContains : [caseData.expect.fileContains]; ? caseData.expect.fileContains : [caseData.expect.fileContains];
@@ -1213,6 +1227,7 @@ function runCase(testCase, opts) {
? caseData.expect.fileNotContains : [caseData.expect.fileNotContains]; ? caseData.expect.fileNotContains : [caseData.expect.fileNotContains];
for (const spec of specs) errors.push(...checkFileContains(workDir, spec, false)); for (const spec of specs) errors.push(...checkFileContains(workDir, spec, false));
} }
if (!caseData.expectError) {
// Snapshot comparison (skip for external/read-only workspaces) // Snapshot comparison (skip for external/read-only workspaces)
if (errors.length === 0 && !caseData.expectError && !workspace.readOnly) { if (errors.length === 0 && !caseData.expectError && !workspace.readOnly) {