sxy-test-runner 2.5.3 → 2.5.4
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/AGENTS.md +7 -5
- package/dist/cli/lib/buildDependencyTree.d.ts +1 -2
- package/dist/cli/lib/buildDependencyTree.js +25 -23
- package/dist/cli/lib/buildDependencyTree.js.map +1 -1
- package/dist/cli/lib/buildDependencyTrees.d.ts +1 -2
- package/dist/cli/lib/buildDependencyTrees.js +18 -16
- package/dist/cli/lib/buildDependencyTrees.js.map +1 -1
- package/dist/cli/lib/makeDependencyGraph.d.ts +9 -0
- package/dist/cli/lib/makeDependencyGraph.js +191 -0
- package/dist/cli/lib/makeDependencyGraph.js.map +1 -0
- package/dist/cli/lib/watchFilesAndRunTestsNodeWatch.d.ts +3 -2
- package/dist/cli/lib/watchFilesAndRunTestsNodeWatch.js +21 -44
- package/dist/cli/lib/watchFilesAndRunTestsNodeWatch.js.map +1 -1
- package/dist/cli/watch.js +11 -11
- package/dist/cli/watch.js.map +1 -1
- package/package.json +7 -5
- package/readme.md +1 -1
package/AGENTS.md
CHANGED
|
@@ -335,8 +335,10 @@ predicted. On a small or fast suite it is often the better setting.
|
|
|
335
335
|
|
|
336
336
|
Important limitations:
|
|
337
337
|
|
|
338
|
-
-
|
|
339
|
-
|
|
338
|
+
- Dependency analysis finds `import()` only when its path is a plain string literal. A path
|
|
339
|
+
computed at runtime (`import(name)`, `import('./' + name)`), or written as a template
|
|
340
|
+
literal, is not found, so a test reached only that way is not rerun when its dependency
|
|
341
|
+
changes. `watch.dependencyEvaluation: false` avoids this.
|
|
340
342
|
- All reruns still share one long-lived process.
|
|
341
343
|
- A fresh ESM instance reloads the test's static module graph, but unrelated global state
|
|
342
344
|
and external resources remain the test author's responsibility.
|
|
@@ -469,9 +471,9 @@ maps it to a test. Either half can miss:
|
|
|
469
471
|
all**. The stream simply stays quiet, and the previous `done` remains the last word while
|
|
470
472
|
silently going stale.
|
|
471
473
|
- Even for a watched file, the changed-to-test mapping is the static import graph, so it
|
|
472
|
-
misses
|
|
473
|
-
that was neither changed nor already failing is not
|
|
474
|
-
`failing`. Setting `watch.dependencyEvaluation: false` removes this gap - every watched
|
|
474
|
+
misses imports whose path is computed at runtime and anything reached through a
|
|
475
|
+
`._cached_.*` boundary. A test file that was neither changed nor already failing is not
|
|
476
|
+
re-run, so a break in it never reaches `failing`. Setting `watch.dependencyEvaluation: false` removes this gap - every watched
|
|
475
477
|
change then reruns everything, and those runs report `covers=all`.
|
|
476
478
|
|
|
477
479
|
So `failing=0` means "nothing is known to be broken", not "everything passes", and silence
|
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import dependencyTree from 'dependency-tree'
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
// import dependencyTree from 'dependency-tree'
|
|
2
|
+
export {};
|
|
3
|
+
// import type { FinalConfig } from '../../types.js'
|
|
4
|
+
// import { debug } from '../../output.js'
|
|
5
|
+
// import slash from '../../packages/slash.js'
|
|
6
|
+
// export function buildDependencyTree(config: FinalConfig, filename: string): string[] {
|
|
7
|
+
// filename = slash(filename)
|
|
8
|
+
// const dependencyTreeConfig = {
|
|
9
|
+
// filename,
|
|
10
|
+
// isListForm: true,
|
|
11
|
+
// directory: config.watch.watchFilesBase,
|
|
12
|
+
// filter: (path: string) => path.indexOf('node_modules') === -1
|
|
13
|
+
// }
|
|
14
|
+
// // isListForm:true makes dependency-tree return a flat string[] at runtime,
|
|
15
|
+
// // which its shipped types don't model (they only type the tree-object form).
|
|
16
|
+
// const dt = dependencyTree(dependencyTreeConfig) as unknown as string[]
|
|
17
|
+
// // process the results into final format
|
|
18
|
+
// // (forward slashes and convert full path to rel path)
|
|
19
|
+
// const cwd = process.cwd()
|
|
20
|
+
// const processed = dt
|
|
21
|
+
// .map(file => slash(file).slice(cwd.length + 1))
|
|
22
|
+
// .filter(file => file !== filename) // remove the current file
|
|
23
|
+
// debug('found dep tree', processed)
|
|
24
|
+
// return processed
|
|
25
|
+
// }
|
|
24
26
|
//# sourceMappingURL=buildDependencyTree.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildDependencyTree.js","sourceRoot":"","sources":["../../../src/cli/lib/buildDependencyTree.ts"],"names":[],"mappings":"AACA,
|
|
1
|
+
{"version":3,"file":"buildDependencyTree.js","sourceRoot":"","sources":["../../../src/cli/lib/buildDependencyTree.ts"],"names":[],"mappings":"AACA,+CAA+C;;AAE/C,oDAAoD;AACpD,0CAA0C;AAC1C,8CAA8C;AAG9C,yFAAyF;AACzF,iCAAiC;AAEjC,qCAAqC;AACrC,oBAAoB;AACpB,4BAA4B;AAC5B,kDAAkD;AAClD,wEAAwE;AACxE,QAAQ;AAER,kFAAkF;AAClF,oFAAoF;AACpF,6EAA6E;AAE7E,+CAA+C;AAC/C,6DAA6D;AAC7D,gCAAgC;AAChC,2BAA2B;AAC3B,0DAA0D;AAC1D,wEAAwE;AAExE,yCAAyC;AAEzC,uBAAuB;AACvB,IAAI","sourcesContent":["\n// import dependencyTree from 'dependency-tree'\n\n// import type { FinalConfig } from '../../types.js'\n// import { debug } from '../../output.js'\n// import slash from '../../packages/slash.js'\n\n\n// export function buildDependencyTree(config: FinalConfig, filename: string): string[] {\n// filename = slash(filename)\n\n// const dependencyTreeConfig = {\n// filename,\n// isListForm: true,\n// directory: config.watch.watchFilesBase,\n// filter: (path: string) => path.indexOf('node_modules') === -1\n// }\n\n// // isListForm:true makes dependency-tree return a flat string[] at runtime,\n// // which its shipped types don't model (they only type the tree-object form).\n// const dt = dependencyTree(dependencyTreeConfig) as unknown as string[]\n\n// // process the results into final format\n// // (forward slashes and convert full path to rel path)\n// const cwd = process.cwd()\n// const processed = dt\n// .map(file => slash(file).slice(cwd.length + 1))\n// .filter(file => file !== filename) // remove the current file\n\n// debug('found dep tree', processed)\n\n// return processed\n// }\n"]}
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
// import type { FinalConfig, DependencyTrees } from '../../types.js'
|
|
2
|
+
// import { createTimeProfiler } from '../../packages/timeProfiler.js'
|
|
3
|
+
// import { showTimeProfiling } from '../../config.js'
|
|
4
|
+
// import { debug } from '../../output.js'
|
|
5
|
+
// import { buildDependencyTree } from './buildDependencyTree.js'
|
|
6
|
+
export {};
|
|
7
|
+
// const { timeProfile } = createTimeProfiler(showTimeProfiling)
|
|
8
|
+
// export function buildDependencyTrees(config: FinalConfig, testFiles: Set<string>): DependencyTrees {
|
|
9
|
+
// return timeProfile('build dependency trees', () => {
|
|
10
|
+
// const dependencyTrees: DependencyTrees = {}
|
|
11
|
+
// for (const testFile of testFiles) {
|
|
12
|
+
// const dependencyTree = buildDependencyTree(config, testFile)
|
|
13
|
+
// dependencyTrees[testFile] = dependencyTree
|
|
14
|
+
// debug('final dep tree', dependencyTrees[testFile])
|
|
15
|
+
// }
|
|
16
|
+
// return dependencyTrees
|
|
17
|
+
// })
|
|
18
|
+
// }
|
|
17
19
|
//# sourceMappingURL=buildDependencyTrees.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildDependencyTrees.js","sourceRoot":"","sources":["../../../src/cli/lib/buildDependencyTrees.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"buildDependencyTrees.js","sourceRoot":"","sources":["../../../src/cli/lib/buildDependencyTrees.ts"],"names":[],"mappings":"AACA,qEAAqE;AACrE,sEAAsE;AACtE,sDAAsD;AACtD,0CAA0C;AAC1C,iEAAiE;;AAGjE,gEAAgE;AAEhE,uGAAuG;AACvG,2DAA2D;AAC3D,sDAAsD;AAEtD,8CAA8C;AAC9C,2EAA2E;AAC3E,yDAAyD;AACzD,iEAAiE;AACjE,YAAY;AAEZ,iCAAiC;AACjC,SAAS;AACT,IAAI","sourcesContent":["\n// import type { FinalConfig, DependencyTrees } from '../../types.js'\n// import { createTimeProfiler } from '../../packages/timeProfiler.js'\n// import { showTimeProfiling } from '../../config.js'\n// import { debug } from '../../output.js'\n// import { buildDependencyTree } from './buildDependencyTree.js'\n\n\n// const { timeProfile } = createTimeProfiler(showTimeProfiling)\n\n// export function buildDependencyTrees(config: FinalConfig, testFiles: Set<string>): DependencyTrees {\n// return timeProfile('build dependency trees', () => {\n// const dependencyTrees: DependencyTrees = {}\n\n// for (const testFile of testFiles) {\n// const dependencyTree = buildDependencyTree(config, testFile)\n// dependencyTrees[testFile] = dependencyTree\n// debug('final dep tree', dependencyTrees[testFile])\n// }\n\n// return dependencyTrees\n// })\n// }\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FinalConfig } from '../../types.js';
|
|
2
|
+
export interface DependencyGraph {
|
|
3
|
+
addTest(file: string): void;
|
|
4
|
+
update(file: string): void;
|
|
5
|
+
remove(file: string): void;
|
|
6
|
+
testsAffectedBy(file: string): Set<string>;
|
|
7
|
+
}
|
|
8
|
+
export declare function makeDependencyGraph(config: FinalConfig, testFiles: Iterable<string>): DependencyGraph;
|
|
9
|
+
//# sourceMappingURL=makeDependencyGraph.d.ts.map
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { isBuiltin } from 'node:module';
|
|
3
|
+
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
4
|
+
import cabinet from 'filing-cabinet';
|
|
5
|
+
import precinct from 'sxy-precinct';
|
|
6
|
+
import slash from '../../packages/slash.js';
|
|
7
|
+
import { createTimeProfiler } from '../../packages/timeProfiler.js';
|
|
8
|
+
import { showTimeProfiling } from '../../config.js';
|
|
9
|
+
const { timeProfile } = createTimeProfiler(showTimeProfiling);
|
|
10
|
+
// precinct type per extension; undefined sniffs ESM vs CommonJS from the source
|
|
11
|
+
const precinctTypes = {
|
|
12
|
+
'.js': undefined, '.jsx': undefined,
|
|
13
|
+
'.mjs': 'es6', '.cjs': 'commonjs',
|
|
14
|
+
'.ts': 'ts', '.mts': 'ts', '.cts': 'ts', '.tsx': 'tsx'
|
|
15
|
+
};
|
|
16
|
+
for (const [extension, from] of [['.mjs', '.js'], ['.cjs', '.js'], ['.mts', '.ts'], ['.cts', '.ts']]) {
|
|
17
|
+
const lookup = cabinet.getLookup(from);
|
|
18
|
+
if (cabinet.getLookup(extension) === undefined && lookup !== undefined)
|
|
19
|
+
cabinet.register(extension, lookup);
|
|
20
|
+
}
|
|
21
|
+
function tryRealpath(path) {
|
|
22
|
+
try {
|
|
23
|
+
return realpathSync.native(path);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// paths in and out are relative to the cwd with forward slashes; edges are kept between real paths
|
|
30
|
+
export function makeDependencyGraph(config, testFiles) {
|
|
31
|
+
const cwd = realpathSync.native(process.cwd());
|
|
32
|
+
const directory = resolve(config.watch.watchFilesBase === '' ? '.' : config.watch.watchFilesBase);
|
|
33
|
+
const imports = new Map();
|
|
34
|
+
const importers = new Map();
|
|
35
|
+
const tests = new Set();
|
|
36
|
+
const toKey = (absolute) => slash(relative(cwd, absolute));
|
|
37
|
+
const toAbsolute = (key) => resolve(cwd, key);
|
|
38
|
+
// cleared by each operation, so a path created, deleted or relinked since is never served stale
|
|
39
|
+
const realCache = new Map();
|
|
40
|
+
const resolveCache = new Map();
|
|
41
|
+
const clearCaches = () => {
|
|
42
|
+
realCache.clear();
|
|
43
|
+
resolveCache.clear();
|
|
44
|
+
};
|
|
45
|
+
function realAbsolute(file) {
|
|
46
|
+
const absolute = resolve(file);
|
|
47
|
+
let real = realCache.get(absolute);
|
|
48
|
+
if (real === undefined) {
|
|
49
|
+
// a missing file's directory may still be reached through a link
|
|
50
|
+
real = tryRealpath(absolute)
|
|
51
|
+
?? join(tryRealpath(dirname(absolute)) ?? dirname(absolute), basename(absolute));
|
|
52
|
+
realCache.set(absolute, real);
|
|
53
|
+
}
|
|
54
|
+
return real;
|
|
55
|
+
}
|
|
56
|
+
const realKey = (file) => toKey(realAbsolute(file));
|
|
57
|
+
// undefined when the file does not parse, so its last known imports stand
|
|
58
|
+
function readImports(key) {
|
|
59
|
+
const filename = toAbsolute(key);
|
|
60
|
+
const extension = extname(filename);
|
|
61
|
+
if (!existsSync(filename) || !(extension in precinctTypes))
|
|
62
|
+
return new Set();
|
|
63
|
+
let specifiers;
|
|
64
|
+
try {
|
|
65
|
+
specifiers = precinct(readFileSync(filename, 'utf8'), {
|
|
66
|
+
type: precinctTypes[extension],
|
|
67
|
+
throwOnParseError: true,
|
|
68
|
+
es6: { mixedImports: true },
|
|
69
|
+
ts: { mixedImports: true },
|
|
70
|
+
tsx: { mixedImports: true }
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
// precinct only leaves an ast for content it sniffed; filing-cabinet otherwise parses again
|
|
77
|
+
const ast = precinctTypes[extension] === undefined ? precinct.ast ?? undefined : undefined;
|
|
78
|
+
const found = new Set();
|
|
79
|
+
for (const specifier of specifiers) {
|
|
80
|
+
if (isBuiltin(specifier))
|
|
81
|
+
continue;
|
|
82
|
+
const resolved = resolveImport(specifier, filename, ast);
|
|
83
|
+
if (resolved === null || slash(resolved).includes('/node_modules/'))
|
|
84
|
+
continue;
|
|
85
|
+
found.add(toKey(resolved));
|
|
86
|
+
}
|
|
87
|
+
return found;
|
|
88
|
+
}
|
|
89
|
+
// resolution depends only on the importer's directory and kind, so its neighbours share it
|
|
90
|
+
function resolveImport(specifier, filename, ast) {
|
|
91
|
+
const cacheKey = `${dirname(filename)}\0${extname(filename)}\0${specifier}`;
|
|
92
|
+
let result = resolveCache.get(cacheKey);
|
|
93
|
+
if (result === undefined) {
|
|
94
|
+
result = resolveUncached(specifier, filename, ast);
|
|
95
|
+
resolveCache.set(cacheKey, result);
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
function resolveUncached(specifier, filename, ast) {
|
|
100
|
+
let resolved = '';
|
|
101
|
+
try {
|
|
102
|
+
resolved = cabinet({ partial: specifier, filename, directory, ...(ast === undefined ? {} : { ast }) });
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// left unresolved
|
|
106
|
+
}
|
|
107
|
+
if (resolved !== '')
|
|
108
|
+
return realAbsolute(resolved);
|
|
109
|
+
// filing-cabinet resolves a missing file to '' - keep the edge so its creation is seen
|
|
110
|
+
if (specifier.startsWith('.') || isAbsolute(specifier)) {
|
|
111
|
+
return realAbsolute(resolve(dirname(filename), specifier));
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
function setImports(key, next) {
|
|
116
|
+
const previous = imports.get(key) ?? new Set();
|
|
117
|
+
for (const dep of previous.difference(next))
|
|
118
|
+
importers.get(dep)?.delete(key);
|
|
119
|
+
for (const dep of next.difference(previous)) {
|
|
120
|
+
let set = importers.get(dep);
|
|
121
|
+
if (set === undefined)
|
|
122
|
+
importers.set(dep, set = new Set());
|
|
123
|
+
set.add(key);
|
|
124
|
+
}
|
|
125
|
+
imports.set(key, next);
|
|
126
|
+
}
|
|
127
|
+
// re-reads `start`, then walks only into files never read before
|
|
128
|
+
function walk(start) {
|
|
129
|
+
const queue = [start];
|
|
130
|
+
const seen = new Set();
|
|
131
|
+
for (let key = queue.pop(); key !== undefined; key = queue.pop()) {
|
|
132
|
+
if (seen.has(key))
|
|
133
|
+
continue;
|
|
134
|
+
seen.add(key);
|
|
135
|
+
const found = readImports(key);
|
|
136
|
+
if (found === undefined) {
|
|
137
|
+
if (!imports.has(key))
|
|
138
|
+
imports.set(key, new Set());
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
setImports(key, found);
|
|
142
|
+
for (const dep of found)
|
|
143
|
+
if (!imports.has(dep))
|
|
144
|
+
queue.push(dep);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
timeProfile('build dependency graph', () => {
|
|
148
|
+
for (const file of testFiles) {
|
|
149
|
+
const key = realKey(file);
|
|
150
|
+
tests.add(key);
|
|
151
|
+
if (!imports.has(key))
|
|
152
|
+
walk(key);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
return {
|
|
156
|
+
addTest(file) {
|
|
157
|
+
clearCaches();
|
|
158
|
+
const key = realKey(file);
|
|
159
|
+
tests.add(key);
|
|
160
|
+
walk(key);
|
|
161
|
+
},
|
|
162
|
+
update(file) {
|
|
163
|
+
clearCaches();
|
|
164
|
+
walk(realKey(file));
|
|
165
|
+
},
|
|
166
|
+
remove(file) {
|
|
167
|
+
clearCaches();
|
|
168
|
+
const key = realKey(file);
|
|
169
|
+
tests.delete(key);
|
|
170
|
+
setImports(key, new Set());
|
|
171
|
+
},
|
|
172
|
+
testsAffectedBy(file) {
|
|
173
|
+
clearCaches();
|
|
174
|
+
const start = realKey(file);
|
|
175
|
+
const affected = new Set();
|
|
176
|
+
const queue = [start];
|
|
177
|
+
const seen = new Set();
|
|
178
|
+
for (let key = queue.pop(); key !== undefined; key = queue.pop()) {
|
|
179
|
+
if (seen.has(key))
|
|
180
|
+
continue;
|
|
181
|
+
seen.add(key);
|
|
182
|
+
if (tests.has(key))
|
|
183
|
+
affected.add(key);
|
|
184
|
+
for (const importer of importers.get(key) ?? [])
|
|
185
|
+
queue.push(importer);
|
|
186
|
+
}
|
|
187
|
+
return affected;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=makeDependencyGraph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"makeDependencyGraph.js","sourceRoot":"","sources":["../../../src/cli/lib/makeDependencyGraph.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport { existsSync, readFileSync, realpathSync } from 'node:fs'\nimport { isBuiltin } from 'node:module'\nimport { basename, dirname, extname, isAbsolute, join, relative, resolve } from 'node:path'\nimport cabinet from 'filing-cabinet'\nimport precinct from 'sxy-precinct'\n\nimport type { FinalConfig } from '../../types.js'\nimport slash from '../../packages/slash.js'\nimport { createTimeProfiler } from '../../packages/timeProfiler.js'\nimport { showTimeProfiling } from '../../config.js'\n\n\nconst { timeProfile } = createTimeProfiler(showTimeProfiling)\n\nexport interface DependencyGraph {\n addTest(file: string): void\n update(file: string): void\n remove(file: string): void\n testsAffectedBy(file: string): Set<string>\n}\n\n// precinct type per extension; undefined sniffs ESM vs CommonJS from the source\nconst precinctTypes: Record<string, string | undefined> = {\n '.js': undefined, '.jsx': undefined,\n '.mjs': 'es6', '.cjs': 'commonjs',\n '.ts': 'ts', '.mts': 'ts', '.cts': 'ts', '.tsx': 'tsx'\n}\n\nfor (const [extension, from] of [['.mjs', '.js'], ['.cjs', '.js'], ['.mts', '.ts'], ['.cts', '.ts']] as const) {\n const lookup = cabinet.getLookup(from)\n if (cabinet.getLookup(extension) === undefined && lookup !== undefined) cabinet.register(extension, lookup)\n}\n\nfunction tryRealpath(path: string): string | undefined {\n try {\n return realpathSync.native(path)\n } catch {\n return undefined\n }\n}\n\n// paths in and out are relative to the cwd with forward slashes; edges are kept between real paths\nexport function makeDependencyGraph(config: FinalConfig, testFiles: Iterable<string>): DependencyGraph {\n const cwd = realpathSync.native(process.cwd())\n const directory = resolve(config.watch.watchFilesBase === '' ? '.' : config.watch.watchFilesBase)\n\n const imports = new Map<string, Set<string>>()\n const importers = new Map<string, Set<string>>()\n const tests = new Set<string>()\n\n const toKey = (absolute: string): string => slash(relative(cwd, absolute))\n const toAbsolute = (key: string): string => resolve(cwd, key)\n\n // cleared by each operation, so a path created, deleted or relinked since is never served stale\n const realCache = new Map<string, string>()\n const resolveCache = new Map<string, string | null>()\n const clearCaches = (): void => {\n realCache.clear()\n resolveCache.clear()\n }\n function realAbsolute(file: string): string {\n const absolute = resolve(file)\n let real = realCache.get(absolute)\n if (real === undefined) {\n // a missing file's directory may still be reached through a link\n real = tryRealpath(absolute)\n ?? join(tryRealpath(dirname(absolute)) ?? dirname(absolute), basename(absolute))\n realCache.set(absolute, real)\n }\n return real\n }\n const realKey = (file: string): string => toKey(realAbsolute(file))\n\n // undefined when the file does not parse, so its last known imports stand\n function readImports(key: string): Set<string> | undefined {\n const filename = toAbsolute(key)\n const extension = extname(filename)\n if (!existsSync(filename) || !(extension in precinctTypes)) return new Set()\n\n let specifiers: string[]\n try {\n specifiers = precinct(readFileSync(filename, 'utf8'), {\n type: precinctTypes[extension],\n throwOnParseError: true,\n es6: { mixedImports: true },\n ts: { mixedImports: true },\n tsx: { mixedImports: true }\n })\n } catch {\n return undefined\n }\n // precinct only leaves an ast for content it sniffed; filing-cabinet otherwise parses again\n const ast = precinctTypes[extension] === undefined ? precinct.ast ?? undefined : undefined\n\n const found = new Set<string>()\n for (const specifier of specifiers) {\n if (isBuiltin(specifier)) continue\n const resolved = resolveImport(specifier, filename, ast)\n if (resolved === null || slash(resolved).includes('/node_modules/')) continue\n found.add(toKey(resolved))\n }\n return found\n }\n\n // resolution depends only on the importer's directory and kind, so its neighbours share it\n function resolveImport(specifier: string, filename: string, ast: object | undefined): string | null {\n const cacheKey = `${dirname(filename)}\\0${extname(filename)}\\0${specifier}`\n let result = resolveCache.get(cacheKey)\n if (result === undefined) {\n result = resolveUncached(specifier, filename, ast)\n resolveCache.set(cacheKey, result)\n }\n return result\n }\n\n function resolveUncached(specifier: string, filename: string, ast: object | undefined): string | null {\n let resolved = ''\n try {\n resolved = cabinet({ partial: specifier, filename, directory, ...(ast === undefined ? {} : { ast }) })\n } catch {\n // left unresolved\n }\n if (resolved !== '') return realAbsolute(resolved)\n // filing-cabinet resolves a missing file to '' - keep the edge so its creation is seen\n if (specifier.startsWith('.') || isAbsolute(specifier)) {\n return realAbsolute(resolve(dirname(filename), specifier))\n }\n return null\n }\n\n function setImports(key: string, next: Set<string>): void {\n const previous = imports.get(key) ?? new Set<string>()\n for (const dep of previous.difference(next)) importers.get(dep)?.delete(key)\n for (const dep of next.difference(previous)) {\n let set = importers.get(dep)\n if (set === undefined) importers.set(dep, set = new Set())\n set.add(key)\n }\n imports.set(key, next)\n }\n\n // re-reads `start`, then walks only into files never read before\n function walk(start: string): void {\n const queue = [start]\n const seen = new Set<string>()\n for (let key = queue.pop(); key !== undefined; key = queue.pop()) {\n if (seen.has(key)) continue\n seen.add(key)\n const found = readImports(key)\n if (found === undefined) {\n if (!imports.has(key)) imports.set(key, new Set())\n continue\n }\n setImports(key, found)\n for (const dep of found) if (!imports.has(dep)) queue.push(dep)\n }\n }\n\n timeProfile('build dependency graph', () => {\n for (const file of testFiles) {\n const key = realKey(file)\n tests.add(key)\n if (!imports.has(key)) walk(key)\n }\n })\n\n return {\n addTest(file) {\n clearCaches()\n const key = realKey(file)\n tests.add(key)\n walk(key)\n },\n update(file) {\n clearCaches()\n walk(realKey(file))\n },\n remove(file) {\n clearCaches()\n const key = realKey(file)\n tests.delete(key)\n setImports(key, new Set())\n },\n testsAffectedBy(file) {\n clearCaches()\n const start = realKey(file)\n const affected = new Set<string>()\n const queue = [start]\n const seen = new Set<string>()\n for (let key = queue.pop(); key !== undefined; key = queue.pop()) {\n if (seen.has(key)) continue\n seen.add(key)\n if (tests.has(key)) affected.add(key)\n for (const importer of importers.get(key) ?? []) queue.push(importer)\n }\n return affected\n }\n }\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { FinalConfig,
|
|
1
|
+
import type { FinalConfig, OutFn } from '../../types.js';
|
|
2
2
|
import type { TestExecutionFilters } from '../cliTypes.js';
|
|
3
3
|
import type { ReRunManager } from './reRunManager.js';
|
|
4
|
+
import type { DependencyGraph } from './makeDependencyGraph.js';
|
|
4
5
|
import type { StopFn } from '../watch.js';
|
|
5
|
-
export declare function watchFilesAndRunTestsNodeWatch(config: FinalConfig,
|
|
6
|
+
export declare function watchFilesAndRunTestsNodeWatch(config: FinalConfig, dependencyGraph: DependencyGraph | null, failingTests: string[], reRunManager: ReRunManager, customOut?: OutFn, executionFilters?: TestExecutionFilters): Promise<StopFn>;
|
|
6
7
|
//# sourceMappingURL=watchFilesAndRunTestsNodeWatch.d.ts.map
|
|
@@ -6,7 +6,6 @@ import { showTimeProfiling } from '../../config.js';
|
|
|
6
6
|
import { out as mainOut, log, debug } from '../../output.js';
|
|
7
7
|
import { agentChange } from './agentReport.js';
|
|
8
8
|
import { runTests } from './runTests.js';
|
|
9
|
-
import { buildDependencyTree } from './buildDependencyTree.js';
|
|
10
9
|
import { globArgCombine } from './globArgCombine.js';
|
|
11
10
|
import { addBasePath } from './addBasePath.js';
|
|
12
11
|
import { watchFilesNodeWatch } from './watchFilesNodeWatch.js';
|
|
@@ -14,10 +13,10 @@ import { filter } from './filter.js';
|
|
|
14
13
|
const { timeProfile, timeProfileAsync } = createTimeProfiler(showTimeProfiling);
|
|
15
14
|
export async function watchFilesAndRunTestsNodeWatch(config,
|
|
16
15
|
//testFiles: Set<string>,
|
|
17
|
-
|
|
16
|
+
// null when watch.dependencyEvaluation is off
|
|
17
|
+
dependencyGraph, failingTests, reRunManager,
|
|
18
18
|
//watchRunState: WatchRunState,
|
|
19
19
|
customOut, executionFilters = {}) {
|
|
20
|
-
const projectDir = process.cwd();
|
|
21
20
|
// agent mode passes a sink here, so its own change lines are the only ones printed
|
|
22
21
|
const out = customOut ?? mainOut;
|
|
23
22
|
return timeProfileAsync('init watching', async () => {
|
|
@@ -48,18 +47,11 @@ customOut, executionFilters = {}) {
|
|
|
48
47
|
function watchEvent(filename, event) {
|
|
49
48
|
debug('handle watch event ', filename, event);
|
|
50
49
|
filename = slash(filename);
|
|
51
|
-
//
|
|
50
|
+
// forget a deleted test, avoiding trying to run it later
|
|
52
51
|
if (event === 'remove') {
|
|
53
52
|
debug('removing test', filename);
|
|
54
53
|
reRunManager.state.withoutTests.delete(filename);
|
|
55
|
-
|
|
56
|
-
reRunManager.state.allTestFiles.delete(filename);
|
|
57
|
-
delete dependencyTrees[filename];
|
|
58
|
-
}
|
|
59
|
-
else if (!config.watch.dependencyEvaluation) {
|
|
60
|
-
// without trees there is nothing to look the file up in
|
|
61
|
-
reRunManager.state.allTestFiles.delete(filename);
|
|
62
|
-
}
|
|
54
|
+
reRunManager.state.allTestFiles.delete(filename);
|
|
63
55
|
}
|
|
64
56
|
// info on the event found
|
|
65
57
|
out(chalk.grey `change: ${filename} (${event})`);
|
|
@@ -75,47 +67,39 @@ customOut, executionFilters = {}) {
|
|
|
75
67
|
timeProfile('handle changed files', () => {
|
|
76
68
|
debug('changedFiles', changedFiles);
|
|
77
69
|
try {
|
|
70
|
+
// the whole batch is applied before any lookup, so an import added in one
|
|
71
|
+
// file can reach a file created in the same batch
|
|
72
|
+
if (dependencyGraph !== null) {
|
|
73
|
+
for (const [file, fileEvent] of changedFiles) {
|
|
74
|
+
if (fileEvent === 'remove')
|
|
75
|
+
dependencyGraph.remove(file);
|
|
76
|
+
else if (testFilter(file))
|
|
77
|
+
dependencyGraph.addTest(file);
|
|
78
|
+
else
|
|
79
|
+
dependencyGraph.update(file);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
78
82
|
// build related test list
|
|
79
|
-
//const tests: string[] = []
|
|
80
83
|
const tests = new Set;
|
|
81
84
|
for (const [file, fileEvent] of changedFiles) {
|
|
82
85
|
debug('check', file);
|
|
83
|
-
debug('1 tests', tests);
|
|
84
86
|
if (fileEvent !== 'remove') { // only check if it's a test if it exists (has not just been removed)
|
|
85
87
|
if (testFilter(file)) { // it is a test file itself, add to run list
|
|
86
88
|
debug('its a test', file);
|
|
87
|
-
//tests.push(file)
|
|
88
89
|
tests.add(file);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
debug('try to add a new test', file);
|
|
92
|
-
addNewTest(file);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
// no trees to record it in, so this is what makes a
|
|
97
|
-
// newly created test part of the run set
|
|
98
|
-
reRunManager.state.allTestFiles.add(file);
|
|
99
|
-
}
|
|
90
|
+
// makes a newly created test part of what `a` runs
|
|
91
|
+
reRunManager.state.allTestFiles.add(file);
|
|
100
92
|
}
|
|
101
93
|
}
|
|
102
94
|
// with evaluation off there is nothing to map the change through:
|
|
103
95
|
// any watched file could affect any test, so run the lot
|
|
104
|
-
if (
|
|
96
|
+
if (dependencyGraph === null) {
|
|
105
97
|
for (const f of reRunManager.state.allTestFiles)
|
|
106
98
|
tests.add(f);
|
|
107
99
|
continue;
|
|
108
100
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
for (const f of Object.getOwnPropertyNames(dependencyTrees)) {
|
|
112
|
-
debug('dep tree', f, dependencyTrees[f]);
|
|
113
|
-
if (dependencyTrees[f]?.some(dep => dep === file) === true) { // a test depends on this file
|
|
114
|
-
debug('its a dependency', file);
|
|
115
|
-
//tests.push(f)
|
|
116
|
-
tests.add(f);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
101
|
+
for (const f of dependencyGraph.testsAffectedBy(file))
|
|
102
|
+
tests.add(f);
|
|
119
103
|
}
|
|
120
104
|
changedFiles = [];
|
|
121
105
|
debug('tests', tests);
|
|
@@ -151,13 +135,6 @@ customOut, executionFilters = {}) {
|
|
|
151
135
|
});
|
|
152
136
|
}, debounceMs);
|
|
153
137
|
} // end of watch event
|
|
154
|
-
function addNewTest(testFile) {
|
|
155
|
-
debug('new test', testFile);
|
|
156
|
-
const dependencyTree = buildDependencyTree(config, testFile);
|
|
157
|
-
dependencyTrees[testFile] = dependencyTree
|
|
158
|
-
.map(file => slash(file).slice(projectDir.length + 1))
|
|
159
|
-
.filter(f => f !== testFile);
|
|
160
|
-
}
|
|
161
138
|
});
|
|
162
139
|
// NOTE: "watching..." is intentionally NOT printed here. watch() already emits it,
|
|
163
140
|
// tied to a real milestone (the initial test run finishing, or no tests found).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watchFilesAndRunTestsNodeWatch.js","sourceRoot":"","sources":["../../../src/cli/lib/watchFilesAndRunTestsNodeWatch.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAMvC,OAAO,KAAK,MAAM,yBAAyB,CAAA;AAC3C,OAAO,KAAK,MAAM,yBAAyB,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,GAAG,IAAI,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGpC,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;AAE/E,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAChD,MAAmB;AACnB,yBAAyB;AACzB,eAAgC,EAChC,YAAsB,EACtB,YAA0B;AAC1B,+BAA+B;AAC/B,SAAiB,EACjB,mBAAyC,EAAE;IAE3C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAChC,mFAAmF;IACnF,MAAM,GAAG,GAAG,SAAS,IAAI,OAAO,CAAA;IAEhC,OAAO,gBAAgB,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;QAChD,KAAK,CAAC,cAAc,EAAE,YAAY,CAAC,CAAA;QAEnC,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;QAC9D,MAAM,gBAAgB,GAAG,WAAW,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;QAE1E,wBAAwB;QACxB,MAAM,UAAU,GAAG,CAAC,IAAY,EAAW,EAAE;YACzC,OAAO,WAAW,CAAC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;mBAC7C,CAAC,WAAW,CAAC,IAAI,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAC;mBACpD,CACC,MAAM,CAAC,WAAW,KAAK,SAAS;uBAC7B,MAAM,CAAC,WAAW,KAAK,EAAE;uBACzB,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CACxD,CAAA;QACT,CAAC,CAAA;QAED,IAAI,YAAY,GAA4B,EAAE,CAAA;QAC9C,IAAI,OAAO,GAAyC,IAAI,CAAA;QAExD,IAAI,MAAM,CAAC,KAAK,CAAC,cAAc,KAAK,EAAE,EAAE,CAAC;YACrC,GAAG,CAAC,8DAA8D,CAAC,CAAA;YACnE,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,GAAG,CAAA;QACrC,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;QAC7D,OAAO,GAAG,EAAE;YACR,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,yEAAyE;YACzE,IAAI,OAAO;gBAAE,YAAY,CAAC,OAAO,CAAC,CAAA;QACtC,CAAC,CAAA;QAED,SAAS,UAAU,CAAC,QAAgB,EAAE,KAAa;YAC/C,KAAK,CAAC,qBAAqB,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA;YAE7C,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAA;YAE1B,kFAAkF;YAClF,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACrB,KAAK,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAA;gBAChC,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;gBAChD,IAAI,QAAQ,IAAI,eAAe,EAAE,CAAC;oBAC9B,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;oBAChD,OAAO,eAAe,CAAC,QAAQ,CAAC,CAAA;gBACpC,CAAC;qBAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC;oBAC5C,wDAAwD;oBACxD,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;gBACpD,CAAC;YACL,CAAC;YAED,0BAA0B;YAC1B,GAAG,CAAC,KAAK,CAAC,IAAI,CAAA,WAAW,QAAQ,KAAK,KAAK,GAAG,CAAC,CAAA;YAC/C,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA;YAEpC,gCAAgC;YAChC,YAAY,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAA;YAEpC,gBAAgB;YAChB,MAAM,UAAU,GAAG,EAAE,CAAA;YACrB,IAAI,OAAO,EAAE,CAAC;gBACV,YAAY,CAAC,OAAO,CAAC,CAAA;YACzB,CAAC;YACD,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBACtB,WAAW,CAAC,sBAAsB,EAAE,GAAG,EAAE;oBACrC,KAAK,CAAC,cAAc,EAAE,YAAY,CAAC,CAAA;oBACnC,IAAI,CAAC;wBACD,0BAA0B;wBAC1B,4BAA4B;wBAC5B,MAAM,KAAK,GAAG,IAAI,GAAW,CAAA;wBAC7B,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,YAAY,EAAE,CAAC;4BAC3C,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;4BACpB,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;4BACvB,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC,CAAC,qEAAqE;gCAC/F,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,4CAA4C;oCAChE,KAAK,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;oCACzB,kBAAkB;oCAClB,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;oCACf,IAAI,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC;wCACpC,IAAI,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC,EAAE,CAAC,CAAC,oBAAoB;4CAClD,KAAK,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAA;4CACpC,UAAU,CAAC,IAAI,CAAC,CAAA;wCACpB,CAAC;oCACL,CAAC;yCAAM,CAAC;wCACJ,oDAAoD;wCACpD,yCAAyC;wCACzC,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;oCAC7C,CAAC;gCACL,CAAC;4BACL,CAAC;4BAED,kEAAkE;4BAClE,yDAAyD;4BACzD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC;gCACrC,KAAK,MAAM,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,YAAY;oCAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;gCAC7D,SAAQ;4BACZ,CAAC;4BAED,KAAK,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAA;4BAChC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;4BACvB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,mBAAmB,CAAC,eAAe,CAAC,EAAE,CAAC;gCAC1D,KAAK,CAAC,UAAU,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAA;gCACxC,IAAI,eAAe,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,8BAA8B;oCACxF,KAAK,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAA;oCAC/B,eAAe;oCACf,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;gCAChB,CAAC;4BACL,CAAC;wBACL,CAAC;wBAED,YAAY,GAAG,EAAE,CAAA;wBAEjB,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;wBAErB,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;4BACjB,WAAW,CAAC,+CAA+C,EACvD,GAAG,EAAE;gCACD,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;gCACrB,KAAK,CAAC,mBAAmB,EAAE,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;gCAE1D,iEAAiE;gCACjE,iEAAiE;gCACjE,iDAAiD;gCACjD,YAAY,CAAC,KAAK,CAAC,aAAa;sCAC1B,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;gCAEnD,KAAK,YAAY,CAAC,UAAU,CACxB,MAAM,EACN,GAAG,EAAE;oCACD,wDAAwD;oCACxD,0DAA0D;oCAC1D,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC;wCAC3C,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,aAAa;6CACjC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,eAAe,CAAC;wCAC1C,CAAC,CAAC,IAAI,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;oCAE/C,wDAAwD;oCACxD,iDAAiD;oCACjD,YAAY,CAAC,KAAK,CAAC,aAAa,GAAG,IAAI,GAAG,EAAE,CAAA;oCAE5C,KAAK,CAAC,qBAAqB,CAAC,CAAA;oCAC5B,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;oCAEvB,OAAO,QAAQ,CACX,MAAM,EACN,MAAM,EACN,YAAY,EACZ,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EACb,SAAS,EACT,SAAS,EACT,gBAAgB,CACnB,CAAA;gCACL,CAAC,CACJ,CAAA;4BACL,CAAC,CACJ,CAAA;wBACL,CAAC;oBACL,CAAC;oBAAC,OAAO,CAAC,EAAE,CAAC;wBACT,GAAG,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAA;oBACjC,CAAC;gBACL,CAAC,CAAC,CAAA;YACN,CAAC,EAAE,UAAU,CAAC,CAAA;QAClB,CAAC,CAAC,qBAAqB;QAEvB,SAAS,UAAU,CAAC,QAAgB;YAChC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;YAC3B,MAAM,cAAc,GAAG,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;YAC5D,eAAe,CAAC,QAAQ,CAAC,GAAG,cAAc;iBACrC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;iBACrD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAA;QACpC,CAAC;IACL,CAAC,CAAC,CAAA;IAEF,mFAAmF;IACnF,gFAAgF;IAChF,8EAA8E;IAC9E,qCAAqC;AACzC,CAAC","sourcesContent":["\nimport { matchesGlob } from 'node:path'\n\nimport type { FinalConfig, DependencyTrees, OutFn } from '../../types.js'\nimport type { TestExecutionFilters } from '../cliTypes.js'\nimport type { ReRunManager } from './reRunManager.js'\nimport type { StopFn } from '../watch.js'\nimport chalk from '../../packages/chalk.js'\nimport slash from '../../packages/slash.js'\nimport { createTimeProfiler } from '../../packages/timeProfiler.js'\nimport { showTimeProfiling } from '../../config.js'\nimport { out as mainOut, log, debug } from '../../output.js'\nimport { agentChange } from './agentReport.js'\nimport { runTests } from './runTests.js'\nimport { buildDependencyTree } from './buildDependencyTree.js'\nimport { globArgCombine } from './globArgCombine.js'\nimport { addBasePath } from './addBasePath.js'\nimport { watchFilesNodeWatch } from './watchFilesNodeWatch.js'\nimport { filter } from './filter.js'\n\n\nconst { timeProfile, timeProfileAsync } = createTimeProfiler(showTimeProfiling)\n\nexport async function watchFilesAndRunTestsNodeWatch(\n config: FinalConfig,\n //testFiles: Set<string>,\n dependencyTrees: DependencyTrees,\n failingTests: string[],\n reRunManager: ReRunManager,\n //watchRunState: WatchRunState,\n customOut?: OutFn,\n executionFilters: TestExecutionFilters = {}\n): Promise<StopFn> {\n const projectDir = process.cwd()\n // agent mode passes a sink here, so its own change lines are the only ones printed\n const out = customOut ?? mainOut\n\n return timeProfileAsync('init watching', async () => {\n debug('failingTests', failingTests)\n\n const testsGlobs = addBasePath(config.testsBase, config.tests)\n const testsIgnoreGlobs = addBasePath(config.testsBase, config.testsIgnore)\n\n // indentify a test file\n const testFilter = (file: string): boolean => {\n return matchesGlob(file, globArgCombine(testsGlobs))\n && !matchesGlob(file, globArgCombine(testsIgnoreGlobs))\n && (\n config.testsFilter === undefined\n || config.testsFilter === ''\n || filter(config.testsBase, config.testsFilter, file)\n )\n }\n\n let changedFiles: Array<[string, string]> = []\n let timeout: ReturnType<typeof setTimeout> | null = null\n\n if (config.watch.watchFilesBase === '') {\n out('No config.watch.watchFilesBase provided, defaulting to \\'.\\'')\n config.watch.watchFilesBase = '.'\n }\n\n const watcher = await watchFilesNodeWatch(config, watchEvent)\n return () => {\n watcher.close()\n // a change seen just before stopping would otherwise still run its tests\n if (timeout) clearTimeout(timeout)\n }\n\n function watchEvent(filename: string, event: string): void {\n debug('handle watch event ', filename, event)\n\n filename = slash(filename)\n\n // remove dep tree for any tests that are deleted, avoiding trying to run it later\n if (event === 'remove') {\n debug('removing test', filename)\n reRunManager.state.withoutTests.delete(filename)\n if (filename in dependencyTrees) {\n reRunManager.state.allTestFiles.delete(filename)\n delete dependencyTrees[filename]\n } else if (!config.watch.dependencyEvaluation) {\n // without trees there is nothing to look the file up in\n reRunManager.state.allTestFiles.delete(filename)\n }\n }\n\n // info on the event found\n out(chalk.grey`change: ${filename} (${event})`)\n agentChange(config, filename, event)\n\n // add the file to changed files\n changedFiles.push([filename, event])\n\n // 33ms debounce\n const debounceMs = 33\n if (timeout) {\n clearTimeout(timeout)\n }\n timeout = setTimeout(() => {\n timeProfile('handle changed files', () => {\n debug('changedFiles', changedFiles)\n try {\n // build related test list\n //const tests: string[] = []\n const tests = new Set<string>\n for (const [file, fileEvent] of changedFiles) {\n debug('check', file)\n debug('1 tests', tests)\n if (fileEvent !== 'remove') { // only check if it's a test if it exists (has not just been removed)\n if (testFilter(file)) { // it is a test file itself, add to run list\n debug('its a test', file)\n //tests.push(file)\n tests.add(file)\n if (config.watch.dependencyEvaluation) {\n if (!(file in dependencyTrees)) { // if its a new test\n debug('try to add a new test', file)\n addNewTest(file)\n }\n } else {\n // no trees to record it in, so this is what makes a\n // newly created test part of the run set\n reRunManager.state.allTestFiles.add(file)\n }\n }\n }\n\n // with evaluation off there is nothing to map the change through:\n // any watched file could affect any test, so run the lot\n if (!config.watch.dependencyEvaluation) {\n for (const f of reRunManager.state.allTestFiles) tests.add(f)\n continue\n }\n\n debug('dtrees', dependencyTrees)\n debug('2 tests', tests)\n for (const f of Object.getOwnPropertyNames(dependencyTrees)) {\n debug('dep tree', f, dependencyTrees[f])\n if (dependencyTrees[f]?.some(dep => dep === file) === true) { // a test depends on this file\n debug('its a dependency', file)\n //tests.push(f)\n tests.add(f)\n }\n }\n }\n\n changedFiles = []\n\n debug('tests', tests)\n\n if (tests.size > 0) {\n timeProfile('build list of files to test and request a run',\n () => {\n debug('tests', tests)\n debug('reRunFailingTests', config.watch.reRunFailingTests)\n\n // changes accumulate here because an 'auto' request made while a\n // run is in flight is coalesced into the queued one - everything\n // edited in the meantime still has to be covered\n reRunManager.state.untestedFiles\n = reRunManager.state.untestedFiles.union(tests)\n\n void reRunManager.requestRun(\n 'auto',\n () => {\n // resolved when the run actually starts, not when it is\n // queued, so a coalesced request picks up the later edits\n const toTest = (config.watch.reRunFailingTests)\n ? reRunManager.state.untestedFiles\n .union(reRunManager.state.failedTestFiles)\n : new Set(reRunManager.state.untestedFiles)\n\n // consumed by this run - without this they are retested\n // on every later run for the rest of the session\n reRunManager.state.untestedFiles = new Set()\n\n debug('run tests on change')\n debug('toTest', toTest)\n\n return runTests(\n config,\n toTest,\n reRunManager,\n { limit: -1 },\n 'refresh',\n customOut,\n executionFilters\n )\n }\n )\n }\n )\n }\n } catch (e) {\n log('watch handler error', e)\n }\n })\n }, debounceMs)\n } // end of watch event\n\n function addNewTest(testFile: string): void {\n debug('new test', testFile)\n const dependencyTree = buildDependencyTree(config, testFile)\n dependencyTrees[testFile] = dependencyTree\n .map(file => slash(file).slice(projectDir.length + 1))\n .filter(f => f !== testFile)\n }\n })\n\n // NOTE: \"watching...\" is intentionally NOT printed here. watch() already emits it,\n // tied to a real milestone (the initial test run finishing, or no tests found).\n // Printing it again here produced a duplicate \"watching...\" on every startup.\n // out(chalk.brightblue`watching...`)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"watchFilesAndRunTestsNodeWatch.js","sourceRoot":"","sources":["../../../src/cli/lib/watchFilesAndRunTestsNodeWatch.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport { matchesGlob } from 'node:path'\n\nimport type { FinalConfig, OutFn } from '../../types.js'\nimport type { TestExecutionFilters } from '../cliTypes.js'\nimport type { ReRunManager } from './reRunManager.js'\nimport type { DependencyGraph } from './makeDependencyGraph.js'\nimport type { StopFn } from '../watch.js'\nimport chalk from '../../packages/chalk.js'\nimport slash from '../../packages/slash.js'\nimport { createTimeProfiler } from '../../packages/timeProfiler.js'\nimport { showTimeProfiling } from '../../config.js'\nimport { out as mainOut, log, debug } from '../../output.js'\nimport { agentChange } from './agentReport.js'\nimport { runTests } from './runTests.js'\nimport { globArgCombine } from './globArgCombine.js'\nimport { addBasePath } from './addBasePath.js'\nimport { watchFilesNodeWatch } from './watchFilesNodeWatch.js'\nimport { filter } from './filter.js'\n\n\nconst { timeProfile, timeProfileAsync } = createTimeProfiler(showTimeProfiling)\n\nexport async function watchFilesAndRunTestsNodeWatch(\n config: FinalConfig,\n //testFiles: Set<string>,\n // null when watch.dependencyEvaluation is off\n dependencyGraph: DependencyGraph | null,\n failingTests: string[],\n reRunManager: ReRunManager,\n //watchRunState: WatchRunState,\n customOut?: OutFn,\n executionFilters: TestExecutionFilters = {}\n): Promise<StopFn> {\n // agent mode passes a sink here, so its own change lines are the only ones printed\n const out = customOut ?? mainOut\n\n return timeProfileAsync('init watching', async () => {\n debug('failingTests', failingTests)\n\n const testsGlobs = addBasePath(config.testsBase, config.tests)\n const testsIgnoreGlobs = addBasePath(config.testsBase, config.testsIgnore)\n\n // indentify a test file\n const testFilter = (file: string): boolean => {\n return matchesGlob(file, globArgCombine(testsGlobs))\n && !matchesGlob(file, globArgCombine(testsIgnoreGlobs))\n && (\n config.testsFilter === undefined\n || config.testsFilter === ''\n || filter(config.testsBase, config.testsFilter, file)\n )\n }\n\n let changedFiles: Array<[string, string]> = []\n let timeout: ReturnType<typeof setTimeout> | null = null\n\n if (config.watch.watchFilesBase === '') {\n out('No config.watch.watchFilesBase provided, defaulting to \\'.\\'')\n config.watch.watchFilesBase = '.'\n }\n\n const watcher = await watchFilesNodeWatch(config, watchEvent)\n return () => {\n watcher.close()\n // a change seen just before stopping would otherwise still run its tests\n if (timeout) clearTimeout(timeout)\n }\n\n function watchEvent(filename: string, event: string): void {\n debug('handle watch event ', filename, event)\n\n filename = slash(filename)\n\n // forget a deleted test, avoiding trying to run it later\n if (event === 'remove') {\n debug('removing test', filename)\n reRunManager.state.withoutTests.delete(filename)\n reRunManager.state.allTestFiles.delete(filename)\n }\n\n // info on the event found\n out(chalk.grey`change: ${filename} (${event})`)\n agentChange(config, filename, event)\n\n // add the file to changed files\n changedFiles.push([filename, event])\n\n // 33ms debounce\n const debounceMs = 33\n if (timeout) {\n clearTimeout(timeout)\n }\n timeout = setTimeout(() => {\n timeProfile('handle changed files', () => {\n debug('changedFiles', changedFiles)\n try {\n // the whole batch is applied before any lookup, so an import added in one\n // file can reach a file created in the same batch\n if (dependencyGraph !== null) {\n for (const [file, fileEvent] of changedFiles) {\n if (fileEvent === 'remove') dependencyGraph.remove(file)\n else if (testFilter(file)) dependencyGraph.addTest(file)\n else dependencyGraph.update(file)\n }\n }\n\n // build related test list\n const tests = new Set<string>\n for (const [file, fileEvent] of changedFiles) {\n debug('check', file)\n if (fileEvent !== 'remove') { // only check if it's a test if it exists (has not just been removed)\n if (testFilter(file)) { // it is a test file itself, add to run list\n debug('its a test', file)\n tests.add(file)\n // makes a newly created test part of what `a` runs\n reRunManager.state.allTestFiles.add(file)\n }\n }\n\n // with evaluation off there is nothing to map the change through:\n // any watched file could affect any test, so run the lot\n if (dependencyGraph === null) {\n for (const f of reRunManager.state.allTestFiles) tests.add(f)\n continue\n }\n\n for (const f of dependencyGraph.testsAffectedBy(file)) tests.add(f)\n }\n\n changedFiles = []\n\n debug('tests', tests)\n\n if (tests.size > 0) {\n timeProfile('build list of files to test and request a run',\n () => {\n debug('tests', tests)\n debug('reRunFailingTests', config.watch.reRunFailingTests)\n\n // changes accumulate here because an 'auto' request made while a\n // run is in flight is coalesced into the queued one - everything\n // edited in the meantime still has to be covered\n reRunManager.state.untestedFiles\n = reRunManager.state.untestedFiles.union(tests)\n\n void reRunManager.requestRun(\n 'auto',\n () => {\n // resolved when the run actually starts, not when it is\n // queued, so a coalesced request picks up the later edits\n const toTest = (config.watch.reRunFailingTests)\n ? reRunManager.state.untestedFiles\n .union(reRunManager.state.failedTestFiles)\n : new Set(reRunManager.state.untestedFiles)\n\n // consumed by this run - without this they are retested\n // on every later run for the rest of the session\n reRunManager.state.untestedFiles = new Set()\n\n debug('run tests on change')\n debug('toTest', toTest)\n\n return runTests(\n config,\n toTest,\n reRunManager,\n { limit: -1 },\n 'refresh',\n customOut,\n executionFilters\n )\n }\n )\n }\n )\n }\n } catch (e) {\n log('watch handler error', e)\n }\n })\n }, debounceMs)\n } // end of watch event\n })\n\n // NOTE: \"watching...\" is intentionally NOT printed here. watch() already emits it,\n // tied to a real milestone (the initial test run finishing, or no tests found).\n // Printing it again here produced a duplicate \"watching...\" on every startup.\n // out(chalk.brightblue`watching...`)\n}\n"]}
|
package/dist/cli/watch.js
CHANGED
|
@@ -135,8 +135,6 @@ export async function doWatch(input = process.stdin) {
|
|
|
135
135
|
const testFiles = await findTestFiles(config);
|
|
136
136
|
debug(testFiles);
|
|
137
137
|
agentFound(config, testFiles.size);
|
|
138
|
-
// global store of the dependencies of tests
|
|
139
|
-
let dependencyTrees = {};
|
|
140
138
|
// store failing tests so we can re-run them.
|
|
141
139
|
const failingTests = [];
|
|
142
140
|
const concurrency = { limit: -1 };
|
|
@@ -145,15 +143,17 @@ export async function doWatch(input = process.stdin) {
|
|
|
145
143
|
lastTestFiles: testFiles
|
|
146
144
|
}), runsOut);
|
|
147
145
|
process.setSourceMapsEnabled(true); // enable source mapping
|
|
148
|
-
if (testFiles.size > 0)
|
|
146
|
+
if (testFiles.size > 0)
|
|
149
147
|
agentOut(chalk.brightblue(foundTestsMessage(testFiles.size)));
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
// the graph is only consulted to narrow a run, so with evaluation off building it is pure
|
|
149
|
+
// cost - and it is the slowest part of startup on a large suite. Built even with no tests,
|
|
150
|
+
// so tests created later are recorded in it.
|
|
151
|
+
let dependencyGraph = null;
|
|
152
|
+
if (config.watch.dependencyEvaluation) {
|
|
153
|
+
const { makeDependencyGraph } = await import('./lib/makeDependencyGraph.js');
|
|
154
|
+
if (testFiles.size > 0)
|
|
155
|
+
agentOut(chalk.brightblue `finding initial dependencies...`);
|
|
156
|
+
dependencyGraph = makeDependencyGraph(config, testFiles);
|
|
157
157
|
}
|
|
158
158
|
// live before the first test runs, for two reasons. A change landing during the initial
|
|
159
159
|
// run (a compiler emit, typically) is seen rather than lost. And the watcher starts on a
|
|
@@ -163,7 +163,7 @@ export async function doWatch(input = process.stdin) {
|
|
|
163
163
|
const { watchFilesAndRunTests } = await import('./lib/watchFilesAndRunTests.js');
|
|
164
164
|
const stopWatcher = await watchFilesAndRunTests(config,
|
|
165
165
|
//testFiles,
|
|
166
|
-
|
|
166
|
+
dependencyGraph, failingTests, // CHECK this should also be in state
|
|
167
167
|
reRunManager,
|
|
168
168
|
//watchRunState,
|
|
169
169
|
runsOut, executionFilters);
|
package/dist/cli/watch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/cli/watch.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,sBAAsB,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9D,0CAA0C;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAK1D,MAAM,CAAC,KAAK,UAAU,KAAK;IACvB,MAAM,OAAO,EAAE,CAAA;IACf,MAAM,IAAI,OAAO,CAAO,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;AACrC,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,QAA2B,OAAO,CAAC,KAAK;IAClE,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAA;IAEtC,MAAM,EAAE,yBAAyB,EAAE,GAAG,MAAM,MAAM,CAAC,oCAAoC,CAAC,CAAA;IACxF,MAAM,kBAAkB,GAAqB;QACzC,QAAQ,EAAE;YACN,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;SACjB;QACD,YAAY,EAAE;YACV,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI;SACf;QACD,QAAQ,EAAE;YACN,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI;SACf;QACD,WAAW,EAAE;YACT,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;SACjB;QACD,iBAAiB,EAAE;YACf,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;SACjB;QACD,aAAa,EAAE;YACX,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;SACjB;QACD,OAAO,EAAE;YACL,QAAQ,EAAE,KAAK;SAClB;QACD,SAAS,EAAE;YACP,QAAQ,EAAE,KAAK;SAClB;KACJ,CAAA;IACD,MAAM,WAAW,GAAG,yBAAyB,CAAC,kBAAkB,CAAC,CAAA;IACjE,mCAAmC;IAEnC,wFAAwF;IACxF,uFAAuF;IACvF,wEAAwE;IACxE,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,KAAK,IAAI,CAAA;IAC5C,MAAM,EACF,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EACjF,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAA;IACxC,SAAS,CAAC,SAAS,CAAC,CAAA;IACpB,iFAAiF;IACjF,IAAI,SAAS,GAAG,SAAS,CAAA;IACzB,MAAM,QAAQ,GAAU,CAAC,GAAG,KAAK,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS;QAAE,GAAG,CAAC,GAAG,KAAK,CAAC,CAAA,CAAC,CAAC,CAAA;IAEvE,MAAM,EAAE,CAAA;IAER,MAAM,OAAO,GAAa,EAAE,CAAA;IAE5B,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;IAC1D,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,MAAM,KAAK,QAAQ,CAAC;QACvD,CAAC,CAAC,MAAM,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC;QACtC,CAAC,CAAC,MAAM,UAAU,EAAE,CAAA;IAExB,IAAI,YAAY,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,gBAAgB,GAAG,WAAW,CAAC,YAAY,CAAC,CAAA;QAClD,IAAI,OAAO,gBAAgB,KAAK,QAAQ,IAAI,gBAAgB,KAAK,EAAE,EAAE,CAAC;YAClE,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAA;QAC3E,CAAC;QACD,UAAU,CAAC,KAAK,GAAG,gBAAgB,CAAA;IACvC,CAAC;IAED,IAAI,QAAQ,IAAI,WAAW,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAA;QACjC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;QACvE,CAAC;QACD,UAAU,CAAC,WAAW,GAAG,MAAM,CAAA;IACnC,CAAC;IAED,IAAI,aAAa,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,WAAW,CAAC,aAAa,CAAC,CAAA;QAC7C,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAA;QAC9E,CAAC;QACD,UAAU,CAAC,KAAK,GAAG,EAAE,GAAG,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,CAAA;IAC1D,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;IACzC,MAAM,cAAc,GAAG,WAAW,CAAC,iBAAiB,CAAC,CAAA;IACrD,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IACnG,IAAI,cAAc,KAAK,IAAI,IAAI,cAAc,KAAK,EAAE,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAA;IACnE,CAAC;IACD,MAAM,gBAAgB,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAA;IAEnE,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,8BAA8B,CAAC,CAAA;IAC5E,MAAM,MAAM,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAA;IAC9C,IAAI,SAAS;QAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAA;SAC7B,IAAI,MAAM,CAAC,KAAK;QAAE,SAAS,CAAC,IAAI,CAAC,CAAA,CAAC,kDAAkD;IACzF,SAAS,GAAG,MAAM,CAAC,KAAK,CAAA;IACxB,WAAW,CAAC,SAAS,CAAC,CAAA;IACtB,MAAM,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAA;IACxD,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAA,IAAI,WAAW,MAAM,CAAC,CAAA;IAC/C,IAAI,WAAW,CAAC,OAAO,KAAK,IAAI;QAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;IACvD,wFAAwF;IACxF,mFAAmF;IACnF,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAA;IAEvB,uFAAuF;IACvF,gDAAgD;IAChD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAA;IAClE,cAAc,CAAC,MAAM,CAAC,CAAA;IAEtB,6EAA6E;IAC7E,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;IAC7F,eAAe,CAAC,MAAM,CAAC,CAAA;IAEvB,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAA;IAC5D,MAAM,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IAEnC,wFAAwF;IACxF,wFAAwF;IACxF,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAA;IAClE,MAAM,EAAE,wBAAwB,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAEtE,MAAM,0BAA0B,GAAG,wBAAwB,CAAC,MAAM,EAAE;QAChE,QAAQ,EAAE,cAAc;QACxB,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;KACnC,CAAC,CAAA;IACF,OAAO,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;IAExC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACvD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAA;IAChE,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;IAC7C,KAAK,CAAC,SAAS,CAAC,CAAA;IAChB,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,CAAA;IAElC,4CAA4C;IAC5C,IAAI,eAAe,GAAoB,EAAE,CAAA;IACzC,6CAA6C;IAC7C,MAAM,YAAY,GAAa,EAAE,CAAA;IAEjC,MAAM,WAAW,GAAgB,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAA;IAE9C,MAAM,YAAY,GAAG,gBAAgB,CACjC,IAAI,EACJ,mBAAmB,CAAC;QAChB,YAAY,EAAE,SAAS;QACvB,aAAa,EAAE,SAAS;KAC3B,CAAC,EACF,OAAO,CACV,CAAA;IAED,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAA,CAAC,wBAAwB;IAE3D,IAAI,SAAS,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACrB,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAE7D,qFAAqF;QACrF,wEAAwE;QACxE,IAAI,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC;YACpC,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAA;YAC9E,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAA,qCAAqC,CAAC,CAAA;YAC/D,eAAe,GAAG,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QAC7D,CAAC;IACL,CAAC;IAED,wFAAwF;IACxF,yFAAyF;IACzF,yFAAyF;IACzF,oFAAoF;IACpF,4FAA4F;IAC5F,MAAM,EAAE,qBAAqB,EAAE,GAAG,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAA;IAChF,MAAM,WAAW,GAAG,MAAM,qBAAqB,CAC3C,MAAM;IACN,YAAY;IACZ,eAAe,EACf,YAAY,EAAE,qCAAqC;IACnD,YAAY;IACZ,gBAAgB;IAChB,OAAO,EACP,gBAAgB,CACnB,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IAEzB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;IACtD,IAAI,cAAc,GAAmC,IAAI,CAAA;IACzD,IAAI,SAAS,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACrB,IAAI,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC;YAC/B,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAA,0BAA0B,CAAC,CAAA;YACpD,cAAc,GAAG,QAAQ,CACrB,MAAM,EAAE,SAAS,EACjB,YAAY,EACZ,WAAW,EACX,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EACxC,OAAO,EAAE,gBAAgB,CAC5B,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;gBACjB,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,SAAS,CAAA;gBAC7C,0DAA0D;gBAC1D,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAA,KAAK,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAA;gBAClD,OAAO,WAAW,CAAA;YACtB,CAAC,CAAC,CAAA;YACF,YAAY,CAAC,KAAK,CAAC,UAAU,GAAG,cAAc,CAAA;QAClD,CAAC;IACL,CAAC;SAAM,CAAC;QACJ,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAA,qBAAqB,CAAC,CAAA;QAC3C,eAAe,CAAC,MAAM,EAAE,WAAW,CAAC,WAAW,EAAE,qBAAqB,CAAC,CAAA;QACvE,8EAA8E;QAC9E,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QACpC,SAAS,CACL,MAAM,EAAE,GAAG,EAAE,WAAW,CAAC,WAAW,EAAE,qBAAqB,EAC3D,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,SAAS,EAAE,CAAC,CAC5C,CAAA;IACL,CAAC;IAED,2FAA2F;IAC3F,oFAAoF;IACpF,IAAI,cAAc,KAAK,IAAI;QAAE,MAAM,cAAc,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;IAEnE,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAA,aAAa,CAAC,CAAA;IACvC,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,CAAA;IAErC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAA;IAC9D,MAAM,UAAU,GAAG,YAAY,CAC3B,YAAY,EACZ,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE;QACV,OAAO,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAA;IACnG,CAAC,EACD,MAAM,CAAC,KAAK,CAAC,oBAAoB,EACjC,cAAc,EACd,KAAK,EACL,OAAO,CACV,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IAExB,MAAM,OAAO,GAAG,GAAG,EAAE;QACjB,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YACzB,IAAI,EAAE,CAAA;QACV,CAAC;QACD,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA,CAAC,gBAAgB;IACvC,CAAC,CAAA;IACD,OAAO,OAAO,CAAA;IAGd,iBAAiB;IACjB,wCAAwC;IACxC,OAAO;IACP,mCAAmC;AACvC,CAAC","sourcesContent":["\nimport type { DependencyTrees, OutFn } from '../types.js'\nimport type { AllowedArguments } from './cliTypes.js'\nimport type { Concurrency } from './lib/runTests.js'\nimport chalk from '../packages/chalk.js'\nimport { packageName } from '../config.js'\nimport { out, debug } from '../output.js'\nimport { setEnv, setAgentEnv } from './lib/setEnv.js'\nimport { findingTestsMessage } from './lib/findingTestsMessage.js'\nimport { foundTestsMessage } from './lib/foundTestsMessage.js'\n//import { isTest } from './lib/isTest.js'\nimport { makeRunManagerState } from './lib/makeWatchRunState.js'\nimport { makeReRunManager } from './lib/reRunManager.js'\nimport { alwaysCacheBust } from './lib/alwaysCacheBust.js'\n\n\nexport type StopFn = () => void\n\nexport async function watch(): Promise<void> {\n await doWatch()\n await new Promise<void>(() => {})\n}\n\n// input is injectable so tests never read the terminal their runner is also reading\nexport async function doWatch(input: NodeJS.ReadStream = process.stdin): Promise<StopFn> {\n const startTime = new Date().getTime()\n\n const { parseCommandLineArguments } = await import('./lib/parseCommandLineArguments.js')\n const allowedClArguments: AllowedArguments = {\n 'config': {\n flag: 'c',\n hasValue: true\n },\n 'test-files': {\n flag: 't',\n hasValue: true,\n isGlob: true\n },\n 'filter': {\n flag: 'f',\n hasValue: true,\n isGlob: true\n },\n 'filter-it': {\n flag: 'i',\n hasValue: true\n },\n 'filter-describe': {\n flag: 'd',\n hasValue: true\n },\n 'status-file': {\n flag: 's',\n hasValue: true\n },\n 'agent': {\n hasValue: false\n },\n 'compact': {\n hasValue: false\n }\n }\n const clArguments = parseCommandLineArguments(allowedClArguments)\n //debug('clArguments', clArguments)\n\n // agent mode owns stdout, so the banner and every later message below is routed through\n // agentOut - a sink in agent mode. Under the flag, init is announced before the config\n // loads, so a reader sees the process is alive even if startup is slow.\n const agentFlag = clArguments.agent === true\n const {\n agentInit, agentFound, agentRunStart, agentDone, agentWatching, agentSilentOut\n } = await import('./lib/agentReport.js')\n agentInit(agentFlag)\n // the config can still turn agent mode on, so this is settled once it has loaded\n let agentMode = agentFlag\n const agentOut: OutFn = (...texts) => { if (!agentMode) out(...texts) }\n\n setEnv()\n\n const stopFns: StopFn[] = []\n\n const { loadConfig } = await import('./lib/loadConfig.js')\n const userConfig = (typeof clArguments.config === 'string')\n ? await loadConfig(clArguments.config)\n : await loadConfig()\n\n if ('test-files' in clArguments) {\n const testFilesPattern = clArguments['test-files']\n if (typeof testFilesPattern !== 'string' || testFilesPattern === '') {\n throw new Error('No pattern specified for --test-files or -t argument')\n }\n userConfig.tests = testFilesPattern\n }\n\n if ('filter' in clArguments) {\n const filter = clArguments.filter\n if (typeof filter !== 'string' || filter === '') {\n throw new Error('No pattern specified for --filter or -f argument')\n }\n userConfig.testsFilter = filter\n }\n\n if ('status-file' in clArguments) {\n const statusFile = clArguments['status-file']\n if (typeof statusFile !== 'string' || statusFile === '') {\n throw new Error('No file path specified for --status-file or -s argument')\n }\n userConfig.watch = { ...userConfig.watch, statusFile }\n }\n\n const filterIt = clArguments['filter-it']\n const filterDescribe = clArguments['filter-describe']\n if (filterIt === true || filterIt === '') throw new Error('No substring specified for --filter-it')\n if (filterDescribe === true || filterDescribe === '') {\n throw new Error('No substring specified for --filter-describe')\n }\n const executionFilters = { it: filterIt, describe: filterDescribe }\n\n const { applyConfigDefaults } = await import('./lib/applyConfigDefaults.js')\n const config = applyConfigDefaults(userConfig)\n if (agentFlag) config.agent = true\n else if (config.agent) agentInit(true) // set by the config: announced once it has loaded\n agentMode = config.agent\n setAgentEnv(agentMode)\n const runsOut = (agentMode) ? agentSilentOut : undefined\n agentOut(chalk.brightblue`[${packageName}]...`)\n if (clArguments.compact === true) config.compact = true\n // there is no watch flag for it, and a config file must not enable it here: a truncated\n // run would still report covers=all, and failing files would drop out of `failing`\n config.failFast = false\n\n // not silenced in agent mode - a config error is fatal, so losing the message is worse\n // than breaking the one-line-per-event contract\n const { validateConfig } = await import('./lib/validateConfig.js')\n validateConfig(config)\n\n // no run has finished yet, so the status file starts at -1 rather than stale\n const { resetStatusFile, statusCodes, writeStatusFile } = await import('./lib/statusFile.js')\n resetStatusFile(config)\n\n const { doUserSetup } = await import('./lib/doUserSetup.js')\n await doUserSetup(config, agentOut)\n\n // watch mode never reaches an end of its own, so teardown only gets a chance on the way\n // out. Registered here so it pairs with the setup above and covers the initial run too.\n const { doUserTeardown } = await import('./lib/doUserTeardown.js')\n const { registerShutdownHandlers } = await import('./lib/shutdown.js')\n \n const unregisterShutdownHandlers = registerShutdownHandlers(config, {\n teardown: doUserTeardown,\n exit: code => process.exit(code)\n })\n stopFns.push(unregisterShutdownHandlers)\n\n agentOut(chalk.brightblue(findingTestsMessage(config)))\n const { findTestFiles } = await import('./lib/findTestFiles.js')\n const testFiles = await findTestFiles(config)\n debug(testFiles)\n agentFound(config, testFiles.size)\n\n // global store of the dependencies of tests\n let dependencyTrees: DependencyTrees = {}\n // store failing tests so we can re-run them.\n const failingTests: string[] = []\n \n const concurrency: Concurrency = { limit: -1 }\n\n const reRunManager = makeReRunManager(\n null,\n makeRunManagerState({\n allTestFiles: testFiles,\n lastTestFiles: testFiles\n }),\n runsOut\n )\n\n process.setSourceMapsEnabled(true) // enable source mapping\n\n if (testFiles.size > 0) {\n agentOut(chalk.brightblue(foundTestsMessage(testFiles.size)))\n\n // the trees are only consulted to narrow a run, so with evaluation off building them\n // is pure cost - and it is the slowest part of startup on a large suite\n if (config.watch.dependencyEvaluation) {\n const { buildDependencyTrees } = await import('./lib/buildDependencyTrees.js')\n agentOut(chalk.brightblue`finding initial dependency trees...`)\n dependencyTrees = buildDependencyTrees(config, testFiles)\n }\n }\n\n // live before the first test runs, for two reasons. A change landing during the initial\n // run (a compiler emit, typically) is seen rather than lost. And the watcher starts on a\n // quiet loop: node-watch probes for native recursive support with a 200ms timeout, and a\n // loop busy running tests fails the probe, so it falls back to a sync walk of every\n // directory - which then starved the tests' own timers (a 10ms interval fired once in 45ms)\n const { watchFilesAndRunTests } = await import('./lib/watchFilesAndRunTests.js')\n const stopWatcher = await watchFilesAndRunTests(\n config,\n //testFiles,\n dependencyTrees,\n failingTests, // CHECK this should also be in state\n reRunManager,\n //watchRunState,\n runsOut,\n executionFilters\n )\n stopFns.push(stopWatcher)\n\n const { runTests } = await import('./lib/runTests.js')\n let initialTestRun: Promise<boolean | null> | null = null\n if (testFiles.size > 0) {\n if (config.watch.runAllOnStartup) {\n agentOut(chalk.brightblue`running initial tests...`)\n initialTestRun = runTests(\n config, testFiles,\n reRunManager,\n concurrency,\n (alwaysCacheBust) ? 'refresh' : 'cached',\n runsOut, executionFilters\n ).then(testsResult => {\n const time = new Date().getTime() - startTime\n //await new Promise((resolve) => setTimeout(resolve, 100))\n agentOut(chalk.grey`\\n${time.toLocaleString()}ms`)\n return testsResult\n })\n reRunManager.state.currentRun = initialTestRun\n }\n } else {\n agentOut(chalk.orange`no test files found`)\n writeStatusFile(config, statusCodes.couldNotRun, 'no test files found')\n // still reported as a run, so a reader waiting on a done line always gets one\n const run = agentRunStart(config, 0)\n agentDone(\n config, run, statusCodes.couldNotRun, 'no test files found',\n null, new Date().getTime() - startTime, 0\n )\n }\n\n // announced once the initial run is over, so `watching` marks a real milestone: startup is\n // complete and the watcher is live. A failed run is reported by listenToUser below.\n if (initialTestRun !== null) await initialTestRun.catch(() => null)\n\n agentOut(chalk.brightblue`watching...`)\n agentWatching(config, testFiles.size)\n\n const { listenToUser } = await import('./lib/listenToUser.js')\n const disposeTty = listenToUser(\n reRunManager,\n files => () => {\n return runTests(config, files, reRunManager, concurrency, 'refresh', runsOut, executionFilters)\n },\n config.watch.ttyActionsOnKeypress,\n initialTestRun,\n input,\n runsOut\n )\n stopFns.push(disposeTty)\n\n const dispose = () => {\n for (const stop of stopFns) {\n stop()\n }\n stopFns.length = 0 // Idempotencize\n }\n return dispose\n\n\n // (async () => {\n // await new Promise<void>(() => {})\n // })()\n //await new Promise<void>(() => {})\n}\n"]}
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/cli/watch.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport type { OutFn } from '../types.js'\nimport type { AllowedArguments } from './cliTypes.js'\nimport type { Concurrency } from './lib/runTests.js'\nimport type { DependencyGraph } from './lib/makeDependencyGraph.js'\nimport chalk from '../packages/chalk.js'\nimport { packageName } from '../config.js'\nimport { out, debug } from '../output.js'\nimport { setEnv, setAgentEnv } from './lib/setEnv.js'\nimport { findingTestsMessage } from './lib/findingTestsMessage.js'\nimport { foundTestsMessage } from './lib/foundTestsMessage.js'\n//import { isTest } from './lib/isTest.js'\nimport { makeRunManagerState } from './lib/makeWatchRunState.js'\nimport { makeReRunManager } from './lib/reRunManager.js'\nimport { alwaysCacheBust } from './lib/alwaysCacheBust.js'\n\n\nexport type StopFn = () => void\n\nexport async function watch(): Promise<void> {\n await doWatch()\n await new Promise<void>(() => {})\n}\n\n// input is injectable so tests never read the terminal their runner is also reading\nexport async function doWatch(input: NodeJS.ReadStream = process.stdin): Promise<StopFn> {\n const startTime = new Date().getTime()\n\n const { parseCommandLineArguments } = await import('./lib/parseCommandLineArguments.js')\n const allowedClArguments: AllowedArguments = {\n 'config': {\n flag: 'c',\n hasValue: true\n },\n 'test-files': {\n flag: 't',\n hasValue: true,\n isGlob: true\n },\n 'filter': {\n flag: 'f',\n hasValue: true,\n isGlob: true\n },\n 'filter-it': {\n flag: 'i',\n hasValue: true\n },\n 'filter-describe': {\n flag: 'd',\n hasValue: true\n },\n 'status-file': {\n flag: 's',\n hasValue: true\n },\n 'agent': {\n hasValue: false\n },\n 'compact': {\n hasValue: false\n }\n }\n const clArguments = parseCommandLineArguments(allowedClArguments)\n //debug('clArguments', clArguments)\n\n // agent mode owns stdout, so the banner and every later message below is routed through\n // agentOut - a sink in agent mode. Under the flag, init is announced before the config\n // loads, so a reader sees the process is alive even if startup is slow.\n const agentFlag = clArguments.agent === true\n const {\n agentInit, agentFound, agentRunStart, agentDone, agentWatching, agentSilentOut\n } = await import('./lib/agentReport.js')\n agentInit(agentFlag)\n // the config can still turn agent mode on, so this is settled once it has loaded\n let agentMode = agentFlag\n const agentOut: OutFn = (...texts) => { if (!agentMode) out(...texts) }\n\n setEnv()\n\n const stopFns: StopFn[] = []\n\n const { loadConfig } = await import('./lib/loadConfig.js')\n const userConfig = (typeof clArguments.config === 'string')\n ? await loadConfig(clArguments.config)\n : await loadConfig()\n\n if ('test-files' in clArguments) {\n const testFilesPattern = clArguments['test-files']\n if (typeof testFilesPattern !== 'string' || testFilesPattern === '') {\n throw new Error('No pattern specified for --test-files or -t argument')\n }\n userConfig.tests = testFilesPattern\n }\n\n if ('filter' in clArguments) {\n const filter = clArguments.filter\n if (typeof filter !== 'string' || filter === '') {\n throw new Error('No pattern specified for --filter or -f argument')\n }\n userConfig.testsFilter = filter\n }\n\n if ('status-file' in clArguments) {\n const statusFile = clArguments['status-file']\n if (typeof statusFile !== 'string' || statusFile === '') {\n throw new Error('No file path specified for --status-file or -s argument')\n }\n userConfig.watch = { ...userConfig.watch, statusFile }\n }\n\n const filterIt = clArguments['filter-it']\n const filterDescribe = clArguments['filter-describe']\n if (filterIt === true || filterIt === '') throw new Error('No substring specified for --filter-it')\n if (filterDescribe === true || filterDescribe === '') {\n throw new Error('No substring specified for --filter-describe')\n }\n const executionFilters = { it: filterIt, describe: filterDescribe }\n\n const { applyConfigDefaults } = await import('./lib/applyConfigDefaults.js')\n const config = applyConfigDefaults(userConfig)\n if (agentFlag) config.agent = true\n else if (config.agent) agentInit(true) // set by the config: announced once it has loaded\n agentMode = config.agent\n setAgentEnv(agentMode)\n const runsOut = (agentMode) ? agentSilentOut : undefined\n agentOut(chalk.brightblue`[${packageName}]...`)\n if (clArguments.compact === true) config.compact = true\n // there is no watch flag for it, and a config file must not enable it here: a truncated\n // run would still report covers=all, and failing files would drop out of `failing`\n config.failFast = false\n\n // not silenced in agent mode - a config error is fatal, so losing the message is worse\n // than breaking the one-line-per-event contract\n const { validateConfig } = await import('./lib/validateConfig.js')\n validateConfig(config)\n\n // no run has finished yet, so the status file starts at -1 rather than stale\n const { resetStatusFile, statusCodes, writeStatusFile } = await import('./lib/statusFile.js')\n resetStatusFile(config)\n\n const { doUserSetup } = await import('./lib/doUserSetup.js')\n await doUserSetup(config, agentOut)\n\n // watch mode never reaches an end of its own, so teardown only gets a chance on the way\n // out. Registered here so it pairs with the setup above and covers the initial run too.\n const { doUserTeardown } = await import('./lib/doUserTeardown.js')\n const { registerShutdownHandlers } = await import('./lib/shutdown.js')\n \n const unregisterShutdownHandlers = registerShutdownHandlers(config, {\n teardown: doUserTeardown,\n exit: code => process.exit(code)\n })\n stopFns.push(unregisterShutdownHandlers)\n\n agentOut(chalk.brightblue(findingTestsMessage(config)))\n const { findTestFiles } = await import('./lib/findTestFiles.js')\n const testFiles = await findTestFiles(config)\n debug(testFiles)\n agentFound(config, testFiles.size)\n\n // store failing tests so we can re-run them.\n const failingTests: string[] = []\n \n const concurrency: Concurrency = { limit: -1 }\n\n const reRunManager = makeReRunManager(\n null,\n makeRunManagerState({\n allTestFiles: testFiles,\n lastTestFiles: testFiles\n }),\n runsOut\n )\n\n process.setSourceMapsEnabled(true) // enable source mapping\n\n if (testFiles.size > 0) agentOut(chalk.brightblue(foundTestsMessage(testFiles.size)))\n\n // the graph is only consulted to narrow a run, so with evaluation off building it is pure\n // cost - and it is the slowest part of startup on a large suite. Built even with no tests,\n // so tests created later are recorded in it.\n let dependencyGraph: DependencyGraph | null = null\n if (config.watch.dependencyEvaluation) {\n const { makeDependencyGraph } = await import('./lib/makeDependencyGraph.js')\n if (testFiles.size > 0) agentOut(chalk.brightblue`finding initial dependencies...`)\n dependencyGraph = makeDependencyGraph(config, testFiles)\n }\n\n // live before the first test runs, for two reasons. A change landing during the initial\n // run (a compiler emit, typically) is seen rather than lost. And the watcher starts on a\n // quiet loop: node-watch probes for native recursive support with a 200ms timeout, and a\n // loop busy running tests fails the probe, so it falls back to a sync walk of every\n // directory - which then starved the tests' own timers (a 10ms interval fired once in 45ms)\n const { watchFilesAndRunTests } = await import('./lib/watchFilesAndRunTests.js')\n const stopWatcher = await watchFilesAndRunTests(\n config,\n //testFiles,\n dependencyGraph,\n failingTests, // CHECK this should also be in state\n reRunManager,\n //watchRunState,\n runsOut,\n executionFilters\n )\n stopFns.push(stopWatcher)\n\n const { runTests } = await import('./lib/runTests.js')\n let initialTestRun: Promise<boolean | null> | null = null\n if (testFiles.size > 0) {\n if (config.watch.runAllOnStartup) {\n agentOut(chalk.brightblue`running initial tests...`)\n initialTestRun = runTests(\n config, testFiles,\n reRunManager,\n concurrency,\n (alwaysCacheBust) ? 'refresh' : 'cached',\n runsOut, executionFilters\n ).then(testsResult => {\n const time = new Date().getTime() - startTime\n //await new Promise((resolve) => setTimeout(resolve, 100))\n agentOut(chalk.grey`\\n${time.toLocaleString()}ms`)\n return testsResult\n })\n reRunManager.state.currentRun = initialTestRun\n }\n } else {\n agentOut(chalk.orange`no test files found`)\n writeStatusFile(config, statusCodes.couldNotRun, 'no test files found')\n // still reported as a run, so a reader waiting on a done line always gets one\n const run = agentRunStart(config, 0)\n agentDone(\n config, run, statusCodes.couldNotRun, 'no test files found',\n null, new Date().getTime() - startTime, 0\n )\n }\n\n // announced once the initial run is over, so `watching` marks a real milestone: startup is\n // complete and the watcher is live. A failed run is reported by listenToUser below.\n if (initialTestRun !== null) await initialTestRun.catch(() => null)\n\n agentOut(chalk.brightblue`watching...`)\n agentWatching(config, testFiles.size)\n\n const { listenToUser } = await import('./lib/listenToUser.js')\n const disposeTty = listenToUser(\n reRunManager,\n files => () => {\n return runTests(config, files, reRunManager, concurrency, 'refresh', runsOut, executionFilters)\n },\n config.watch.ttyActionsOnKeypress,\n initialTestRun,\n input,\n runsOut\n )\n stopFns.push(disposeTty)\n\n const dispose = () => {\n for (const stop of stopFns) {\n stop()\n }\n stopFns.length = 0 // Idempotencize\n }\n return dispose\n\n\n // (async () => {\n // await new Promise<void>(() => {})\n // })()\n //await new Promise<void>(() => {})\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sxy-test-runner",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"homepage": "https://github.com/RobertSandiford/sxy-test-runner",
|
|
6
6
|
"repository": {
|
|
@@ -41,11 +41,12 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"chalk": "^4.1.2",
|
|
43
43
|
"cross-env": "^7.0.3",
|
|
44
|
-
"dependency-tree": "^12.0.1",
|
|
45
44
|
"esm-reload": "^1.0.1",
|
|
45
|
+
"filing-cabinet": "^6.0.0",
|
|
46
46
|
"node-watch": "^0.7.4",
|
|
47
47
|
"rimraf": "^6.1.3",
|
|
48
|
-
"sxy-lib": "^3.0.7"
|
|
48
|
+
"sxy-lib": "^3.0.7",
|
|
49
|
+
"sxy-precinct": "^13.1.1"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"@types/chai": "^5.2.3",
|
|
@@ -71,8 +72,9 @@
|
|
|
71
72
|
"typescript": "^6.0.3"
|
|
72
73
|
},
|
|
73
74
|
"scripts": {
|
|
74
|
-
"build": "
|
|
75
|
-
"build-once": "
|
|
75
|
+
"build": "tscmon",
|
|
76
|
+
"build-once": "tscmon --once",
|
|
77
|
+
"time-dep-graph": "node bench/depGraph.ts",
|
|
76
78
|
"dev-mon": "cross-env NODE_OPTIONS=\"--experimental-specifier-resolution=node\" nodemon --experimental-specifier-resolution=node --watch dist/cli --watch dist/cli/lib --watch sxy-test-runner.config.js --watch sxy-loader.config.js dist/cli/index.js",
|
|
77
79
|
"dev-mon-input": "cross-env NODE_OPTIONS=\"--experimental-specifier-resolution=node\" nodemon --no-stdin --experimental-specifier-resolution=node --watch dist/cli --watch dist/cli/lib --watch sxy-test-runner.config.js --watch sxy-loader.config.js dist/cli/index.js",
|
|
78
80
|
"dev": "cross-env NODE_OPTIONS=\"--experimental-specifier-resolution=node\" node --experimental-specifier-resolution=node dist/cli/index.js",
|
package/readme.md
CHANGED
|
@@ -275,7 +275,7 @@ If your code is isolated, and asyncronous, you can use parallel exeecution modes
|
|
|
275
275
|
|
|
276
276
|
## Dependencies
|
|
277
277
|
|
|
278
|
-
|
|
278
|
+
Dynamic imports will not be detected and will not trigger test re-runs.
|
|
279
279
|
|
|
280
280
|
To re-run every test on any watched change instead, set `config.watch.dependencyEvaluation`
|
|
281
281
|
to `false`. The dependency analysis is then skipped entirely - no trees are built at startup,
|