@rstest/browser 0.9.9 → 0.10.0
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/{464.89762ff658.js → 484.af891b432a.js} +3183 -3152
- package/dist/browser-container/container-static/js/484.af891b432a.js.LICENSE.txt +1 -0
- package/dist/browser-container/container-static/js/{index.c13dfe1ecf.js → index.463ae8de87.js} +12 -12
- 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 -24
- 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 -71
- package/src/protocol.ts +4 -0
- package/dist/browser-container/container-static/js/464.89762ff658.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;
|
|
@@ -2949,7 +2952,7 @@ const applyDefaultWatchOptions = (rspackConfig, isWatchMode)=>{
|
|
|
2949
2952
|
}
|
|
2950
2953
|
rspackConfig.watchOptions.ignored = castArray(rspackConfig.watchOptions.ignored || []);
|
|
2951
2954
|
if (0 === rspackConfig.watchOptions.ignored.length) rspackConfig.watchOptions.ignored.push('**/.git', '**/node_modules');
|
|
2952
|
-
rspackConfig.output?.path
|
|
2955
|
+
if (rspackConfig.output?.path) rspackConfig.watchOptions.ignored.push(rspackConfig.output.path);
|
|
2953
2956
|
};
|
|
2954
2957
|
const resolveListenPort = (listenPort, httpServer)=>{
|
|
2955
2958
|
if (listenPort) return listenPort;
|
|
@@ -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, 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,
|
|
@@ -3083,7 +3089,8 @@ const getRuntimeConfigFromProject = (project)=>{
|
|
|
3083
3089
|
bail,
|
|
3084
3090
|
logHeapUsage,
|
|
3085
3091
|
chaiConfig,
|
|
3086
|
-
includeTaskLocation
|
|
3092
|
+
includeTaskLocation,
|
|
3093
|
+
silent
|
|
3087
3094
|
};
|
|
3088
3095
|
};
|
|
3089
3096
|
const getBrowserProjects = (context)=>context.projects.filter((project)=>project.normalizedConfig.browser.enabled);
|
|
@@ -3123,7 +3130,8 @@ const collectProjectEntries = async (context)=>{
|
|
|
3123
3130
|
includeSource,
|
|
3124
3131
|
rootPath: context.rootPath,
|
|
3125
3132
|
projectRoot: project.rootPath,
|
|
3126
|
-
fileFilters: context.fileFilters || []
|
|
3133
|
+
fileFilters: context.fileFilters || [],
|
|
3134
|
+
fileFilterMode: context.fileFilterMode
|
|
3127
3135
|
});
|
|
3128
3136
|
const setup = getSetupFiles(setupFiles, project.rootPath);
|
|
3129
3137
|
return {
|
|
@@ -3326,8 +3334,18 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
3326
3334
|
const project = projectByEnvironmentName.get(name);
|
|
3327
3335
|
if (!project) return config;
|
|
3328
3336
|
const userRsbuildConfig = project.normalizedConfig;
|
|
3337
|
+
const buildCache = resolveProjectBuildCache({
|
|
3338
|
+
context,
|
|
3339
|
+
project
|
|
3340
|
+
});
|
|
3329
3341
|
const setupFiles = Object.values(getSetupFiles(project.normalizedConfig.setupFiles, project.rootPath));
|
|
3330
|
-
const merged = mergeEnvironmentConfig(config,
|
|
3342
|
+
const merged = mergeEnvironmentConfig(config, {
|
|
3343
|
+
...userRsbuildConfig,
|
|
3344
|
+
performance: buildCache ? {
|
|
3345
|
+
...userRsbuildConfig.performance,
|
|
3346
|
+
buildCache
|
|
3347
|
+
} : userRsbuildConfig.performance
|
|
3348
|
+
}, {
|
|
3331
3349
|
resolve: {
|
|
3332
3350
|
alias: rstestInternalAliases
|
|
3333
3351
|
},
|
|
@@ -3572,8 +3590,10 @@ async function resolveProjectEntries(context, shardedEntries) {
|
|
|
3572
3590
|
return collectProjectEntries(context);
|
|
3573
3591
|
}
|
|
3574
3592
|
const runBrowserController = async (context, options)=>{
|
|
3575
|
-
const { skipOnTestRunEnd = false } = options ?? {};
|
|
3593
|
+
const { skipOnTestRunEnd = false, allowEmptyWatchRun = false, onTraceEvents } = options ?? {};
|
|
3576
3594
|
const buildStart = Date.now();
|
|
3595
|
+
const isWatchMode = 'watch' === context.command;
|
|
3596
|
+
const phaseTrackers = onTraceEvents ? new Map() : void 0;
|
|
3577
3597
|
const browserProjects = getBrowserProjects(context);
|
|
3578
3598
|
const useHeadlessDirect = browserProjects.every((project)=>project.normalizedConfig.browser.headless);
|
|
3579
3599
|
const browserSourceMapCache = new Map();
|
|
@@ -3696,18 +3716,24 @@ const runBrowserController = async (context, options)=>{
|
|
|
3696
3716
|
}
|
|
3697
3717
|
const projectEntries = await resolveProjectEntries(context, options?.shardedEntries);
|
|
3698
3718
|
const totalTests = projectEntries.reduce((total, item)=>total + item.testFiles.length, 0);
|
|
3719
|
+
const shouldKeepWatchingWithEmptySet = isWatchMode && allowEmptyWatchRun;
|
|
3699
3720
|
if (0 === totalTests) {
|
|
3700
3721
|
const code = context.normalizedConfig.passWithNoTests ? 0 : 1;
|
|
3701
3722
|
if (!skipOnTestRunEnd) {
|
|
3702
|
-
const message =
|
|
3723
|
+
const message = shouldKeepWatchingWithEmptySet ? 'No test files found.' : getNoTestFilesMessage({
|
|
3724
|
+
context,
|
|
3725
|
+
code,
|
|
3726
|
+
defaultMessage: `No test files found, exiting with code ${code}.`
|
|
3727
|
+
});
|
|
3703
3728
|
if (0 === code) logger.log(color.yellow(message));
|
|
3704
3729
|
else logger.error(color.red(message));
|
|
3730
|
+
if (context.relatedFilters?.length) logger.log(color.gray('related: '), context.relatedFilters.join(color.gray(', ')));
|
|
3731
|
+
else if (context.fileFilters?.length) logger.log(color.gray('filter: '), context.fileFilters.join(color.gray(', ')));
|
|
3705
3732
|
}
|
|
3706
|
-
if (0 !== code) ensureProcessExitCode(code);
|
|
3707
|
-
return;
|
|
3733
|
+
if (0 !== code && !shouldKeepWatchingWithEmptySet) ensureProcessExitCode(code);
|
|
3734
|
+
if (!shouldKeepWatchingWithEmptySet) return;
|
|
3708
3735
|
}
|
|
3709
3736
|
await notifyTestRunStart();
|
|
3710
|
-
const isWatchMode = 'watch' === context.command;
|
|
3711
3737
|
const enableCliShortcuts = isWatchMode && isBrowserWatchCliShortcutsEnabled();
|
|
3712
3738
|
const browserTempOutputRoot = context.normalizedConfig.output.distPath.root;
|
|
3713
3739
|
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 +3869,57 @@ const runBrowserController = async (context, options)=>{
|
|
|
3843
3869
|
}
|
|
3844
3870
|
};
|
|
3845
3871
|
const handleTestFileStart = async (payload)=>{
|
|
3872
|
+
if (phaseTrackers) {
|
|
3873
|
+
const tracker = new PhaseTracker({
|
|
3874
|
+
trace: {
|
|
3875
|
+
testPath: payload.testPath,
|
|
3876
|
+
project: payload.projectName
|
|
3877
|
+
},
|
|
3878
|
+
pid: nextBrowserFilePid++
|
|
3879
|
+
});
|
|
3880
|
+
tracker.transition('prepare');
|
|
3881
|
+
phaseTrackers.set(payload.testPath, tracker);
|
|
3882
|
+
}
|
|
3846
3883
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestFileStart?.({
|
|
3884
|
+
testId: getFileTaskId(payload.testPath),
|
|
3847
3885
|
testPath: payload.testPath,
|
|
3848
3886
|
tests: []
|
|
3849
3887
|
})));
|
|
3850
3888
|
};
|
|
3851
3889
|
const handleTestFileReady = async (payload)=>{
|
|
3890
|
+
phaseTrackers?.get(payload.testPath)?.transition('tests');
|
|
3852
3891
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestFileReady?.(payload)));
|
|
3853
3892
|
};
|
|
3854
3893
|
const handleTestSuiteStart = async (payload)=>{
|
|
3894
|
+
phaseTrackers?.get(payload.testPath)?.recordSuiteStart(payload);
|
|
3855
3895
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestSuiteStart?.(payload)));
|
|
3856
3896
|
};
|
|
3857
3897
|
const handleTestSuiteResult = async (payload)=>{
|
|
3898
|
+
phaseTrackers?.get(payload.testPath)?.recordSuiteResult(payload);
|
|
3858
3899
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestSuiteResult?.(payload)));
|
|
3900
|
+
if ('passed-only' === context.normalizedConfig.silent) await flushBufferedLogsForTask({
|
|
3901
|
+
taskId: payload.testId,
|
|
3902
|
+
status: payload.status,
|
|
3903
|
+
taskParentNames: payload.parentNames,
|
|
3904
|
+
taskType: 'suite',
|
|
3905
|
+
testPath: payload.testPath
|
|
3906
|
+
});
|
|
3859
3907
|
};
|
|
3860
3908
|
const handleTestCaseStart = async (payload)=>{
|
|
3909
|
+
phaseTrackers?.get(payload.testPath)?.recordCaseStart(payload);
|
|
3861
3910
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestCaseStart?.(payload)));
|
|
3862
3911
|
};
|
|
3863
3912
|
const handleTestCaseResult = async (payload)=>{
|
|
3864
3913
|
caseResults.push(payload);
|
|
3914
|
+
phaseTrackers?.get(payload.testPath)?.recordCaseResult(payload);
|
|
3865
3915
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestCaseResult?.(payload)));
|
|
3916
|
+
if ('passed-only' === context.normalizedConfig.silent) await flushBufferedLogsForTask({
|
|
3917
|
+
taskId: payload.testId,
|
|
3918
|
+
status: payload.status,
|
|
3919
|
+
taskParentNames: payload.parentNames,
|
|
3920
|
+
taskType: 'case',
|
|
3921
|
+
testPath: payload.testPath
|
|
3922
|
+
});
|
|
3866
3923
|
};
|
|
3867
3924
|
const handleTestFileComplete = async (payload)=>{
|
|
3868
3925
|
reporterResults.push(payload);
|
|
@@ -3870,6 +3927,22 @@ const runBrowserController = async (context, options)=>{
|
|
|
3870
3927
|
payload
|
|
3871
3928
|
], payload.results);
|
|
3872
3929
|
if (payload.snapshotResult) context.snapshotManager.add(payload.snapshotResult);
|
|
3930
|
+
if (phaseTrackers) {
|
|
3931
|
+
const tracker = phaseTrackers.get(payload.testPath);
|
|
3932
|
+
if (tracker) {
|
|
3933
|
+
tracker.end();
|
|
3934
|
+
const events = tracker.getTraceEvents();
|
|
3935
|
+
if (events) onTraceEvents?.(events);
|
|
3936
|
+
phaseTrackers.delete(payload.testPath);
|
|
3937
|
+
}
|
|
3938
|
+
}
|
|
3939
|
+
if ('passed-only' === context.normalizedConfig.silent) await flushBufferedLogsForTask({
|
|
3940
|
+
taskId: payload.testId,
|
|
3941
|
+
status: payload.status,
|
|
3942
|
+
taskParentNames: payload.parentNames,
|
|
3943
|
+
taskType: 'file',
|
|
3944
|
+
testPath: payload.testPath
|
|
3945
|
+
});
|
|
3873
3946
|
await Promise.all(context.reporters.map((reporter)=>reporter.onTestFileResult?.(payload)));
|
|
3874
3947
|
if ('fail' === payload.status) ensureProcessExitCode(1);
|
|
3875
3948
|
};
|
|
@@ -3877,12 +3950,18 @@ const runBrowserController = async (context, options)=>{
|
|
|
3877
3950
|
const log = {
|
|
3878
3951
|
content: payload.content,
|
|
3879
3952
|
name: payload.level,
|
|
3953
|
+
taskId: payload.taskId,
|
|
3954
|
+
taskName: payload.taskName,
|
|
3955
|
+
taskParentNames: payload.taskParentNames,
|
|
3956
|
+
taskType: payload.taskType,
|
|
3880
3957
|
testPath: payload.testPath,
|
|
3881
3958
|
type: payload.type,
|
|
3882
3959
|
trace: payload.trace
|
|
3883
3960
|
};
|
|
3884
|
-
|
|
3885
|
-
if (
|
|
3961
|
+
if (true === context.normalizedConfig.silent) return;
|
|
3962
|
+
if ('passed-only' === context.normalizedConfig.silent) return void bufferConsoleLog(log);
|
|
3963
|
+
if (context.normalizedConfig.disableConsoleIntercept) return;
|
|
3964
|
+
await emitUserConsoleLog(log);
|
|
3886
3965
|
};
|
|
3887
3966
|
const handleFatal = async (payload)=>{
|
|
3888
3967
|
const error = new Error(payload.message);
|
|
@@ -3890,6 +3969,52 @@ const runBrowserController = async (context, options)=>{
|
|
|
3890
3969
|
fatalError = error;
|
|
3891
3970
|
ensureProcessExitCode(1);
|
|
3892
3971
|
};
|
|
3972
|
+
const bufferedConsoleLogs = new Map();
|
|
3973
|
+
const suiteIdsByChain = new Map();
|
|
3974
|
+
const getSuiteChainKey = (names)=>names.join('\u0000');
|
|
3975
|
+
const pushTaskId = (taskIds, taskId)=>{
|
|
3976
|
+
if (!taskIds.includes(taskId)) taskIds.push(taskId);
|
|
3977
|
+
};
|
|
3978
|
+
const shouldEmitUserConsoleLog = (log)=>context.normalizedConfig.onConsoleLog?.(log.content) !== false;
|
|
3979
|
+
const emitUserConsoleLog = async (log)=>{
|
|
3980
|
+
if (!shouldEmitUserConsoleLog(log)) return;
|
|
3981
|
+
await Promise.all(context.reporters.map((reporter)=>reporter.onUserConsoleLog?.(log)));
|
|
3982
|
+
};
|
|
3983
|
+
const bufferConsoleLog = (log)=>{
|
|
3984
|
+
const taskId = getBufferedLogTaskId(log);
|
|
3985
|
+
const logs = bufferedConsoleLogs.get(taskId) || [];
|
|
3986
|
+
logs.push(log);
|
|
3987
|
+
bufferedConsoleLogs.set(taskId, logs);
|
|
3988
|
+
if ('suite' === log.taskType && log.taskId) suiteIdsByChain.set(getSuiteChainKey([
|
|
3989
|
+
...log.taskParentNames || [],
|
|
3990
|
+
log.taskName || ''
|
|
3991
|
+
]), log.taskId);
|
|
3992
|
+
};
|
|
3993
|
+
const flushBufferedLogsForTask = async ({ taskId, status, taskParentNames, taskType, testPath })=>{
|
|
3994
|
+
if ('fail' !== status) return void bufferedConsoleLogs.delete(taskId);
|
|
3995
|
+
const taskIdsToFlush = [];
|
|
3996
|
+
if ('case' === taskType) {
|
|
3997
|
+
pushTaskId(taskIdsToFlush, getFileTaskId(testPath));
|
|
3998
|
+
const suiteNames = taskParentNames || [];
|
|
3999
|
+
for(let i = 0; i < suiteNames.length; i++){
|
|
4000
|
+
const suiteId = suiteIdsByChain.get(getSuiteChainKey(suiteNames.slice(0, i + 1)));
|
|
4001
|
+
if (suiteId) pushTaskId(taskIdsToFlush, suiteId);
|
|
4002
|
+
}
|
|
4003
|
+
pushTaskId(taskIdsToFlush, taskId);
|
|
4004
|
+
}
|
|
4005
|
+
if ('suite' === taskType) {
|
|
4006
|
+
pushTaskId(taskIdsToFlush, getFileTaskId(testPath));
|
|
4007
|
+
pushTaskId(taskIdsToFlush, taskId);
|
|
4008
|
+
}
|
|
4009
|
+
if ('file' === taskType) pushTaskId(taskIdsToFlush, taskId);
|
|
4010
|
+
for (const bufferedTaskId of taskIdsToFlush){
|
|
4011
|
+
const logs = bufferedConsoleLogs.get(bufferedTaskId);
|
|
4012
|
+
if (logs) {
|
|
4013
|
+
bufferedConsoleLogs.delete(bufferedTaskId);
|
|
4014
|
+
for (const log of logs)await Promise.all(context.reporters.map((reporter)=>reporter.onUserConsoleLog?.(log)));
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
};
|
|
3893
4018
|
const runSnapshotRpc = async (request)=>{
|
|
3894
4019
|
switch(request.method){
|
|
3895
4020
|
case 'resolveSnapshotPath':
|
|
@@ -4148,6 +4273,54 @@ const runBrowserController = async (context, options)=>{
|
|
|
4148
4273
|
logger.debug(`[Headless] Interrupting active run token ${run.token} before scheduling latest rerun`);
|
|
4149
4274
|
}
|
|
4150
4275
|
});
|
|
4276
|
+
if (0 === allTestFiles.length) {
|
|
4277
|
+
const duration = {
|
|
4278
|
+
totalTime: buildTime,
|
|
4279
|
+
buildTime,
|
|
4280
|
+
testTime: 0
|
|
4281
|
+
};
|
|
4282
|
+
const result = {
|
|
4283
|
+
results: reporterResults,
|
|
4284
|
+
testResults: caseResults,
|
|
4285
|
+
duration,
|
|
4286
|
+
hasFailure: false,
|
|
4287
|
+
getSourcemap: getBrowserSourcemap,
|
|
4288
|
+
resolveSourcemap: resolveBrowserSourcemap,
|
|
4289
|
+
close: skipOnTestRunEnd ? async ()=>{
|
|
4290
|
+
sessionRegistry.clear();
|
|
4291
|
+
await destroyBrowserRuntime(runtime);
|
|
4292
|
+
} : void 0
|
|
4293
|
+
};
|
|
4294
|
+
if (!skipOnTestRunEnd) await notifyTestRunEnd({
|
|
4295
|
+
duration
|
|
4296
|
+
});
|
|
4297
|
+
if (isWatchMode) {
|
|
4298
|
+
triggerRerun = async ()=>{
|
|
4299
|
+
const newProjectEntries = await collectProjectEntries(context);
|
|
4300
|
+
const rerunPlan = planWatchRerun({
|
|
4301
|
+
projectEntries: newProjectEntries,
|
|
4302
|
+
previousTestFiles: watchContext.lastTestFiles,
|
|
4303
|
+
affectedTestFiles: watchContext.affectedTestFiles
|
|
4304
|
+
});
|
|
4305
|
+
watchContext.affectedTestFiles = [];
|
|
4306
|
+
if (rerunPlan.filesChanged) {
|
|
4307
|
+
watchContext.lastTestFiles = rerunPlan.currentTestFiles;
|
|
4308
|
+
if (0 === rerunPlan.currentTestFiles.length) {
|
|
4309
|
+
logger.log(color.cyan('No browser test files remain after update.\n'));
|
|
4310
|
+
logBrowserWatchReadyMessage(enableCliShortcuts);
|
|
4311
|
+
return;
|
|
4312
|
+
}
|
|
4313
|
+
logger.log(color.cyan(`Test file set changed, re-running ${rerunPlan.currentTestFiles.length} file(s)...\n`));
|
|
4314
|
+
latestRerunScheduler.enqueueLatest(rerunPlan.currentTestFiles);
|
|
4315
|
+
return;
|
|
4316
|
+
}
|
|
4317
|
+
logBrowserWatchReadyMessage(enableCliShortcuts);
|
|
4318
|
+
};
|
|
4319
|
+
watchContext.hooksEnabled = true;
|
|
4320
|
+
logBrowserWatchReadyMessage(enableCliShortcuts);
|
|
4321
|
+
}
|
|
4322
|
+
return result;
|
|
4323
|
+
}
|
|
4151
4324
|
const testStart = Date.now();
|
|
4152
4325
|
await runFilesWithPool(allTestFiles);
|
|
4153
4326
|
const testTime = Date.now() - testStart;
|
|
@@ -4418,18 +4591,21 @@ const runBrowserController = async (context, options)=>{
|
|
|
4418
4591
|
if (fatalError) return;
|
|
4419
4592
|
await reloadTestFileWithTimeout(file, testNamePattern);
|
|
4420
4593
|
});
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
await
|
|
4426
|
-
|
|
4594
|
+
let testTime = 0;
|
|
4595
|
+
if (currentTestFiles.length > 0) {
|
|
4596
|
+
const testStart = Date.now();
|
|
4597
|
+
try {
|
|
4598
|
+
await waitForRunnerFramesReady(currentTestFiles.map((file)=>file.testPath));
|
|
4599
|
+
for (const file of currentTestFiles){
|
|
4600
|
+
await enqueueHeadedReload(file);
|
|
4601
|
+
if (fatalError) break;
|
|
4602
|
+
}
|
|
4603
|
+
} catch (error) {
|
|
4604
|
+
fatalError = fatalError ?? toError(error);
|
|
4605
|
+
ensureProcessExitCode(1);
|
|
4427
4606
|
}
|
|
4428
|
-
|
|
4429
|
-
fatalError = fatalError ?? toError(error);
|
|
4430
|
-
ensureProcessExitCode(1);
|
|
4607
|
+
testTime = Date.now() - testStart;
|
|
4431
4608
|
}
|
|
4432
|
-
const testTime = Date.now() - testStart;
|
|
4433
4609
|
if (isWatchMode) triggerRerun = async ()=>{
|
|
4434
4610
|
const newProjectEntries = await collectProjectEntries(context);
|
|
4435
4611
|
const rerunPlan = planWatchRerun({
|
|
@@ -4444,6 +4620,11 @@ const runBrowserController = async (context, options)=>{
|
|
|
4444
4620
|
watchContext.lastTestFiles = rerunPlan.currentTestFiles;
|
|
4445
4621
|
currentTestFiles = rerunPlan.currentTestFiles;
|
|
4446
4622
|
await rpcManager.notifyTestFileUpdate(currentTestFiles);
|
|
4623
|
+
if (0 === currentTestFiles.length) {
|
|
4624
|
+
logger.log(color.cyan('No browser test files remain after update.\n'));
|
|
4625
|
+
logBrowserWatchReadyMessage(enableCliShortcuts);
|
|
4626
|
+
return;
|
|
4627
|
+
}
|
|
4447
4628
|
await waitForRunnerFramesReady(currentTestFiles.map((file)=>file.testPath));
|
|
4448
4629
|
}
|
|
4449
4630
|
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.0",
|
|
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.4",
|
|
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.20260512.1",
|
|
56
56
|
"@vitest/snapshot": "^3.2.4",
|
|
57
57
|
"birpc": "^4.0.0",
|
|
58
58
|
"picomatch": "^4.0.4",
|
|
59
|
-
"playwright": "^1.
|
|
59
|
+
"playwright": "^1.60.0",
|
|
60
60
|
"@rstest/browser-ui": "0.0.0",
|
|
61
|
-
"@rstest/
|
|
62
|
-
"@rstest/
|
|
61
|
+
"@rstest/tsconfig": "0.0.1",
|
|
62
|
+
"@rstest/core": "0.10.0"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"playwright": "^1.49.1",
|
|
66
|
-
"@rstest/core": "^0.
|
|
66
|
+
"@rstest/core": "^0.10.0"
|
|
67
67
|
},
|
|
68
68
|
"peerDependenciesMeta": {
|
|
69
69
|
"playwright": {
|