@rstest/browser 0.9.10 → 0.10.1
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/augmentExpect.d.ts +1 -1
- package/dist/browser-container/container-static/js/{102.e63e4aa16d.js → 188.480c3c49b5.js} +4543 -4250
- package/dist/browser-container/container-static/js/188.480c3c49b5.js.LICENSE.txt +1 -0
- package/dist/browser-container/container-static/js/{index.af52585634.js → index.29fc60be33.js} +10 -10
- package/dist/browser-container/container-static/js/{lib-react.9e703e1b29.js → lib-react.5ae9b90ee5.js} +24 -24
- package/dist/browser-container/container-static/js/lib-react.5ae9b90ee5.js.LICENSE.txt +1 -0
- package/dist/browser-container/index.html +1 -1
- package/dist/browser.d.ts +2 -2
- package/dist/client/api.d.ts +2 -2
- package/dist/client/browserRpc.d.ts +2 -2
- package/dist/client/dispatchTransport.d.ts +1 -1
- package/dist/client/locator.d.ts +2 -2
- package/dist/concurrency.d.ts +1 -1
- package/dist/dispatchCapabilities.d.ts +2 -2
- package/dist/dispatchRouter.d.ts +1 -1
- package/dist/headlessTransport.d.ts +2 -2
- package/dist/hostController.d.ts +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +205 -23
- package/dist/protocol.d.ts +6 -2
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/playwright/compileLocator.d.ts +1 -1
- package/dist/providers/playwright/dispatchBrowserRpc.d.ts +1 -1
- package/dist/providers/playwright/expectUtils.d.ts +1 -1
- package/dist/providers/playwright/implementation.d.ts +1 -1
- package/dist/providers/playwright/index.d.ts +1 -1
- package/dist/providers/playwright/runtime.d.ts +1 -1
- package/dist/providers/playwright/textMatcher.d.ts +2 -2
- package/dist/sessionRegistry.d.ts +1 -1
- package/dist/viewportPresets.d.ts +1 -1
- package/dist/watchRerunPlanner.d.ts +1 -1
- package/package.json +9 -9
- package/src/client/entry.ts +75 -14
- package/src/hostController.ts +405 -70
- package/src/protocol.ts +4 -0
- package/dist/browser-container/container-static/js/102.e63e4aa16d.js.LICENSE.txt +0 -1
- package/dist/browser-container/container-static/js/lib-react.9e703e1b29.js.LICENSE.txt +0 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import promises from "node:fs/promises";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { isDeepStrictEqual } from "node:util";
|
|
5
|
-
import { color, createCoverageProvider, getSetupFiles, getTestEntries, isDebug, loadCoverageProvider, logger, rsbuild, serializableConfig } from "@rstest/core/browser";
|
|
5
|
+
import { PhaseTracker, color, createCoverageProvider, getNoTestFilesMessage, getSetupFiles, getTestEntries, isDebug, loadCoverageProvider, logger, resolveProjectBuildCache, rsbuild, serializableConfig } from "@rstest/core/browser";
|
|
6
6
|
import open_editor from "open-editor";
|
|
7
7
|
import { basename, dirname, join, normalize, relative, resolve as external_pathe_resolve } from "pathe";
|
|
8
8
|
import sirv from "sirv";
|
|
@@ -2800,11 +2800,14 @@ var picomatch_default = /*#__PURE__*/ __webpack_require__.n(picomatch);
|
|
|
2800
2800
|
const { createRsbuild: createRsbuild, rspack: rspack } = rsbuild;
|
|
2801
2801
|
const hostController_dirname = dirname(fileURLToPath(import.meta.url));
|
|
2802
2802
|
const OPTIONS_PLACEHOLDER = '__RSTEST_OPTIONS_PLACEHOLDER__';
|
|
2803
|
+
let nextBrowserFilePid = 1000000000;
|
|
2803
2804
|
const serializeForInlineScript = (value)=>JSON.stringify(value).replace(/</g, '\\u003c').replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
|
|
2804
2805
|
const getBrowserProviderOptions = (project)=>{
|
|
2805
2806
|
const browserConfig = project.normalizedConfig.browser;
|
|
2806
2807
|
return browserConfig.providerOptions ?? {};
|
|
2807
2808
|
};
|
|
2809
|
+
const getFileTaskId = (testPath)=>`file:${testPath}`;
|
|
2810
|
+
const getBufferedLogTaskId = (log)=>log.taskId ?? getFileTaskId(log.testPath);
|
|
2808
2811
|
const createDeferredPromise = ()=>{
|
|
2809
2812
|
let resolve;
|
|
2810
2813
|
let reject;
|
|
@@ -3059,9 +3062,12 @@ const getAffectedTestFiles = (chunks, entryTestFiles)=>{
|
|
|
3059
3062
|
return Array.from(affectedFiles);
|
|
3060
3063
|
};
|
|
3061
3064
|
const getRuntimeConfigFromProject = (project)=>{
|
|
3062
|
-
const { testNamePattern, testTimeout, passWithNoTests, retry, globals, clearMocks, resetMocks, restoreMocks, unstubEnvs, unstubGlobals, maxConcurrency, printConsoleTrace, disableConsoleIntercept, testEnvironment, hookTimeout, isolate, coverage, snapshotFormat, env, bail, logHeapUsage, chaiConfig, includeTaskLocation } = project.normalizedConfig;
|
|
3065
|
+
const { testNamePattern, testTimeout, passWithNoTests, retry, globals, clearMocks, resetMocks, restoreMocks, unstubEnvs, unstubGlobals, maxConcurrency, printConsoleTrace, disableConsoleIntercept, testEnvironment, hookTimeout, isolate, coverage, snapshotFormat, env, bail, logHeapUsage, detectAsyncLeaks, chaiConfig, includeTaskLocation, silent } = project.normalizedConfig;
|
|
3063
3066
|
return {
|
|
3064
|
-
env
|
|
3067
|
+
env: {
|
|
3068
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
3069
|
+
...env
|
|
3070
|
+
},
|
|
3065
3071
|
testNamePattern,
|
|
3066
3072
|
testTimeout,
|
|
3067
3073
|
hookTimeout,
|
|
@@ -3082,8 +3088,10 @@ const getRuntimeConfigFromProject = (project)=>{
|
|
|
3082
3088
|
snapshotFormat,
|
|
3083
3089
|
bail,
|
|
3084
3090
|
logHeapUsage,
|
|
3091
|
+
detectAsyncLeaks,
|
|
3085
3092
|
chaiConfig,
|
|
3086
|
-
includeTaskLocation
|
|
3093
|
+
includeTaskLocation,
|
|
3094
|
+
silent
|
|
3087
3095
|
};
|
|
3088
3096
|
};
|
|
3089
3097
|
const getBrowserProjects = (context)=>context.projects.filter((project)=>project.normalizedConfig.browser.enabled);
|
|
@@ -3123,7 +3131,8 @@ const collectProjectEntries = async (context)=>{
|
|
|
3123
3131
|
includeSource,
|
|
3124
3132
|
rootPath: context.rootPath,
|
|
3125
3133
|
projectRoot: project.rootPath,
|
|
3126
|
-
fileFilters: context.fileFilters || []
|
|
3134
|
+
fileFilters: context.fileFilters || [],
|
|
3135
|
+
fileFilterMode: context.fileFilterMode
|
|
3127
3136
|
});
|
|
3128
3137
|
const setup = getSetupFiles(setupFiles, project.rootPath);
|
|
3129
3138
|
return {
|
|
@@ -3326,8 +3335,18 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
3326
3335
|
const project = projectByEnvironmentName.get(name);
|
|
3327
3336
|
if (!project) return config;
|
|
3328
3337
|
const userRsbuildConfig = project.normalizedConfig;
|
|
3338
|
+
const buildCache = resolveProjectBuildCache({
|
|
3339
|
+
context,
|
|
3340
|
+
project
|
|
3341
|
+
});
|
|
3329
3342
|
const setupFiles = Object.values(getSetupFiles(project.normalizedConfig.setupFiles, project.rootPath));
|
|
3330
|
-
const merged = mergeEnvironmentConfig(config,
|
|
3343
|
+
const merged = mergeEnvironmentConfig(config, {
|
|
3344
|
+
...userRsbuildConfig,
|
|
3345
|
+
performance: buildCache ? {
|
|
3346
|
+
...userRsbuildConfig.performance,
|
|
3347
|
+
buildCache
|
|
3348
|
+
} : userRsbuildConfig.performance
|
|
3349
|
+
}, {
|
|
3331
3350
|
resolve: {
|
|
3332
3351
|
alias: rstestInternalAliases
|
|
3333
3352
|
},
|
|
@@ -3572,8 +3591,10 @@ async function resolveProjectEntries(context, shardedEntries) {
|
|
|
3572
3591
|
return collectProjectEntries(context);
|
|
3573
3592
|
}
|
|
3574
3593
|
const runBrowserController = async (context, options)=>{
|
|
3575
|
-
const { skipOnTestRunEnd = false } = options ?? {};
|
|
3594
|
+
const { skipOnTestRunEnd = false, allowEmptyWatchRun = false, onTraceEvents } = options ?? {};
|
|
3576
3595
|
const buildStart = Date.now();
|
|
3596
|
+
const isWatchMode = 'watch' === context.command;
|
|
3597
|
+
const phaseTrackers = onTraceEvents ? new Map() : void 0;
|
|
3577
3598
|
const browserProjects = getBrowserProjects(context);
|
|
3578
3599
|
const useHeadlessDirect = browserProjects.every((project)=>project.normalizedConfig.browser.headless);
|
|
3579
3600
|
const browserSourceMapCache = new Map();
|
|
@@ -3696,18 +3717,24 @@ const runBrowserController = async (context, options)=>{
|
|
|
3696
3717
|
}
|
|
3697
3718
|
const projectEntries = await resolveProjectEntries(context, options?.shardedEntries);
|
|
3698
3719
|
const totalTests = projectEntries.reduce((total, item)=>total + item.testFiles.length, 0);
|
|
3720
|
+
const shouldKeepWatchingWithEmptySet = isWatchMode && allowEmptyWatchRun;
|
|
3699
3721
|
if (0 === totalTests) {
|
|
3700
3722
|
const code = context.normalizedConfig.passWithNoTests ? 0 : 1;
|
|
3701
3723
|
if (!skipOnTestRunEnd) {
|
|
3702
|
-
const message =
|
|
3724
|
+
const message = shouldKeepWatchingWithEmptySet ? 'No test files found.' : getNoTestFilesMessage({
|
|
3725
|
+
context,
|
|
3726
|
+
code,
|
|
3727
|
+
defaultMessage: `No test files found, exiting with code ${code}.`
|
|
3728
|
+
});
|
|
3703
3729
|
if (0 === code) logger.log(color.yellow(message));
|
|
3704
3730
|
else logger.error(color.red(message));
|
|
3731
|
+
if (context.relatedFilters?.length) logger.log(color.gray('related: '), context.relatedFilters.join(color.gray(', ')));
|
|
3732
|
+
else if (context.fileFilters?.length) logger.log(color.gray('filter: '), context.fileFilters.join(color.gray(', ')));
|
|
3705
3733
|
}
|
|
3706
|
-
if (0 !== code) ensureProcessExitCode(code);
|
|
3707
|
-
return;
|
|
3734
|
+
if (0 !== code && !shouldKeepWatchingWithEmptySet) ensureProcessExitCode(code);
|
|
3735
|
+
if (!shouldKeepWatchingWithEmptySet) return;
|
|
3708
3736
|
}
|
|
3709
3737
|
await notifyTestRunStart();
|
|
3710
|
-
const isWatchMode = 'watch' === context.command;
|
|
3711
3738
|
const enableCliShortcuts = isWatchMode && isBrowserWatchCliShortcutsEnabled();
|
|
3712
3739
|
const browserTempOutputRoot = context.normalizedConfig.output.distPath.root;
|
|
3713
3740
|
const tempDir = isWatchMode && watchContext.runtime ? watchContext.runtime.tempDir : isWatchMode ? join(context.rootPath, browserTempOutputRoot, 'browser', 'watch') : join(context.rootPath, browserTempOutputRoot, 'browser', Date.now().toString());
|
|
@@ -3843,26 +3870,57 @@ const runBrowserController = async (context, options)=>{
|
|
|
3843
3870
|
}
|
|
3844
3871
|
};
|
|
3845
3872
|
const handleTestFileStart = async (payload)=>{
|
|
3873
|
+
if (phaseTrackers) {
|
|
3874
|
+
const tracker = new PhaseTracker({
|
|
3875
|
+
trace: {
|
|
3876
|
+
testPath: payload.testPath,
|
|
3877
|
+
project: payload.projectName
|
|
3878
|
+
},
|
|
3879
|
+
pid: nextBrowserFilePid++
|
|
3880
|
+
});
|
|
3881
|
+
tracker.transition('prepare');
|
|
3882
|
+
phaseTrackers.set(payload.testPath, tracker);
|
|
3883
|
+
}
|
|
3846
3884
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestFileStart?.({
|
|
3885
|
+
testId: getFileTaskId(payload.testPath),
|
|
3847
3886
|
testPath: payload.testPath,
|
|
3848
3887
|
tests: []
|
|
3849
3888
|
})));
|
|
3850
3889
|
};
|
|
3851
3890
|
const handleTestFileReady = async (payload)=>{
|
|
3891
|
+
phaseTrackers?.get(payload.testPath)?.transition('tests');
|
|
3852
3892
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestFileReady?.(payload)));
|
|
3853
3893
|
};
|
|
3854
3894
|
const handleTestSuiteStart = async (payload)=>{
|
|
3895
|
+
phaseTrackers?.get(payload.testPath)?.recordSuiteStart(payload);
|
|
3855
3896
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestSuiteStart?.(payload)));
|
|
3856
3897
|
};
|
|
3857
3898
|
const handleTestSuiteResult = async (payload)=>{
|
|
3899
|
+
phaseTrackers?.get(payload.testPath)?.recordSuiteResult(payload);
|
|
3858
3900
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestSuiteResult?.(payload)));
|
|
3901
|
+
if ('passed-only' === context.normalizedConfig.silent) await flushBufferedLogsForTask({
|
|
3902
|
+
taskId: payload.testId,
|
|
3903
|
+
status: payload.status,
|
|
3904
|
+
taskParentNames: payload.parentNames,
|
|
3905
|
+
taskType: 'suite',
|
|
3906
|
+
testPath: payload.testPath
|
|
3907
|
+
});
|
|
3859
3908
|
};
|
|
3860
3909
|
const handleTestCaseStart = async (payload)=>{
|
|
3910
|
+
phaseTrackers?.get(payload.testPath)?.recordCaseStart(payload);
|
|
3861
3911
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestCaseStart?.(payload)));
|
|
3862
3912
|
};
|
|
3863
3913
|
const handleTestCaseResult = async (payload)=>{
|
|
3864
3914
|
caseResults.push(payload);
|
|
3915
|
+
phaseTrackers?.get(payload.testPath)?.recordCaseResult(payload);
|
|
3865
3916
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestCaseResult?.(payload)));
|
|
3917
|
+
if ('passed-only' === context.normalizedConfig.silent) await flushBufferedLogsForTask({
|
|
3918
|
+
taskId: payload.testId,
|
|
3919
|
+
status: payload.status,
|
|
3920
|
+
taskParentNames: payload.parentNames,
|
|
3921
|
+
taskType: 'case',
|
|
3922
|
+
testPath: payload.testPath
|
|
3923
|
+
});
|
|
3866
3924
|
};
|
|
3867
3925
|
const handleTestFileComplete = async (payload)=>{
|
|
3868
3926
|
reporterResults.push(payload);
|
|
@@ -3870,6 +3928,22 @@ const runBrowserController = async (context, options)=>{
|
|
|
3870
3928
|
payload
|
|
3871
3929
|
], payload.results);
|
|
3872
3930
|
if (payload.snapshotResult) context.snapshotManager.add(payload.snapshotResult);
|
|
3931
|
+
if (phaseTrackers) {
|
|
3932
|
+
const tracker = phaseTrackers.get(payload.testPath);
|
|
3933
|
+
if (tracker) {
|
|
3934
|
+
tracker.end();
|
|
3935
|
+
const events = tracker.getTraceEvents();
|
|
3936
|
+
if (events) onTraceEvents?.(events);
|
|
3937
|
+
phaseTrackers.delete(payload.testPath);
|
|
3938
|
+
}
|
|
3939
|
+
}
|
|
3940
|
+
if ('passed-only' === context.normalizedConfig.silent) await flushBufferedLogsForTask({
|
|
3941
|
+
taskId: payload.testId,
|
|
3942
|
+
status: payload.status,
|
|
3943
|
+
taskParentNames: payload.parentNames,
|
|
3944
|
+
taskType: 'file',
|
|
3945
|
+
testPath: payload.testPath
|
|
3946
|
+
});
|
|
3873
3947
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestFileResult?.(payload)));
|
|
3874
3948
|
if ('fail' === payload.status) ensureProcessExitCode(1);
|
|
3875
3949
|
};
|
|
@@ -3877,12 +3951,18 @@ const runBrowserController = async (context, options)=>{
|
|
|
3877
3951
|
const log = {
|
|
3878
3952
|
content: payload.content,
|
|
3879
3953
|
name: payload.level,
|
|
3954
|
+
taskId: payload.taskId,
|
|
3955
|
+
taskName: payload.taskName,
|
|
3956
|
+
taskParentNames: payload.taskParentNames,
|
|
3957
|
+
taskType: payload.taskType,
|
|
3880
3958
|
testPath: payload.testPath,
|
|
3881
3959
|
type: payload.type,
|
|
3882
3960
|
trace: payload.trace
|
|
3883
3961
|
};
|
|
3884
|
-
|
|
3885
|
-
if (
|
|
3962
|
+
if (true === context.normalizedConfig.silent) return;
|
|
3963
|
+
if ('passed-only' === context.normalizedConfig.silent) return void bufferConsoleLog(log);
|
|
3964
|
+
if (context.normalizedConfig.disableConsoleIntercept) return;
|
|
3965
|
+
await emitUserConsoleLog(log);
|
|
3886
3966
|
};
|
|
3887
3967
|
const handleFatal = async (payload)=>{
|
|
3888
3968
|
const error = new Error(payload.message);
|
|
@@ -3890,6 +3970,52 @@ const runBrowserController = async (context, options)=>{
|
|
|
3890
3970
|
fatalError = error;
|
|
3891
3971
|
ensureProcessExitCode(1);
|
|
3892
3972
|
};
|
|
3973
|
+
const bufferedConsoleLogs = new Map();
|
|
3974
|
+
const suiteIdsByChain = new Map();
|
|
3975
|
+
const getSuiteChainKey = (names)=>names.join('\u0000');
|
|
3976
|
+
const pushTaskId = (taskIds, taskId)=>{
|
|
3977
|
+
if (!taskIds.includes(taskId)) taskIds.push(taskId);
|
|
3978
|
+
};
|
|
3979
|
+
const shouldEmitUserConsoleLog = (log)=>context.normalizedConfig.onConsoleLog?.(log.content) !== false;
|
|
3980
|
+
const emitUserConsoleLog = async (log)=>{
|
|
3981
|
+
if (!shouldEmitUserConsoleLog(log)) return;
|
|
3982
|
+
await Promise.all(context.reporters.map((reporter)=>reporter.onUserConsoleLog?.(log)));
|
|
3983
|
+
};
|
|
3984
|
+
const bufferConsoleLog = (log)=>{
|
|
3985
|
+
const taskId = getBufferedLogTaskId(log);
|
|
3986
|
+
const logs = bufferedConsoleLogs.get(taskId) || [];
|
|
3987
|
+
logs.push(log);
|
|
3988
|
+
bufferedConsoleLogs.set(taskId, logs);
|
|
3989
|
+
if ('suite' === log.taskType && log.taskId) suiteIdsByChain.set(getSuiteChainKey([
|
|
3990
|
+
...log.taskParentNames || [],
|
|
3991
|
+
log.taskName || ''
|
|
3992
|
+
]), log.taskId);
|
|
3993
|
+
};
|
|
3994
|
+
const flushBufferedLogsForTask = async ({ taskId, status, taskParentNames, taskType, testPath })=>{
|
|
3995
|
+
if ('fail' !== status) return void bufferedConsoleLogs.delete(taskId);
|
|
3996
|
+
const taskIdsToFlush = [];
|
|
3997
|
+
if ('case' === taskType) {
|
|
3998
|
+
pushTaskId(taskIdsToFlush, getFileTaskId(testPath));
|
|
3999
|
+
const suiteNames = taskParentNames || [];
|
|
4000
|
+
for(let i = 0; i < suiteNames.length; i++){
|
|
4001
|
+
const suiteId = suiteIdsByChain.get(getSuiteChainKey(suiteNames.slice(0, i + 1)));
|
|
4002
|
+
if (suiteId) pushTaskId(taskIdsToFlush, suiteId);
|
|
4003
|
+
}
|
|
4004
|
+
pushTaskId(taskIdsToFlush, taskId);
|
|
4005
|
+
}
|
|
4006
|
+
if ('suite' === taskType) {
|
|
4007
|
+
pushTaskId(taskIdsToFlush, getFileTaskId(testPath));
|
|
4008
|
+
pushTaskId(taskIdsToFlush, taskId);
|
|
4009
|
+
}
|
|
4010
|
+
if ('file' === taskType) pushTaskId(taskIdsToFlush, taskId);
|
|
4011
|
+
for (const bufferedTaskId of taskIdsToFlush){
|
|
4012
|
+
const logs = bufferedConsoleLogs.get(bufferedTaskId);
|
|
4013
|
+
if (logs) {
|
|
4014
|
+
bufferedConsoleLogs.delete(bufferedTaskId);
|
|
4015
|
+
for (const log of logs)await Promise.all(context.reporters.map((reporter)=>reporter.onUserConsoleLog?.(log)));
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
};
|
|
3893
4019
|
const runSnapshotRpc = async (request)=>{
|
|
3894
4020
|
switch(request.method){
|
|
3895
4021
|
case 'resolveSnapshotPath':
|
|
@@ -4148,6 +4274,54 @@ const runBrowserController = async (context, options)=>{
|
|
|
4148
4274
|
logger.debug(`[Headless] Interrupting active run token ${run.token} before scheduling latest rerun`);
|
|
4149
4275
|
}
|
|
4150
4276
|
});
|
|
4277
|
+
if (0 === allTestFiles.length) {
|
|
4278
|
+
const duration = {
|
|
4279
|
+
totalTime: buildTime,
|
|
4280
|
+
buildTime,
|
|
4281
|
+
testTime: 0
|
|
4282
|
+
};
|
|
4283
|
+
const result = {
|
|
4284
|
+
results: reporterResults,
|
|
4285
|
+
testResults: caseResults,
|
|
4286
|
+
duration,
|
|
4287
|
+
hasFailure: false,
|
|
4288
|
+
getSourcemap: getBrowserSourcemap,
|
|
4289
|
+
resolveSourcemap: resolveBrowserSourcemap,
|
|
4290
|
+
close: skipOnTestRunEnd ? async ()=>{
|
|
4291
|
+
sessionRegistry.clear();
|
|
4292
|
+
await destroyBrowserRuntime(runtime);
|
|
4293
|
+
} : void 0
|
|
4294
|
+
};
|
|
4295
|
+
if (!skipOnTestRunEnd) await notifyTestRunEnd({
|
|
4296
|
+
duration
|
|
4297
|
+
});
|
|
4298
|
+
if (isWatchMode) {
|
|
4299
|
+
triggerRerun = async ()=>{
|
|
4300
|
+
const newProjectEntries = await collectProjectEntries(context);
|
|
4301
|
+
const rerunPlan = planWatchRerun({
|
|
4302
|
+
projectEntries: newProjectEntries,
|
|
4303
|
+
previousTestFiles: watchContext.lastTestFiles,
|
|
4304
|
+
affectedTestFiles: watchContext.affectedTestFiles
|
|
4305
|
+
});
|
|
4306
|
+
watchContext.affectedTestFiles = [];
|
|
4307
|
+
if (rerunPlan.filesChanged) {
|
|
4308
|
+
watchContext.lastTestFiles = rerunPlan.currentTestFiles;
|
|
4309
|
+
if (0 === rerunPlan.currentTestFiles.length) {
|
|
4310
|
+
logger.log(color.cyan('No browser test files remain after update.\n'));
|
|
4311
|
+
logBrowserWatchReadyMessage(enableCliShortcuts);
|
|
4312
|
+
return;
|
|
4313
|
+
}
|
|
4314
|
+
logger.log(color.cyan(`Test file set changed, re-running ${rerunPlan.currentTestFiles.length} file(s)...\n`));
|
|
4315
|
+
latestRerunScheduler.enqueueLatest(rerunPlan.currentTestFiles);
|
|
4316
|
+
return;
|
|
4317
|
+
}
|
|
4318
|
+
logBrowserWatchReadyMessage(enableCliShortcuts);
|
|
4319
|
+
};
|
|
4320
|
+
watchContext.hooksEnabled = true;
|
|
4321
|
+
logBrowserWatchReadyMessage(enableCliShortcuts);
|
|
4322
|
+
}
|
|
4323
|
+
return result;
|
|
4324
|
+
}
|
|
4151
4325
|
const testStart = Date.now();
|
|
4152
4326
|
await runFilesWithPool(allTestFiles);
|
|
4153
4327
|
const testTime = Date.now() - testStart;
|
|
@@ -4418,18 +4592,21 @@ const runBrowserController = async (context, options)=>{
|
|
|
4418
4592
|
if (fatalError) return;
|
|
4419
4593
|
await reloadTestFileWithTimeout(file, testNamePattern);
|
|
4420
4594
|
});
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
await
|
|
4426
|
-
|
|
4595
|
+
let testTime = 0;
|
|
4596
|
+
if (currentTestFiles.length > 0) {
|
|
4597
|
+
const testStart = Date.now();
|
|
4598
|
+
try {
|
|
4599
|
+
await waitForRunnerFramesReady(currentTestFiles.map((file)=>file.testPath));
|
|
4600
|
+
for (const file of currentTestFiles){
|
|
4601
|
+
await enqueueHeadedReload(file);
|
|
4602
|
+
if (fatalError) break;
|
|
4603
|
+
}
|
|
4604
|
+
} catch (error) {
|
|
4605
|
+
fatalError = fatalError ?? toError(error);
|
|
4606
|
+
ensureProcessExitCode(1);
|
|
4427
4607
|
}
|
|
4428
|
-
|
|
4429
|
-
fatalError = fatalError ?? toError(error);
|
|
4430
|
-
ensureProcessExitCode(1);
|
|
4608
|
+
testTime = Date.now() - testStart;
|
|
4431
4609
|
}
|
|
4432
|
-
const testTime = Date.now() - testStart;
|
|
4433
4610
|
if (isWatchMode) triggerRerun = async ()=>{
|
|
4434
4611
|
const newProjectEntries = await collectProjectEntries(context);
|
|
4435
4612
|
const rerunPlan = planWatchRerun({
|
|
@@ -4444,6 +4621,11 @@ const runBrowserController = async (context, options)=>{
|
|
|
4444
4621
|
watchContext.lastTestFiles = rerunPlan.currentTestFiles;
|
|
4445
4622
|
currentTestFiles = rerunPlan.currentTestFiles;
|
|
4446
4623
|
await rpcManager.notifyTestFileUpdate(currentTestFiles);
|
|
4624
|
+
if (0 === currentTestFiles.length) {
|
|
4625
|
+
logger.log(color.cyan('No browser test files remain after update.\n'));
|
|
4626
|
+
logBrowserWatchReadyMessage(enableCliShortcuts);
|
|
4627
|
+
return;
|
|
4628
|
+
}
|
|
4447
4629
|
await waitForRunnerFramesReady(currentTestFiles.map((file)=>file.testPath));
|
|
4448
4630
|
}
|
|
4449
4631
|
if (rerunPlan.normalizedAffectedTestFiles.length > 0) {
|
package/dist/protocol.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { DevicePreset } from '@rstest/core/browser';
|
|
2
2
|
import type { RuntimeConfig, TestFileResult, TestInfo, TestResult } from '@rstest/core/browser-runtime';
|
|
3
3
|
import type { SnapshotUpdateState } from '@vitest/snapshot';
|
|
4
|
-
export type { BrowserLocatorIR, BrowserRpcRequest, SnapshotRpcRequest, } from './rpcProtocol';
|
|
5
|
-
export { validateBrowserRpcRequest } from './rpcProtocol';
|
|
4
|
+
export type { BrowserLocatorIR, BrowserRpcRequest, SnapshotRpcRequest, } from './rpcProtocol.js';
|
|
5
|
+
export { validateBrowserRpcRequest } from './rpcProtocol.js';
|
|
6
6
|
export declare const DISPATCH_MESSAGE_TYPE = "__rstest_dispatch__";
|
|
7
7
|
export declare const DISPATCH_RESPONSE_TYPE = "__rstest_dispatch_response__";
|
|
8
8
|
export declare const DISPATCH_RPC_BRIDGE_NAME = "__rstest_dispatch_rpc__";
|
|
@@ -91,6 +91,10 @@ export type BrowserClientMessage = {
|
|
|
91
91
|
payload: {
|
|
92
92
|
level: 'log' | 'warn' | 'error' | 'info' | 'debug';
|
|
93
93
|
content: string;
|
|
94
|
+
taskId?: string;
|
|
95
|
+
taskName?: string;
|
|
96
|
+
taskParentNames?: string[];
|
|
97
|
+
taskType?: 'file' | 'suite' | 'case';
|
|
94
98
|
testPath: string;
|
|
95
99
|
type: 'stdout' | 'stderr';
|
|
96
100
|
trace?: string;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { FrameLocator, Locator, Page } from 'playwright';
|
|
2
|
-
import type { BrowserLocatorIR } from '../../protocol';
|
|
2
|
+
import type { BrowserLocatorIR } from '../../protocol.js';
|
|
3
3
|
export declare const compilePlaywrightLocator: (frame: FrameLocator | Page, locatorIR: BrowserLocatorIR) => Locator;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Copyright (c) Microsoft Corporation, Apache-2.0.
|
|
5
5
|
*/
|
|
6
6
|
import type { Page } from 'playwright';
|
|
7
|
-
import type { BrowserRpcRequest } from '../../rpcProtocol';
|
|
7
|
+
import type { BrowserRpcRequest } from '../../rpcProtocol.js';
|
|
8
8
|
export declare function dispatchPlaywrightBrowserRpc({ containerPage, runnerPage, request, timeoutFallbackMs, }: {
|
|
9
9
|
containerPage?: Page;
|
|
10
10
|
runnerPage?: Page;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* https://github.com/microsoft/playwright/blob/main/packages/playwright/src/matchers/matchers.ts
|
|
4
4
|
* Copyright (c) Microsoft Corporation, Apache-2.0.
|
|
5
5
|
*/
|
|
6
|
-
import type { BrowserLocatorText } from '../../rpcProtocol';
|
|
6
|
+
import type { BrowserLocatorText } from '../../rpcProtocol.js';
|
|
7
7
|
type ExpectedTextValue = {
|
|
8
8
|
string?: string;
|
|
9
9
|
regexSource?: string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { BrowserProviderImplementation } from '../index';
|
|
1
|
+
import type { BrowserProviderImplementation } from '../index.js';
|
|
2
2
|
export declare const playwrightProviderImplementation: BrowserProviderImplementation;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { playwrightProviderImplementation } from './implementation';
|
|
1
|
+
export { playwrightProviderImplementation } from './implementation.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BrowserProviderRuntime } from '../index';
|
|
1
|
+
import type { BrowserProviderRuntime } from '../index.js';
|
|
2
2
|
export declare function launchPlaywrightBrowser({ browserName, headless, providerOptions, }: {
|
|
3
3
|
browserName: 'chromium' | 'firefox' | 'webkit';
|
|
4
4
|
headless: boolean | undefined;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* `@rstest/core` (`packages/core/src/types/config.ts`) so `defineConfig`
|
|
6
6
|
* autocomplete and runtime validation stay consistent.
|
|
7
7
|
*/
|
|
8
|
-
export declare const BROWSER_VIEWPORT_PRESET_IDS: readonly [
|
|
8
|
+
export declare const BROWSER_VIEWPORT_PRESET_IDS: readonly ['iPhoneSE', 'iPhoneXR', 'iPhone12Pro', 'iPhone14ProMax', 'Pixel7', 'SamsungGalaxyS8Plus', 'SamsungGalaxyS20Ultra', 'iPadMini', 'iPadAir', 'iPadPro', 'SurfacePro7', 'SurfaceDuo', 'GalaxyZFold5', 'AsusZenbookFold', 'SamsungGalaxyA51A71', 'NestHub', 'NestHubMax'];
|
|
9
9
|
type BrowserViewportPresetId = (typeof BROWSER_VIEWPORT_PRESET_IDS)[number];
|
|
10
10
|
type BrowserViewportSize = {
|
|
11
11
|
width: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rstest/browser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Browser mode support for Rstest testing framework.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rstest",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"default": "./package.json"
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
|
-
"main": "./dist/
|
|
35
|
+
"main": "./dist/browser.js",
|
|
36
36
|
"files": [
|
|
37
37
|
"dist",
|
|
38
38
|
"src",
|
|
@@ -45,25 +45,25 @@
|
|
|
45
45
|
"open-editor": "^6.0.0",
|
|
46
46
|
"pathe": "^2.0.3",
|
|
47
47
|
"sirv": "^3.0.2",
|
|
48
|
-
"ws": "^8.20.
|
|
48
|
+
"ws": "^8.20.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@rslib/core": "0.21.
|
|
51
|
+
"@rslib/core": "0.21.5",
|
|
52
52
|
"@types/convert-source-map": "^2.0.3",
|
|
53
53
|
"@types/picomatch": "^4.0.3",
|
|
54
54
|
"@types/ws": "^8.18.1",
|
|
55
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
55
|
+
"@typescript/native-preview": "7.0.0-dev.20260516.1",
|
|
56
56
|
"@vitest/snapshot": "^3.2.4",
|
|
57
57
|
"birpc": "^4.0.0",
|
|
58
58
|
"picomatch": "^4.0.4",
|
|
59
|
-
"playwright": "^1.
|
|
60
|
-
"@rstest/browser-ui": "0.0.0",
|
|
59
|
+
"playwright": "^1.60.0",
|
|
61
60
|
"@rstest/tsconfig": "0.0.1",
|
|
62
|
-
"@rstest/
|
|
61
|
+
"@rstest/browser-ui": "0.0.0",
|
|
62
|
+
"@rstest/core": "0.10.1"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"playwright": "^1.49.1",
|
|
66
|
-
"@rstest/core": "^0.
|
|
66
|
+
"@rstest/core": "^0.10.1"
|
|
67
67
|
},
|
|
68
68
|
"peerDependenciesMeta": {
|
|
69
69
|
"playwright": {
|