@7n/test 0.7.1 → 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 CHANGED
@@ -1,5 +1,11 @@
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
+
3
9
  ## [0.7.1] - 2026-06-27
4
10
 
5
11
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@7n/test",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "CLI-утиліта @7n/test",
5
5
  "keywords": [
6
6
  "7n",
@@ -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
@@ -73,10 +70,13 @@ function parseFailingTests(jsonPath, dir) {
73
70
  return `${name}:\n${msg}`
74
71
  })
75
72
  // Module-level errors (import/syntax) produce no assertionResults
76
- const errors = assertionErrors.length > 0
77
- ? assertionErrors
78
- : [`Suite error: ${(r.message ?? r.failureMessage ?? 'module-level failure').split('\n').slice(0, MAX_ERROR_LINES).join('\n')}`]
79
- return { file: relative(dir, r.testFilePath), errors }
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
80
  })
81
81
  .filter(f => !f.file.startsWith('..'))
82
82
  } catch {
@@ -140,8 +140,19 @@ export function getUncoveredFiles(files, threshold = 80) {
140
140
 
141
141
  const SOURCE_EXT_RE = /\.(mjs|js|ts|vue|py)$/
142
142
  const IGNORE_DIRS = new Set([
143
- 'node_modules', 'dist', 'build', 'out', '.git', '__pycache__',
144
- 'coverage', '.cursor', '.claude', '.pi', 'docs', 'bin', 'reports'
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'
145
156
  ])
146
157
 
147
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(process.execPath, [VITEST_BIN, 'run', '--reporter=json', `--outputFile=${outputFile}`, '--passWithNoTests'], {
39
- cwd: dir,
40
- stdio: 'inherit',
41
- env
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
- file: relative(dir, r.testFilePath),
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
- .filter(f => !f.file.startsWith('..') && f.errors.length > 0)
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
  }