@rstest/browser 0.10.3 → 0.10.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/626.js +2 -1
- package/dist/browser-container/container-static/js/{27.099feaf1da.js → 3.d3d6c6e4cf.js} +436 -436
- package/dist/browser-container/container-static/js/3.d3d6c6e4cf.js.LICENSE.txt +1 -0
- package/dist/browser-container/container-static/js/{index.be8c8d2626.js → index.8fb1588e4a.js} +109 -136
- package/dist/browser-container/container-static/js/{lib-react.5ae9b90ee5.js → lib-react.62b27a21db.js} +21 -21
- package/dist/browser-container/container-static/js/lib-react.62b27a21db.js.LICENSE.txt +1 -0
- package/dist/browser-container/index.html +1 -1
- package/dist/browser.js +4 -4
- package/dist/client/dispatchTransport.d.ts +19 -0
- package/dist/client/public.d.ts +3 -3
- package/dist/client/sourceMapSupport.d.ts +1 -1
- package/dist/concurrency.d.ts +3 -3
- package/dist/configValidation.d.ts +2 -2
- package/dist/dispatchCapabilities.d.ts +1 -1
- package/dist/hostController.d.ts +3 -3
- package/dist/index.d.ts +5 -5
- package/dist/index.js +169 -216
- package/dist/protocol.d.ts +45 -18
- package/dist/providers/index.d.ts +8 -1
- package/dist/rpcProtocol.d.ts +32 -18
- package/dist/viewportPresets.d.ts +5 -0
- package/package.json +6 -6
- package/src/AGENTS.md +7 -1
- package/src/client/dispatchTransport.ts +63 -1
- package/src/client/entry.ts +25 -58
- package/src/client/public.ts +3 -3
- package/src/client/snapshot.ts +24 -22
- package/src/client/sourceMapSupport.ts +1 -1
- package/src/concurrency.ts +6 -20
- package/src/configValidation.ts +2 -2
- package/src/dispatchCapabilities.ts +102 -83
- package/src/env.d.ts +6 -2
- package/src/hostController.ts +76 -42
- package/src/index.ts +22 -11
- package/src/protocol.ts +66 -22
- package/src/providers/index.ts +8 -1
- package/src/rpcProtocol.ts +34 -21
- package/src/viewportPresets.ts +5 -0
- package/src/watchCliShortcuts.ts +2 -4
- package/dist/browser-container/container-static/js/27.099feaf1da.js.LICENSE.txt +0 -1
- package/dist/browser-container/container-static/js/lib-react.5ae9b90ee5.js.LICENSE.txt +0 -1
package/dist/index.js
CHANGED
|
@@ -2,15 +2,14 @@ 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 { PhaseTracker, color, createCoverageProvider, getNoTestFilesMessage, getSetupFiles, getTestEntries, isDebug, loadCoverageProvider, logger, resolveProjectBuildCache, rsbuild, serializableConfig } from "@rstest/core/browser";
|
|
5
|
+
import { DEFAULT_TEST_TIMEOUT, PhaseTracker, RSTEST_ENV_SYMBOL_KEY, color, createCoverageProvider, getNoTestFilesMessage, getNumCpus, getSetupFiles, getTestEntries, isDebug, isTTY, loadCoverageProvider, logger, parseWorkers, resolveProjectBuildCache, rsbuild, serializableConfig } from "@rstest/core/internal/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";
|
|
9
9
|
import { WebSocketServer } from "ws";
|
|
10
|
-
import node_os from "node:os";
|
|
11
10
|
import convert_source_map from "convert-source-map";
|
|
12
11
|
import { __webpack_require__ } from "./rslib-runtime.js";
|
|
13
|
-
import { DISPATCH_RPC_BRIDGE_NAME, DISPATCH_MESSAGE_TYPE } from "./626.js";
|
|
12
|
+
import { DISPATCH_RPC_BRIDGE_NAME, DISPATCH_NAMESPACE_SNAPSHOT, DISPATCH_MESSAGE_TYPE, DISPATCH_NAMESPACE_BROWSER } from "./626.js";
|
|
14
13
|
__webpack_require__.add({
|
|
15
14
|
"../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/index.js" (module, __unused_rspack_exports, __webpack_require__) {
|
|
16
15
|
const pico = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/picomatch.js");
|
|
@@ -1632,6 +1631,113 @@ __webpack_require__.add({
|
|
|
1632
1631
|
};
|
|
1633
1632
|
}
|
|
1634
1633
|
});
|
|
1634
|
+
const BROWSER_VIEWPORT_PRESET_DIMENSIONS = {
|
|
1635
|
+
iPhoneSE: {
|
|
1636
|
+
width: 375,
|
|
1637
|
+
height: 667
|
|
1638
|
+
},
|
|
1639
|
+
iPhoneXR: {
|
|
1640
|
+
width: 414,
|
|
1641
|
+
height: 896
|
|
1642
|
+
},
|
|
1643
|
+
iPhone12Pro: {
|
|
1644
|
+
width: 390,
|
|
1645
|
+
height: 844
|
|
1646
|
+
},
|
|
1647
|
+
iPhone14ProMax: {
|
|
1648
|
+
width: 430,
|
|
1649
|
+
height: 932
|
|
1650
|
+
},
|
|
1651
|
+
Pixel7: {
|
|
1652
|
+
width: 412,
|
|
1653
|
+
height: 915
|
|
1654
|
+
},
|
|
1655
|
+
SamsungGalaxyS8Plus: {
|
|
1656
|
+
width: 360,
|
|
1657
|
+
height: 740
|
|
1658
|
+
},
|
|
1659
|
+
SamsungGalaxyS20Ultra: {
|
|
1660
|
+
width: 412,
|
|
1661
|
+
height: 915
|
|
1662
|
+
},
|
|
1663
|
+
iPadMini: {
|
|
1664
|
+
width: 768,
|
|
1665
|
+
height: 1024
|
|
1666
|
+
},
|
|
1667
|
+
iPadAir: {
|
|
1668
|
+
width: 820,
|
|
1669
|
+
height: 1180
|
|
1670
|
+
},
|
|
1671
|
+
iPadPro: {
|
|
1672
|
+
width: 1024,
|
|
1673
|
+
height: 1366
|
|
1674
|
+
},
|
|
1675
|
+
SurfacePro7: {
|
|
1676
|
+
width: 912,
|
|
1677
|
+
height: 1368
|
|
1678
|
+
},
|
|
1679
|
+
SurfaceDuo: {
|
|
1680
|
+
width: 540,
|
|
1681
|
+
height: 720
|
|
1682
|
+
},
|
|
1683
|
+
GalaxyZFold5: {
|
|
1684
|
+
width: 344,
|
|
1685
|
+
height: 882
|
|
1686
|
+
},
|
|
1687
|
+
AsusZenbookFold: {
|
|
1688
|
+
width: 853,
|
|
1689
|
+
height: 1280
|
|
1690
|
+
},
|
|
1691
|
+
SamsungGalaxyA51A71: {
|
|
1692
|
+
width: 412,
|
|
1693
|
+
height: 914
|
|
1694
|
+
},
|
|
1695
|
+
NestHub: {
|
|
1696
|
+
width: 1024,
|
|
1697
|
+
height: 600
|
|
1698
|
+
},
|
|
1699
|
+
NestHubMax: {
|
|
1700
|
+
width: 1280,
|
|
1701
|
+
height: 800
|
|
1702
|
+
}
|
|
1703
|
+
};
|
|
1704
|
+
const resolveBrowserViewportPreset = (presetId)=>{
|
|
1705
|
+
const size = BROWSER_VIEWPORT_PRESET_DIMENSIONS[presetId];
|
|
1706
|
+
return size ?? null;
|
|
1707
|
+
};
|
|
1708
|
+
const SUPPORTED_PROVIDERS = [
|
|
1709
|
+
'playwright'
|
|
1710
|
+
];
|
|
1711
|
+
const isPlainObject = (value)=>'[object Object]' === Object.prototype.toString.call(value);
|
|
1712
|
+
const validateViewport = (viewport)=>{
|
|
1713
|
+
if (null == viewport) return;
|
|
1714
|
+
if ('string' == typeof viewport) {
|
|
1715
|
+
const presetId = viewport.trim();
|
|
1716
|
+
if (!presetId) throw new Error('browser.viewport must be a non-empty preset id.');
|
|
1717
|
+
if (!resolveBrowserViewportPreset(presetId)) throw new Error(`browser.viewport must be a valid preset id. Received: ${viewport}`);
|
|
1718
|
+
return;
|
|
1719
|
+
}
|
|
1720
|
+
if (isPlainObject(viewport)) {
|
|
1721
|
+
const width = viewport.width;
|
|
1722
|
+
const height = viewport.height;
|
|
1723
|
+
if (!Number.isFinite(width) || width <= 0) throw new Error('browser.viewport.width must be a positive number.');
|
|
1724
|
+
if (!Number.isFinite(height) || height <= 0) throw new Error('browser.viewport.height must be a positive number.');
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1727
|
+
throw new Error('browser.viewport must be either a preset id or { width, height }.');
|
|
1728
|
+
};
|
|
1729
|
+
const validateBrowserConfig = (context)=>{
|
|
1730
|
+
for (const project of context.projects){
|
|
1731
|
+
const { browser, output } = project.normalizedConfig;
|
|
1732
|
+
if (browser.enabled) {
|
|
1733
|
+
if (!browser.provider) throw new Error('browser.provider is required when browser.enabled is true.');
|
|
1734
|
+
if (!SUPPORTED_PROVIDERS.includes(browser.provider)) throw new Error(`browser.provider must be one of: ${SUPPORTED_PROVIDERS.join(', ')}.`);
|
|
1735
|
+
validateViewport(browser.viewport);
|
|
1736
|
+
if (!isPlainObject(browser.providerOptions)) throw new Error('browser.providerOptions must be a plain object.');
|
|
1737
|
+
if (output?.bundleDependencies === false) throw new Error('output.bundleDependencies false is not supported in browser mode.');
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
};
|
|
1635
1741
|
const TYPE_REQUEST = "q";
|
|
1636
1742
|
const TYPE_RESPONSE = "s";
|
|
1637
1743
|
function createPromiseWithResolvers() {
|
|
@@ -1828,15 +1934,6 @@ function createBirpc($functions, options) {
|
|
|
1828
1934
|
return rpc;
|
|
1829
1935
|
}
|
|
1830
1936
|
const DEFAULT_MAX_HEADLESS_WORKERS = 12;
|
|
1831
|
-
const getNumCpus = ()=>node_os.availableParallelism?.() ?? node_os.cpus().length;
|
|
1832
|
-
const parseWorkers = (maxWorkers, numCpus = getNumCpus())=>{
|
|
1833
|
-
const parsed = Number.parseInt(maxWorkers.toString(), 10);
|
|
1834
|
-
if ('string' == typeof maxWorkers && maxWorkers.trim().endsWith('%')) {
|
|
1835
|
-
const workers = Math.floor(parsed / 100 * numCpus);
|
|
1836
|
-
return Math.max(workers, 1);
|
|
1837
|
-
}
|
|
1838
|
-
return parsed > 0 ? parsed : 1;
|
|
1839
|
-
};
|
|
1840
1937
|
const resolveDefaultHeadlessWorkers = (command, numCpus = getNumCpus())=>{
|
|
1841
1938
|
const baseWorkers = Math.max(Math.min(DEFAULT_MAX_HEADLESS_WORKERS, numCpus - 1), 1);
|
|
1842
1939
|
return 'watch' === command ? Math.max(Math.floor(baseWorkers / 2), 1) : baseWorkers;
|
|
@@ -1895,72 +1992,49 @@ class HostDispatchRouter {
|
|
|
1895
1992
|
}
|
|
1896
1993
|
}
|
|
1897
1994
|
}
|
|
1995
|
+
const snapshotRequestBuilders = {
|
|
1996
|
+
resolveSnapshotPath: (id, args)=>({
|
|
1997
|
+
id,
|
|
1998
|
+
method: 'resolveSnapshotPath',
|
|
1999
|
+
args: args
|
|
2000
|
+
}),
|
|
2001
|
+
readSnapshotFile: (id, args)=>({
|
|
2002
|
+
id,
|
|
2003
|
+
method: 'readSnapshotFile',
|
|
2004
|
+
args: args
|
|
2005
|
+
}),
|
|
2006
|
+
saveSnapshotFile: (id, args)=>({
|
|
2007
|
+
id,
|
|
2008
|
+
method: 'saveSnapshotFile',
|
|
2009
|
+
args: args
|
|
2010
|
+
}),
|
|
2011
|
+
removeSnapshotFile: (id, args)=>({
|
|
2012
|
+
id,
|
|
2013
|
+
method: 'removeSnapshotFile',
|
|
2014
|
+
args: args
|
|
2015
|
+
})
|
|
2016
|
+
};
|
|
1898
2017
|
const toSnapshotRpcRequest = (request)=>{
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
return {
|
|
1902
|
-
id: request.requestId,
|
|
1903
|
-
method: 'resolveSnapshotPath',
|
|
1904
|
-
args: request.args
|
|
1905
|
-
};
|
|
1906
|
-
case 'readSnapshotFile':
|
|
1907
|
-
return {
|
|
1908
|
-
id: request.requestId,
|
|
1909
|
-
method: 'readSnapshotFile',
|
|
1910
|
-
args: request.args
|
|
1911
|
-
};
|
|
1912
|
-
case 'saveSnapshotFile':
|
|
1913
|
-
return {
|
|
1914
|
-
id: request.requestId,
|
|
1915
|
-
method: 'saveSnapshotFile',
|
|
1916
|
-
args: request.args
|
|
1917
|
-
};
|
|
1918
|
-
case 'removeSnapshotFile':
|
|
1919
|
-
return {
|
|
1920
|
-
id: request.requestId,
|
|
1921
|
-
method: 'removeSnapshotFile',
|
|
1922
|
-
args: request.args
|
|
1923
|
-
};
|
|
1924
|
-
default:
|
|
1925
|
-
return null;
|
|
1926
|
-
}
|
|
2018
|
+
const builder = snapshotRequestBuilders[request.method];
|
|
2019
|
+
return builder ? builder(request.requestId, request.args) : null;
|
|
1927
2020
|
};
|
|
1928
2021
|
const createHostDispatchRouter = ({ routerOptions, runnerCallbacks, runSnapshotRpc, extensionHandlers, onDuplicateNamespace })=>{
|
|
1929
2022
|
const router = new HostDispatchRouter(routerOptions);
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
break;
|
|
1944
|
-
case 'case-start':
|
|
1945
|
-
await runnerCallbacks.onTestCaseStart(request.args);
|
|
1946
|
-
break;
|
|
1947
|
-
case 'case-result':
|
|
1948
|
-
await runnerCallbacks.onTestCaseResult(request.args);
|
|
1949
|
-
break;
|
|
1950
|
-
case 'file-complete':
|
|
1951
|
-
await runnerCallbacks.onTestFileComplete(request.args);
|
|
1952
|
-
break;
|
|
1953
|
-
case 'log':
|
|
1954
|
-
await runnerCallbacks.onLog(request.args);
|
|
1955
|
-
break;
|
|
1956
|
-
case 'fatal':
|
|
1957
|
-
await runnerCallbacks.onFatal(request.args);
|
|
1958
|
-
break;
|
|
1959
|
-
default:
|
|
1960
|
-
break;
|
|
1961
|
-
}
|
|
2023
|
+
const runnerMethodHandlers = {
|
|
2024
|
+
'file-start': (args)=>runnerCallbacks.onTestFileStart(args),
|
|
2025
|
+
'file-ready': (args)=>runnerCallbacks.onTestFileReady(args),
|
|
2026
|
+
'suite-start': (args)=>runnerCallbacks.onTestSuiteStart(args),
|
|
2027
|
+
'suite-result': (args)=>runnerCallbacks.onTestSuiteResult(args),
|
|
2028
|
+
'case-start': (args)=>runnerCallbacks.onTestCaseStart(args),
|
|
2029
|
+
'case-result': (args)=>runnerCallbacks.onTestCaseResult(args),
|
|
2030
|
+
'file-complete': (args)=>runnerCallbacks.onTestFileComplete(args),
|
|
2031
|
+
log: (args)=>runnerCallbacks.onLog(args),
|
|
2032
|
+
fatal: (args)=>runnerCallbacks.onFatal(args)
|
|
2033
|
+
};
|
|
2034
|
+
router.register("runner", async (request)=>{
|
|
2035
|
+
await runnerMethodHandlers[request.method]?.(request.args);
|
|
1962
2036
|
});
|
|
1963
|
-
router.register(
|
|
2037
|
+
router.register(DISPATCH_NAMESPACE_SNAPSHOT, async (request)=>{
|
|
1964
2038
|
const snapshotRequest = toSnapshotRpcRequest(request);
|
|
1965
2039
|
if (!snapshotRequest) return;
|
|
1966
2040
|
return runSnapshotRpc(snapshotRequest);
|
|
@@ -2672,101 +2746,7 @@ const loadSourceMapWithCache = async ({ jsUrl, cache, force = false, origin, fet
|
|
|
2672
2746
|
return null;
|
|
2673
2747
|
}
|
|
2674
2748
|
};
|
|
2675
|
-
const
|
|
2676
|
-
'iPhoneSE',
|
|
2677
|
-
'iPhoneXR',
|
|
2678
|
-
'iPhone12Pro',
|
|
2679
|
-
'iPhone14ProMax',
|
|
2680
|
-
'Pixel7',
|
|
2681
|
-
'SamsungGalaxyS8Plus',
|
|
2682
|
-
'SamsungGalaxyS20Ultra',
|
|
2683
|
-
'iPadMini',
|
|
2684
|
-
'iPadAir',
|
|
2685
|
-
'iPadPro',
|
|
2686
|
-
'SurfacePro7',
|
|
2687
|
-
'SurfaceDuo',
|
|
2688
|
-
'GalaxyZFold5',
|
|
2689
|
-
'AsusZenbookFold',
|
|
2690
|
-
'SamsungGalaxyA51A71',
|
|
2691
|
-
'NestHub',
|
|
2692
|
-
'NestHubMax'
|
|
2693
|
-
];
|
|
2694
|
-
const BROWSER_VIEWPORT_PRESET_DIMENSIONS = {
|
|
2695
|
-
iPhoneSE: {
|
|
2696
|
-
width: 375,
|
|
2697
|
-
height: 667
|
|
2698
|
-
},
|
|
2699
|
-
iPhoneXR: {
|
|
2700
|
-
width: 414,
|
|
2701
|
-
height: 896
|
|
2702
|
-
},
|
|
2703
|
-
iPhone12Pro: {
|
|
2704
|
-
width: 390,
|
|
2705
|
-
height: 844
|
|
2706
|
-
},
|
|
2707
|
-
iPhone14ProMax: {
|
|
2708
|
-
width: 430,
|
|
2709
|
-
height: 932
|
|
2710
|
-
},
|
|
2711
|
-
Pixel7: {
|
|
2712
|
-
width: 412,
|
|
2713
|
-
height: 915
|
|
2714
|
-
},
|
|
2715
|
-
SamsungGalaxyS8Plus: {
|
|
2716
|
-
width: 360,
|
|
2717
|
-
height: 740
|
|
2718
|
-
},
|
|
2719
|
-
SamsungGalaxyS20Ultra: {
|
|
2720
|
-
width: 412,
|
|
2721
|
-
height: 915
|
|
2722
|
-
},
|
|
2723
|
-
iPadMini: {
|
|
2724
|
-
width: 768,
|
|
2725
|
-
height: 1024
|
|
2726
|
-
},
|
|
2727
|
-
iPadAir: {
|
|
2728
|
-
width: 820,
|
|
2729
|
-
height: 1180
|
|
2730
|
-
},
|
|
2731
|
-
iPadPro: {
|
|
2732
|
-
width: 1024,
|
|
2733
|
-
height: 1366
|
|
2734
|
-
},
|
|
2735
|
-
SurfacePro7: {
|
|
2736
|
-
width: 912,
|
|
2737
|
-
height: 1368
|
|
2738
|
-
},
|
|
2739
|
-
SurfaceDuo: {
|
|
2740
|
-
width: 540,
|
|
2741
|
-
height: 720
|
|
2742
|
-
},
|
|
2743
|
-
GalaxyZFold5: {
|
|
2744
|
-
width: 344,
|
|
2745
|
-
height: 882
|
|
2746
|
-
},
|
|
2747
|
-
AsusZenbookFold: {
|
|
2748
|
-
width: 853,
|
|
2749
|
-
height: 1280
|
|
2750
|
-
},
|
|
2751
|
-
SamsungGalaxyA51A71: {
|
|
2752
|
-
width: 412,
|
|
2753
|
-
height: 914
|
|
2754
|
-
},
|
|
2755
|
-
NestHub: {
|
|
2756
|
-
width: 1024,
|
|
2757
|
-
height: 600
|
|
2758
|
-
},
|
|
2759
|
-
NestHubMax: {
|
|
2760
|
-
width: 1280,
|
|
2761
|
-
height: 800
|
|
2762
|
-
}
|
|
2763
|
-
};
|
|
2764
|
-
const resolveBrowserViewportPreset = (presetId)=>{
|
|
2765
|
-
const size = BROWSER_VIEWPORT_PRESET_DIMENSIONS[presetId];
|
|
2766
|
-
return size ?? null;
|
|
2767
|
-
};
|
|
2768
|
-
const isTTY = ()=>Boolean(process.stdin.isTTY && !process.env.CI);
|
|
2769
|
-
const isBrowserWatchCliShortcutsEnabled = ()=>isTTY();
|
|
2749
|
+
const isBrowserWatchCliShortcutsEnabled = ()=>isTTY('stdin');
|
|
2770
2750
|
const getBrowserWatchCliShortcutsHintMessage = ()=>` ${color.dim('press')} ${color.bold('q')} ${color.dim('to quit')}\n`;
|
|
2771
2751
|
const logBrowserWatchReadyMessage = (enableCliShortcuts)=>{
|
|
2772
2752
|
logger.log(color.green(' Waiting for file changes...'));
|
|
@@ -2835,6 +2815,7 @@ var picomatch_default = /*#__PURE__*/ __webpack_require__.n(picomatch);
|
|
|
2835
2815
|
const { createRsbuild: createRsbuild, rspack: rspack } = rsbuild;
|
|
2836
2816
|
const hostController_dirname = dirname(fileURLToPath(import.meta.url));
|
|
2837
2817
|
const OPTIONS_PLACEHOLDER = '__RSTEST_OPTIONS_PLACEHOLDER__';
|
|
2818
|
+
const PER_FILE_TIMEOUT_BUFFER_MS = 30000;
|
|
2838
2819
|
let nextBrowserFilePid = 1000000000;
|
|
2839
2820
|
const serializeForInlineScript = (value)=>JSON.stringify(value).replace(/</g, '\\u003c').replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
|
|
2840
2821
|
const getBrowserProviderOptions = (project)=>{
|
|
@@ -3101,6 +3082,7 @@ const getRuntimeConfigFromProject = (project)=>{
|
|
|
3101
3082
|
return {
|
|
3102
3083
|
env: {
|
|
3103
3084
|
NODE_ENV: process.env.NODE_ENV,
|
|
3085
|
+
RSTEST: 'true',
|
|
3104
3086
|
...env
|
|
3105
3087
|
},
|
|
3106
3088
|
testNamePattern,
|
|
@@ -3328,12 +3310,12 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
3328
3310
|
]));
|
|
3329
3311
|
const userPlugins = browserProjects.flatMap((project)=>project.normalizedConfig.plugins || []);
|
|
3330
3312
|
const browserLaunchOptions = ensureConsistentBrowserLaunchOptions(browserProjects);
|
|
3331
|
-
const browserRuntimePath = fileURLToPath(import.meta.resolve('@rstest/core/browser-runtime'));
|
|
3313
|
+
const browserRuntimePath = fileURLToPath(import.meta.resolve('@rstest/core/internal/browser-runtime'));
|
|
3332
3314
|
const rstestInternalAliases = {
|
|
3333
3315
|
'@rstest/browser-manifest': manifestPath,
|
|
3334
3316
|
'@rstest/core': resolveBrowserFile('client/public.ts'),
|
|
3335
3317
|
'@rstest/browser': resolveBrowserFile('browser.ts'),
|
|
3336
|
-
'@rstest/core/browser-runtime': browserRuntimePath,
|
|
3318
|
+
'@rstest/core/internal/browser-runtime': browserRuntimePath,
|
|
3337
3319
|
'@sinonjs/fake-timers': resolveBrowserFile('client/fakeTimersStub.ts')
|
|
3338
3320
|
};
|
|
3339
3321
|
const rsbuildInstance = await createRsbuild({
|
|
@@ -3375,6 +3357,7 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
3375
3357
|
project
|
|
3376
3358
|
});
|
|
3377
3359
|
const setupFiles = Object.values(getSetupFiles(project.normalizedConfig.setupFiles, project.rootPath));
|
|
3360
|
+
const rstestEnvDefine = `globalThis[Symbol.for(${JSON.stringify(RSTEST_ENV_SYMBOL_KEY)})]`;
|
|
3378
3361
|
const merged = mergeEnvironmentConfig(config, {
|
|
3379
3362
|
...userRsbuildConfig,
|
|
3380
3363
|
performance: buildCache ? {
|
|
@@ -3387,8 +3370,8 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
|
|
|
3387
3370
|
},
|
|
3388
3371
|
source: {
|
|
3389
3372
|
define: {
|
|
3390
|
-
'process.env':
|
|
3391
|
-
'import.meta.env':
|
|
3373
|
+
'process.env': rstestEnvDefine,
|
|
3374
|
+
'import.meta.env': rstestEnvDefine
|
|
3392
3375
|
}
|
|
3393
3376
|
},
|
|
3394
3377
|
output: {
|
|
@@ -3824,7 +3807,7 @@ const runBrowserController = async (context, options)=>{
|
|
|
3824
3807
|
runtimeConfig: serializableConfig(getRuntimeConfigFromProject(project)),
|
|
3825
3808
|
viewport: project.normalizedConfig.browser.viewport
|
|
3826
3809
|
}));
|
|
3827
|
-
const maxTestTimeoutForRpc = Math.max(...browserProjects.map((p)=>p.normalizedConfig.testTimeout ??
|
|
3810
|
+
const maxTestTimeoutForRpc = Math.max(...browserProjects.map((p)=>p.normalizedConfig.testTimeout ?? DEFAULT_TEST_TIMEOUT));
|
|
3828
3811
|
const hostOptions = {
|
|
3829
3812
|
rootPath: normalize(context.rootPath),
|
|
3830
3813
|
projects: projectRuntimeConfigs,
|
|
@@ -3867,7 +3850,7 @@ const runBrowserController = async (context, options)=>{
|
|
|
3867
3850
|
throw String(error);
|
|
3868
3851
|
}
|
|
3869
3852
|
};
|
|
3870
|
-
runtime.dispatchHandlers.set(
|
|
3853
|
+
runtime.dispatchHandlers.set(DISPATCH_NAMESPACE_BROWSER, async (dispatchRequest)=>{
|
|
3871
3854
|
const request = validateBrowserRpcRequest(dispatchRequest.args);
|
|
3872
3855
|
return dispatchBrowserRpcRequest({
|
|
3873
3856
|
request,
|
|
@@ -4011,7 +3994,7 @@ const runBrowserController = async (context, options)=>{
|
|
|
4011
3994
|
const pushTaskId = (taskIds, taskId)=>{
|
|
4012
3995
|
if (!taskIds.includes(taskId)) taskIds.push(taskId);
|
|
4013
3996
|
};
|
|
4014
|
-
const shouldEmitUserConsoleLog = (log)=>context.normalizedConfig.onConsoleLog?.(log.content) !== false;
|
|
3997
|
+
const shouldEmitUserConsoleLog = (log)=>context.normalizedConfig.onConsoleLog?.(log.content, log.type) !== false;
|
|
4015
3998
|
const emitUserConsoleLog = async (log)=>{
|
|
4016
3999
|
if (!shouldEmitUserConsoleLog(log)) return;
|
|
4017
4000
|
await Promise.all(context.reporters.map((reporter)=>reporter.onUserConsoleLog?.(log)));
|
|
@@ -4062,7 +4045,10 @@ const runBrowserController = async (context, options)=>{
|
|
|
4062
4045
|
case 'removeSnapshotFile':
|
|
4063
4046
|
return snapshotRpcMethods.removeSnapshotFile(request.args.filepath);
|
|
4064
4047
|
default:
|
|
4065
|
-
|
|
4048
|
+
{
|
|
4049
|
+
const _exhaustive = request;
|
|
4050
|
+
return _exhaustive;
|
|
4051
|
+
}
|
|
4066
4052
|
}
|
|
4067
4053
|
};
|
|
4068
4054
|
const createDispatchRouter = (options)=>createHostDispatchRouter({
|
|
@@ -4112,7 +4098,7 @@ const runBrowserController = async (context, options)=>{
|
|
|
4112
4098
|
});
|
|
4113
4099
|
const dispatchRunnerMessage = async (run, file, sessionId, message)=>{
|
|
4114
4100
|
const response = await dispatchRouter.dispatch({
|
|
4115
|
-
requestId: nextDispatchRequestId(
|
|
4101
|
+
requestId: nextDispatchRequestId("runner"),
|
|
4116
4102
|
runToken: run.token,
|
|
4117
4103
|
namespace: "runner",
|
|
4118
4104
|
method: message.type,
|
|
@@ -4148,7 +4134,7 @@ const runBrowserController = async (context, options)=>{
|
|
|
4148
4134
|
resolveDone = resolve;
|
|
4149
4135
|
});
|
|
4150
4136
|
const projectRuntime = projectRuntimeConfigs.find((project)=>project.name === file.projectName);
|
|
4151
|
-
const perFileTimeoutMs = (projectRuntime?.runtimeConfig.testTimeout ?? maxTestTimeoutForRpc) +
|
|
4137
|
+
const perFileTimeoutMs = (projectRuntime?.runtimeConfig.testTimeout ?? maxTestTimeoutForRpc) + PER_FILE_TIMEOUT_BUFFER_MS;
|
|
4152
4138
|
let timeoutId;
|
|
4153
4139
|
try {
|
|
4154
4140
|
page = await browserContext.newPage();
|
|
@@ -4471,7 +4457,7 @@ const runBrowserController = async (context, options)=>{
|
|
|
4471
4457
|
};
|
|
4472
4458
|
const getHeadedPerFileTimeoutMs = (file)=>{
|
|
4473
4459
|
const projectRuntime = projectRuntimeConfigs.find((project)=>project.name === file.projectName);
|
|
4474
|
-
return (projectRuntime?.runtimeConfig.testTimeout ?? maxTestTimeoutForRpc) +
|
|
4460
|
+
return (projectRuntime?.runtimeConfig.testTimeout ?? maxTestTimeoutForRpc) + PER_FILE_TIMEOUT_BUFFER_MS;
|
|
4475
4461
|
};
|
|
4476
4462
|
let containerContext;
|
|
4477
4463
|
let containerPage;
|
|
@@ -4779,7 +4765,7 @@ const listBrowserTests = async (context, options)=>{
|
|
|
4779
4765
|
runtimeConfig: serializableConfig(getRuntimeConfigFromProject(project)),
|
|
4780
4766
|
viewport: project.normalizedConfig.browser.viewport
|
|
4781
4767
|
}));
|
|
4782
|
-
const maxTestTimeoutForRpc = Math.max(...browserProjects.map((p)=>p.normalizedConfig.testTimeout ??
|
|
4768
|
+
const maxTestTimeoutForRpc = Math.max(...browserProjects.map((p)=>p.normalizedConfig.testTimeout ?? DEFAULT_TEST_TIMEOUT));
|
|
4783
4769
|
const hostOptions = {
|
|
4784
4770
|
rootPath: normalize(context.rootPath),
|
|
4785
4771
|
projects: projectRuntimeConfigs,
|
|
@@ -4885,43 +4871,10 @@ const listBrowserTests = async (context, options)=>{
|
|
|
4885
4871
|
close: cleanup
|
|
4886
4872
|
};
|
|
4887
4873
|
};
|
|
4888
|
-
const SUPPORTED_PROVIDERS = [
|
|
4889
|
-
'playwright'
|
|
4890
|
-
];
|
|
4891
|
-
const isPlainObject = (value)=>'[object Object]' === Object.prototype.toString.call(value);
|
|
4892
|
-
const validateViewport = (viewport)=>{
|
|
4893
|
-
if (null == viewport) return;
|
|
4894
|
-
if ('string' == typeof viewport) {
|
|
4895
|
-
const presetId = viewport.trim();
|
|
4896
|
-
if (!presetId) throw new Error('browser.viewport must be a non-empty preset id.');
|
|
4897
|
-
if (!resolveBrowserViewportPreset(presetId)) throw new Error(`browser.viewport must be a valid preset id. Received: ${viewport}`);
|
|
4898
|
-
return;
|
|
4899
|
-
}
|
|
4900
|
-
if (isPlainObject(viewport)) {
|
|
4901
|
-
const width = viewport.width;
|
|
4902
|
-
const height = viewport.height;
|
|
4903
|
-
if (!Number.isFinite(width) || width <= 0) throw new Error('browser.viewport.width must be a positive number.');
|
|
4904
|
-
if (!Number.isFinite(height) || height <= 0) throw new Error('browser.viewport.height must be a positive number.');
|
|
4905
|
-
return;
|
|
4906
|
-
}
|
|
4907
|
-
throw new Error('browser.viewport must be either a preset id or { width, height }.');
|
|
4908
|
-
};
|
|
4909
|
-
const validateBrowserConfig = (context)=>{
|
|
4910
|
-
for (const project of context.projects){
|
|
4911
|
-
const { browser, output } = project.normalizedConfig;
|
|
4912
|
-
if (browser.enabled) {
|
|
4913
|
-
if (!browser.provider) throw new Error('browser.provider is required when browser.enabled is true.');
|
|
4914
|
-
if (!SUPPORTED_PROVIDERS.includes(browser.provider)) throw new Error(`browser.provider must be one of: ${SUPPORTED_PROVIDERS.join(', ')}.`);
|
|
4915
|
-
validateViewport(browser.viewport);
|
|
4916
|
-
if (!isPlainObject(browser.providerOptions)) throw new Error('browser.providerOptions must be a plain object.');
|
|
4917
|
-
if (output?.bundleDependencies === false) throw new Error('output.bundleDependencies false is not supported in browser mode.');
|
|
4918
|
-
}
|
|
4919
|
-
}
|
|
4920
|
-
};
|
|
4921
4874
|
async function runBrowserTests(context, options) {
|
|
4922
4875
|
return runBrowserController(context, options);
|
|
4923
4876
|
}
|
|
4924
|
-
async function src_listBrowserTests(context) {
|
|
4925
|
-
return listBrowserTests(context);
|
|
4877
|
+
async function src_listBrowserTests(context, options) {
|
|
4878
|
+
return listBrowserTests(context, options);
|
|
4926
4879
|
}
|
|
4927
|
-
export {
|
|
4880
|
+
export { runBrowserTests, src_listBrowserTests as listBrowserTests, validateBrowserConfig };
|
package/dist/protocol.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { RuntimeConfig, TestFileResult, TestInfo, TestResult } from '@rstest/core/browser-runtime';
|
|
1
|
+
import type { BrowserViewport } from '@rstest/core/internal/browser';
|
|
2
|
+
import type { RuntimeConfig, TestFileResult, TestInfo, TestResult } from '@rstest/core/internal/browser-runtime';
|
|
3
3
|
import type { SnapshotUpdateState } from '@vitest/snapshot';
|
|
4
|
-
export type { BrowserLocatorIR, BrowserRpcRequest, SnapshotRpcRequest, } from './rpcProtocol.js';
|
|
4
|
+
export type { BrowserLocatorIR, BrowserRpcRequest, SnapshotRpcCall, SnapshotRpcMethod, SnapshotRpcMethodArgs, SnapshotRpcRequest, } from './rpcProtocol.js';
|
|
5
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__";
|
|
@@ -13,10 +13,7 @@ export declare const DISPATCH_NAMESPACE_BROWSER = "browser";
|
|
|
13
13
|
export declare const DISPATCH_NAMESPACE_SNAPSHOT = "snapshot";
|
|
14
14
|
export declare const DISPATCH_METHOD_RPC = "rpc";
|
|
15
15
|
export type SerializedRuntimeConfig = RuntimeConfig;
|
|
16
|
-
export type BrowserViewport
|
|
17
|
-
width: number;
|
|
18
|
-
height: number;
|
|
19
|
-
} | DevicePreset;
|
|
16
|
+
export type { BrowserViewport };
|
|
20
17
|
export type BrowserProjectRuntime = {
|
|
21
18
|
name: string;
|
|
22
19
|
environmentName: string;
|
|
@@ -38,6 +35,24 @@ export type TestFileInfo = {
|
|
|
38
35
|
* - 'collect': Only collect test metadata without running
|
|
39
36
|
*/
|
|
40
37
|
export type BrowserExecutionMode = 'run' | 'collect';
|
|
38
|
+
/**
|
|
39
|
+
* Wire shape of a `log` client message payload. The host receives this and maps
|
|
40
|
+
* it onto core's {@link UserConsoleLog} (notably `level` → `name`); that mapper
|
|
41
|
+
* (`hostController.ts` `handleLog`) annotates its result as `UserConsoleLog`, so
|
|
42
|
+
* the map→core direction is compiler-checked. Owning the wire shape here as one
|
|
43
|
+
* named type keeps the host's input type from drifting away from the producer.
|
|
44
|
+
*/
|
|
45
|
+
export type BrowserLogPayload = {
|
|
46
|
+
level: 'log' | 'warn' | 'error' | 'info' | 'debug';
|
|
47
|
+
content: string;
|
|
48
|
+
taskId?: string;
|
|
49
|
+
taskName?: string;
|
|
50
|
+
taskParentNames?: string[];
|
|
51
|
+
taskType?: 'file' | 'suite' | 'case';
|
|
52
|
+
testPath: string;
|
|
53
|
+
type: 'stdout' | 'stderr';
|
|
54
|
+
trace?: string;
|
|
55
|
+
};
|
|
41
56
|
export type BrowserHostConfig = {
|
|
42
57
|
rootPath: string;
|
|
43
58
|
projects: BrowserProjectRuntime[];
|
|
@@ -88,17 +103,7 @@ export type BrowserClientMessage = {
|
|
|
88
103
|
payload: TestFileResult;
|
|
89
104
|
} | {
|
|
90
105
|
type: 'log';
|
|
91
|
-
payload:
|
|
92
|
-
level: 'log' | 'warn' | 'error' | 'info' | 'debug';
|
|
93
|
-
content: string;
|
|
94
|
-
taskId?: string;
|
|
95
|
-
taskName?: string;
|
|
96
|
-
taskParentNames?: string[];
|
|
97
|
-
taskType?: 'file' | 'suite' | 'case';
|
|
98
|
-
testPath: string;
|
|
99
|
-
type: 'stdout' | 'stderr';
|
|
100
|
-
trace?: string;
|
|
101
|
-
};
|
|
106
|
+
payload: BrowserLogPayload;
|
|
102
107
|
} | {
|
|
103
108
|
type: 'fatal';
|
|
104
109
|
payload: {
|
|
@@ -120,6 +125,28 @@ export type BrowserClientMessage = {
|
|
|
120
125
|
type: typeof DISPATCH_RPC_REQUEST_TYPE;
|
|
121
126
|
payload: BrowserDispatchRequest;
|
|
122
127
|
};
|
|
128
|
+
/**
|
|
129
|
+
* Lifecycle methods the runner emits via `dispatchRunnerLifecycle()` as
|
|
130
|
+
* dispatch-rpc-requests on the `runner` namespace (as opposed to the
|
|
131
|
+
* {@link BrowserClientMessage} types it `send()`s). The runner client imports
|
|
132
|
+
* this instead of redeclaring the list, so the emit site cannot drift from the
|
|
133
|
+
* host router.
|
|
134
|
+
*/
|
|
135
|
+
export type RunnerLifecycleMethod = 'file-ready' | 'suite-start' | 'suite-result' | 'case-start';
|
|
136
|
+
/**
|
|
137
|
+
* {@link BrowserClientMessage} types that are forwarded to the `runner`
|
|
138
|
+
* namespace (by message `type`) rather than handled at the transport layer.
|
|
139
|
+
* `Extract` keeps this a checked subset of the message union — renaming a
|
|
140
|
+
* message type drops it here, surfacing as a missing handler downstream.
|
|
141
|
+
*/
|
|
142
|
+
type RunnerMessageMethod = Extract<BrowserClientMessage['type'], 'file-start' | 'case-result' | 'file-complete' | 'log' | 'fatal'>;
|
|
143
|
+
/**
|
|
144
|
+
* Single source of truth for every method handled by the `runner` dispatch
|
|
145
|
+
* namespace. The host handler table is keyed by this union (a missing key is a
|
|
146
|
+
* compile error), so adding a runner method here forces a matching handler and
|
|
147
|
+
* cannot silently no-op at runtime.
|
|
148
|
+
*/
|
|
149
|
+
export type RunnerDispatchMethod = RunnerLifecycleMethod | RunnerMessageMethod;
|
|
123
150
|
/**
|
|
124
151
|
* Transport-agnostic envelope used by host routing.
|
|
125
152
|
* `namespace + method + args + target` describes an operation independent of
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BrowserProvider } from '@rstest/core/internal/browser';
|
|
1
2
|
import type { BrowserRpcRequest } from '../rpcProtocol.js';
|
|
2
3
|
/**
|
|
3
4
|
* Browser provider contract hub.
|
|
@@ -12,8 +13,14 @@ import type { BrowserRpcRequest } from '../rpcProtocol.js';
|
|
|
12
13
|
* - do not reference optional peer provider types from public declarations
|
|
13
14
|
* - keep provider-specific behavior and config decoding inside provider implementations
|
|
14
15
|
* - prefer direct passthrough to provider APIs over provider-specific translation
|
|
16
|
+
*
|
|
17
|
+
* The provider-name union is owned by `@rstest/core` (see `BROWSER_PROVIDERS`)
|
|
18
|
+
* because core's CLI `init` templates need it but cannot import this package
|
|
19
|
+
* (peer-dependency direction). `providerImplementations` below is keyed by the
|
|
20
|
+
* re-exported union, so a provider added in core without an implementation here
|
|
21
|
+
* is a compile error.
|
|
15
22
|
*/
|
|
16
|
-
export type BrowserProvider
|
|
23
|
+
export type { BrowserProvider };
|
|
17
24
|
/** Minimal console shape needed by host logging bridge. */
|
|
18
25
|
export type BrowserConsoleMessage = {
|
|
19
26
|
text: () => string;
|