@rstest/browser 0.8.1 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/entry.d.ts +1 -0
- package/dist/hostController.d.ts +5 -1
- package/dist/index.js +44 -12
- package/package.json +3 -3
- package/src/client/entry.ts +8 -0
- package/src/hostController.ts +68 -14
package/dist/client/entry.d.ts
CHANGED
package/dist/hostController.d.ts
CHANGED
|
@@ -14,4 +14,8 @@ export type ListBrowserTestsResult = {
|
|
|
14
14
|
* This function creates a headless browser runtime, loads test files,
|
|
15
15
|
* and collects their test structure (describe/test declarations).
|
|
16
16
|
*/
|
|
17
|
-
export declare const listBrowserTests: (context: Rstest
|
|
17
|
+
export declare const listBrowserTests: (context: Rstest, options?: {
|
|
18
|
+
shardedEntries?: Map<string, {
|
|
19
|
+
entries: Record<string, string>;
|
|
20
|
+
}>;
|
|
21
|
+
}) => Promise<ListBrowserTestsResult>;
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { __webpack_require__ } from "./rslib-runtime.js";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import promises from "node:fs/promises";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { TEMP_RSTEST_OUTPUT_DIR, color, getSetupFiles, getTestEntries, isDebug, logger, rsbuild, serializableConfig } from "@rstest/core/browser";
|
|
5
|
+
import { TEMP_RSTEST_OUTPUT_DIR, color, getSetupFiles, getTestEntries, isDebug, loadCoverageProvider, logger, 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";
|
|
@@ -1917,6 +1917,7 @@ const htmlTemplate = `<!DOCTYPE html>
|
|
|
1917
1917
|
</body>
|
|
1918
1918
|
</html>
|
|
1919
1919
|
`;
|
|
1920
|
+
const VIRTUAL_MANIFEST_FILENAME = 'virtual-manifest.ts';
|
|
1920
1921
|
const destroyBrowserRuntime = async (runtime)=>{
|
|
1921
1922
|
try {
|
|
1922
1923
|
await runtime.browser?.close?.();
|
|
@@ -1966,6 +1967,7 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
1966
1967
|
const firstProject = browserProjects[0];
|
|
1967
1968
|
const userPlugins = firstProject?.normalizedConfig.plugins || [];
|
|
1968
1969
|
const userRsbuildConfig = firstProject?.normalizedConfig ?? {};
|
|
1970
|
+
const browserConfig = firstProject?.normalizedConfig.browser ?? context.normalizedConfig.browser;
|
|
1969
1971
|
const browserRuntimePath = fileURLToPath(import.meta.resolve('@rstest/core/browser-runtime'));
|
|
1970
1972
|
const rstestInternalAliases = {
|
|
1971
1973
|
'@rstest/browser-manifest': manifestPath,
|
|
@@ -1981,8 +1983,8 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
1981
1983
|
plugins: userPlugins,
|
|
1982
1984
|
server: {
|
|
1983
1985
|
printUrls: false,
|
|
1984
|
-
port:
|
|
1985
|
-
strictPort:
|
|
1986
|
+
port: browserConfig.port ?? 4000,
|
|
1987
|
+
strictPort: browserConfig.strictPort
|
|
1986
1988
|
},
|
|
1987
1989
|
dev: {
|
|
1988
1990
|
client: {
|
|
@@ -1990,7 +1992,7 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
1990
1992
|
}
|
|
1991
1993
|
},
|
|
1992
1994
|
environments: {
|
|
1993
|
-
web: {}
|
|
1995
|
+
[firstProject?.environmentName || 'web']: {}
|
|
1994
1996
|
}
|
|
1995
1997
|
}
|
|
1996
1998
|
});
|
|
@@ -2067,6 +2069,13 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
2067
2069
|
}
|
|
2068
2070
|
}
|
|
2069
2071
|
]);
|
|
2072
|
+
const coverage = firstProject?.normalizedConfig.coverage;
|
|
2073
|
+
if (coverage?.enabled && 'list' !== context.command) {
|
|
2074
|
+
const { pluginCoverage } = await loadCoverageProvider(coverage, context.rootPath);
|
|
2075
|
+
rsbuildInstance.addPlugins([
|
|
2076
|
+
pluginCoverage(coverage)
|
|
2077
|
+
]);
|
|
2078
|
+
}
|
|
2070
2079
|
const devServer = await rsbuildInstance.createDevServer({
|
|
2071
2080
|
getPortSilently: true
|
|
2072
2081
|
});
|
|
@@ -2177,7 +2186,7 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
2177
2186
|
const wsPort = wss.address().port;
|
|
2178
2187
|
logger.debug(`[Browser UI] WebSocket server started on port ${wsPort}`);
|
|
2179
2188
|
let browserLauncher;
|
|
2180
|
-
const browserName =
|
|
2189
|
+
const browserName = browserConfig.browser;
|
|
2181
2190
|
try {
|
|
2182
2191
|
const playwright = await import("playwright");
|
|
2183
2192
|
browserLauncher = playwright[browserName];
|
|
@@ -2189,7 +2198,7 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
2189
2198
|
let browser;
|
|
2190
2199
|
try {
|
|
2191
2200
|
browser = await browserLauncher.launch({
|
|
2192
|
-
headless: forceHeadless ??
|
|
2201
|
+
headless: forceHeadless ?? browserConfig.headless,
|
|
2193
2202
|
args: 'chromium' === browserName ? [
|
|
2194
2203
|
'--disable-popup-blocking',
|
|
2195
2204
|
'--no-first-run',
|
|
@@ -2214,6 +2223,25 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
2214
2223
|
wss
|
|
2215
2224
|
};
|
|
2216
2225
|
};
|
|
2226
|
+
async function resolveProjectEntries(context, shardedEntries) {
|
|
2227
|
+
if (shardedEntries) {
|
|
2228
|
+
const browserProjects = getBrowserProjects(context);
|
|
2229
|
+
const projectEntries = [];
|
|
2230
|
+
for (const project of browserProjects){
|
|
2231
|
+
const entryInfo = shardedEntries.get(project.environmentName);
|
|
2232
|
+
if (entryInfo && Object.keys(entryInfo.entries).length > 0) {
|
|
2233
|
+
const setup = getSetupFiles(project.normalizedConfig.setupFiles, project.rootPath);
|
|
2234
|
+
projectEntries.push({
|
|
2235
|
+
project,
|
|
2236
|
+
setupFiles: Object.values(setup),
|
|
2237
|
+
testFiles: Object.values(entryInfo.entries)
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
return projectEntries;
|
|
2242
|
+
}
|
|
2243
|
+
return collectProjectEntries(context);
|
|
2244
|
+
}
|
|
2217
2245
|
const runBrowserController = async (context, options)=>{
|
|
2218
2246
|
const { skipOnTestRunEnd = false } = options ?? {};
|
|
2219
2247
|
const buildStart = Date.now();
|
|
@@ -2235,17 +2263,21 @@ const runBrowserController = async (context, options)=>{
|
|
|
2235
2263
|
ensureProcessExitCode(1);
|
|
2236
2264
|
return;
|
|
2237
2265
|
}
|
|
2238
|
-
const projectEntries = await
|
|
2266
|
+
const projectEntries = await resolveProjectEntries(context, options?.shardedEntries);
|
|
2239
2267
|
const totalTests = projectEntries.reduce((total, item)=>total + item.testFiles.length, 0);
|
|
2240
2268
|
if (0 === totalTests) {
|
|
2241
2269
|
const code = context.normalizedConfig.passWithNoTests ? 0 : 1;
|
|
2242
|
-
if (!skipOnTestRunEnd)
|
|
2270
|
+
if (!skipOnTestRunEnd) {
|
|
2271
|
+
const message = `No test files found, exiting with code ${code}.`;
|
|
2272
|
+
if (0 === code) logger.log(color.yellow(message));
|
|
2273
|
+
else logger.error(color.red(message));
|
|
2274
|
+
}
|
|
2243
2275
|
if (0 !== code) ensureProcessExitCode(code);
|
|
2244
2276
|
return;
|
|
2245
2277
|
}
|
|
2246
2278
|
const isWatchMode = 'watch' === context.command;
|
|
2247
2279
|
const tempDir = isWatchMode && watchContext.runtime ? watchContext.runtime.tempDir : isWatchMode ? join(context.rootPath, TEMP_RSTEST_OUTPUT_DIR, 'browser', 'watch') : join(context.rootPath, TEMP_RSTEST_OUTPUT_DIR, 'browser', Date.now().toString());
|
|
2248
|
-
const manifestPath = join(tempDir,
|
|
2280
|
+
const manifestPath = join(tempDir, VIRTUAL_MANIFEST_FILENAME);
|
|
2249
2281
|
const manifestSource = generateManifestModule({
|
|
2250
2282
|
manifestPath,
|
|
2251
2283
|
entries: projectEntries
|
|
@@ -2499,15 +2531,15 @@ const runBrowserController = async (context, options)=>{
|
|
|
2499
2531
|
}
|
|
2500
2532
|
return result;
|
|
2501
2533
|
};
|
|
2502
|
-
const listBrowserTests = async (context)=>{
|
|
2503
|
-
const projectEntries = await
|
|
2534
|
+
const listBrowserTests = async (context, options)=>{
|
|
2535
|
+
const projectEntries = await resolveProjectEntries(context, options?.shardedEntries);
|
|
2504
2536
|
const totalTests = projectEntries.reduce((total, item)=>total + item.testFiles.length, 0);
|
|
2505
2537
|
if (0 === totalTests) return {
|
|
2506
2538
|
list: [],
|
|
2507
2539
|
close: async ()=>{}
|
|
2508
2540
|
};
|
|
2509
2541
|
const tempDir = join(context.rootPath, TEMP_RSTEST_OUTPUT_DIR, 'browser', `list-${Date.now()}`);
|
|
2510
|
-
const manifestPath = join(tempDir,
|
|
2542
|
+
const manifestPath = join(tempDir, VIRTUAL_MANIFEST_FILENAME);
|
|
2511
2543
|
const manifestSource = generateManifestModule({
|
|
2512
2544
|
manifestPath,
|
|
2513
2545
|
entries: projectEntries
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rstest/browser",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Browser mode support for Rstest testing framework.",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/web-infra-dev/rstest/issues"
|
|
@@ -53,12 +53,12 @@
|
|
|
53
53
|
"picomatch": "^4.0.3",
|
|
54
54
|
"playwright": "^1.49.1",
|
|
55
55
|
"@rstest/browser-ui": "0.0.0",
|
|
56
|
-
"@rstest/core": "0.8.
|
|
56
|
+
"@rstest/core": "0.8.3",
|
|
57
57
|
"@rstest/tsconfig": "0.0.1"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"playwright": "^1.49.1",
|
|
61
|
-
"@rstest/core": "^0.8.
|
|
61
|
+
"@rstest/core": "^0.8.3"
|
|
62
62
|
},
|
|
63
63
|
"peerDependenciesMeta": {
|
|
64
64
|
"playwright": {
|
package/src/client/entry.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
projectTestContexts,
|
|
8
8
|
} from '@rstest/browser-manifest';
|
|
9
9
|
import type {
|
|
10
|
+
CoverageMapData,
|
|
10
11
|
RunnerHooks,
|
|
11
12
|
RuntimeConfig,
|
|
12
13
|
WorkerState,
|
|
@@ -35,6 +36,8 @@ declare global {
|
|
|
35
36
|
__RSTEST_BROWSER_OPTIONS__?: BrowserHostConfig;
|
|
36
37
|
__rstest_dispatch__?: (message: BrowserClientMessage) => void;
|
|
37
38
|
}
|
|
39
|
+
// eslint-disable-next-line no-var
|
|
40
|
+
var __coverage__: Record<string, unknown> | undefined;
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
/**
|
|
@@ -589,6 +592,11 @@ const run = async () => {
|
|
|
589
592
|
runtime.api,
|
|
590
593
|
);
|
|
591
594
|
|
|
595
|
+
// Collect coverage data from global __coverage__ object
|
|
596
|
+
if (globalThis.__coverage__) {
|
|
597
|
+
result.coverage = globalThis.__coverage__ as CoverageMapData;
|
|
598
|
+
}
|
|
599
|
+
|
|
592
600
|
send({
|
|
593
601
|
type: 'file-complete',
|
|
594
602
|
payload: result,
|
package/src/hostController.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
getTestEntries,
|
|
13
13
|
isDebug,
|
|
14
14
|
type ListCommandResult,
|
|
15
|
+
loadCoverageProvider,
|
|
15
16
|
logger,
|
|
16
17
|
type ProjectContext,
|
|
17
18
|
type Reporter,
|
|
@@ -715,6 +716,11 @@ const htmlTemplate = `<!DOCTYPE html>
|
|
|
715
716
|
</html>
|
|
716
717
|
`;
|
|
717
718
|
|
|
719
|
+
// Workaround for noisy "removed ..." logs caused by VirtualModulesPlugin.
|
|
720
|
+
// Rsbuild suppresses the removed-file log if all removed paths include "virtual":
|
|
721
|
+
// https://github.com/web-infra-dev/rsbuild/blob/1258fa9dba5c321a4629b591a6dadbd2e26c6963/packages/core/src/createCompiler.ts#L73-L76
|
|
722
|
+
const VIRTUAL_MANIFEST_FILENAME = 'virtual-manifest.ts';
|
|
723
|
+
|
|
718
724
|
// ============================================================================
|
|
719
725
|
// Browser Runtime Lifecycle
|
|
720
726
|
// ============================================================================
|
|
@@ -817,6 +823,8 @@ const createBrowserRuntime = async ({
|
|
|
817
823
|
const firstProject = browserProjects[0];
|
|
818
824
|
const userPlugins = firstProject?.normalizedConfig.plugins || [];
|
|
819
825
|
const userRsbuildConfig = firstProject?.normalizedConfig ?? {};
|
|
826
|
+
const browserConfig =
|
|
827
|
+
firstProject?.normalizedConfig.browser ?? context.normalizedConfig.browser;
|
|
820
828
|
|
|
821
829
|
// Rstest internal aliases that must not be overridden by user config
|
|
822
830
|
const browserRuntimePath = fileURLToPath(
|
|
@@ -841,8 +849,8 @@ const createBrowserRuntime = async ({
|
|
|
841
849
|
plugins: userPlugins,
|
|
842
850
|
server: {
|
|
843
851
|
printUrls: false,
|
|
844
|
-
port:
|
|
845
|
-
strictPort:
|
|
852
|
+
port: browserConfig.port ?? 4000,
|
|
853
|
+
strictPort: browserConfig.strictPort,
|
|
846
854
|
},
|
|
847
855
|
dev: {
|
|
848
856
|
client: {
|
|
@@ -850,7 +858,7 @@ const createBrowserRuntime = async ({
|
|
|
850
858
|
},
|
|
851
859
|
},
|
|
852
860
|
environments: {
|
|
853
|
-
web: {},
|
|
861
|
+
[firstProject?.environmentName || 'web']: {},
|
|
854
862
|
},
|
|
855
863
|
},
|
|
856
864
|
});
|
|
@@ -970,6 +978,16 @@ const createBrowserRuntime = async ({
|
|
|
970
978
|
]);
|
|
971
979
|
}
|
|
972
980
|
|
|
981
|
+
// Register coverage plugin for browser mode
|
|
982
|
+
const coverage = firstProject?.normalizedConfig.coverage;
|
|
983
|
+
if (coverage?.enabled && context.command !== 'list') {
|
|
984
|
+
const { pluginCoverage } = await loadCoverageProvider(
|
|
985
|
+
coverage,
|
|
986
|
+
context.rootPath,
|
|
987
|
+
);
|
|
988
|
+
rsbuildInstance.addPlugins([pluginCoverage(coverage)]);
|
|
989
|
+
}
|
|
990
|
+
|
|
973
991
|
const devServer = await rsbuildInstance.createDevServer({
|
|
974
992
|
getPortSilently: true,
|
|
975
993
|
});
|
|
@@ -1134,7 +1152,7 @@ const createBrowserRuntime = async ({
|
|
|
1134
1152
|
logger.debug(`[Browser UI] WebSocket server started on port ${wsPort}`);
|
|
1135
1153
|
|
|
1136
1154
|
let browserLauncher: BrowserType;
|
|
1137
|
-
const browserName =
|
|
1155
|
+
const browserName = browserConfig.browser;
|
|
1138
1156
|
try {
|
|
1139
1157
|
const playwright = await import('playwright');
|
|
1140
1158
|
browserLauncher = playwright[browserName];
|
|
@@ -1147,7 +1165,7 @@ const createBrowserRuntime = async ({
|
|
|
1147
1165
|
let browser: BrowserInstance;
|
|
1148
1166
|
try {
|
|
1149
1167
|
browser = await browserLauncher.launch({
|
|
1150
|
-
headless: forceHeadless ??
|
|
1168
|
+
headless: forceHeadless ?? browserConfig.headless,
|
|
1151
1169
|
// Chromium-specific args (ignored by other browsers)
|
|
1152
1170
|
args:
|
|
1153
1171
|
browserName === 'chromium'
|
|
@@ -1178,6 +1196,32 @@ const createBrowserRuntime = async ({
|
|
|
1178
1196
|
};
|
|
1179
1197
|
};
|
|
1180
1198
|
|
|
1199
|
+
async function resolveProjectEntries(
|
|
1200
|
+
context: Rstest,
|
|
1201
|
+
shardedEntries?: Map<string, { entries: Record<string, string> }>,
|
|
1202
|
+
): Promise<BrowserProjectEntries[]> {
|
|
1203
|
+
if (shardedEntries) {
|
|
1204
|
+
const browserProjects = getBrowserProjects(context);
|
|
1205
|
+
const projectEntries: BrowserProjectEntries[] = [];
|
|
1206
|
+
for (const project of browserProjects) {
|
|
1207
|
+
const entryInfo = shardedEntries.get(project.environmentName);
|
|
1208
|
+
if (entryInfo && Object.keys(entryInfo.entries).length > 0) {
|
|
1209
|
+
const setup = getSetupFiles(
|
|
1210
|
+
project.normalizedConfig.setupFiles,
|
|
1211
|
+
project.rootPath,
|
|
1212
|
+
);
|
|
1213
|
+
projectEntries.push({
|
|
1214
|
+
project,
|
|
1215
|
+
setupFiles: Object.values(setup),
|
|
1216
|
+
testFiles: Object.values(entryInfo.entries),
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
return projectEntries;
|
|
1221
|
+
}
|
|
1222
|
+
return collectProjectEntries(context);
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1181
1225
|
// ============================================================================
|
|
1182
1226
|
// Main Entry Point
|
|
1183
1227
|
// ============================================================================
|
|
@@ -1219,7 +1263,10 @@ export const runBrowserController = async (
|
|
|
1219
1263
|
}
|
|
1220
1264
|
}
|
|
1221
1265
|
|
|
1222
|
-
const projectEntries = await
|
|
1266
|
+
const projectEntries = await resolveProjectEntries(
|
|
1267
|
+
context,
|
|
1268
|
+
options?.shardedEntries,
|
|
1269
|
+
);
|
|
1223
1270
|
const totalTests = projectEntries.reduce(
|
|
1224
1271
|
(total, item) => total + item.testFiles.length,
|
|
1225
1272
|
0,
|
|
@@ -1228,11 +1275,12 @@ export const runBrowserController = async (
|
|
|
1228
1275
|
if (totalTests === 0) {
|
|
1229
1276
|
const code = context.normalizedConfig.passWithNoTests ? 0 : 1;
|
|
1230
1277
|
if (!skipOnTestRunEnd) {
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1278
|
+
const message = `No test files found, exiting with code ${code}.`;
|
|
1279
|
+
if (code === 0) {
|
|
1280
|
+
logger.log(color.yellow(message));
|
|
1281
|
+
} else {
|
|
1282
|
+
logger.error(color.red(message));
|
|
1283
|
+
}
|
|
1236
1284
|
}
|
|
1237
1285
|
|
|
1238
1286
|
if (code !== 0) {
|
|
@@ -1253,8 +1301,8 @@ export const runBrowserController = async (
|
|
|
1253
1301
|
'browser',
|
|
1254
1302
|
Date.now().toString(),
|
|
1255
1303
|
);
|
|
1256
|
-
const manifestPath = join(tempDir, 'manifest.ts');
|
|
1257
1304
|
|
|
1305
|
+
const manifestPath = join(tempDir, VIRTUAL_MANIFEST_FILENAME);
|
|
1258
1306
|
const manifestSource = generateManifestModule({
|
|
1259
1307
|
manifestPath,
|
|
1260
1308
|
entries: projectEntries,
|
|
@@ -1700,8 +1748,14 @@ export type ListBrowserTestsResult = {
|
|
|
1700
1748
|
*/
|
|
1701
1749
|
export const listBrowserTests = async (
|
|
1702
1750
|
context: Rstest,
|
|
1751
|
+
options?: {
|
|
1752
|
+
shardedEntries?: Map<string, { entries: Record<string, string> }>;
|
|
1753
|
+
},
|
|
1703
1754
|
): Promise<ListBrowserTestsResult> => {
|
|
1704
|
-
const projectEntries = await
|
|
1755
|
+
const projectEntries = await resolveProjectEntries(
|
|
1756
|
+
context,
|
|
1757
|
+
options?.shardedEntries,
|
|
1758
|
+
);
|
|
1705
1759
|
const totalTests = projectEntries.reduce(
|
|
1706
1760
|
(total, item) => total + item.testFiles.length,
|
|
1707
1761
|
0,
|
|
@@ -1720,8 +1774,8 @@ export const listBrowserTests = async (
|
|
|
1720
1774
|
'browser',
|
|
1721
1775
|
`list-${Date.now()}`,
|
|
1722
1776
|
);
|
|
1723
|
-
const manifestPath = join(tempDir, 'manifest.ts');
|
|
1724
1777
|
|
|
1778
|
+
const manifestPath = join(tempDir, VIRTUAL_MANIFEST_FILENAME);
|
|
1725
1779
|
const manifestSource = generateManifestModule({
|
|
1726
1780
|
manifestPath,
|
|
1727
1781
|
entries: projectEntries,
|