@rstest/browser 0.11.2 → 0.11.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/dist/browser-container/container-static/js/{117.3da95caa39.js → 243.a8eed2b9e7.js} +936 -910
- package/dist/browser-container/container-static/js/243.a8eed2b9e7.js.LICENSE.txt +1 -0
- package/dist/browser-container/container-static/js/{index.6e4da8c9ab.js → index.84aaafaf21.js} +80 -75
- package/dist/browser-container/index.html +1 -1
- package/dist/index.js +263 -148
- package/package.json +10 -9
- package/src/browserExecutor.ts +5 -3
- package/src/client/entry.ts +21 -13
- package/src/configValidation.ts +6 -0
- package/src/hostController.ts +496 -129
- package/dist/browser-container/container-static/js/117.3da95caa39.js.LICENSE.txt +0 -1
- package/dist/watchCliShortcuts.d.ts +0 -6
- package/src/AGENTS.md +0 -150
- package/src/client/AGENTS.md +0 -89
- package/src/client/formatConsole.ts +0 -77
- package/src/client/public.ts +0 -12
- package/src/watchCliShortcuts.ts +0 -77
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_TEST_TIMEOUT, PhaseTracker, RSTEST_ENV_SYMBOL_KEY, browserIgnoredRuntimeConfigKeys, buildBrowserCoverageMap, color, createCoverageProvider, createRunnerEventSink, createSilentConsoleController, getNoTestFilesMessage, getNumCpus as browser_getNumCpus, getSetupFiles, getTestEntries, hasUserRstestConfigPlugins, initModifyRstestConfigHooks, isDebug, isTTY, loadCoverageProvider, logger, prepareWatchRerunState, projectRuntimeConfig, resolveProjectBuildCache, resolveShardedEntries, resolveSnapshotPathDefault, resolveWorkerCount, rsbuild, serializableConfig } from "@rstest/core/internal/browser";
|
|
1
|
+
import { DEFAULT_TEST_TIMEOUT, FATAL_SIGNALS, PhaseTracker, RSTEST_ENV_SYMBOL_KEY, applyWatchInvalidation, applyWebMockRspackConfig, browserIgnoredRuntimeConfigKeys, buildBrowserCoverageMap, color, createCoverageProvider, createRunnerEventSink, createSilentConsoleController, finalizeRunCycle, getNoTestFilesMessage, getNumCpus as browser_getNumCpus, getPrettyConsoleName, getSetupFiles, getTestEntries, hasUserRstestConfigPlugins, importMetaRstestDefine, initModifyRstestConfigHooks, isDebug, isTTY, loadCoverageProvider, logWatchReadyMessage, logger, pluginMockRuntime, prepareWatchRerunState, projectRuntimeConfig, resolveProjectBuildCache, resolveShardedEntries, resolveSnapshotPathDefault, resolveWorkerCount, rsbuild, serializableConfig } from "@rstest/core/internal/browser";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import promises from "node:fs/promises";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -2054,6 +2054,11 @@ const ignoredKeyWarnings = {
|
|
|
2054
2054
|
message: ()=>"Ignoring isolate: false in browser mode: each test file still runs in a fresh context.",
|
|
2055
2055
|
browserOnly: true
|
|
2056
2056
|
},
|
|
2057
|
+
federation: {
|
|
2058
|
+
isNonDefault: (config)=>true === config.federation,
|
|
2059
|
+
message: ()=>'Ignoring federation in browser mode: it only applies to the Node runner.',
|
|
2060
|
+
browserOnly: true
|
|
2061
|
+
},
|
|
2057
2062
|
detectAsyncLeaks: {
|
|
2058
2063
|
isNonDefault: (config)=>true === config.detectAsyncLeaks,
|
|
2059
2064
|
message: ()=>"Ignoring detectAsyncLeaks in browser mode: it relies on node async_hooks."
|
|
@@ -2835,44 +2840,6 @@ const loadSourceMapWithCache = async ({ jsUrl, cache, force = false, origin, fet
|
|
|
2835
2840
|
return null;
|
|
2836
2841
|
}
|
|
2837
2842
|
};
|
|
2838
|
-
const isBrowserWatchCliShortcutsEnabled = ()=>isTTY('stdin');
|
|
2839
|
-
const getBrowserWatchCliShortcutsHintMessage = ()=>` ${color.dim('press')} ${color.bold('q')} ${color.dim('to quit')}\n`;
|
|
2840
|
-
const logBrowserWatchReadyMessage = (enableCliShortcuts)=>{
|
|
2841
|
-
logger.log(color.green(' Waiting for file changes...'));
|
|
2842
|
-
if (enableCliShortcuts) logger.log(getBrowserWatchCliShortcutsHintMessage());
|
|
2843
|
-
};
|
|
2844
|
-
async function setupBrowserWatchCliShortcuts({ close }) {
|
|
2845
|
-
const { emitKeypressEvents } = await import("node:readline");
|
|
2846
|
-
emitKeypressEvents(process.stdin);
|
|
2847
|
-
process.stdin.setRawMode(true);
|
|
2848
|
-
process.stdin.resume();
|
|
2849
|
-
process.stdin.setEncoding('utf8');
|
|
2850
|
-
let isClosing = false;
|
|
2851
|
-
const handleKeypress = (str, key)=>{
|
|
2852
|
-
if (key.ctrl && 'c' === key.name) return void process.kill(process.pid, 'SIGINT');
|
|
2853
|
-
if (key.ctrl && 'z' === key.name) {
|
|
2854
|
-
if ('win32' !== process.platform) process.kill(process.pid, 'SIGTSTP');
|
|
2855
|
-
return;
|
|
2856
|
-
}
|
|
2857
|
-
if ('q' !== str || isClosing) return;
|
|
2858
|
-
isClosing = true;
|
|
2859
|
-
(async ()=>{
|
|
2860
|
-
try {
|
|
2861
|
-
await close();
|
|
2862
|
-
} finally{
|
|
2863
|
-
process.exit(0);
|
|
2864
|
-
}
|
|
2865
|
-
})();
|
|
2866
|
-
};
|
|
2867
|
-
process.stdin.on('keypress', handleKeypress);
|
|
2868
|
-
return ()=>{
|
|
2869
|
-
try {
|
|
2870
|
-
process.stdin.setRawMode(false);
|
|
2871
|
-
process.stdin.pause();
|
|
2872
|
-
} catch {}
|
|
2873
|
-
process.stdin.off('keypress', handleKeypress);
|
|
2874
|
-
};
|
|
2875
|
-
}
|
|
2876
2843
|
const serializeTestFiles = (files)=>JSON.stringify(files.map((f)=>`${f.projectName}:${f.testPath}`).sort());
|
|
2877
2844
|
const normalizeTestFiles = (files)=>files.map((file)=>({
|
|
2878
2845
|
...file,
|
|
@@ -3004,6 +2971,9 @@ class ContainerRpcManager {
|
|
|
3004
2971
|
async notifyTestFileUpdate(files) {
|
|
3005
2972
|
await this.rpc?.onTestFileUpdate(files);
|
|
3006
2973
|
}
|
|
2974
|
+
async updateHostConfig(config) {
|
|
2975
|
+
await this.rpc?.onHostConfigUpdate(config);
|
|
2976
|
+
}
|
|
3007
2977
|
async reloadTestFile(testFile, testNamePattern) {
|
|
3008
2978
|
logger.debug(`[Browser UI] reloadTestFile called, rpc: ${this.rpc ? 'exists' : 'null'}, ws: ${this.ws ? 'exists' : 'null'}`);
|
|
3009
2979
|
if (!this.rpc) throw new Error('Browser UI RPC not available for reloadTestFile');
|
|
@@ -3011,15 +2981,29 @@ class ContainerRpcManager {
|
|
|
3011
2981
|
return this.rpc.reloadTestFile(testFile, testNamePattern);
|
|
3012
2982
|
}
|
|
3013
2983
|
}
|
|
2984
|
+
const createBrowserWatchState = ()=>({
|
|
2985
|
+
lastTestFiles: [],
|
|
2986
|
+
hooksEnabled: false,
|
|
2987
|
+
invalidation: new Map(),
|
|
2988
|
+
pendingAffectedTestFiles: new Map(),
|
|
2989
|
+
compileStartTimes: new Map(),
|
|
2990
|
+
pendingBuildTimeMs: 0
|
|
2991
|
+
});
|
|
2992
|
+
const drainPendingBuildTime = (watchState)=>{
|
|
2993
|
+
const buildTime = watchState.pendingBuildTimeMs;
|
|
2994
|
+
watchState.pendingBuildTimeMs = 0;
|
|
2995
|
+
return buildTime;
|
|
2996
|
+
};
|
|
2997
|
+
const drainPendingAffectedTestFiles = (watchState)=>{
|
|
2998
|
+
const affected = new Set();
|
|
2999
|
+
for (const files of watchState.pendingAffectedTestFiles.values())for (const file of files)affected.add(file);
|
|
3000
|
+
watchState.pendingAffectedTestFiles.clear();
|
|
3001
|
+
return Array.from(affected);
|
|
3002
|
+
};
|
|
3014
3003
|
const watchContext = {
|
|
3015
3004
|
runtime: null,
|
|
3016
|
-
lastTestFiles: [],
|
|
3017
|
-
hooksEnabled: false,
|
|
3018
3005
|
cleanupRegistered: false,
|
|
3019
|
-
cleanupPromise: null
|
|
3020
|
-
closeCliShortcuts: null,
|
|
3021
|
-
chunkHashes: new Map(),
|
|
3022
|
-
affectedTestFiles: []
|
|
3006
|
+
cleanupPromise: null
|
|
3023
3007
|
};
|
|
3024
3008
|
const resolveViewport = (viewport)=>{
|
|
3025
3009
|
if (!viewport) return null;
|
|
@@ -3202,25 +3186,42 @@ const getChunkKey = (chunk)=>{
|
|
|
3202
3186
|
if (chunk.files && chunk.files.length > 0) return chunk.files[0];
|
|
3203
3187
|
return null;
|
|
3204
3188
|
};
|
|
3205
|
-
const getAffectedTestFiles = (chunks, entryTestFiles)=>{
|
|
3206
|
-
|
|
3207
|
-
const
|
|
3208
|
-
const
|
|
3209
|
-
|
|
3189
|
+
const getAffectedTestFiles = ({ chunks, entryTestFiles, setupFiles, state })=>{
|
|
3190
|
+
const entryHashes = new Map();
|
|
3191
|
+
const setupHashes = new Map();
|
|
3192
|
+
const recordChunk = (snapshot, entryPath, chunkKey, hash)=>{
|
|
3193
|
+
const record = snapshot.get(entryPath) ?? {};
|
|
3194
|
+
record[chunkKey] = hash;
|
|
3195
|
+
snapshot.set(entryPath, record);
|
|
3196
|
+
};
|
|
3197
|
+
for (const chunk of chunks || []){
|
|
3210
3198
|
if (!chunk.hash) continue;
|
|
3211
|
-
const testFile = findTestFileInModules(chunk.modules, entryTestFiles);
|
|
3212
|
-
if (!testFile) continue;
|
|
3213
3199
|
const chunkKey = getChunkKey(chunk);
|
|
3214
3200
|
if (!chunkKey) continue;
|
|
3215
|
-
const
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
logger.debug(`[Watch] Chunk hash changed for ${chunkKey}: ${prevHash} -> ${chunk.hash} (test: ${testFile})`);
|
|
3201
|
+
const testFile = findTestFileInModules(chunk.modules, entryTestFiles);
|
|
3202
|
+
if (testFile) {
|
|
3203
|
+
recordChunk(entryHashes, testFile, chunkKey, chunk.hash);
|
|
3204
|
+
continue;
|
|
3220
3205
|
}
|
|
3206
|
+
const setupFile = findTestFileInModules(chunk.modules, setupFiles);
|
|
3207
|
+
if (setupFile) recordChunk(setupHashes, setupFile, chunkKey, chunk.hash);
|
|
3208
|
+
}
|
|
3209
|
+
const seedFirstSeen = (baseline, current)=>{
|
|
3210
|
+
if (!baseline) return;
|
|
3211
|
+
for (const [entryPath, record] of current)if (!baseline.has(entryPath)) baseline.set(entryPath, record);
|
|
3212
|
+
};
|
|
3213
|
+
seedFirstSeen(state.entryHashes, entryHashes);
|
|
3214
|
+
seedFirstSeen(state.setupHashes, setupHashes);
|
|
3215
|
+
const outcome = applyWatchInvalidation(state, {
|
|
3216
|
+
entryHashes,
|
|
3217
|
+
setupHashes
|
|
3218
|
+
});
|
|
3219
|
+
if (outcome.rerunAll) {
|
|
3220
|
+
logger.debug('[Watch] Setup file changed, re-running all test files of the project');
|
|
3221
|
+
return Array.from(entryTestFiles);
|
|
3221
3222
|
}
|
|
3222
|
-
|
|
3223
|
-
return
|
|
3223
|
+
for (const affected of outcome.affectedPaths)logger.debug(`[Watch] Chunk hash changed for test: ${affected}`);
|
|
3224
|
+
return outcome.affectedPaths;
|
|
3224
3225
|
};
|
|
3225
3226
|
const getBrowserProjects = (context)=>context.projects.filter((project)=>project.normalizedConfig.browser.enabled);
|
|
3226
3227
|
const getBrowserRsbuildEnvironmentConfig = (project)=>({
|
|
@@ -3332,12 +3333,29 @@ const generateManifestModule = ({ manifestPath, entries, isWatchMode })=>{
|
|
|
3332
3333
|
if (isWatchMode) {
|
|
3333
3334
|
const includeRegExp = globPatternsToRegExp(project.normalizedConfig.include);
|
|
3334
3335
|
const excludeRegExp = createBrowserContextExcludeRegExp(project.normalizedConfig.exclude.patterns, projectRootPosix);
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3336
|
+
const { includeSource } = project.normalizedConfig;
|
|
3337
|
+
const emitContext = (contextVarName, regExp)=>{
|
|
3338
|
+
lines.push(`const ${contextVarName} = import.meta.webpackContext(${JSON.stringify(projectRootPosix)}, {`);
|
|
3339
|
+
lines.push(' recursive: true,');
|
|
3340
|
+
lines.push(` regExp: ${regExp.toString()},`);
|
|
3341
|
+
if (excludeRegExp) lines.push(` exclude: ${excludeRegExp.toString()},`);
|
|
3342
|
+
lines.push(" mode: 'lazy',");
|
|
3343
|
+
lines.push('});');
|
|
3344
|
+
};
|
|
3345
|
+
if (0 === includeSource.length) emitContext(varName, includeRegExp);
|
|
3346
|
+
else {
|
|
3347
|
+
emitContext(`${varName}_include`, includeRegExp);
|
|
3348
|
+
emitContext(`${varName}_source`, globPatternsToRegExp(includeSource));
|
|
3349
|
+
const probedKeys = testFiles.map((filePath)=>toContextKey(filePath, projectRootPosix));
|
|
3350
|
+
lines.push(`const ${varName}_probed = ${JSON.stringify(probedKeys)};`);
|
|
3351
|
+
lines.push(`const ${varName}_includeKeys = new Set(${varName}_include.keys());`);
|
|
3352
|
+
lines.push(`const ${varName} = Object.assign(`);
|
|
3353
|
+
lines.push(` (key) => ${varName}_includeKeys.has(key) ? ${varName}_include(key) : ${varName}_source(key),`);
|
|
3354
|
+
lines.push(' {');
|
|
3355
|
+
lines.push(` keys: () => Array.from(new Set([...${varName}_includeKeys, ...${varName}_probed])),`);
|
|
3356
|
+
lines.push(' },');
|
|
3357
|
+
lines.push(');');
|
|
3358
|
+
}
|
|
3341
3359
|
} else {
|
|
3342
3360
|
lines.push(`const ${varName}_modules = {`);
|
|
3343
3361
|
for (const filePath of testFiles){
|
|
@@ -3409,27 +3427,22 @@ const destroyBrowserRuntime = async (runtime)=>{
|
|
|
3409
3427
|
const cleanupWatchRuntime = ()=>{
|
|
3410
3428
|
if (watchContext.cleanupPromise) return watchContext.cleanupPromise;
|
|
3411
3429
|
watchContext.cleanupPromise = (async ()=>{
|
|
3412
|
-
watchContext.closeCliShortcuts?.();
|
|
3413
|
-
watchContext.closeCliShortcuts = null;
|
|
3414
3430
|
if (!watchContext.runtime) return;
|
|
3415
3431
|
await destroyBrowserRuntime(watchContext.runtime);
|
|
3416
3432
|
watchContext.runtime = null;
|
|
3417
3433
|
})();
|
|
3418
3434
|
return watchContext.cleanupPromise;
|
|
3419
3435
|
};
|
|
3420
|
-
const registerWatchCleanup = ()=>{
|
|
3436
|
+
const registerWatchCleanup = (embedded)=>{
|
|
3421
3437
|
if (watchContext.cleanupRegistered) return;
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
'SIGTSTP'
|
|
3426
|
-
])process.once(signal, ()=>{
|
|
3438
|
+
watchContext.cleanupRegistered = true;
|
|
3439
|
+
if (embedded) return;
|
|
3440
|
+
for (const signal of FATAL_SIGNALS)process.once(signal, ()=>{
|
|
3427
3441
|
cleanupWatchRuntime();
|
|
3428
3442
|
});
|
|
3429
3443
|
process.once('exit', ()=>{
|
|
3430
3444
|
cleanupWatchRuntime();
|
|
3431
3445
|
});
|
|
3432
|
-
watchContext.cleanupRegistered = true;
|
|
3433
3446
|
};
|
|
3434
3447
|
const createBrowserRuntime = async ({ context, projectEntries: initialProjectEntries, browserProjects, shardedEntries, freezeShardedEntries, tempDir, isWatchMode, onTriggerRerun, containerDistPath, containerDevServer, forceHeadless, skipProviderLaunch, appliedModifyRstestConfigEnvironments })=>{
|
|
3435
3448
|
const containerHtmlTemplate = containerDistPath ? await promises.readFile(join(containerDistPath, 'index.html'), 'utf-8') : null;
|
|
@@ -3442,6 +3455,7 @@ const createBrowserRuntime = async ({ context, projectEntries: initialProjectEnt
|
|
|
3442
3455
|
};
|
|
3443
3456
|
let browserLaunchOptions = ensureConsistentBrowserLaunchOptions(browserProjects);
|
|
3444
3457
|
let projectEntries = initialProjectEntries;
|
|
3458
|
+
const watchState = createBrowserWatchState();
|
|
3445
3459
|
const manifestModules = [];
|
|
3446
3460
|
const createRuntimeWithoutProvider = ()=>{
|
|
3447
3461
|
const firstProject = browserProjects[0];
|
|
@@ -3464,7 +3478,8 @@ const createBrowserRuntime = async ({ context, projectEntries: initialProjectEnt
|
|
|
3464
3478
|
setContainerOptions,
|
|
3465
3479
|
dispatchHandlers,
|
|
3466
3480
|
wss: void 0,
|
|
3467
|
-
projectEntries
|
|
3481
|
+
projectEntries,
|
|
3482
|
+
watchState
|
|
3468
3483
|
};
|
|
3469
3484
|
};
|
|
3470
3485
|
const getProjectEntry = (project)=>projectEntries.find((item)=>item.project.environmentName === project.environmentName);
|
|
@@ -3493,7 +3508,6 @@ const createBrowserRuntime = async ({ context, projectEntries: initialProjectEnt
|
|
|
3493
3508
|
};
|
|
3494
3509
|
const browserRuntimePath = fileURLToPath(import.meta.resolve('@rstest/core/internal/browser-runtime'));
|
|
3495
3510
|
const staticRstestAliases = {
|
|
3496
|
-
'@rstest/core': resolveBrowserFile('client/public.ts'),
|
|
3497
3511
|
'@rstest/browser': resolveBrowserFile('browser.ts'),
|
|
3498
3512
|
'@rstest/core/internal/browser-runtime': browserRuntimePath
|
|
3499
3513
|
};
|
|
@@ -3589,6 +3603,7 @@ const createBrowserRuntime = async ({ context, projectEntries: initialProjectEnt
|
|
|
3589
3603
|
appliedEnvironmentNames: appliedModifyRstestConfigEnvironments
|
|
3590
3604
|
});
|
|
3591
3605
|
rsbuildInstance.addPlugins([
|
|
3606
|
+
pluginMockRuntime,
|
|
3592
3607
|
{
|
|
3593
3608
|
name: 'rstest:browser-user-config',
|
|
3594
3609
|
setup (api) {
|
|
@@ -3619,18 +3634,33 @@ const createBrowserRuntime = async ({ context, projectEntries: initialProjectEnt
|
|
|
3619
3634
|
source: {
|
|
3620
3635
|
define: {
|
|
3621
3636
|
'process.env': rstestEnvDefine,
|
|
3622
|
-
'import.meta.env': rstestEnvDefine
|
|
3637
|
+
'import.meta.env': rstestEnvDefine,
|
|
3638
|
+
'import.meta.rstest': importMetaRstestDefine('web')
|
|
3623
3639
|
}
|
|
3624
3640
|
},
|
|
3625
3641
|
output: {
|
|
3626
3642
|
target: 'web',
|
|
3627
3643
|
sourceMap: {
|
|
3628
3644
|
js: 'source-map'
|
|
3645
|
+
},
|
|
3646
|
+
distPath: {
|
|
3647
|
+
root: join(tempDir, 'server', toSafeVarName(project.environmentName))
|
|
3629
3648
|
}
|
|
3630
3649
|
},
|
|
3631
3650
|
tools: {
|
|
3651
|
+
swc: (swcConfig)=>{
|
|
3652
|
+
swcConfig.env ??= {};
|
|
3653
|
+
swcConfig.env.exclude = Array.from(new Set([
|
|
3654
|
+
...swcConfig.env.exclude ?? [],
|
|
3655
|
+
'transform-parameters'
|
|
3656
|
+
]));
|
|
3657
|
+
},
|
|
3632
3658
|
rspack: (rspackConfig)=>{
|
|
3633
3659
|
rspackConfig.mode = 'development';
|
|
3660
|
+
applyWebMockRspackConfig(rspackConfig, {
|
|
3661
|
+
rspack: rspack,
|
|
3662
|
+
rootPath: project.rootPath
|
|
3663
|
+
});
|
|
3634
3664
|
rspackConfig.lazyCompilation = enableHmr ? createBrowserLazyCompilationConfig(setupFiles) : false;
|
|
3635
3665
|
rspackConfig.plugins = rspackConfig.plugins || [];
|
|
3636
3666
|
rspackConfig.plugins.push(virtualManifestPlugin);
|
|
@@ -3663,21 +3693,46 @@ const createBrowserRuntime = async ({ context, projectEntries: initialProjectEnt
|
|
|
3663
3693
|
name: 'rstest:browser-watch',
|
|
3664
3694
|
setup (api) {
|
|
3665
3695
|
api.onBeforeDevCompile(()=>{
|
|
3666
|
-
|
|
3696
|
+
watchState.compileStartTimes.set(project.name, Date.now());
|
|
3697
|
+
if (!watchState.hooksEnabled) return;
|
|
3667
3698
|
logger.log(color.cyan('\nFile changed, re-running tests...\n'));
|
|
3668
3699
|
});
|
|
3669
3700
|
api.onAfterDevCompile(async ({ stats })=>{
|
|
3701
|
+
const compileStart = watchState.compileStartTimes.get(project.name);
|
|
3702
|
+
if (void 0 !== compileStart) {
|
|
3703
|
+
watchState.compileStartTimes.delete(project.name);
|
|
3704
|
+
if (watchState.hooksEnabled) watchState.pendingBuildTimeMs = Math.max(watchState.pendingBuildTimeMs, Date.now() - compileStart);
|
|
3705
|
+
}
|
|
3670
3706
|
if (stats) {
|
|
3671
|
-
const
|
|
3672
|
-
|
|
3707
|
+
const [projectEntry] = await collectProjectEntries(context, [
|
|
3708
|
+
project
|
|
3709
|
+
]);
|
|
3710
|
+
const entryTestFiles = new Set(collectWatchTestFiles(projectEntry ? [
|
|
3711
|
+
projectEntry
|
|
3712
|
+
] : []).map((file)=>file.testPath));
|
|
3713
|
+
const setupFiles = new Set((projectEntry?.setupFiles ?? []).map((file)=>normalize(file)));
|
|
3714
|
+
let state = watchState.invalidation.get(project.name);
|
|
3715
|
+
if (!state) {
|
|
3716
|
+
state = {};
|
|
3717
|
+
watchState.invalidation.set(project.name, state);
|
|
3718
|
+
}
|
|
3673
3719
|
const statsJson = stats.toJson({
|
|
3674
3720
|
all: true
|
|
3675
3721
|
});
|
|
3676
|
-
const affected = getAffectedTestFiles(
|
|
3677
|
-
|
|
3678
|
-
|
|
3722
|
+
const affected = getAffectedTestFiles({
|
|
3723
|
+
chunks: statsJson.chunks,
|
|
3724
|
+
entryTestFiles,
|
|
3725
|
+
setupFiles,
|
|
3726
|
+
state
|
|
3727
|
+
});
|
|
3728
|
+
if (affected.length > 0) {
|
|
3729
|
+
const pending = watchState.pendingAffectedTestFiles.get(project.name) ?? new Set();
|
|
3730
|
+
for (const file of affected)pending.add(file);
|
|
3731
|
+
watchState.pendingAffectedTestFiles.set(project.name, pending);
|
|
3732
|
+
logger.debug(`[Watch] Affected test files: ${affected.join(', ')}`);
|
|
3733
|
+
}
|
|
3679
3734
|
}
|
|
3680
|
-
if (!
|
|
3735
|
+
if (!watchState.hooksEnabled) return;
|
|
3681
3736
|
await onTriggerRerun();
|
|
3682
3737
|
});
|
|
3683
3738
|
}
|
|
@@ -3710,6 +3765,7 @@ const createBrowserRuntime = async ({ context, projectEntries: initialProjectEnt
|
|
|
3710
3765
|
});
|
|
3711
3766
|
if (isDebug()) await rsbuildInstance.inspectConfig({
|
|
3712
3767
|
writeToDisk: true,
|
|
3768
|
+
outputPath: external_pathe_resolve(context.rootPath, context.normalizedConfig.output.distPath.root, '.rsbuild'),
|
|
3713
3769
|
extraConfigs: {
|
|
3714
3770
|
rstest: {
|
|
3715
3771
|
...context.normalizedConfig,
|
|
@@ -3822,7 +3878,8 @@ const createBrowserRuntime = async ({ context, projectEntries: initialProjectEnt
|
|
|
3822
3878
|
setContainerOptions,
|
|
3823
3879
|
dispatchHandlers,
|
|
3824
3880
|
wss,
|
|
3825
|
-
projectEntries
|
|
3881
|
+
projectEntries,
|
|
3882
|
+
watchState
|
|
3826
3883
|
};
|
|
3827
3884
|
} catch (error) {
|
|
3828
3885
|
wss.close();
|
|
@@ -4012,12 +4069,12 @@ const runBrowserController = async (context, options)=>{
|
|
|
4012
4069
|
if (reportEmptyTestSet()) return allowEmptyRun ? createEmptyRunResult() : void 0;
|
|
4013
4070
|
}
|
|
4014
4071
|
if (!filesOnly) await notifyTestRunStart();
|
|
4015
|
-
const enableCliShortcuts = isWatchMode &&
|
|
4072
|
+
const enableCliShortcuts = isWatchMode && isTTY('stdin');
|
|
4016
4073
|
const browserTempOutputRoot = context.normalizedConfig.output.distPath.root;
|
|
4017
4074
|
const tempDir = isWatchMode && watchContext.runtime ? watchContext.runtime.tempDir : isWatchMode ? join(context.rootPath, browserTempOutputRoot, 'browser', 'watch') : join(context.rootPath, browserTempOutputRoot, 'browser', Date.now().toString());
|
|
4018
|
-
if (isWatchMode) watchContext.lastTestFiles = collectWatchTestFiles(projectEntries);
|
|
4019
4075
|
let runtime = isWatchMode ? watchContext.runtime : null;
|
|
4020
4076
|
let triggerRerun;
|
|
4077
|
+
let awaitHeadlessRerunIdle;
|
|
4021
4078
|
if (!runtime) {
|
|
4022
4079
|
try {
|
|
4023
4080
|
runtime = await createBrowserRuntime({
|
|
@@ -4046,12 +4103,63 @@ const runBrowserController = async (context, options)=>{
|
|
|
4046
4103
|
}
|
|
4047
4104
|
if (isWatchMode) {
|
|
4048
4105
|
watchContext.runtime = runtime;
|
|
4049
|
-
registerWatchCleanup();
|
|
4050
|
-
if (enableCliShortcuts && !watchContext.closeCliShortcuts) watchContext.closeCliShortcuts = await setupBrowserWatchCliShortcuts({
|
|
4051
|
-
close: cleanupWatchRuntime
|
|
4052
|
-
});
|
|
4106
|
+
registerWatchCleanup(context.embedded);
|
|
4053
4107
|
}
|
|
4054
4108
|
}
|
|
4109
|
+
const watchState = runtime.watchState;
|
|
4110
|
+
if (isWatchMode) watchState.lastTestFiles = collectWatchTestFiles(projectEntries);
|
|
4111
|
+
const seedPendingRerun = (testPaths)=>{
|
|
4112
|
+
const wanted = testPaths ? new Set(testPaths.map((testPath)=>normalize(testPath))) : null;
|
|
4113
|
+
let seeded = 0;
|
|
4114
|
+
for (const file of watchState.lastTestFiles){
|
|
4115
|
+
if (wanted && !wanted.has(file.testPath)) continue;
|
|
4116
|
+
const pending = watchState.pendingAffectedTestFiles.get(file.projectName) ?? new Set();
|
|
4117
|
+
pending.add(file.testPath);
|
|
4118
|
+
watchState.pendingAffectedTestFiles.set(file.projectName, pending);
|
|
4119
|
+
seeded += 1;
|
|
4120
|
+
}
|
|
4121
|
+
return seeded;
|
|
4122
|
+
};
|
|
4123
|
+
const watchHandles = isWatchMode ? {
|
|
4124
|
+
rerun: async (testPaths)=>{
|
|
4125
|
+
const seeded = seedPendingRerun(testPaths);
|
|
4126
|
+
if (testPaths && 0 === seeded) return;
|
|
4127
|
+
await triggerRerun?.();
|
|
4128
|
+
await awaitHeadlessRerunIdle?.();
|
|
4129
|
+
},
|
|
4130
|
+
close: cleanupWatchRuntime
|
|
4131
|
+
} : void 0;
|
|
4132
|
+
const finalizeWatchRerun = async ({ rerunTestPaths, testTime, unhandledErrors })=>{
|
|
4133
|
+
const rerunPathSet = new Set(rerunTestPaths);
|
|
4134
|
+
let sessionCoverage;
|
|
4135
|
+
const coverageMap = buildBrowserCoverageMap(context.reporterResults.results, coverageProvider, {
|
|
4136
|
+
keepResultCoverage: true
|
|
4137
|
+
});
|
|
4138
|
+
if (coverageMap && coverageMap.files().length > 0) sessionCoverage = coverageMap.toJSON();
|
|
4139
|
+
const outcome = {
|
|
4140
|
+
results: context.reporterResults.results.filter((result)=>rerunPathSet.has(result.testPath)),
|
|
4141
|
+
testResults: context.reporterResults.testResults.filter((result)=>rerunPathSet.has(result.testPath)),
|
|
4142
|
+
errors: unhandledErrors ?? [],
|
|
4143
|
+
testPaths: rerunTestPaths,
|
|
4144
|
+
duration: {
|
|
4145
|
+
buildTime: drainPendingBuildTime(watchState),
|
|
4146
|
+
testTime
|
|
4147
|
+
},
|
|
4148
|
+
coverage: sessionCoverage ? {
|
|
4149
|
+
map: sessionCoverage
|
|
4150
|
+
} : void 0,
|
|
4151
|
+
resolveSourcemap: resolveBrowserSourcemap
|
|
4152
|
+
};
|
|
4153
|
+
await finalizeRunCycle(context, {
|
|
4154
|
+
outcomes: [
|
|
4155
|
+
outcome
|
|
4156
|
+
],
|
|
4157
|
+
mode: 'on-demand',
|
|
4158
|
+
isWatchMode: true,
|
|
4159
|
+
coverageProvider,
|
|
4160
|
+
reportOnFailure: coverageConfig?.reportOnFailure ?? false
|
|
4161
|
+
});
|
|
4162
|
+
};
|
|
4055
4163
|
projectEntries = runtime.projectEntries;
|
|
4056
4164
|
totalTests = projectEntries.reduce((total, item)=>total + item.testFiles.length, 0);
|
|
4057
4165
|
const buildTime = Date.now() - buildStart;
|
|
@@ -4098,7 +4206,7 @@ const runBrowserController = async (context, options)=>{
|
|
|
4098
4206
|
rootPath: normalize(context.rootPath),
|
|
4099
4207
|
projects: projectRuntimeConfigs,
|
|
4100
4208
|
snapshot: {
|
|
4101
|
-
updateSnapshot: context.snapshotManager.options.updateSnapshot
|
|
4209
|
+
updateSnapshot: options?.updateSnapshot ?? context.snapshotManager.options.updateSnapshot
|
|
4102
4210
|
},
|
|
4103
4211
|
runnerUrl: `http://localhost:${runtime.containerServer.port}`,
|
|
4104
4212
|
projectRunnerUrls,
|
|
@@ -4272,7 +4380,7 @@ const runBrowserController = async (context, options)=>{
|
|
|
4272
4380
|
const handleLog = async (payload)=>{
|
|
4273
4381
|
const log = {
|
|
4274
4382
|
content: payload.content,
|
|
4275
|
-
name: payload.level,
|
|
4383
|
+
name: getPrettyConsoleName(payload.level),
|
|
4276
4384
|
taskId: payload.taskId,
|
|
4277
4385
|
taskName: payload.taskName,
|
|
4278
4386
|
taskParentNames: payload.taskParentNames,
|
|
@@ -4439,6 +4547,9 @@ const runBrowserController = async (context, options)=>{
|
|
|
4439
4547
|
});
|
|
4440
4548
|
const inlineOptions = {
|
|
4441
4549
|
...hostOptions,
|
|
4550
|
+
snapshot: {
|
|
4551
|
+
updateSnapshot: context.snapshotManager.options.updateSnapshot
|
|
4552
|
+
},
|
|
4442
4553
|
testFile: file.testPath,
|
|
4443
4554
|
runId: `${run.token}:${session.id}`
|
|
4444
4555
|
};
|
|
@@ -4551,20 +4662,16 @@ const runBrowserController = async (context, options)=>{
|
|
|
4551
4662
|
} finally{
|
|
4552
4663
|
const testTime = Math.max(0, Date.now() - rerunStartTime);
|
|
4553
4664
|
const rerunFatalError = fatalError && fatalError !== fatalErrorBeforeRun ? fatalError : void 0;
|
|
4554
|
-
await
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
buildTime: 0,
|
|
4558
|
-
testTime
|
|
4559
|
-
},
|
|
4560
|
-
filterRerunTestPaths: files.map((file)=>file.testPath),
|
|
4665
|
+
await finalizeWatchRerun({
|
|
4666
|
+
rerunTestPaths: files.map((file)=>file.testPath),
|
|
4667
|
+
testTime,
|
|
4561
4668
|
unhandledErrors: rerunError ? [
|
|
4562
4669
|
rerunError
|
|
4563
4670
|
] : rerunFatalError ? [
|
|
4564
4671
|
rerunFatalError
|
|
4565
4672
|
] : void 0
|
|
4566
4673
|
});
|
|
4567
|
-
|
|
4674
|
+
logWatchReadyMessage(context, enableCliShortcuts);
|
|
4568
4675
|
}
|
|
4569
4676
|
},
|
|
4570
4677
|
onError: async (error)=>{
|
|
@@ -4578,6 +4685,7 @@ const runBrowserController = async (context, options)=>{
|
|
|
4578
4685
|
logger.debug(`[Headless] Interrupting active run token ${run.token} before scheduling latest rerun`);
|
|
4579
4686
|
}
|
|
4580
4687
|
});
|
|
4688
|
+
awaitHeadlessRerunIdle = ()=>latestRerunScheduler.whenIdle();
|
|
4581
4689
|
if (0 === allTestFiles.length) {
|
|
4582
4690
|
const duration = {
|
|
4583
4691
|
totalTime: buildTime,
|
|
@@ -4594,7 +4702,8 @@ const runBrowserController = async (context, options)=>{
|
|
|
4594
4702
|
close: isWatchMode ? void 0 : async ()=>{
|
|
4595
4703
|
sessionRegistry.clear();
|
|
4596
4704
|
await destroyBrowserRuntime(runtime);
|
|
4597
|
-
}
|
|
4705
|
+
},
|
|
4706
|
+
watch: watchHandles
|
|
4598
4707
|
};
|
|
4599
4708
|
if (isWatchMode) await notifyTestRunEnd({
|
|
4600
4709
|
duration
|
|
@@ -4604,25 +4713,24 @@ const runBrowserController = async (context, options)=>{
|
|
|
4604
4713
|
const newProjectEntries = await collectProjectEntries(context);
|
|
4605
4714
|
const rerunPlan = planWatchRerun({
|
|
4606
4715
|
projectEntries: newProjectEntries,
|
|
4607
|
-
previousTestFiles:
|
|
4608
|
-
affectedTestFiles:
|
|
4716
|
+
previousTestFiles: watchState.lastTestFiles,
|
|
4717
|
+
affectedTestFiles: drainPendingAffectedTestFiles(watchState)
|
|
4609
4718
|
});
|
|
4610
|
-
watchContext.affectedTestFiles = [];
|
|
4611
4719
|
if (rerunPlan.filesChanged) {
|
|
4612
|
-
|
|
4720
|
+
watchState.lastTestFiles = rerunPlan.currentTestFiles;
|
|
4613
4721
|
if (0 === rerunPlan.currentTestFiles.length) {
|
|
4614
4722
|
logger.log(color.cyan('No browser test files remain after update.\n'));
|
|
4615
|
-
|
|
4723
|
+
logWatchReadyMessage(context, enableCliShortcuts);
|
|
4616
4724
|
return;
|
|
4617
4725
|
}
|
|
4618
4726
|
logger.log(color.cyan(`Test file set changed, re-running ${rerunPlan.currentTestFiles.length} file(s)...\n`));
|
|
4619
|
-
latestRerunScheduler.enqueueLatest(rerunPlan.currentTestFiles);
|
|
4727
|
+
await latestRerunScheduler.enqueueLatest(rerunPlan.currentTestFiles);
|
|
4620
4728
|
return;
|
|
4621
4729
|
}
|
|
4622
|
-
|
|
4730
|
+
logWatchReadyMessage(context, enableCliShortcuts);
|
|
4623
4731
|
};
|
|
4624
|
-
|
|
4625
|
-
|
|
4732
|
+
watchState.hooksEnabled = true;
|
|
4733
|
+
logWatchReadyMessage(context, enableCliShortcuts);
|
|
4626
4734
|
}
|
|
4627
4735
|
return result;
|
|
4628
4736
|
}
|
|
@@ -4633,31 +4741,30 @@ const runBrowserController = async (context, options)=>{
|
|
|
4633
4741
|
const newProjectEntries = await collectProjectEntries(context);
|
|
4634
4742
|
const rerunPlan = planWatchRerun({
|
|
4635
4743
|
projectEntries: newProjectEntries,
|
|
4636
|
-
previousTestFiles:
|
|
4637
|
-
affectedTestFiles:
|
|
4744
|
+
previousTestFiles: watchState.lastTestFiles,
|
|
4745
|
+
affectedTestFiles: drainPendingAffectedTestFiles(watchState)
|
|
4638
4746
|
});
|
|
4639
|
-
watchContext.affectedTestFiles = [];
|
|
4640
4747
|
if (rerunPlan.filesChanged) {
|
|
4641
|
-
const deletedTestPaths = collectDeletedTestPaths(
|
|
4748
|
+
const deletedTestPaths = collectDeletedTestPaths(watchState.lastTestFiles, rerunPlan.currentTestFiles);
|
|
4642
4749
|
if (deletedTestPaths.length > 0) context.updateReporterResultState([], [], deletedTestPaths);
|
|
4643
|
-
|
|
4750
|
+
watchState.lastTestFiles = rerunPlan.currentTestFiles;
|
|
4644
4751
|
if (0 === rerunPlan.currentTestFiles.length) {
|
|
4645
4752
|
await latestRerunScheduler.enqueueLatest([]);
|
|
4646
4753
|
logger.log(color.cyan('No browser test files remain after update.\n'));
|
|
4647
|
-
|
|
4754
|
+
logWatchReadyMessage(context, enableCliShortcuts);
|
|
4648
4755
|
return;
|
|
4649
4756
|
}
|
|
4650
4757
|
logger.log(color.cyan(`Test file set changed, re-running ${rerunPlan.currentTestFiles.length} file(s)...\n`));
|
|
4651
|
-
latestRerunScheduler.enqueueLatest(rerunPlan.currentTestFiles);
|
|
4758
|
+
await latestRerunScheduler.enqueueLatest(rerunPlan.currentTestFiles);
|
|
4652
4759
|
return;
|
|
4653
4760
|
}
|
|
4654
4761
|
if (0 === rerunPlan.affectedTestFiles.length) {
|
|
4655
4762
|
logger.log(color.cyan('No affected browser test files detected, skipping re-run.\n'));
|
|
4656
|
-
|
|
4763
|
+
logWatchReadyMessage(context, enableCliShortcuts);
|
|
4657
4764
|
return;
|
|
4658
4765
|
}
|
|
4659
4766
|
logger.log(color.cyan(`Re-running ${rerunPlan.affectedTestFiles.length} affected test file(s)...\n`));
|
|
4660
|
-
latestRerunScheduler.enqueueLatest(rerunPlan.affectedTestFiles);
|
|
4767
|
+
await latestRerunScheduler.enqueueLatest(rerunPlan.affectedTestFiles);
|
|
4661
4768
|
};
|
|
4662
4769
|
const closeHeadlessRuntime = isWatchMode ? void 0 : async ()=>{
|
|
4663
4770
|
sessionRegistry.clear();
|
|
@@ -4679,7 +4786,8 @@ const runBrowserController = async (context, options)=>{
|
|
|
4679
4786
|
hasFailure: isFailure,
|
|
4680
4787
|
getSourcemap: getBrowserSourcemap,
|
|
4681
4788
|
resolveSourcemap: resolveBrowserSourcemap,
|
|
4682
|
-
close: closeHeadlessRuntime
|
|
4789
|
+
close: closeHeadlessRuntime,
|
|
4790
|
+
watch: watchHandles
|
|
4683
4791
|
};
|
|
4684
4792
|
if (isWatchMode) try {
|
|
4685
4793
|
await notifyTestRunEnd({
|
|
@@ -4689,8 +4797,8 @@ const runBrowserController = async (context, options)=>{
|
|
|
4689
4797
|
await closeHeadlessRuntime?.();
|
|
4690
4798
|
}
|
|
4691
4799
|
if (isWatchMode && triggerRerun) {
|
|
4692
|
-
|
|
4693
|
-
|
|
4800
|
+
watchState.hooksEnabled = true;
|
|
4801
|
+
logWatchReadyMessage(context, enableCliShortcuts);
|
|
4694
4802
|
}
|
|
4695
4803
|
return result;
|
|
4696
4804
|
}
|
|
@@ -4897,22 +5005,31 @@ const runBrowserController = async (context, options)=>{
|
|
|
4897
5005
|
testTime = Date.now() - testStart;
|
|
4898
5006
|
}
|
|
4899
5007
|
if (isWatchMode) triggerRerun = async ()=>{
|
|
4900
|
-
const
|
|
5008
|
+
const refreshedHostOptions = {
|
|
5009
|
+
...hostOptions,
|
|
5010
|
+
snapshot: {
|
|
5011
|
+
updateSnapshot: context.snapshotManager.options.updateSnapshot
|
|
5012
|
+
}
|
|
5013
|
+
};
|
|
5014
|
+
runtime.setContainerOptions(refreshedHostOptions);
|
|
5015
|
+
const [, newProjectEntries] = await Promise.all([
|
|
5016
|
+
rpcManager.updateHostConfig(refreshedHostOptions),
|
|
5017
|
+
collectProjectEntries(context)
|
|
5018
|
+
]);
|
|
4901
5019
|
const rerunPlan = planWatchRerun({
|
|
4902
5020
|
projectEntries: newProjectEntries,
|
|
4903
|
-
previousTestFiles:
|
|
4904
|
-
affectedTestFiles:
|
|
5021
|
+
previousTestFiles: watchState.lastTestFiles,
|
|
5022
|
+
affectedTestFiles: drainPendingAffectedTestFiles(watchState)
|
|
4905
5023
|
});
|
|
4906
|
-
watchContext.affectedTestFiles = [];
|
|
4907
5024
|
if (rerunPlan.filesChanged) {
|
|
4908
|
-
const deletedTestPaths = collectDeletedTestPaths(
|
|
5025
|
+
const deletedTestPaths = collectDeletedTestPaths(watchState.lastTestFiles, rerunPlan.currentTestFiles);
|
|
4909
5026
|
if (deletedTestPaths.length > 0) context.updateReporterResultState([], [], deletedTestPaths);
|
|
4910
|
-
|
|
5027
|
+
watchState.lastTestFiles = rerunPlan.currentTestFiles;
|
|
4911
5028
|
currentTestFiles = rerunPlan.currentTestFiles;
|
|
4912
5029
|
await rpcManager.notifyTestFileUpdate(currentTestFiles);
|
|
4913
5030
|
if (0 === currentTestFiles.length) {
|
|
4914
5031
|
logger.log(color.cyan('No browser test files remain after update.\n'));
|
|
4915
|
-
|
|
5032
|
+
logWatchReadyMessage(context, enableCliShortcuts);
|
|
4916
5033
|
return;
|
|
4917
5034
|
}
|
|
4918
5035
|
await waitForRunnerFramesReady(currentTestFiles.map((file)=>file.testPath));
|
|
@@ -4932,25 +5049,21 @@ const runBrowserController = async (context, options)=>{
|
|
|
4932
5049
|
} finally{
|
|
4933
5050
|
const testTime = Math.max(0, Date.now() - rerunStartTime);
|
|
4934
5051
|
const rerunFatalError = fatalError && fatalError !== fatalErrorBeforeRun ? fatalError : void 0;
|
|
4935
|
-
await
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
buildTime: 0,
|
|
4939
|
-
testTime
|
|
4940
|
-
},
|
|
4941
|
-
filterRerunTestPaths: rerunPlan.normalizedAffectedTestFiles,
|
|
5052
|
+
await finalizeWatchRerun({
|
|
5053
|
+
rerunTestPaths: rerunPlan.normalizedAffectedTestFiles,
|
|
5054
|
+
testTime,
|
|
4942
5055
|
unhandledErrors: rerunError ? [
|
|
4943
5056
|
rerunError
|
|
4944
5057
|
] : rerunFatalError ? [
|
|
4945
5058
|
rerunFatalError
|
|
4946
5059
|
] : void 0
|
|
4947
5060
|
});
|
|
4948
|
-
|
|
5061
|
+
logWatchReadyMessage(context, enableCliShortcuts);
|
|
4949
5062
|
}
|
|
4950
|
-
} else if (rerunPlan.filesChanged)
|
|
5063
|
+
} else if (rerunPlan.filesChanged) logWatchReadyMessage(context, enableCliShortcuts);
|
|
4951
5064
|
else {
|
|
4952
5065
|
logger.log(color.cyan('Tests will be re-executed automatically\n'));
|
|
4953
|
-
|
|
5066
|
+
logWatchReadyMessage(context, enableCliShortcuts);
|
|
4954
5067
|
}
|
|
4955
5068
|
};
|
|
4956
5069
|
const closeContainerRuntime = isWatchMode ? void 0 : async ()=>{
|
|
@@ -4978,7 +5091,8 @@ const runBrowserController = async (context, options)=>{
|
|
|
4978
5091
|
hasFailure: isFailure,
|
|
4979
5092
|
getSourcemap: getBrowserSourcemap,
|
|
4980
5093
|
resolveSourcemap: resolveBrowserSourcemap,
|
|
4981
|
-
close: closeContainerRuntime
|
|
5094
|
+
close: closeContainerRuntime,
|
|
5095
|
+
watch: watchHandles
|
|
4982
5096
|
};
|
|
4983
5097
|
if (isWatchMode) try {
|
|
4984
5098
|
await notifyTestRunEnd({
|
|
@@ -4988,8 +5102,8 @@ const runBrowserController = async (context, options)=>{
|
|
|
4988
5102
|
await closeContainerRuntime?.();
|
|
4989
5103
|
}
|
|
4990
5104
|
if (isWatchMode && triggerRerun) {
|
|
4991
|
-
|
|
4992
|
-
|
|
5105
|
+
watchState.hooksEnabled = true;
|
|
5106
|
+
logWatchReadyMessage(context, enableCliShortcuts);
|
|
4993
5107
|
}
|
|
4994
5108
|
return result;
|
|
4995
5109
|
};
|
|
@@ -5182,7 +5296,7 @@ const emptyOutcome = ()=>({
|
|
|
5182
5296
|
}
|
|
5183
5297
|
});
|
|
5184
5298
|
async function createBrowserExecutor(context, options) {
|
|
5185
|
-
const { projects, coverageProvider, freezeShardedEntries, filesOnly, allowEmptyRun, appliedModifyRstestConfigEnvironments } = options;
|
|
5299
|
+
const { projects, coverageProvider, shardedEntries, freezeShardedEntries, filesOnly, allowEmptyRun, appliedModifyRstestConfigEnvironments } = options;
|
|
5186
5300
|
let deferredClose;
|
|
5187
5301
|
let inFlightCycle;
|
|
5188
5302
|
const foldOutcome = (result)=>{
|
|
@@ -5210,12 +5324,13 @@ async function createBrowserExecutor(context, options) {
|
|
|
5210
5324
|
async runCycle (opts) {
|
|
5211
5325
|
const cycle = runBrowserController(context, {
|
|
5212
5326
|
projects,
|
|
5213
|
-
shardedEntries
|
|
5327
|
+
shardedEntries,
|
|
5214
5328
|
freezeShardedEntries,
|
|
5215
5329
|
allowEmptyRun,
|
|
5216
5330
|
appliedModifyRstestConfigEnvironments,
|
|
5217
5331
|
onTraceEvents: opts.onTraceEvents,
|
|
5218
|
-
env: opts.env
|
|
5332
|
+
env: opts.env,
|
|
5333
|
+
updateSnapshot: opts.updateSnapshot
|
|
5219
5334
|
});
|
|
5220
5335
|
inFlightCycle = cycle;
|
|
5221
5336
|
try {
|
|
@@ -5226,10 +5341,10 @@ async function createBrowserExecutor(context, options) {
|
|
|
5226
5341
|
inFlightCycle = void 0;
|
|
5227
5342
|
}
|
|
5228
5343
|
},
|
|
5229
|
-
async collect (
|
|
5344
|
+
async collect () {
|
|
5230
5345
|
const pending = listBrowserTests(context, {
|
|
5231
5346
|
projects,
|
|
5232
|
-
shardedEntries
|
|
5347
|
+
shardedEntries,
|
|
5233
5348
|
freezeShardedEntries,
|
|
5234
5349
|
filesOnly,
|
|
5235
5350
|
appliedModifyRstestConfigEnvironments
|