@rstest/core 0.9.2 → 0.9.3
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/LICENSE.md +1 -1
- package/dist/0~8843.js +5 -5
- package/dist/0~browserLoader.js +8 -8
- package/dist/0~browser~1.js +31 -31
- package/dist/0~checkThresholds.js +5 -5
- package/dist/{0~esm.js → 0~chokidar.js} +61 -18
- package/dist/0~console.js +7 -7
- package/dist/0~generate.js +4 -0
- package/dist/0~listTests.js +2 -2
- package/dist/0~mergeReports.js +127 -0
- package/dist/0~restart.js +3 -3
- package/dist/0~runTests.js +41 -41
- package/dist/1949.js +27 -11
- package/dist/255.js +3 -3
- package/dist/3145.js +160 -81
- package/dist/4411.js +3 -3
- package/dist/6830.js +43 -28
- package/dist/7552.js +82 -65
- package/dist/7704.js +2 -2
- package/dist/browser-runtime/723.js +142 -93
- package/dist/browser-runtime/index.d.ts +40 -5
- package/dist/browser.d.ts +40 -5
- package/dist/globalSetupWorker.js +4 -2
- package/dist/index.d.ts +53 -6
- package/dist/worker.d.ts +30 -3
- package/dist/worker.js +2 -2
- package/package.json +19 -18
- /package/dist/{0~esm.js.LICENSE.txt → 0~chokidar.js.LICENSE.txt} +0 -0
package/LICENSE.md
CHANGED
|
@@ -1183,7 +1183,7 @@ Licensed under MIT license in the repository at https://github.com/facebook/reac
|
|
|
1183
1183
|
|
|
1184
1184
|
### readdirp
|
|
1185
1185
|
|
|
1186
|
-
Licensed under MIT license in the repository at
|
|
1186
|
+
Licensed under MIT license in the repository at https://github.com/paulmillr/readdirp.git.
|
|
1187
1187
|
|
|
1188
1188
|
> MIT License
|
|
1189
1189
|
>
|
package/dist/0~8843.js
CHANGED
|
@@ -9,7 +9,7 @@ import node_path from "node:path";
|
|
|
9
9
|
import { isBuiltin } from "node:module";
|
|
10
10
|
import node_inspector from "node:inspector";
|
|
11
11
|
import node_fs from "node:fs";
|
|
12
|
-
import { basename, bgColor, isDeno, dirname, castArray, resolve as pathe_M_eThtNZ_resolve, isDebug, color, getForceColorEnv, ADDITIONAL_NODE_BUILTINS, needFlagExperimentalDetectModule, join } from "./6830.js";
|
|
12
|
+
import { basename, bgColor, isDeno, dirname, castArray, resolve as pathe_M_eThtNZ_resolve, isDebug, color as logger_color, getForceColorEnv, ADDITIONAL_NODE_BUILTINS, needFlagExperimentalDetectModule, join } from "./6830.js";
|
|
13
13
|
import { parseWorkerMetaMessage, createBirpc } from "./1983.js";
|
|
14
14
|
import { TEMP_RSTEST_OUTPUT_DIR, TEMP_RSTEST_OUTPUT_DIR_GLOB } from "./4411.js";
|
|
15
15
|
import { posix } from "./7011.js";
|
|
@@ -454,8 +454,8 @@ const createPool = async ({ context, recommendWorkerCount = 1 / 0 })=>{
|
|
|
454
454
|
const runningModule = context.stateManager.runningModules.get(entryInfo.testPath);
|
|
455
455
|
if (runningModule?.runningTests.length) {
|
|
456
456
|
const getCaseName = (test)=>`"${test.name}"${test.parentNames?.length ? ` (Under suite: ${test.parentNames?.join(' > ')})` : ''}`;
|
|
457
|
-
if (runningModule?.runningTests.length === 1) err.message += `\n\n${
|
|
458
|
-
else err.message += `\n\n${
|
|
457
|
+
if (runningModule?.runningTests.length === 1) err.message += `\n\n${logger_color.white(`Maybe relevant test case: ${getCaseName(runningModule.runningTests[0])} which is running when the error occurs.`)}`;
|
|
458
|
+
else err.message += `\n\n${logger_color.white(`The below test cases may be relevant, as they were running when the error occurred:\n - ${runningModule.runningTests.map((t)=>getCaseName(t)).join('\n - ')}`)}`;
|
|
459
459
|
}
|
|
460
460
|
return {
|
|
461
461
|
testId: '0',
|
|
@@ -598,8 +598,8 @@ async function runGlobalTeardown() {
|
|
|
598
598
|
await teardown();
|
|
599
599
|
} catch (error) {
|
|
600
600
|
console.error(bgColor('bgRed', 'Error during global teardown'));
|
|
601
|
-
if (error instanceof Error) error.stack ? console.error(
|
|
602
|
-
else console.error(
|
|
601
|
+
if (error instanceof Error) error.stack ? console.error(logger_color.red(error.stack)) : console.error(logger_color.red(error.message));
|
|
602
|
+
else console.error(logger_color.red(String(error)));
|
|
603
603
|
process.exitCode = 1;
|
|
604
604
|
}
|
|
605
605
|
}
|
package/dist/0~browserLoader.js
CHANGED
|
@@ -2,9 +2,9 @@ import "node:module";
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
import "./4411.js";
|
|
5
|
-
import { logger as logger_logger, color } from "./6830.js";
|
|
5
|
+
import { logger as logger_logger, color as logger_color } from "./6830.js";
|
|
6
6
|
async function loadBrowserModule(options = {}) {
|
|
7
|
-
const coreVersion = "0.9.
|
|
7
|
+
const coreVersion = "0.9.3";
|
|
8
8
|
const { projectRoots = [] } = options;
|
|
9
9
|
let browserModule;
|
|
10
10
|
let browserVersion;
|
|
@@ -24,9 +24,9 @@ async function loadBrowserModule(options = {}) {
|
|
|
24
24
|
const browserPkg = userRequire(browserPkgPath);
|
|
25
25
|
browserVersion = browserPkg.version;
|
|
26
26
|
if (browserVersion !== coreVersion) {
|
|
27
|
-
logger_logger.error(`\n${
|
|
28
|
-
logger_logger.error(` @rstest/core version: ${
|
|
29
|
-
logger_logger.error(`Please ensure both packages have the same version:\n\n ${
|
|
27
|
+
logger_logger.error(`\n${logger_color.red('Error:')} Version mismatch between ${logger_color.cyan('@rstest/core')} and ${logger_color.cyan('@rstest/browser')}.\n`);
|
|
28
|
+
logger_logger.error(` @rstest/core version: ${logger_color.yellow(coreVersion)}\n @rstest/browser version: ${logger_color.yellow(browserVersion)}\n`);
|
|
29
|
+
logger_logger.error(`Please ensure both packages have the same version:\n\n ${logger_color.cyan(`npm install @rstest/browser@${coreVersion}`)}\n`);
|
|
30
30
|
process.exit(1);
|
|
31
31
|
}
|
|
32
32
|
return browserModule;
|
|
@@ -35,9 +35,9 @@ async function loadBrowserModule(options = {}) {
|
|
|
35
35
|
if ('ERR_MODULE_NOT_FOUND' === err.code || 'MODULE_NOT_FOUND' === err.code) continue;
|
|
36
36
|
throw error;
|
|
37
37
|
}
|
|
38
|
-
logger_logger.error(`\n${
|
|
39
|
-
logger_logger.error(`Please install it with:\n\n ${
|
|
40
|
-
logger_logger.error(`Or if using pnpm:\n\n ${
|
|
38
|
+
logger_logger.error(`\n${logger_color.red('Error:')} Browser mode requires ${logger_color.cyan('@rstest/browser')} to be installed.\n`);
|
|
39
|
+
logger_logger.error(`Please install it with:\n\n ${logger_color.cyan(`npm install @rstest/browser@${coreVersion}`)}\n`);
|
|
40
|
+
logger_logger.error(`Or if using pnpm:\n\n ${logger_color.cyan(`pnpm add @rstest/browser@${coreVersion}`)}\n`);
|
|
41
41
|
process.exit(1);
|
|
42
42
|
}
|
|
43
43
|
export { loadBrowserModule };
|
package/dist/0~browser~1.js
CHANGED
|
@@ -4,7 +4,7 @@ import node_fs from "node:fs";
|
|
|
4
4
|
import { detect, resolveCommand } from "./3145.js";
|
|
5
5
|
import { confirm as Rt, intro as dist_Wt, log as R, note as dist_Vt, outro as Gt, cancel as Nt, isCancel as Ct, spinner as be, select as Jt } from "./0~dist.js";
|
|
6
6
|
import "./4411.js";
|
|
7
|
-
import { determineAgent, color } from "./6830.js";
|
|
7
|
+
import { determineAgent, color as logger_color } from "./6830.js";
|
|
8
8
|
function getUniqueBaseName(dir, baseName, ext) {
|
|
9
9
|
const fullPath = node_path.join(dir, `${baseName}${ext}`);
|
|
10
10
|
if (!node_fs.existsSync(fullPath)) return baseName;
|
|
@@ -323,14 +323,14 @@ async function createNonInteractive(cwd, projectInfo) {
|
|
|
323
323
|
const { agent, testDir, framework, reactVersion } = projectInfo;
|
|
324
324
|
const provider = 'playwright';
|
|
325
325
|
console.log();
|
|
326
|
-
console.log(
|
|
326
|
+
console.log(logger_color.cyan('◆'), logger_color.bold('rstest init browser --yes'));
|
|
327
327
|
console.log();
|
|
328
328
|
console.log(' Detecting project...');
|
|
329
|
-
if ('react' === framework && reactVersion) console.log(
|
|
330
|
-
else if ('react' === framework) console.log(
|
|
331
|
-
else console.log(
|
|
332
|
-
console.log(
|
|
333
|
-
console.log(
|
|
329
|
+
if ('react' === framework && reactVersion) console.log(logger_color.green(' ✓'), `Found React ${reactVersion}`);
|
|
330
|
+
else if ('react' === framework) console.log(logger_color.green(' ✓'), 'Found React');
|
|
331
|
+
else console.log(logger_color.yellow(' ⚠'), 'Framework not detected, generating vanilla DOM example');
|
|
332
|
+
console.log(logger_color.green(' ✓'), 'Using playwright as browser provider');
|
|
333
|
+
console.log(logger_color.green(' ✓'), `Test directory: ${testDir}/`);
|
|
334
334
|
console.log();
|
|
335
335
|
const createdFiles = await generateFiles(cwd, projectInfo, provider);
|
|
336
336
|
console.log(' Created files:');
|
|
@@ -342,20 +342,20 @@ async function createNonInteractive(cwd, projectInfo) {
|
|
|
342
342
|
console.log(` ${getPlaywrightInstallCommand(agent, provider)}`);
|
|
343
343
|
console.log(` ${getRunCommand(agent)}`);
|
|
344
344
|
console.log();
|
|
345
|
-
console.log(
|
|
345
|
+
console.log(logger_color.green('└'), 'Done!');
|
|
346
346
|
}
|
|
347
347
|
async function createInteractive(cwd, projectInfo, isAgent) {
|
|
348
348
|
const { agent, language, testDir, framework, reactVersion } = projectInfo;
|
|
349
349
|
const effectiveFramework = 'react' === framework ? 'react' : 'vanilla';
|
|
350
|
-
dist_Wt(
|
|
350
|
+
dist_Wt(logger_color.bgCyan(logger_color.black(' rstest init browser ')));
|
|
351
351
|
const detectionLines = [];
|
|
352
|
-
if ('react' === framework && reactVersion) detectionLines.push(`${
|
|
353
|
-
else if ('react' === framework) detectionLines.push(`${
|
|
354
|
-
else detectionLines.push(`${
|
|
355
|
-
detectionLines.push(`${
|
|
356
|
-
detectionLines.push(`${
|
|
352
|
+
if ('react' === framework && reactVersion) detectionLines.push(`${logger_color.green('✓')} Found React ${reactVersion}`);
|
|
353
|
+
else if ('react' === framework) detectionLines.push(`${logger_color.green('✓')} Found React`);
|
|
354
|
+
else detectionLines.push(`${logger_color.yellow('⚠')} Framework not detected, will generate vanilla DOM example`);
|
|
355
|
+
detectionLines.push(`${logger_color.green('✓')} Found ${'ts' === language ? 'TypeScript' : 'JavaScript'}`);
|
|
356
|
+
detectionLines.push(`${logger_color.green('✓')} Test directory: ${testDir}/`);
|
|
357
357
|
dist_Vt(detectionLines.join('\n'), 'Detecting project...');
|
|
358
|
-
if (isAgent) R.info(`AI Agent detected. For non-interactive mode, run:\n ${
|
|
358
|
+
if (isAgent) R.info(`AI Agent detected. For non-interactive mode, run:\n ${logger_color.cyan('npx rstest init browser --yes')}`);
|
|
359
359
|
const providerSelection = await Jt({
|
|
360
360
|
message: 'Choose a browser provider (so far, only Playwright)',
|
|
361
361
|
options: [
|
|
@@ -372,15 +372,15 @@ async function createInteractive(cwd, projectInfo, isAgent) {
|
|
|
372
372
|
}
|
|
373
373
|
const provider = providerSelection;
|
|
374
374
|
const preview = computeFilePreview(cwd, projectInfo);
|
|
375
|
-
const deps = getDependenciesWithVersions(effectiveFramework, provider, "0.9.
|
|
375
|
+
const deps = getDependenciesWithVersions(effectiveFramework, provider, "0.9.3");
|
|
376
376
|
const depsList = Object.entries(deps).map(([name, version])=>`${name}@${version}`).join(', ');
|
|
377
377
|
const previewLines = [
|
|
378
|
-
`${
|
|
379
|
-
`${
|
|
380
|
-
`${
|
|
381
|
-
`${
|
|
378
|
+
`${logger_color.cyan('+')} Create ${preview.configFile}`,
|
|
379
|
+
`${logger_color.cyan('+')} Create ${preview.componentFile}`,
|
|
380
|
+
`${logger_color.cyan('+')} Create ${preview.testFile}`,
|
|
381
|
+
`${logger_color.yellow('~')} Modify package.json`,
|
|
382
382
|
' - Add "test:browser" script',
|
|
383
|
-
` - Add devDependencies: ${
|
|
383
|
+
` - Add devDependencies: ${logger_color.dim(depsList)}`
|
|
384
384
|
];
|
|
385
385
|
dist_Vt(previewLines.join('\n'), 'Changes to be made');
|
|
386
386
|
const confirmed = await Rt({
|
|
@@ -395,21 +395,21 @@ async function createInteractive(cwd, projectInfo, isAgent) {
|
|
|
395
395
|
s.start('Creating files...');
|
|
396
396
|
const createdFiles = await generateFiles(cwd, projectInfo, provider);
|
|
397
397
|
s.stop('Created files');
|
|
398
|
-
const fileLines = createdFiles.map((f)=>`${
|
|
399
|
-
fileLines.push(`${
|
|
398
|
+
const fileLines = createdFiles.map((f)=>`${logger_color.green('✓')} Created ${f}`);
|
|
399
|
+
fileLines.push(`${logger_color.green('✓')} Updated package.json`);
|
|
400
400
|
dist_Vt(fileLines.join('\n'), 'Files');
|
|
401
401
|
const nextStepsLines = [
|
|
402
|
-
`${
|
|
403
|
-
` ${
|
|
402
|
+
`${logger_color.bold('1.')} Install dependencies:`,
|
|
403
|
+
` ${logger_color.cyan(getInstallCommand(agent))}`,
|
|
404
404
|
'',
|
|
405
|
-
`${
|
|
406
|
-
` ${
|
|
405
|
+
`${logger_color.bold('2.')} Install Playwright browsers:`,
|
|
406
|
+
` ${logger_color.cyan(getPlaywrightInstallCommand(agent, provider))}`,
|
|
407
407
|
'',
|
|
408
|
-
`${
|
|
409
|
-
` ${
|
|
408
|
+
`${logger_color.bold('3.')} Run your tests:`,
|
|
409
|
+
` ${logger_color.cyan(getRunCommand(agent))}`
|
|
410
410
|
];
|
|
411
411
|
dist_Vt(nextStepsLines.join('\n'), 'Next steps');
|
|
412
|
-
Gt(
|
|
412
|
+
Gt(logger_color.green('Done! Happy testing with Rstest!'));
|
|
413
413
|
}
|
|
414
414
|
async function generateFiles(cwd, projectInfo, provider) {
|
|
415
415
|
const { language, testDir, framework } = projectInfo;
|
|
@@ -450,7 +450,7 @@ async function generateFiles(cwd, projectInfo, provider) {
|
|
|
450
450
|
updatePackageJsonScripts(cwd, {
|
|
451
451
|
'test:browser': 'rstest --config=rstest.browser.config.ts'
|
|
452
452
|
});
|
|
453
|
-
const deps = getDependenciesWithVersions(effectiveFramework, provider, "0.9.
|
|
453
|
+
const deps = getDependenciesWithVersions(effectiveFramework, provider, "0.9.3");
|
|
454
454
|
updatePackageJsonDevDeps(cwd, deps);
|
|
455
455
|
return createdFiles;
|
|
456
456
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "node:module";
|
|
2
2
|
import { __webpack_require__ } from "./rslib-runtime.js";
|
|
3
3
|
import "./4411.js";
|
|
4
|
-
import { relative, color } from "./6830.js";
|
|
4
|
+
import { relative, color as logger_color } from "./6830.js";
|
|
5
5
|
const picomatch = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/index.js");
|
|
6
6
|
var picomatch_default = /*#__PURE__*/ __webpack_require__.n(picomatch);
|
|
7
7
|
const THRESHOLD_KEYS = [
|
|
@@ -34,7 +34,7 @@ function checkThresholds({ coverageMap, thresholds, coverageProvider, rootPath }
|
|
|
34
34
|
const matcher = picomatch_default()(key);
|
|
35
35
|
const matchedFiles = allFiles.filter((file)=>matcher(relative(rootPath, file)));
|
|
36
36
|
if (!matchedFiles.length) {
|
|
37
|
-
failedThresholds.push(`${
|
|
37
|
+
failedThresholds.push(`${logger_color.red('Error')}: coverage data for "${key}" was not found`);
|
|
38
38
|
continue;
|
|
39
39
|
}
|
|
40
40
|
for (const file of matchedFiles){
|
|
@@ -52,10 +52,10 @@ function checkThresholds({ coverageMap, thresholds, coverageProvider, rootPath }
|
|
|
52
52
|
if (void 0 !== expected) {
|
|
53
53
|
if (expected < 0) {
|
|
54
54
|
const uncovered = actual.total - actual.covered;
|
|
55
|
-
if (uncovered > -expected) errorMsg += `uncovered ${name} ${
|
|
56
|
-
} else if (actual.pct < expected) errorMsg += `coverage for ${name} ${
|
|
55
|
+
if (uncovered > -expected) errorMsg += `uncovered ${name} ${logger_color.red(`${uncovered}`)} exceeds maximum ${'global' === type ? 'global' : `"${type}"`} threshold allowed ${logger_color.yellow(`${-expected}`)}`;
|
|
56
|
+
} else if (actual.pct < expected) errorMsg += `coverage for ${name} ${logger_color.red(`${actual.pct}%`)} does not meet ${'global' === type ? 'global' : `"${type}"`} threshold ${logger_color.yellow(`${expected}%`)}`;
|
|
57
57
|
}
|
|
58
|
-
if (errorMsg) failedThresholds.push(`${
|
|
58
|
+
if (errorMsg) failedThresholds.push(`${logger_color.red('Error')}: ${file ? `${relative(rootPath, file)} ` : ''}${errorMsg}`);
|
|
59
59
|
};
|
|
60
60
|
thresholdGroup.forEach(({ name, coverageMap, ...thresholds })=>{
|
|
61
61
|
const summaries = thresholds.perFile ? coverageMap.files().map((file)=>({
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
/*! LICENSE: 0~
|
|
1
|
+
/*! LICENSE: 0~chokidar.js.LICENSE.txt */
|
|
2
2
|
import "node:module";
|
|
3
|
+
import { EventEmitter } from "node:events";
|
|
3
4
|
import { stat as external_node_fs_stat, unwatchFile, watch, watchFile } from "node:fs";
|
|
4
|
-
import { lstat
|
|
5
|
-
import { EventEmitter } from "events";
|
|
5
|
+
import { lstat, open as promises_open, readdir, realpath as promises_realpath, stat as promises_stat } from "node:fs/promises";
|
|
6
6
|
import { basename as external_node_path_basename, dirname as external_node_path_dirname, extname, isAbsolute, join, normalize, relative as external_node_path_relative, resolve as external_node_path_resolve, sep } from "node:path";
|
|
7
|
-
import { lstat, readdir as promises_readdir, realpath as promises_realpath, stat as external_node_fs_promises_stat } from "node:fs/promises";
|
|
8
7
|
import { Readable } from "node:stream";
|
|
9
8
|
import { type as external_node_os_type } from "node:os";
|
|
10
9
|
const EntryTypes = {
|
|
@@ -65,6 +64,20 @@ const normalizeFilter = (filter)=>{
|
|
|
65
64
|
return emptyFn;
|
|
66
65
|
};
|
|
67
66
|
class ReaddirpStream extends Readable {
|
|
67
|
+
parents;
|
|
68
|
+
reading;
|
|
69
|
+
parent;
|
|
70
|
+
_stat;
|
|
71
|
+
_maxDepth;
|
|
72
|
+
_wantsDir;
|
|
73
|
+
_wantsFile;
|
|
74
|
+
_wantsEverything;
|
|
75
|
+
_root;
|
|
76
|
+
_isDirent;
|
|
77
|
+
_statsProp;
|
|
78
|
+
_rdOptions;
|
|
79
|
+
_fileFilter;
|
|
80
|
+
_directoryFilter;
|
|
68
81
|
constructor(options = {}){
|
|
69
82
|
super({
|
|
70
83
|
objectMode: true,
|
|
@@ -78,12 +91,12 @@ class ReaddirpStream extends Readable {
|
|
|
78
91
|
const { root, type } = opts;
|
|
79
92
|
this._fileFilter = normalizeFilter(opts.fileFilter);
|
|
80
93
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
81
|
-
const statMethod = opts.lstat ? lstat :
|
|
94
|
+
const statMethod = opts.lstat ? lstat : promises_stat;
|
|
82
95
|
if (wantBigintFsStats) this._stat = (path)=>statMethod(path, {
|
|
83
96
|
bigint: true
|
|
84
97
|
});
|
|
85
98
|
else this._stat = statMethod;
|
|
86
|
-
this._maxDepth = opts.depth
|
|
99
|
+
this._maxDepth = null != opts.depth && Number.isSafeInteger(opts.depth) ? opts.depth : defaultOptions.depth;
|
|
87
100
|
this._wantsDir = type ? DIR_TYPES.has(type) : false;
|
|
88
101
|
this._wantsFile = type ? FILE_TYPES.has(type) : false;
|
|
89
102
|
this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
|
|
@@ -147,7 +160,7 @@ class ReaddirpStream extends Readable {
|
|
|
147
160
|
async _exploreDir(path, depth) {
|
|
148
161
|
let files;
|
|
149
162
|
try {
|
|
150
|
-
files = await
|
|
163
|
+
files = await readdir(path, this._rdOptions);
|
|
151
164
|
} catch (error) {
|
|
152
165
|
this._onError(error);
|
|
153
166
|
}
|
|
@@ -244,7 +257,7 @@ const EVENTS = {
|
|
|
244
257
|
const EV = EVENTS;
|
|
245
258
|
const THROTTLE_MODE_WATCH = 'watch';
|
|
246
259
|
const statMethods = {
|
|
247
|
-
lstat:
|
|
260
|
+
lstat: lstat,
|
|
248
261
|
stat: promises_stat
|
|
249
262
|
};
|
|
250
263
|
const KEY_LISTENERS = 'listeners';
|
|
@@ -655,6 +668,8 @@ const setFsWatchFileListener = (path, fullPath, options, handlers)=>{
|
|
|
655
668
|
};
|
|
656
669
|
};
|
|
657
670
|
class NodeFsHandler {
|
|
671
|
+
fsw;
|
|
672
|
+
_boundHandleError;
|
|
658
673
|
constructor(fsW){
|
|
659
674
|
this.fsw = fsW;
|
|
660
675
|
this._boundHandleError = (error)=>fsW._handleError(error);
|
|
@@ -732,7 +747,7 @@ class NodeFsHandler {
|
|
|
732
747
|
this.fsw._incrReadyCount();
|
|
733
748
|
let linkPath;
|
|
734
749
|
try {
|
|
735
|
-
linkPath = await
|
|
750
|
+
linkPath = await promises_realpath(path);
|
|
736
751
|
} catch (e) {
|
|
737
752
|
this.fsw._emitReady();
|
|
738
753
|
return true;
|
|
@@ -756,7 +771,8 @@ class NodeFsHandler {
|
|
|
756
771
|
}
|
|
757
772
|
_handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
|
|
758
773
|
directory = join(directory, '');
|
|
759
|
-
|
|
774
|
+
const throttleKey = target ? `${directory}:${target}` : directory;
|
|
775
|
+
throttler = this.fsw._throttle('readdir', throttleKey, 1000);
|
|
760
776
|
if (!throttler) return;
|
|
761
777
|
const previous = this.fsw._getWatchedDir(wh.path);
|
|
762
778
|
const current = new Set();
|
|
@@ -844,13 +860,13 @@ class NodeFsHandler {
|
|
|
844
860
|
let closer;
|
|
845
861
|
if (stats.isDirectory()) {
|
|
846
862
|
const absPath = external_node_path_resolve(path);
|
|
847
|
-
const targetPath = follow ? await
|
|
863
|
+
const targetPath = follow ? await promises_realpath(path) : path;
|
|
848
864
|
if (this.fsw.closed) return;
|
|
849
865
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
850
866
|
if (this.fsw.closed) return;
|
|
851
867
|
if (absPath !== targetPath && void 0 !== targetPath) this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
852
868
|
} else if (stats.isSymbolicLink()) {
|
|
853
|
-
const targetPath = follow ? await
|
|
869
|
+
const targetPath = follow ? await promises_realpath(path) : path;
|
|
854
870
|
if (this.fsw.closed) return;
|
|
855
871
|
const parent = external_node_path_dirname(wh.watchPath);
|
|
856
872
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
@@ -876,7 +892,7 @@ const ONE_DOT = '.';
|
|
|
876
892
|
const TWO_DOTS = '..';
|
|
877
893
|
const STRING_TYPE = 'string';
|
|
878
894
|
const BACK_SLASH_RE = /\\/g;
|
|
879
|
-
const
|
|
895
|
+
const DOUBLE_SLASH_RE = /\/\//g;
|
|
880
896
|
const DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
|
|
881
897
|
const REPLACER_RE = /^\.[/\\]/;
|
|
882
898
|
function arrify(item) {
|
|
@@ -906,8 +922,7 @@ function normalizePath(path) {
|
|
|
906
922
|
path = path.replace(/\\/g, '/');
|
|
907
923
|
let prepend = false;
|
|
908
924
|
if (path.startsWith('//')) prepend = true;
|
|
909
|
-
|
|
910
|
-
while(path.match(DOUBLE_SLASH_RE))path = path.replace(DOUBLE_SLASH_RE, '/');
|
|
925
|
+
path = path.replace(DOUBLE_SLASH_RE, '/');
|
|
911
926
|
if (prepend) path = '/' + path;
|
|
912
927
|
return path;
|
|
913
928
|
}
|
|
@@ -935,7 +950,7 @@ const toUnix = (string)=>{
|
|
|
935
950
|
let str = string.replace(BACK_SLASH_RE, SLASH);
|
|
936
951
|
let prepend = false;
|
|
937
952
|
if (str.startsWith(SLASH_SLASH)) prepend = true;
|
|
938
|
-
|
|
953
|
+
str = str.replace(DOUBLE_SLASH_RE, SLASH);
|
|
939
954
|
if (prepend) str = SLASH + str;
|
|
940
955
|
return str;
|
|
941
956
|
};
|
|
@@ -950,6 +965,9 @@ const getAbsolutePath = (path, cwd)=>{
|
|
|
950
965
|
};
|
|
951
966
|
const EMPTY_SET = Object.freeze(new Set());
|
|
952
967
|
class DirEntry {
|
|
968
|
+
path;
|
|
969
|
+
_removeWatcher;
|
|
970
|
+
items;
|
|
953
971
|
constructor(dir, removeWatcher){
|
|
954
972
|
this.path = dir;
|
|
955
973
|
this._removeWatcher = removeWatcher;
|
|
@@ -995,6 +1013,13 @@ class DirEntry {
|
|
|
995
1013
|
const STAT_METHOD_F = 'stat';
|
|
996
1014
|
const STAT_METHOD_L = 'lstat';
|
|
997
1015
|
class WatchHelper {
|
|
1016
|
+
fsw;
|
|
1017
|
+
path;
|
|
1018
|
+
watchPath;
|
|
1019
|
+
fullWatchPath;
|
|
1020
|
+
dirParts;
|
|
1021
|
+
followSymlinks;
|
|
1022
|
+
statMethod;
|
|
998
1023
|
constructor(path, follow, fsw){
|
|
999
1024
|
this.fsw = fsw;
|
|
1000
1025
|
const watchPath = path;
|
|
@@ -1022,6 +1047,24 @@ class WatchHelper {
|
|
|
1022
1047
|
}
|
|
1023
1048
|
}
|
|
1024
1049
|
class FSWatcher extends EventEmitter {
|
|
1050
|
+
closed;
|
|
1051
|
+
options;
|
|
1052
|
+
_closers;
|
|
1053
|
+
_ignoredPaths;
|
|
1054
|
+
_throttled;
|
|
1055
|
+
_streams;
|
|
1056
|
+
_symlinkPaths;
|
|
1057
|
+
_watched;
|
|
1058
|
+
_pendingWrites;
|
|
1059
|
+
_pendingUnlinks;
|
|
1060
|
+
_readyCount;
|
|
1061
|
+
_emitReady;
|
|
1062
|
+
_closePromise;
|
|
1063
|
+
_userIgnored;
|
|
1064
|
+
_readyEmitted;
|
|
1065
|
+
_emitRaw;
|
|
1066
|
+
_boundRemove;
|
|
1067
|
+
_nodeFsHandler;
|
|
1025
1068
|
constructor(_opts = {}){
|
|
1026
1069
|
super();
|
|
1027
1070
|
this.closed = false;
|
|
@@ -1413,9 +1456,9 @@ class FSWatcher extends EventEmitter {
|
|
|
1413
1456
|
return stream;
|
|
1414
1457
|
}
|
|
1415
1458
|
}
|
|
1416
|
-
function
|
|
1459
|
+
function chokidar_watch(paths, options = {}) {
|
|
1417
1460
|
const watcher = new FSWatcher(options);
|
|
1418
1461
|
watcher.add(paths);
|
|
1419
1462
|
return watcher;
|
|
1420
1463
|
}
|
|
1421
|
-
export {
|
|
1464
|
+
export { chokidar_watch as watch };
|
package/dist/0~console.js
CHANGED
|
@@ -2,7 +2,7 @@ import "node:module";
|
|
|
2
2
|
import { AssertionError, strict } from "node:assert";
|
|
3
3
|
import { Console } from "node:console";
|
|
4
4
|
import { format, formatWithOptions, inspect } from "node:util";
|
|
5
|
-
import { prettyTime, color } from "./6830.js";
|
|
5
|
+
import { prettyTime, color as logger_color } from "./6830.js";
|
|
6
6
|
const RealDate = Date;
|
|
7
7
|
function createCustomConsole({ rpc, testPath, printConsoleTrace }) {
|
|
8
8
|
const getConsoleTrace = ()=>{
|
|
@@ -21,13 +21,13 @@ function createCustomConsole({ rpc, testPath, printConsoleTrace }) {
|
|
|
21
21
|
getPrettyName(type) {
|
|
22
22
|
switch(type){
|
|
23
23
|
case 'error':
|
|
24
|
-
return
|
|
24
|
+
return logger_color.red(type);
|
|
25
25
|
case 'warn':
|
|
26
|
-
return
|
|
26
|
+
return logger_color.yellow(type);
|
|
27
27
|
case 'info':
|
|
28
|
-
return
|
|
28
|
+
return logger_color.cyan(type);
|
|
29
29
|
default:
|
|
30
|
-
return
|
|
30
|
+
return logger_color.gray(type);
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
_log(name, message, type = 'stdout') {
|
|
@@ -69,11 +69,11 @@ function createCustomConsole({ rpc, testPath, printConsoleTrace }) {
|
|
|
69
69
|
}
|
|
70
70
|
group(title, ...args) {
|
|
71
71
|
this._groupDepth++;
|
|
72
|
-
if (null != title || args.length > 0) this._log('group',
|
|
72
|
+
if (null != title || args.length > 0) this._log('group', logger_color.bold(format(title, ...args)));
|
|
73
73
|
}
|
|
74
74
|
groupCollapsed(title, ...args) {
|
|
75
75
|
this._groupDepth++;
|
|
76
|
-
if (null != title || args.length > 0) this._log('groupCollapsed',
|
|
76
|
+
if (null != title || args.length > 0) this._log('groupCollapsed', logger_color.bold(format(title, ...args)));
|
|
77
77
|
}
|
|
78
78
|
groupEnd() {
|
|
79
79
|
if (this._groupDepth > 0) this._groupDepth--;
|
package/dist/0~generate.js
CHANGED
|
@@ -22,6 +22,10 @@ async function generateCoverage(context, results, coverageProvider) {
|
|
|
22
22
|
try {
|
|
23
23
|
const finalCoverageMap = coverageProvider.createCoverageMap();
|
|
24
24
|
for (const result of results)if (result.coverage) finalCoverageMap.merge(result.coverage);
|
|
25
|
+
if (!coverage.allowExternal) finalCoverageMap.filter((filePath)=>{
|
|
26
|
+
const normalizedFile = normalize(filePath);
|
|
27
|
+
return normalizedFile.startsWith(normalize(rootPath));
|
|
28
|
+
});
|
|
25
29
|
if (coverage.include?.length) {
|
|
26
30
|
const coveredFiles = finalCoverageMap.files().map(normalize);
|
|
27
31
|
let isTimeout = false;
|
package/dist/0~listTests.js
CHANGED
|
@@ -3,7 +3,7 @@ import { mkdirSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import { dirname, isAbsolute, join, relative } from "node:path";
|
|
4
4
|
import { prepareRsbuild, createPool, createRsbuildServer, runGlobalTeardown, runGlobalSetup } from "./0~8843.js";
|
|
5
5
|
import { getTestEntries, resolveShardedEntries, prettyTestPath, ROOT_SUITE_NAME } from "./4411.js";
|
|
6
|
-
import { logger as logger_logger, getTaskNameWithPrefix, color, bgColor } from "./6830.js";
|
|
6
|
+
import { logger as logger_logger, getTaskNameWithPrefix, color as logger_color, bgColor } from "./6830.js";
|
|
7
7
|
const collectNodeTests = async ({ context, nodeProjects, globTestSourceEntries })=>{
|
|
8
8
|
const { getSetupFiles } = await import("./255.js");
|
|
9
9
|
if (0 === nodeProjects.length) return {
|
|
@@ -262,7 +262,7 @@ async function listTests(context, { filesOnly, json, printLocation, includeSuite
|
|
|
262
262
|
} else for (const test of tests){
|
|
263
263
|
let shortPath = relative(rootPath, test.file);
|
|
264
264
|
if (test.location && printLocation) shortPath = `${shortPath}:${test.location.line}:${test.location.column}`;
|
|
265
|
-
logger_logger.log(test.name ? `${
|
|
265
|
+
logger_logger.log(test.name ? `${logger_color.dim(`${shortPath} > `)}${test.name}` : prettyTestPath(shortPath));
|
|
266
266
|
}
|
|
267
267
|
await close();
|
|
268
268
|
return list;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
3
|
+
import { createCoverageProvider } from "./7704.js";
|
|
4
|
+
import "./4411.js";
|
|
5
|
+
import { prettyTime, logger as logger_logger, relative, color as logger_color, join } from "./6830.js";
|
|
6
|
+
const DEFAULT_BLOB_DIR = '.rstest-reports';
|
|
7
|
+
function loadBlobFiles(blobDir) {
|
|
8
|
+
if (!existsSync(blobDir)) throw new Error(`Blob reports directory not found: ${logger_color.cyan(blobDir)}\nRun tests with --reporter=blob first to generate shard reports.`);
|
|
9
|
+
const files = readdirSync(blobDir).filter((f)=>/^blob(-\d+-\d+)?\.json$/.test(f)).sort();
|
|
10
|
+
if (0 === files.length) throw new Error(`No blob report files found in: ${logger_color.cyan(blobDir)}\nRun tests with --reporter=blob first to generate shard reports.`);
|
|
11
|
+
return files.map((file)=>{
|
|
12
|
+
const content = readFileSync(join(blobDir, file), 'utf-8');
|
|
13
|
+
return JSON.parse(content);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function mergeSnapshots(summaries) {
|
|
17
|
+
const merged = {
|
|
18
|
+
added: 0,
|
|
19
|
+
didUpdate: false,
|
|
20
|
+
failure: false,
|
|
21
|
+
filesAdded: 0,
|
|
22
|
+
filesRemoved: 0,
|
|
23
|
+
filesRemovedList: [],
|
|
24
|
+
filesUnmatched: 0,
|
|
25
|
+
filesUpdated: 0,
|
|
26
|
+
matched: 0,
|
|
27
|
+
total: 0,
|
|
28
|
+
unchecked: 0,
|
|
29
|
+
uncheckedKeysByFile: [],
|
|
30
|
+
unmatched: 0,
|
|
31
|
+
updated: 0
|
|
32
|
+
};
|
|
33
|
+
for (const s of summaries){
|
|
34
|
+
merged.added += s.added;
|
|
35
|
+
merged.filesAdded += s.filesAdded;
|
|
36
|
+
merged.filesRemoved += s.filesRemoved;
|
|
37
|
+
merged.filesRemovedList.push(...s.filesRemovedList);
|
|
38
|
+
merged.filesUnmatched += s.filesUnmatched;
|
|
39
|
+
merged.filesUpdated += s.filesUpdated;
|
|
40
|
+
merged.matched += s.matched;
|
|
41
|
+
merged.total += s.total;
|
|
42
|
+
merged.unchecked += s.unchecked;
|
|
43
|
+
merged.uncheckedKeysByFile.push(...s.uncheckedKeysByFile);
|
|
44
|
+
merged.unmatched += s.unmatched;
|
|
45
|
+
merged.updated += s.updated;
|
|
46
|
+
if (s.didUpdate) merged.didUpdate = true;
|
|
47
|
+
if (s.failure) merged.failure = true;
|
|
48
|
+
}
|
|
49
|
+
return merged;
|
|
50
|
+
}
|
|
51
|
+
function mergeDurations(durations) {
|
|
52
|
+
let totalTime = 0;
|
|
53
|
+
let buildTime = 0;
|
|
54
|
+
let testTime = 0;
|
|
55
|
+
for (const d of durations){
|
|
56
|
+
totalTime += d.totalTime;
|
|
57
|
+
buildTime += d.buildTime;
|
|
58
|
+
testTime += d.testTime;
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
totalTime,
|
|
62
|
+
buildTime,
|
|
63
|
+
testTime
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
async function mergeReports(context, options) {
|
|
67
|
+
const { path, cleanup } = options || {};
|
|
68
|
+
const blobDir = path ? join(context.rootPath, path) : join(context.rootPath, DEFAULT_BLOB_DIR);
|
|
69
|
+
const blobs = loadBlobFiles(blobDir);
|
|
70
|
+
const relativeBlobDir = relative(context.rootPath, blobDir) || '.';
|
|
71
|
+
logger_logger.log(`\nMerging ${logger_color.bold(String(blobs.length))} blob ${1 === blobs.length ? 'report' : 'reports'} from ${logger_color.cyan(relativeBlobDir)}\n`);
|
|
72
|
+
const allResults = [];
|
|
73
|
+
const allTestResults = [];
|
|
74
|
+
const allDurations = [];
|
|
75
|
+
const shardDurations = [];
|
|
76
|
+
const allSnapshotSummaries = [];
|
|
77
|
+
const allUnhandledErrors = [];
|
|
78
|
+
for (const blob of blobs){
|
|
79
|
+
allResults.push(...blob.results);
|
|
80
|
+
allTestResults.push(...blob.testResults);
|
|
81
|
+
allDurations.push(blob.duration);
|
|
82
|
+
allSnapshotSummaries.push(blob.snapshotSummary);
|
|
83
|
+
const shardLabel = blob.shard ? `Shard ${blob.shard.index}/${blob.shard.count}` : 'Shard';
|
|
84
|
+
shardDurations.push({
|
|
85
|
+
label: shardLabel,
|
|
86
|
+
duration: blob.duration
|
|
87
|
+
});
|
|
88
|
+
if (blob.unhandledErrors) for (const e of blob.unhandledErrors){
|
|
89
|
+
const error = new Error(e.message);
|
|
90
|
+
error.name = e.name || 'Error';
|
|
91
|
+
error.stack = e.stack;
|
|
92
|
+
allUnhandledErrors.push(error);
|
|
93
|
+
}
|
|
94
|
+
if (blob.consoleLogs) for (const log of blob.consoleLogs)for (const reporter of context.reporters)reporter.onUserConsoleLog?.(log);
|
|
95
|
+
}
|
|
96
|
+
const mergedDuration = mergeDurations(allDurations);
|
|
97
|
+
const mergedSnapshotSummary = mergeSnapshots(allSnapshotSummaries);
|
|
98
|
+
const hasFailure = allResults.some((r)=>'fail' === r.status) || allUnhandledErrors.length > 0;
|
|
99
|
+
if (hasFailure) process.exitCode = 1;
|
|
100
|
+
for (const reporter of context.reporters)await reporter.onTestRunStart?.();
|
|
101
|
+
for (const { label, duration } of shardDurations)logger_logger.log(logger_color.gray(` ${label}: ${prettyTime(duration.totalTime)} (build ${prettyTime(duration.buildTime)}, tests ${prettyTime(duration.testTime)})`));
|
|
102
|
+
if (shardDurations.length > 0) logger_logger.log('');
|
|
103
|
+
for (const result of allResults)for (const reporter of context.reporters)reporter.onTestFileResult?.(result);
|
|
104
|
+
for (const reporter of context.reporters)await reporter.onTestRunEnd?.({
|
|
105
|
+
results: allResults,
|
|
106
|
+
testResults: allTestResults,
|
|
107
|
+
duration: mergedDuration,
|
|
108
|
+
snapshotSummary: mergedSnapshotSummary,
|
|
109
|
+
unhandledErrors: allUnhandledErrors.length ? allUnhandledErrors : void 0,
|
|
110
|
+
getSourcemap: async ()=>null
|
|
111
|
+
});
|
|
112
|
+
const { coverage } = context.normalizedConfig;
|
|
113
|
+
if (coverage.enabled && (!hasFailure || coverage.reportOnFailure)) {
|
|
114
|
+
const coverageProvider = await createCoverageProvider(coverage, context.rootPath);
|
|
115
|
+
if (coverageProvider) {
|
|
116
|
+
const { generateCoverage } = await import("./0~generate.js");
|
|
117
|
+
await generateCoverage(context, allResults, coverageProvider);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (cleanup && existsSync(blobDir)) {
|
|
121
|
+
rmSync(blobDir, {
|
|
122
|
+
recursive: true
|
|
123
|
+
});
|
|
124
|
+
logger_logger.log(logger_color.gray(`Cleaned up blob reports directory: ${relativeBlobDir}\n`));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export { mergeReports };
|