@7n/test 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/src/coverage-per-file.mjs +26 -11
- package/src/fix-tests.mjs +18 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.2] - 2026-06-27
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Виправлено парсинг JSON-репорту vitest 4.x: поле `name` замість `testFilePath` (breaking change у vitest JSON reporter). Наслідок: падаючі тести тепер коректно детектуються і передаються у fix-loop замість bootstrap.
|
|
8
|
+
|
|
9
|
+
## [0.7.1] - 2026-06-27
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- `parseFailingTests` тепер коректно обробляє module-level помилки (import/syntax errors) — тести, що падають ще до запуску (`assertionResults: []`), більше не пропускаються, що усувало нескінченну bootstrap-петлю.
|
|
14
|
+
|
|
3
15
|
## [0.7.0] - 2026-06-27
|
|
4
16
|
|
|
5
17
|
### Added
|
package/package.json
CHANGED
|
@@ -13,10 +13,7 @@ import { join, relative, dirname } from 'node:path'
|
|
|
13
13
|
import { env } from 'node:process'
|
|
14
14
|
|
|
15
15
|
const _require = createRequire(import.meta.url)
|
|
16
|
-
const VITEST_BIN = join(
|
|
17
|
-
dirname(_require.resolve('vitest/package.json')),
|
|
18
|
-
'vitest.mjs'
|
|
19
|
-
)
|
|
16
|
+
const VITEST_BIN = join(dirname(_require.resolve('vitest/package.json')), 'vitest.mjs')
|
|
20
17
|
|
|
21
18
|
const TEST_FILE_RE = /\.(test|spec)\.[^.]+$|[/\\]tests?[/\\]/
|
|
22
19
|
const MAX_ERRORS_PER_FILE = 5
|
|
@@ -63,9 +60,8 @@ function parseFailingTests(jsonPath, dir) {
|
|
|
63
60
|
const data = JSON.parse(readFileSync(jsonPath, 'utf8'))
|
|
64
61
|
return (data.testResults ?? [])
|
|
65
62
|
.filter(r => r.status === 'failed')
|
|
66
|
-
.map(r =>
|
|
67
|
-
|
|
68
|
-
errors: (r.assertionResults ?? [])
|
|
63
|
+
.map(r => {
|
|
64
|
+
const assertionErrors = (r.assertionResults ?? [])
|
|
69
65
|
.filter(a => a.status === 'failed')
|
|
70
66
|
.slice(0, MAX_ERRORS_PER_FILE)
|
|
71
67
|
.map(a => {
|
|
@@ -73,8 +69,16 @@ function parseFailingTests(jsonPath, dir) {
|
|
|
73
69
|
const msg = (a.failureMessages?.[0] ?? '').split('\n').slice(0, MAX_ERROR_LINES).join('\n')
|
|
74
70
|
return `${name}:\n${msg}`
|
|
75
71
|
})
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
// Module-level errors (import/syntax) produce no assertionResults
|
|
73
|
+
const errors =
|
|
74
|
+
assertionErrors.length > 0
|
|
75
|
+
? assertionErrors
|
|
76
|
+
: [
|
|
77
|
+
`Suite error: ${(r.message ?? r.failureMessage ?? 'module-level failure').split('\n').slice(0, MAX_ERROR_LINES).join('\n')}`
|
|
78
|
+
]
|
|
79
|
+
return { file: relative(dir, r.testFilePath ?? r.name), errors }
|
|
80
|
+
})
|
|
81
|
+
.filter(f => !f.file.startsWith('..'))
|
|
78
82
|
} catch {
|
|
79
83
|
return []
|
|
80
84
|
}
|
|
@@ -136,8 +140,19 @@ export function getUncoveredFiles(files, threshold = 80) {
|
|
|
136
140
|
|
|
137
141
|
const SOURCE_EXT_RE = /\.(mjs|js|ts|vue|py)$/
|
|
138
142
|
const IGNORE_DIRS = new Set([
|
|
139
|
-
'node_modules',
|
|
140
|
-
'
|
|
143
|
+
'node_modules',
|
|
144
|
+
'dist',
|
|
145
|
+
'build',
|
|
146
|
+
'out',
|
|
147
|
+
'.git',
|
|
148
|
+
'__pycache__',
|
|
149
|
+
'coverage',
|
|
150
|
+
'.cursor',
|
|
151
|
+
'.claude',
|
|
152
|
+
'.pi',
|
|
153
|
+
'docs',
|
|
154
|
+
'bin',
|
|
155
|
+
'reports'
|
|
141
156
|
])
|
|
142
157
|
|
|
143
158
|
/**
|
package/src/fix-tests.mjs
CHANGED
|
@@ -16,10 +16,7 @@ import { join, relative, dirname } from 'node:path'
|
|
|
16
16
|
import { env } from 'node:process'
|
|
17
17
|
|
|
18
18
|
const _require = createRequire(import.meta.url)
|
|
19
|
-
const VITEST_BIN = join(
|
|
20
|
-
dirname(_require.resolve('vitest/package.json')),
|
|
21
|
-
'vitest.mjs'
|
|
22
|
-
)
|
|
19
|
+
const VITEST_BIN = join(dirname(_require.resolve('vitest/package.json')), 'vitest.mjs')
|
|
23
20
|
|
|
24
21
|
const MODEL = env.N_CURSOR_FIX_TESTS_MODEL ?? env.N_CLOUD_MAX_MODEL ?? ''
|
|
25
22
|
const MAX_ERRORS_PER_FILE = 5
|
|
@@ -35,11 +32,15 @@ export async function getFailingTests(dir) {
|
|
|
35
32
|
const outputFile = join(tmpDir, 'results.json')
|
|
36
33
|
|
|
37
34
|
try {
|
|
38
|
-
spawnSync(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
spawnSync(
|
|
36
|
+
process.execPath,
|
|
37
|
+
[VITEST_BIN, 'run', '--reporter=json', `--outputFile=${outputFile}`, '--passWithNoTests'],
|
|
38
|
+
{
|
|
39
|
+
cwd: dir,
|
|
40
|
+
stdio: 'inherit',
|
|
41
|
+
env
|
|
42
|
+
}
|
|
43
|
+
)
|
|
43
44
|
|
|
44
45
|
if (!existsSync(outputFile)) return []
|
|
45
46
|
|
|
@@ -52,9 +53,8 @@ export async function getFailingTests(dir) {
|
|
|
52
53
|
|
|
53
54
|
return (data.testResults ?? [])
|
|
54
55
|
.filter(r => r.status === 'failed')
|
|
55
|
-
.map(r =>
|
|
56
|
-
|
|
57
|
-
errors: (r.assertionResults ?? [])
|
|
56
|
+
.map(r => {
|
|
57
|
+
const assertionErrors = (r.assertionResults ?? [])
|
|
58
58
|
.filter(a => a.status === 'failed')
|
|
59
59
|
.slice(0, MAX_ERRORS_PER_FILE)
|
|
60
60
|
.map(a => {
|
|
@@ -62,8 +62,12 @@ export async function getFailingTests(dir) {
|
|
|
62
62
|
const msg = (a.failureMessages?.[0] ?? '').split('\n').slice(0, MAX_ERROR_LINES).join('\n')
|
|
63
63
|
return `${name}:\n${msg}`
|
|
64
64
|
})
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
const errors = assertionErrors.length > 0
|
|
66
|
+
? assertionErrors
|
|
67
|
+
: [`Suite error: ${(r.message ?? r.failureMessage ?? 'module-level failure').split('\n').slice(0, MAX_ERROR_LINES).join('\n')}`]
|
|
68
|
+
return { file: relative(dir, r.testFilePath ?? r.name), errors }
|
|
69
|
+
})
|
|
70
|
+
.filter(f => !f.file.startsWith('..'))
|
|
67
71
|
} finally {
|
|
68
72
|
await rm(tmpDir, { recursive: true, force: true }).catch(() => {})
|
|
69
73
|
}
|