@rstest/browser 0.8.2 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-container/container-static/css/index.5a71c757.css +1 -0
- package/dist/browser-container/container-static/js/{837.e631233e.js → 392.28f9a733.js} +14259 -9646
- package/dist/browser-container/container-static/js/392.28f9a733.js.LICENSE.txt +1 -0
- package/dist/browser-container/container-static/js/{container.93bdade7.js → index.129eaf9c.js} +854 -321
- package/dist/browser-container/container-static/js/{lib-react.48335539.js → lib-react.97ee79b0.js} +22 -22
- package/dist/browser-container/container-static/js/lib-react.97ee79b0.js.LICENSE.txt +1 -0
- package/dist/browser-container/container-static/js/scheduler.6976de44.js +411 -0
- package/dist/browser-container/{container.html → index.html} +1 -1
- package/dist/browser-container/scheduler.html +19 -0
- package/dist/configValidation.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +227 -39
- package/dist/protocol.d.ts +6 -0
- package/dist/viewportPresets.d.ts +16 -0
- package/package.json +4 -4
- package/src/configValidation.ts +66 -0
- package/src/hostController.ts +156 -46
- package/src/index.ts +8 -0
- package/src/protocol.ts +9 -0
- package/src/viewportPresets.ts +64 -0
- package/dist/browser-container/container-static/css/container.425b2695.css +0 -1
- package/dist/browser-container/container-static/js/837.e631233e.js.LICENSE.txt +0 -1
- package/dist/browser-container/container-static/js/lib-react.48335539.js.LICENSE.txt +0 -1
package/src/hostController.ts
CHANGED
|
@@ -44,6 +44,19 @@ type RsbuildDevServer = rsbuild.RsbuildDevServer;
|
|
|
44
44
|
type RsbuildInstance = rsbuild.RsbuildInstance;
|
|
45
45
|
|
|
46
46
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
47
|
+
const OPTIONS_PLACEHOLDER = '__RSTEST_OPTIONS_PLACEHOLDER__';
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Serialize JSON for inline <script> injection.
|
|
51
|
+
* Escapes '<' to prevent accidental </script> break-out.
|
|
52
|
+
* Escapes U+2028/U+2029 to keep script parsing safe.
|
|
53
|
+
*/
|
|
54
|
+
const serializeForInlineScript = (value: unknown): string => {
|
|
55
|
+
return JSON.stringify(value)
|
|
56
|
+
.replace(/</g, '\\u003c')
|
|
57
|
+
.replace(/\u2028/g, '\\u2028')
|
|
58
|
+
.replace(/\u2029/g, '\\u2029');
|
|
59
|
+
};
|
|
47
60
|
|
|
48
61
|
// ============================================================================
|
|
49
62
|
// Type Definitions
|
|
@@ -716,6 +729,26 @@ const htmlTemplate = `<!DOCTYPE html>
|
|
|
716
729
|
</html>
|
|
717
730
|
`;
|
|
718
731
|
|
|
732
|
+
const fallbackSchedulerHtmlTemplate = `<!DOCTYPE html>
|
|
733
|
+
<html lang="en">
|
|
734
|
+
<head>
|
|
735
|
+
<meta charset="UTF-8" />
|
|
736
|
+
<title>Rstest Browser Scheduler</title>
|
|
737
|
+
<script>
|
|
738
|
+
window.__RSTEST_BROWSER_OPTIONS__ = ${OPTIONS_PLACEHOLDER};
|
|
739
|
+
</script>
|
|
740
|
+
</head>
|
|
741
|
+
<body>
|
|
742
|
+
<script type="module" src="/container-static/js/scheduler.js"></script>
|
|
743
|
+
</body>
|
|
744
|
+
</html>
|
|
745
|
+
`;
|
|
746
|
+
|
|
747
|
+
// Workaround for noisy "removed ..." logs caused by VirtualModulesPlugin.
|
|
748
|
+
// Rsbuild suppresses the removed-file log if all removed paths include "virtual":
|
|
749
|
+
// https://github.com/web-infra-dev/rsbuild/blob/1258fa9dba5c321a4629b591a6dadbd2e26c6963/packages/core/src/createCompiler.ts#L73-L76
|
|
750
|
+
const VIRTUAL_MANIFEST_FILENAME = 'virtual-manifest.ts';
|
|
751
|
+
|
|
719
752
|
// ============================================================================
|
|
720
753
|
// Browser Runtime Lifecycle
|
|
721
754
|
// ============================================================================
|
|
@@ -795,22 +828,30 @@ const createBrowserRuntime = async ({
|
|
|
795
828
|
[manifestPath]: manifestSource,
|
|
796
829
|
});
|
|
797
830
|
|
|
798
|
-
const optionsPlaceholder = '__RSTEST_OPTIONS_PLACEHOLDER__';
|
|
799
831
|
const containerHtmlTemplate = containerDistPath
|
|
800
|
-
? await fs.readFile(join(containerDistPath, '
|
|
832
|
+
? await fs.readFile(join(containerDistPath, 'index.html'), 'utf-8')
|
|
833
|
+
: null;
|
|
834
|
+
const schedulerHtmlTemplate = containerDistPath
|
|
835
|
+
? await fs
|
|
836
|
+
.readFile(join(containerDistPath, 'scheduler.html'), 'utf-8')
|
|
837
|
+
.catch(() => null)
|
|
801
838
|
: null;
|
|
802
839
|
|
|
803
840
|
let injectedContainerHtml: string | null = null;
|
|
841
|
+
let injectedSchedulerHtml: string | null = null;
|
|
804
842
|
let serializedOptions = 'null';
|
|
805
843
|
|
|
806
844
|
const setContainerOptions = (options: BrowserHostConfig): void => {
|
|
807
|
-
serializedOptions =
|
|
845
|
+
serializedOptions = serializeForInlineScript(options);
|
|
808
846
|
if (containerHtmlTemplate) {
|
|
809
847
|
injectedContainerHtml = containerHtmlTemplate.replace(
|
|
810
|
-
|
|
848
|
+
OPTIONS_PLACEHOLDER,
|
|
811
849
|
serializedOptions,
|
|
812
850
|
);
|
|
813
851
|
}
|
|
852
|
+
injectedSchedulerHtml = (
|
|
853
|
+
schedulerHtmlTemplate || fallbackSchedulerHtmlTemplate
|
|
854
|
+
).replace(OPTIONS_PLACEHOLDER, serializedOptions);
|
|
814
855
|
};
|
|
815
856
|
|
|
816
857
|
// Get user Rsbuild config from the first browser project
|
|
@@ -991,7 +1032,7 @@ const createBrowserRuntime = async ({
|
|
|
991
1032
|
const serveContainer = containerDistPath
|
|
992
1033
|
? sirv(containerDistPath, {
|
|
993
1034
|
dev: false,
|
|
994
|
-
single: '
|
|
1035
|
+
single: 'index.html',
|
|
995
1036
|
})
|
|
996
1037
|
: null;
|
|
997
1038
|
|
|
@@ -1015,7 +1056,7 @@ const createBrowserRuntime = async ({
|
|
|
1015
1056
|
}
|
|
1016
1057
|
|
|
1017
1058
|
let html = await response.text();
|
|
1018
|
-
html = html.replace(
|
|
1059
|
+
html = html.replace(OPTIONS_PLACEHOLDER, serializedOptions);
|
|
1019
1060
|
|
|
1020
1061
|
res.statusCode = response.status;
|
|
1021
1062
|
response.headers.forEach((value, key) => {
|
|
@@ -1092,14 +1133,26 @@ const createBrowserRuntime = async ({
|
|
|
1092
1133
|
}
|
|
1093
1134
|
return;
|
|
1094
1135
|
}
|
|
1095
|
-
if (url.pathname === '/') {
|
|
1136
|
+
if (url.pathname === '/' || url.pathname === '/scheduler.html') {
|
|
1096
1137
|
if (await respondWithDevServerHtml(url, res)) {
|
|
1097
1138
|
return;
|
|
1098
1139
|
}
|
|
1099
1140
|
|
|
1141
|
+
if (url.pathname === '/scheduler.html') {
|
|
1142
|
+
res.setHeader('Content-Type', 'text/html');
|
|
1143
|
+
res.end(
|
|
1144
|
+
injectedSchedulerHtml ||
|
|
1145
|
+
(schedulerHtmlTemplate || fallbackSchedulerHtmlTemplate).replace(
|
|
1146
|
+
OPTIONS_PLACEHOLDER,
|
|
1147
|
+
'null',
|
|
1148
|
+
),
|
|
1149
|
+
);
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1100
1153
|
const html =
|
|
1101
1154
|
injectedContainerHtml ||
|
|
1102
|
-
containerHtmlTemplate?.replace(
|
|
1155
|
+
containerHtmlTemplate?.replace(OPTIONS_PLACEHOLDER, 'null');
|
|
1103
1156
|
|
|
1104
1157
|
if (html) {
|
|
1105
1158
|
res.setHeader('Content-Type', 'text/html');
|
|
@@ -1227,6 +1280,56 @@ export const runBrowserController = async (
|
|
|
1227
1280
|
): Promise<BrowserTestRunResult | void> => {
|
|
1228
1281
|
const { skipOnTestRunEnd = false } = options ?? {};
|
|
1229
1282
|
const buildStart = Date.now();
|
|
1283
|
+
const browserProjects = getBrowserProjects(context);
|
|
1284
|
+
const useSchedulerPage = browserProjects.every(
|
|
1285
|
+
(project) => project.normalizedConfig.browser.headless,
|
|
1286
|
+
);
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Build an error BrowserTestRunResult and call onTestRunEnd if needed.
|
|
1290
|
+
* Used for early-exit error paths to ensure errors reach the summary report.
|
|
1291
|
+
*/
|
|
1292
|
+
const buildErrorResult = async (
|
|
1293
|
+
error: Error,
|
|
1294
|
+
): Promise<BrowserTestRunResult> => {
|
|
1295
|
+
const elapsed = Math.max(0, Date.now() - buildStart);
|
|
1296
|
+
const errorResult: BrowserTestRunResult = {
|
|
1297
|
+
results: [],
|
|
1298
|
+
testResults: [],
|
|
1299
|
+
duration: { totalTime: elapsed, buildTime: elapsed, testTime: 0 },
|
|
1300
|
+
hasFailure: true,
|
|
1301
|
+
unhandledErrors: [error],
|
|
1302
|
+
};
|
|
1303
|
+
|
|
1304
|
+
if (!skipOnTestRunEnd) {
|
|
1305
|
+
for (const reporter of context.reporters) {
|
|
1306
|
+
await (reporter as Reporter).onTestRunEnd?.({
|
|
1307
|
+
results: [],
|
|
1308
|
+
testResults: [],
|
|
1309
|
+
duration: errorResult.duration,
|
|
1310
|
+
snapshotSummary: context.snapshotManager.summary,
|
|
1311
|
+
getSourcemap: async () => null,
|
|
1312
|
+
unhandledErrors: errorResult.unhandledErrors,
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
return errorResult;
|
|
1318
|
+
};
|
|
1319
|
+
|
|
1320
|
+
const toError = (error: unknown): Error => {
|
|
1321
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
1322
|
+
};
|
|
1323
|
+
|
|
1324
|
+
const failWithError = async (
|
|
1325
|
+
error: unknown,
|
|
1326
|
+
cleanup?: () => Promise<void>,
|
|
1327
|
+
): Promise<BrowserTestRunResult> => {
|
|
1328
|
+
ensureProcessExitCode(1);
|
|
1329
|
+
await cleanup?.();
|
|
1330
|
+
return buildErrorResult(toError(error));
|
|
1331
|
+
};
|
|
1332
|
+
|
|
1230
1333
|
const containerDevServerEnv = process.env.RSTEST_CONTAINER_DEV_SERVER;
|
|
1231
1334
|
let containerDevServer: string | undefined;
|
|
1232
1335
|
let containerDistPath: string | undefined;
|
|
@@ -1238,13 +1341,9 @@ export const runBrowserController = async (
|
|
|
1238
1341
|
`[Browser UI] Using dev server for container: ${containerDevServer}`,
|
|
1239
1342
|
);
|
|
1240
1343
|
} catch (error) {
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
),
|
|
1245
|
-
);
|
|
1246
|
-
ensureProcessExitCode(1);
|
|
1247
|
-
return;
|
|
1344
|
+
const originalError = toError(error);
|
|
1345
|
+
originalError.message = `Invalid RSTEST_CONTAINER_DEV_SERVER value: ${originalError.message}`;
|
|
1346
|
+
return failWithError(originalError);
|
|
1248
1347
|
}
|
|
1249
1348
|
}
|
|
1250
1349
|
|
|
@@ -1252,9 +1351,7 @@ export const runBrowserController = async (
|
|
|
1252
1351
|
try {
|
|
1253
1352
|
containerDistPath = resolveContainerDist();
|
|
1254
1353
|
} catch (error) {
|
|
1255
|
-
|
|
1256
|
-
ensureProcessExitCode(1);
|
|
1257
|
-
return;
|
|
1354
|
+
return failWithError(error);
|
|
1258
1355
|
}
|
|
1259
1356
|
}
|
|
1260
1357
|
|
|
@@ -1296,8 +1393,8 @@ export const runBrowserController = async (
|
|
|
1296
1393
|
'browser',
|
|
1297
1394
|
Date.now().toString(),
|
|
1298
1395
|
);
|
|
1299
|
-
const manifestPath = join(tempDir, 'manifest.ts');
|
|
1300
1396
|
|
|
1397
|
+
const manifestPath = join(tempDir, VIRTUAL_MANIFEST_FILENAME);
|
|
1301
1398
|
const manifestSource = generateManifestModule({
|
|
1302
1399
|
manifestPath,
|
|
1303
1400
|
entries: projectEntries,
|
|
@@ -1335,10 +1432,9 @@ export const runBrowserController = async (
|
|
|
1335
1432
|
containerDevServer,
|
|
1336
1433
|
});
|
|
1337
1434
|
} catch (error) {
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
return;
|
|
1435
|
+
return failWithError(error, async () => {
|
|
1436
|
+
await fs.rm(tempDir, { recursive: true, force: true }).catch(() => {});
|
|
1437
|
+
});
|
|
1342
1438
|
}
|
|
1343
1439
|
|
|
1344
1440
|
if (isWatchMode) {
|
|
@@ -1361,20 +1457,19 @@ export const runBrowserController = async (
|
|
|
1361
1457
|
|
|
1362
1458
|
// Only include browser mode projects in runtime configs
|
|
1363
1459
|
// Normalize projectRoot to posix format for cross-platform compatibility
|
|
1364
|
-
const
|
|
1365
|
-
|
|
1366
|
-
browserProjectsForRuntime.map((project: ProjectContext) => ({
|
|
1460
|
+
const projectRuntimeConfigs: BrowserProjectRuntime[] = browserProjects.map(
|
|
1461
|
+
(project: ProjectContext) => ({
|
|
1367
1462
|
name: project.name,
|
|
1368
1463
|
environmentName: project.environmentName,
|
|
1369
1464
|
projectRoot: normalize(project.rootPath),
|
|
1370
1465
|
runtimeConfig: serializableConfig(getRuntimeConfigFromProject(project)),
|
|
1371
|
-
|
|
1466
|
+
viewport: project.normalizedConfig.browser.viewport,
|
|
1467
|
+
}),
|
|
1468
|
+
);
|
|
1372
1469
|
|
|
1373
1470
|
// Get max testTimeout from all browser projects for RPC timeout
|
|
1374
1471
|
const maxTestTimeoutForRpc = Math.max(
|
|
1375
|
-
...
|
|
1376
|
-
(p) => p.normalizedConfig.testTimeout ?? 5000,
|
|
1377
|
-
),
|
|
1472
|
+
...browserProjects.map((p) => p.normalizedConfig.testTimeout ?? 5000),
|
|
1378
1473
|
);
|
|
1379
1474
|
|
|
1380
1475
|
const hostOptions: BrowserHostConfig = {
|
|
@@ -1438,7 +1533,11 @@ export const runBrowserController = async (
|
|
|
1438
1533
|
// Forward browser console to terminal
|
|
1439
1534
|
containerPage.on('console', (msg: ConsoleMessage) => {
|
|
1440
1535
|
const text = msg.text();
|
|
1441
|
-
if (
|
|
1536
|
+
if (
|
|
1537
|
+
text.startsWith('[Container]') ||
|
|
1538
|
+
text.startsWith('[Runner]') ||
|
|
1539
|
+
text.startsWith('[Scheduler]')
|
|
1540
|
+
) {
|
|
1442
1541
|
logger.log(color.gray(`[Browser Console] ${text}`));
|
|
1443
1542
|
}
|
|
1444
1543
|
});
|
|
@@ -1579,21 +1678,28 @@ export const runBrowserController = async (
|
|
|
1579
1678
|
|
|
1580
1679
|
// Only navigate on first creation
|
|
1581
1680
|
if (isNewPage) {
|
|
1582
|
-
|
|
1681
|
+
const pagePath = useSchedulerPage ? '/scheduler.html' : '/';
|
|
1682
|
+
if (useSchedulerPage) {
|
|
1683
|
+
const serializedOptions = serializeForInlineScript(hostOptions);
|
|
1684
|
+
await containerPage.addInitScript(
|
|
1685
|
+
`window.__RSTEST_BROWSER_OPTIONS__ = ${serializedOptions};`,
|
|
1686
|
+
);
|
|
1687
|
+
}
|
|
1688
|
+
await containerPage.goto(`http://localhost:${port}${pagePath}`, {
|
|
1583
1689
|
waitUntil: 'load',
|
|
1584
1690
|
});
|
|
1585
1691
|
|
|
1586
1692
|
logger.log(
|
|
1587
|
-
color.cyan(
|
|
1693
|
+
color.cyan(
|
|
1694
|
+
`\nBrowser mode opened at http://localhost:${port}${pagePath}\n`,
|
|
1695
|
+
),
|
|
1588
1696
|
);
|
|
1589
1697
|
}
|
|
1590
1698
|
|
|
1591
1699
|
// Wait for all tests to complete
|
|
1592
1700
|
// Calculate total timeout based on config: max testTimeout * file count + buffer
|
|
1593
1701
|
const maxTestTimeout = Math.max(
|
|
1594
|
-
...
|
|
1595
|
-
(p) => p.normalizedConfig.testTimeout ?? 5000,
|
|
1596
|
-
),
|
|
1702
|
+
...browserProjects.map((p) => p.normalizedConfig.testTimeout ?? 5000),
|
|
1597
1703
|
);
|
|
1598
1704
|
const totalTimeoutMs = maxTestTimeout * allTestFiles.length + 30_000;
|
|
1599
1705
|
|
|
@@ -1665,15 +1771,21 @@ export const runBrowserController = async (
|
|
|
1665
1771
|
}
|
|
1666
1772
|
|
|
1667
1773
|
if (!isWatchMode) {
|
|
1774
|
+
try {
|
|
1775
|
+
await containerPage.close();
|
|
1776
|
+
} catch {
|
|
1777
|
+
// ignore
|
|
1778
|
+
}
|
|
1779
|
+
try {
|
|
1780
|
+
await containerContext.close();
|
|
1781
|
+
} catch {
|
|
1782
|
+
// ignore
|
|
1783
|
+
}
|
|
1668
1784
|
await destroyBrowserRuntime(runtime);
|
|
1669
1785
|
}
|
|
1670
1786
|
|
|
1671
1787
|
if (fatalError) {
|
|
1672
|
-
|
|
1673
|
-
color.red(`Browser test run failed: ${(fatalError as Error).message}`),
|
|
1674
|
-
);
|
|
1675
|
-
ensureProcessExitCode(1);
|
|
1676
|
-
return;
|
|
1788
|
+
return failWithError(fatalError);
|
|
1677
1789
|
}
|
|
1678
1790
|
|
|
1679
1791
|
const duration = {
|
|
@@ -1769,8 +1881,8 @@ export const listBrowserTests = async (
|
|
|
1769
1881
|
'browser',
|
|
1770
1882
|
`list-${Date.now()}`,
|
|
1771
1883
|
);
|
|
1772
|
-
const manifestPath = join(tempDir, 'manifest.ts');
|
|
1773
1884
|
|
|
1885
|
+
const manifestPath = join(tempDir, VIRTUAL_MANIFEST_FILENAME);
|
|
1774
1886
|
const manifestSource = generateManifestModule({
|
|
1775
1887
|
manifestPath,
|
|
1776
1888
|
entries: projectEntries,
|
|
@@ -1810,6 +1922,7 @@ export const listBrowserTests = async (
|
|
|
1810
1922
|
environmentName: project.environmentName,
|
|
1811
1923
|
projectRoot: normalize(project.rootPath),
|
|
1812
1924
|
runtimeConfig: serializableConfig(getRuntimeConfigFromProject(project)),
|
|
1925
|
+
viewport: project.normalizedConfig.browser.viewport,
|
|
1813
1926
|
}),
|
|
1814
1927
|
);
|
|
1815
1928
|
|
|
@@ -1890,10 +2003,7 @@ export const listBrowserTests = async (
|
|
|
1890
2003
|
);
|
|
1891
2004
|
|
|
1892
2005
|
// Inject host options before navigation so the runner can access them
|
|
1893
|
-
const serializedOptions =
|
|
1894
|
-
/</g,
|
|
1895
|
-
'\\u003c',
|
|
1896
|
-
);
|
|
2006
|
+
const serializedOptions = serializeForInlineScript(hostOptions);
|
|
1897
2007
|
await page.addInitScript(
|
|
1898
2008
|
`window.__RSTEST_BROWSER_OPTIONS__ = ${serializedOptions};`,
|
|
1899
2009
|
);
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,14 @@ import {
|
|
|
9
9
|
runBrowserController,
|
|
10
10
|
} from './hostController';
|
|
11
11
|
|
|
12
|
+
export { validateBrowserConfig } from './configValidation';
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
BROWSER_VIEWPORT_PRESET_DIMENSIONS,
|
|
16
|
+
BROWSER_VIEWPORT_PRESET_IDS,
|
|
17
|
+
resolveBrowserViewportPreset,
|
|
18
|
+
} from './viewportPresets';
|
|
19
|
+
|
|
12
20
|
export async function runBrowserTests(
|
|
13
21
|
context: Rstest,
|
|
14
22
|
options?: BrowserTestRunOptions,
|
package/src/protocol.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DevicePreset } from '@rstest/core/browser';
|
|
1
2
|
import type {
|
|
2
3
|
RuntimeConfig,
|
|
3
4
|
Test,
|
|
@@ -8,11 +9,19 @@ import type { SnapshotUpdateState } from '@vitest/snapshot';
|
|
|
8
9
|
|
|
9
10
|
export type SerializedRuntimeConfig = RuntimeConfig;
|
|
10
11
|
|
|
12
|
+
export type BrowserViewport =
|
|
13
|
+
| {
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
}
|
|
17
|
+
| DevicePreset;
|
|
18
|
+
|
|
11
19
|
export type BrowserProjectRuntime = {
|
|
12
20
|
name: string;
|
|
13
21
|
environmentName: string;
|
|
14
22
|
projectRoot: string;
|
|
15
23
|
runtimeConfig: SerializedRuntimeConfig;
|
|
24
|
+
viewport?: BrowserViewport;
|
|
16
25
|
};
|
|
17
26
|
|
|
18
27
|
/**
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime source of truth for browser viewport presets.
|
|
3
|
+
*
|
|
4
|
+
* IMPORTANT: Keep this list/map in sync with `DevicePreset` typing in
|
|
5
|
+
* `@rstest/core` (`packages/core/src/types/config.ts`) so `defineConfig`
|
|
6
|
+
* autocomplete and runtime validation stay consistent.
|
|
7
|
+
*/
|
|
8
|
+
export const BROWSER_VIEWPORT_PRESET_IDS = [
|
|
9
|
+
'iPhoneSE',
|
|
10
|
+
'iPhoneXR',
|
|
11
|
+
'iPhone12Pro',
|
|
12
|
+
'iPhone14ProMax',
|
|
13
|
+
'Pixel7',
|
|
14
|
+
'SamsungGalaxyS8Plus',
|
|
15
|
+
'SamsungGalaxyS20Ultra',
|
|
16
|
+
'iPadMini',
|
|
17
|
+
'iPadAir',
|
|
18
|
+
'iPadPro',
|
|
19
|
+
'SurfacePro7',
|
|
20
|
+
'SurfaceDuo',
|
|
21
|
+
'GalaxyZFold5',
|
|
22
|
+
'AsusZenbookFold',
|
|
23
|
+
'SamsungGalaxyA51A71',
|
|
24
|
+
'NestHub',
|
|
25
|
+
'NestHubMax',
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
type BrowserViewportPresetId = (typeof BROWSER_VIEWPORT_PRESET_IDS)[number];
|
|
29
|
+
|
|
30
|
+
type BrowserViewportSize = {
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const BROWSER_VIEWPORT_PRESET_DIMENSIONS: Record<
|
|
36
|
+
BrowserViewportPresetId,
|
|
37
|
+
BrowserViewportSize
|
|
38
|
+
> = {
|
|
39
|
+
iPhoneSE: { width: 375, height: 667 },
|
|
40
|
+
iPhoneXR: { width: 414, height: 896 },
|
|
41
|
+
iPhone12Pro: { width: 390, height: 844 },
|
|
42
|
+
iPhone14ProMax: { width: 430, height: 932 },
|
|
43
|
+
Pixel7: { width: 412, height: 915 },
|
|
44
|
+
SamsungGalaxyS8Plus: { width: 360, height: 740 },
|
|
45
|
+
SamsungGalaxyS20Ultra: { width: 412, height: 915 },
|
|
46
|
+
iPadMini: { width: 768, height: 1024 },
|
|
47
|
+
iPadAir: { width: 820, height: 1180 },
|
|
48
|
+
iPadPro: { width: 1024, height: 1366 },
|
|
49
|
+
SurfacePro7: { width: 912, height: 1368 },
|
|
50
|
+
SurfaceDuo: { width: 540, height: 720 },
|
|
51
|
+
GalaxyZFold5: { width: 344, height: 882 },
|
|
52
|
+
AsusZenbookFold: { width: 853, height: 1280 },
|
|
53
|
+
SamsungGalaxyA51A71: { width: 412, height: 914 },
|
|
54
|
+
NestHub: { width: 1024, height: 600 },
|
|
55
|
+
NestHubMax: { width: 1280, height: 800 },
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const resolveBrowserViewportPreset = (
|
|
59
|
+
presetId: string,
|
|
60
|
+
): BrowserViewportSize | null => {
|
|
61
|
+
const size =
|
|
62
|
+
BROWSER_VIEWPORT_PRESET_DIMENSIONS[presetId as BrowserViewportPresetId];
|
|
63
|
+
return size ?? null;
|
|
64
|
+
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@import "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap";@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-duration:initial;--tw-ease:initial}::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-zinc-950:#09090b;--color-black:#000;--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--font-weight-light:300;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wider:.05em;--tracking-widest:.1em;--radius-md:.375rem;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1)}@supports (color:color(display-p3 0 0 0)){:root,:host{--color-zinc-950:color(display-p3 .0353716 .0353595 .0435539)}}@supports (color:lab(0% 0 0)){:root,:host{--color-zinc-950:lab(2.51107% .242703 -.886115)}}}@layer base,components;@layer utilities{.absolute{position:absolute}.relative{position:relative}.inset-0{inset:calc(var(--spacing)*0)}.inset-x-0{inset-inline:calc(var(--spacing)*0)}.inset-y-0{inset-block:calc(var(--spacing)*0)}.bottom-0{bottom:calc(var(--spacing)*0)}.left-0{left:calc(var(--spacing)*0)}.z-10{z-index:10}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.m-0{margin:calc(var(--spacing)*0)}.ml-1{margin-left:calc(var(--spacing)*1)}.block{display:block}.flex{display:flex}.grid{display:grid}.inline{display:inline}.inline-flex{display:inline-flex}.h-2{height:calc(var(--spacing)*2)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-\[1px\]{height:1px}.h-\[48px\]{height:48px}.h-full{height:100%}.h-screen{height:100vh}.min-h-0{min-height:calc(var(--spacing)*0)}.w-2{width:calc(var(--spacing)*2)}.w-5{width:calc(var(--spacing)*5)}.w-8{width:calc(var(--spacing)*8)}.w-\[16px\]{width:16px}.w-full{width:100%}.max-w-\[400px\]{max-width:400px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.grid-cols-\[auto_minmax\(0\,1fr\)_auto\]{grid-template-columns:auto minmax(0,1fr) auto}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.bg-black\/\[0\.02\]{background-color:#00000005}@supports (color:color-mix(in lab, red, red)){.bg-black\/\[0\.02\]{background-color:color-mix(in oklab,var(--color-black)2%,transparent)}}.bg-transparent{background-color:#0000}.bg-zinc-950{background-color:var(--color-zinc-950)}.p-0{padding:calc(var(--spacing)*0)}.p-3{padding:calc(var(--spacing)*3)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-4{padding-inline:calc(var(--spacing)*4)}.py-0{padding-block:calc(var(--spacing)*0)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-3{padding-block:calc(var(--spacing)*3)}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-\(--accents-3\){color:var(--accents-3)}.text-\(--accents-4\){color:var(--accents-4)}.text-\(--accents-5\){color:var(--accents-5)}.text-\(--accents-7\){color:var(--accents-7)}.text-\(--muted-foreground\){color:var(--muted-foreground)}.text-\(--warning\){color:var(--warning)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal, )var(--tw-slashed-zero, )var(--tw-numeric-figure, )var(--tw-numeric-spacing, )var(--tw-numeric-fraction, )}.opacity-0{opacity:0}.opacity-40{opacity:.4}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.ease-\[cubic-bezier\(0\.4\,0\,0\.2\,1\)\]{--tw-ease:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1)}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}.hover\:bg-\(--accents-1\):hover{background-color:var(--accents-1)}.hover\:text-\(--accents-6\):hover{color:var(--accents-6)}}}.ant-typography.font-mono{font-family:var(--font-mono)}:root{--font-mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--background:#fff;--foreground:#000;--ds-gray-100:#fafafa;--ds-gray-200:#eaeaea;--ds-gray-300:#999;--ds-gray-400:#888;--ds-gray-500:#666;--ds-gray-600:#444;--ds-gray-700:#333;--ds-gray-800:#111;--ds-gray-900:#000;--ds-gray-1000:#000;--ds-red-100:#fff0f0;--ds-red-200:#ffebeb;--ds-red-300:#ffe6e6;--ds-red-700:#e5484d;--ds-red-800:#da2f35;--ds-red-900:#cb2a2f;--ds-green-100:#effbef;--ds-green-200:#ebfaeb;--ds-green-300:#daf6da;--ds-green-700:#45a557;--ds-green-800:#398e4a;--ds-green-900:#297a3a;--ds-amber-100:#fff6e6;--ds-amber-200:#fff4d6;--ds-amber-300:#fef0cd;--ds-amber-700:#ffb224;--ds-amber-800:#ff990a;--ds-amber-900:#a35200;--ds-blue-700:#0070f3;--accents-1:var(--ds-gray-100);--accents-2:var(--ds-gray-200);--accents-3:var(--ds-gray-300);--accents-4:var(--ds-gray-400);--accents-5:var(--ds-gray-500);--accents-6:var(--ds-gray-600);--accents-7:var(--ds-gray-700);--accents-8:var(--ds-gray-800);--border:var(--accents-2);--muted:var(--accents-1);--muted-foreground:var(--accents-5);--primary:var(--foreground);--success:var(--ds-green-700);--error:var(--ds-red-800);--warning:var(--ds-amber-700);--lightningcss-light:initial;--lightningcss-dark: ;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}[data-theme=dark]{--background:#000;--foreground:#fff;--ds-gray-100:#111;--ds-gray-200:#333;--ds-gray-300:#444;--ds-gray-400:#666;--ds-gray-500:#888;--ds-gray-600:#999;--ds-gray-700:#eaeaea;--ds-gray-800:#fafafa;--ds-gray-900:#fff;--ds-gray-1000:#fff;--ds-red-100:#2a1314;--ds-red-200:#3c1618;--ds-red-300:#561a1e;--ds-red-700:#e5484d;--ds-red-800:#d93036;--ds-red-900:#ff6166;--ds-green-100:#0b2212;--ds-green-200:#0f2e18;--ds-green-300:#12361b;--ds-green-700:#45a557;--ds-green-800:#398e4a;--ds-green-900:#62c073;--ds-amber-100:#291800;--ds-amber-200:#331b00;--ds-amber-300:#4d2a00;--ds-amber-700:#ffb224;--ds-amber-800:#ff990a;--ds-amber-900:#f2a20d;--ds-blue-700:#0070f3;--accents-1:var(--ds-gray-100);--accents-2:var(--ds-gray-200);--accents-3:var(--ds-gray-300);--accents-4:var(--ds-gray-400);--accents-5:var(--ds-gray-500);--accents-6:var(--ds-gray-600);--accents-7:var(--ds-gray-700);--accents-8:var(--ds-gray-800);--border:var(--accents-2);--muted:var(--accents-1);--muted-foreground:var(--accents-5);--primary:var(--foreground);--success:var(--ds-green-700);--error:var(--ds-red-800);--warning:var(--ds-amber-700);--lightningcss-light: ;--lightningcss-dark:initial;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}*{box-sizing:border-box}body{background:var(--background);min-height:100vh;color:var(--foreground);margin:0;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;overflow:hidden}.ant-input-affix-wrapper:focus,.ant-input-affix-wrapper-focused{border-color:var(--foreground);box-shadow:0 0 0 1px var(--foreground)}.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected{transition:none}@keyframes status-flash{0%{filter:brightness()}5%{filter:brightness(2.5)}15%{filter:brightness(1.8)}40%{filter:brightness(1.3)}to{filter:brightness()}}.status-icon-flash{animation:1.5s ease-out status-flash}@keyframes progress-segment-flash{0%{filter:brightness();box-shadow:none}10%{filter:brightness(2.5);box-shadow:0 0 8px 1px}to{filter:brightness();box-shadow:none}}.progress-flash-active{animation:1s cubic-bezier(.4,0,.2,1) progress-segment-flash}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/*! For license information please see 837.e631233e.js.LICENSE.txt */
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/*! For license information please see lib-react.48335539.js.LICENSE.txt */
|