@vitest/browser 2.0.0-beta.11 → 2.0.0-beta.12
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/context.d.ts +5 -0
- package/dist/client/.vite/manifest.json +7 -7
- package/dist/client/__vitest__/assets/index-BcWipdNi.js +52 -0
- package/dist/client/__vitest__/assets/index-goqgbqVs.css +1 -0
- package/dist/client/__vitest__/index.html +2 -2
- package/dist/client/__vitest_browser__/{rpc-D6HtJ5Rb.js → client-Dz5Ebwug.js} +28 -65
- package/dist/client/__vitest_browser__/{orchestrator-DQ4hbmZ_.js → orchestrator-DJ6H4qlM.js} +192 -159
- package/dist/client/__vitest_browser__/tester-DHXll_4H.js +12164 -0
- package/dist/client/orchestrator.html +2 -2
- package/dist/client/tester/tester.html +2 -2
- package/dist/context.js +4 -1
- package/dist/index.d.ts +22 -3
- package/dist/index.js +210 -45
- package/dist/providers.js +1 -1
- package/dist/state.js +1 -1
- package/dist/{webdriver-BRud6NtS.js → webdriver-CJA71Bgl.js} +49 -2
- package/jest-dom.d.ts +816 -0
- package/matchers.d.ts +22 -0
- package/package.json +11 -7
- package/providers/playwright.d.ts +25 -1
- package/providers/webdriverio.d.ts +1 -0
- package/dist/client/__vitest__/assets/index-BfnqOMHY.js +0 -51
- package/dist/client/__vitest__/assets/index-qZYZB8Y3.css +0 -1
- package/dist/client/__vitest_browser__/tester-IF8AbWCS.js +0 -837
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
</style>
|
|
26
26
|
<script>{__VITEST_INJECTOR__}</script>
|
|
27
27
|
{__VITEST_SCRIPTS__}
|
|
28
|
-
<script type="module" crossorigin src="/__vitest_browser__/orchestrator-
|
|
29
|
-
<link rel="modulepreload" crossorigin href="/__vitest_browser__/
|
|
28
|
+
<script type="module" crossorigin src="/__vitest_browser__/orchestrator-DJ6H4qlM.js"></script>
|
|
29
|
+
<link rel="modulepreload" crossorigin href="/__vitest_browser__/client-Dz5Ebwug.js">
|
|
30
30
|
</head>
|
|
31
31
|
<body>
|
|
32
32
|
<div id="vitest-tester"></div>
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
<script>{__VITEST_INJECTOR__}</script>
|
|
20
20
|
<script>{__VITEST_STATE__}</script>
|
|
21
21
|
{__VITEST_SCRIPTS__}
|
|
22
|
-
<script type="module" crossorigin src="/__vitest_browser__/tester-
|
|
23
|
-
<link rel="modulepreload" crossorigin href="/__vitest_browser__/
|
|
22
|
+
<script type="module" crossorigin src="/__vitest_browser__/tester-DHXll_4H.js"></script>
|
|
23
|
+
<link rel="modulepreload" crossorigin href="/__vitest_browser__/client-Dz5Ebwug.js">
|
|
24
24
|
</head>
|
|
25
25
|
<body
|
|
26
26
|
data-vitest-body
|
package/dist/context.js
CHANGED
|
@@ -125,6 +125,9 @@ function getSimpleSelectOptions(element, value) {
|
|
|
125
125
|
return v;
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
|
+
function cdp() {
|
|
129
|
+
return runner().cdp;
|
|
130
|
+
}
|
|
128
131
|
const screenshotIds = {};
|
|
129
132
|
const page = {
|
|
130
133
|
get config() {
|
|
@@ -172,4 +175,4 @@ function getTaskFullName(task) {
|
|
|
172
175
|
return task.suite ? `${getTaskFullName(task.suite)} ${task.name}` : task.name;
|
|
173
176
|
}
|
|
174
177
|
|
|
175
|
-
export { page, userEvent };
|
|
178
|
+
export { cdp, page, userEvent };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BrowserServerState as BrowserServerState$1, BrowserServerStateContext, BrowserServer as BrowserServer$1, WorkspaceProject, Vite, BrowserProvider, BrowserScript, Vitest, ProcessPool } from 'vitest/node';
|
|
1
|
+
import { CDPSession, BrowserServerState as BrowserServerState$1, BrowserServerStateContext, BrowserServer as BrowserServer$1, WorkspaceProject, Vite, BrowserProvider, BrowserScript, Vitest, ProcessPool } from 'vitest/node';
|
|
2
2
|
import { Plugin } from 'vitest/config';
|
|
3
3
|
import { File, TaskResultPack, AfterSuiteRunMeta, CancelReason, UserConsoleLog, SnapshotResult, ResolvedConfig } from 'vitest';
|
|
4
4
|
|
|
@@ -46,10 +46,13 @@ interface WebSocketBrowserHandlers {
|
|
|
46
46
|
getBrowserFileSourceMap: (id: string) => SourceMap | null | {
|
|
47
47
|
mappings: '';
|
|
48
48
|
} | undefined;
|
|
49
|
+
sendCdpEvent: (contextId: string, event: string, payload?: Record<string, unknown>) => unknown;
|
|
50
|
+
trackCdpEvent: (contextId: string, type: 'on' | 'once' | 'off', event: string, listenerId: string) => void;
|
|
49
51
|
}
|
|
50
52
|
interface WebSocketBrowserEvents {
|
|
51
53
|
onCancel: (reason: CancelReason) => void;
|
|
52
54
|
createTesters: (files: string[]) => Promise<void>;
|
|
55
|
+
cdpEvent: (event: string, payload: unknown) => void;
|
|
53
56
|
}
|
|
54
57
|
type WebSocketBrowserRPC = BirpcReturn<WebSocketBrowserEvents, WebSocketBrowserHandlers>;
|
|
55
58
|
interface SourceMap {
|
|
@@ -63,12 +66,26 @@ interface SourceMap {
|
|
|
63
66
|
toUrl: () => string;
|
|
64
67
|
}
|
|
65
68
|
|
|
69
|
+
declare class BrowserServerCDPHandler {
|
|
70
|
+
private session;
|
|
71
|
+
private tester;
|
|
72
|
+
private listenerIds;
|
|
73
|
+
private listeners;
|
|
74
|
+
constructor(session: CDPSession, tester: WebSocketBrowserRPC);
|
|
75
|
+
send(method: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
76
|
+
on(event: string, id: string, once?: boolean): void;
|
|
77
|
+
off(event: string, id: string): void;
|
|
78
|
+
once(event: string, listener: string): void;
|
|
79
|
+
}
|
|
80
|
+
|
|
66
81
|
declare class BrowserServerState implements BrowserServerState$1 {
|
|
67
|
-
orchestrators: Map<string, WebSocketBrowserRPC>;
|
|
68
|
-
testers: Map<string, WebSocketBrowserRPC>;
|
|
82
|
+
readonly orchestrators: Map<string, WebSocketBrowserRPC>;
|
|
83
|
+
readonly testers: Map<string, WebSocketBrowserRPC>;
|
|
84
|
+
readonly cdps: Map<string, BrowserServerCDPHandler>;
|
|
69
85
|
private contexts;
|
|
70
86
|
getContext(contextId: string): BrowserServerStateContext | undefined;
|
|
71
87
|
createAsyncContext(contextId: string, files: string[]): Promise<void>;
|
|
88
|
+
removeCDPHandler(sessionId: string): Promise<void>;
|
|
72
89
|
}
|
|
73
90
|
|
|
74
91
|
declare class BrowserServer implements BrowserServer$1 {
|
|
@@ -95,6 +112,8 @@ declare class BrowserServer implements BrowserServer$1 {
|
|
|
95
112
|
};
|
|
96
113
|
formatScripts(scripts: BrowserScript[] | undefined): Promise<string>;
|
|
97
114
|
initBrowserProvider(): Promise<void>;
|
|
115
|
+
private cdpSessions;
|
|
116
|
+
ensureCDPHandler(contextId: string, sessionId: string): Promise<BrowserServerCDPHandler>;
|
|
98
117
|
close(): Promise<void>;
|
|
99
118
|
}
|
|
100
119
|
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
8
8
|
import { createDefer, slash, toArray } from '@vitest/utils';
|
|
9
9
|
import sirv from 'sirv';
|
|
10
10
|
import { defaultBrowserPort, coverageConfigDefaults } from 'vitest/config';
|
|
11
|
-
import { P as PlaywrightBrowserProvider, W as WebdriverBrowserProvider } from './webdriver-
|
|
11
|
+
import { P as PlaywrightBrowserProvider, W as WebdriverBrowserProvider } from './webdriver-CJA71Bgl.js';
|
|
12
12
|
import { resolve as resolve$1, dirname as dirname$1, normalize as normalize$1 } from 'node:path';
|
|
13
13
|
import MagicString from 'magic-string';
|
|
14
14
|
import { esmWalker } from '@vitest/utils/ast';
|
|
@@ -517,7 +517,7 @@ function setupBrowserRpc(server) {
|
|
|
517
517
|
const sessionId = searchParams.get("sessionId") ?? "0";
|
|
518
518
|
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
519
519
|
wss.emit("connection", ws, request);
|
|
520
|
-
const rpc = setupClient(ws);
|
|
520
|
+
const rpc = setupClient(sessionId, ws);
|
|
521
521
|
const state = server.state;
|
|
522
522
|
const clients = type === "tester" ? state.testers : state.orchestrators;
|
|
523
523
|
clients.set(sessionId, rpc);
|
|
@@ -525,6 +525,7 @@ function setupBrowserRpc(server) {
|
|
|
525
525
|
ws.on("close", () => {
|
|
526
526
|
debug$1?.("[%s] Browser API disconnected from %s", sessionId, type);
|
|
527
527
|
clients.delete(sessionId);
|
|
528
|
+
server.state.removeCDPHandler(sessionId);
|
|
528
529
|
});
|
|
529
530
|
});
|
|
530
531
|
});
|
|
@@ -535,7 +536,7 @@ function setupBrowserRpc(server) {
|
|
|
535
536
|
);
|
|
536
537
|
}
|
|
537
538
|
}
|
|
538
|
-
function setupClient(ws) {
|
|
539
|
+
function setupClient(sessionId, ws) {
|
|
539
540
|
const rpc = createBirpc(
|
|
540
541
|
{
|
|
541
542
|
async onUnhandledError(error, type) {
|
|
@@ -653,12 +654,21 @@ function setupBrowserRpc(server) {
|
|
|
653
654
|
moduleGraph.invalidateModule(module, /* @__PURE__ */ new Set(), Date.now(), true);
|
|
654
655
|
}
|
|
655
656
|
});
|
|
657
|
+
},
|
|
658
|
+
// CDP
|
|
659
|
+
async sendCdpEvent(contextId, event, payload) {
|
|
660
|
+
const cdp = await server.ensureCDPHandler(contextId, sessionId);
|
|
661
|
+
return cdp.send(event, payload);
|
|
662
|
+
},
|
|
663
|
+
async trackCdpEvent(contextId, type, event, listenerId) {
|
|
664
|
+
const cdp = await server.ensureCDPHandler(contextId, sessionId);
|
|
665
|
+
cdp[type](event, listenerId);
|
|
656
666
|
}
|
|
657
667
|
},
|
|
658
668
|
{
|
|
659
669
|
post: (msg) => ws.send(msg),
|
|
660
670
|
on: (fn) => ws.on("message", fn),
|
|
661
|
-
eventNames: ["onCancel"],
|
|
671
|
+
eventNames: ["onCancel", "cdpEvent"],
|
|
662
672
|
serialize: (data) => stringify(data, stringifyReplace),
|
|
663
673
|
deserialize: parse,
|
|
664
674
|
onTimeoutError(functionName) {
|
|
@@ -696,6 +706,7 @@ function stringifyReplace(key, value) {
|
|
|
696
706
|
class BrowserServerState {
|
|
697
707
|
orchestrators = /* @__PURE__ */ new Map();
|
|
698
708
|
testers = /* @__PURE__ */ new Map();
|
|
709
|
+
cdps = /* @__PURE__ */ new Map();
|
|
699
710
|
contexts = /* @__PURE__ */ new Map();
|
|
700
711
|
getContext(contextId) {
|
|
701
712
|
return this.contexts.get(contextId);
|
|
@@ -712,6 +723,9 @@ class BrowserServerState {
|
|
|
712
723
|
});
|
|
713
724
|
return defer;
|
|
714
725
|
}
|
|
726
|
+
async removeCDPHandler(sessionId) {
|
|
727
|
+
this.cdps.delete(sessionId);
|
|
728
|
+
}
|
|
715
729
|
}
|
|
716
730
|
|
|
717
731
|
function replacer(code, values) {
|
|
@@ -743,6 +757,49 @@ async function getBrowserProvider(options, project) {
|
|
|
743
757
|
return customProviderModule.default;
|
|
744
758
|
}
|
|
745
759
|
|
|
760
|
+
class BrowserServerCDPHandler {
|
|
761
|
+
constructor(session, tester) {
|
|
762
|
+
this.session = session;
|
|
763
|
+
this.tester = tester;
|
|
764
|
+
}
|
|
765
|
+
listenerIds = {};
|
|
766
|
+
listeners = {};
|
|
767
|
+
send(method, params) {
|
|
768
|
+
return this.session.send(method, params);
|
|
769
|
+
}
|
|
770
|
+
on(event, id, once = false) {
|
|
771
|
+
if (!this.listenerIds[event]) {
|
|
772
|
+
this.listenerIds[event] = [];
|
|
773
|
+
}
|
|
774
|
+
this.listenerIds[event].push(id);
|
|
775
|
+
if (!this.listeners[event]) {
|
|
776
|
+
this.listeners[event] = (payload) => {
|
|
777
|
+
this.tester.cdpEvent(
|
|
778
|
+
event,
|
|
779
|
+
payload
|
|
780
|
+
);
|
|
781
|
+
if (once) {
|
|
782
|
+
this.off(event, id);
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
this.session.on(event, this.listeners[event]);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
off(event, id) {
|
|
789
|
+
if (!this.listenerIds[event]) {
|
|
790
|
+
this.listenerIds[event] = [];
|
|
791
|
+
}
|
|
792
|
+
this.listenerIds[event] = this.listenerIds[event].filter((l) => l !== id);
|
|
793
|
+
if (!this.listenerIds[event].length) {
|
|
794
|
+
this.session.off(event, this.listeners[event]);
|
|
795
|
+
delete this.listeners[event];
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
once(event, listener) {
|
|
799
|
+
this.on(event, listener, true);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
746
803
|
class BrowserServer {
|
|
747
804
|
constructor(project, base) {
|
|
748
805
|
this.project = project;
|
|
@@ -837,6 +894,35 @@ class BrowserServer {
|
|
|
837
894
|
options: providerOptions
|
|
838
895
|
});
|
|
839
896
|
}
|
|
897
|
+
cdpSessions = /* @__PURE__ */ new Map();
|
|
898
|
+
async ensureCDPHandler(contextId, sessionId) {
|
|
899
|
+
const cachedHandler = this.state.cdps.get(sessionId);
|
|
900
|
+
if (cachedHandler) {
|
|
901
|
+
return cachedHandler;
|
|
902
|
+
}
|
|
903
|
+
const provider = this.provider;
|
|
904
|
+
if (!provider.getCDPSession) {
|
|
905
|
+
throw new Error(`CDP is not supported by the provider "${provider.name}".`);
|
|
906
|
+
}
|
|
907
|
+
const promise = this.cdpSessions.get(sessionId) ?? await (async () => {
|
|
908
|
+
const promise2 = provider.getCDPSession(contextId).finally(() => {
|
|
909
|
+
this.cdpSessions.delete(sessionId);
|
|
910
|
+
});
|
|
911
|
+
this.cdpSessions.set(sessionId, promise2);
|
|
912
|
+
return promise2;
|
|
913
|
+
})();
|
|
914
|
+
const session = await promise;
|
|
915
|
+
const rpc = this.state.testers.get(sessionId);
|
|
916
|
+
if (!rpc) {
|
|
917
|
+
throw new Error(`Tester RPC "${sessionId}" was not established.`);
|
|
918
|
+
}
|
|
919
|
+
const handler = new BrowserServerCDPHandler(session, rpc);
|
|
920
|
+
this.state.cdps.set(
|
|
921
|
+
sessionId,
|
|
922
|
+
handler
|
|
923
|
+
);
|
|
924
|
+
return handler;
|
|
925
|
+
}
|
|
840
926
|
async close() {
|
|
841
927
|
await this.vite.close();
|
|
842
928
|
}
|
|
@@ -852,7 +938,7 @@ function wrapConfig(config) {
|
|
|
852
938
|
const click = async (context, xpath, options = {}) => {
|
|
853
939
|
const provider = context.provider;
|
|
854
940
|
if (provider instanceof PlaywrightBrowserProvider) {
|
|
855
|
-
const tester = context.
|
|
941
|
+
const tester = context.iframe;
|
|
856
942
|
await tester.locator(`xpath=${xpath}`).click({
|
|
857
943
|
timeout: 1e3,
|
|
858
944
|
...options
|
|
@@ -868,7 +954,7 @@ const click = async (context, xpath, options = {}) => {
|
|
|
868
954
|
const dblClick = async (context, xpath, options = {}) => {
|
|
869
955
|
const provider = context.provider;
|
|
870
956
|
if (provider instanceof PlaywrightBrowserProvider) {
|
|
871
|
-
const tester = context.
|
|
957
|
+
const tester = context.iframe;
|
|
872
958
|
await tester.locator(`xpath=${xpath}`).dblclick(options);
|
|
873
959
|
} else if (provider instanceof WebdriverBrowserProvider) {
|
|
874
960
|
const browser = context.browser;
|
|
@@ -1250,7 +1336,8 @@ const keyboard = async (context, text) => {
|
|
|
1250
1336
|
}
|
|
1251
1337
|
}
|
|
1252
1338
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1253
|
-
await context.frame
|
|
1339
|
+
const frame = await context.frame();
|
|
1340
|
+
await frame.evaluate(focusIframe);
|
|
1254
1341
|
} else if (context.provider instanceof WebdriverBrowserProvider) {
|
|
1255
1342
|
await context.browser.execute(focusIframe);
|
|
1256
1343
|
}
|
|
@@ -1266,7 +1353,8 @@ const keyboard = async (context, text) => {
|
|
|
1266
1353
|
}
|
|
1267
1354
|
}
|
|
1268
1355
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1269
|
-
await context.frame
|
|
1356
|
+
const frame = await context.frame();
|
|
1357
|
+
await frame.evaluate(selectAll);
|
|
1270
1358
|
} else if (context.provider instanceof WebdriverBrowserProvider) {
|
|
1271
1359
|
await context.browser.execute(selectAll);
|
|
1272
1360
|
} else {
|
|
@@ -1350,8 +1438,8 @@ async function keyboardImplementation(provider, contextId, text, selectAll, skip
|
|
|
1350
1438
|
const type = async (context, xpath, text, options = {}) => {
|
|
1351
1439
|
const { skipClick = false, skipAutoClose = false } = options;
|
|
1352
1440
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1353
|
-
const {
|
|
1354
|
-
const element =
|
|
1441
|
+
const { iframe } = context;
|
|
1442
|
+
const element = iframe.locator(`xpath=${xpath}`);
|
|
1355
1443
|
if (!skipClick) {
|
|
1356
1444
|
await element.focus();
|
|
1357
1445
|
}
|
|
@@ -1388,8 +1476,8 @@ const type = async (context, xpath, text, options = {}) => {
|
|
|
1388
1476
|
|
|
1389
1477
|
const clear = async (context, xpath) => {
|
|
1390
1478
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1391
|
-
const {
|
|
1392
|
-
const element =
|
|
1479
|
+
const { iframe } = context;
|
|
1480
|
+
const element = iframe.locator(`xpath=${xpath}`);
|
|
1393
1481
|
await element.clear({
|
|
1394
1482
|
timeout: 1e3
|
|
1395
1483
|
});
|
|
@@ -1405,8 +1493,8 @@ const clear = async (context, xpath) => {
|
|
|
1405
1493
|
|
|
1406
1494
|
const fill = async (context, xpath, text, options = {}) => {
|
|
1407
1495
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1408
|
-
const {
|
|
1409
|
-
const element =
|
|
1496
|
+
const { iframe } = context;
|
|
1497
|
+
const element = iframe.locator(`xpath=${xpath}`);
|
|
1410
1498
|
await element.fill(text, { timeout: 1e3, ...options });
|
|
1411
1499
|
} else if (context.provider instanceof WebdriverBrowserProvider) {
|
|
1412
1500
|
const browser = context.browser;
|
|
@@ -1420,13 +1508,13 @@ const fill = async (context, xpath, text, options = {}) => {
|
|
|
1420
1508
|
const selectOptions = async (context, xpath, userValues, options = {}) => {
|
|
1421
1509
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1422
1510
|
const value = userValues;
|
|
1423
|
-
const {
|
|
1424
|
-
const selectElement =
|
|
1511
|
+
const { iframe } = context;
|
|
1512
|
+
const selectElement = iframe.locator(`xpath=${xpath}`);
|
|
1425
1513
|
const values = await Promise.all(value.map(async (v) => {
|
|
1426
1514
|
if (typeof v === "string") {
|
|
1427
1515
|
return v;
|
|
1428
1516
|
}
|
|
1429
|
-
const elementHandler = await
|
|
1517
|
+
const elementHandler = await iframe.locator(`xpath=${v.element}`).elementHandle();
|
|
1430
1518
|
if (!elementHandler) {
|
|
1431
1519
|
throw new Error(`Element not found: ${v.element}`);
|
|
1432
1520
|
}
|
|
@@ -1472,7 +1560,8 @@ const tab = async (context, options = {}) => {
|
|
|
1472
1560
|
|
|
1473
1561
|
const dragAndDrop = async (context, source, target, options) => {
|
|
1474
1562
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1475
|
-
await context.frame
|
|
1563
|
+
const frame = await context.frame();
|
|
1564
|
+
await frame.dragAndDrop(
|
|
1476
1565
|
`xpath=${source}`,
|
|
1477
1566
|
`xpath=${target}`,
|
|
1478
1567
|
{
|
|
@@ -1494,7 +1583,7 @@ const dragAndDrop = async (context, source, target, options) => {
|
|
|
1494
1583
|
|
|
1495
1584
|
const hover = async (context, xpath, options = {}) => {
|
|
1496
1585
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1497
|
-
await context.
|
|
1586
|
+
await context.iframe.locator(`xpath=${xpath}`).hover({
|
|
1498
1587
|
timeout: 1e3,
|
|
1499
1588
|
...options
|
|
1500
1589
|
});
|
|
@@ -1551,11 +1640,13 @@ const screenshot = async (context, name, options = {}) => {
|
|
|
1551
1640
|
if (context.provider instanceof PlaywrightBrowserProvider) {
|
|
1552
1641
|
if (options.element) {
|
|
1553
1642
|
const { element: elementXpath, ...config } = options;
|
|
1554
|
-
const
|
|
1555
|
-
const element = iframe.locator(`xpath=${elementXpath}`);
|
|
1643
|
+
const element = context.iframe.locator(`xpath=${elementXpath}`);
|
|
1556
1644
|
await element.screenshot({ ...config, path: savePath });
|
|
1557
1645
|
} else {
|
|
1558
|
-
await context.
|
|
1646
|
+
await context.iframe.locator("body").screenshot({
|
|
1647
|
+
...options,
|
|
1648
|
+
path: savePath
|
|
1649
|
+
});
|
|
1559
1650
|
}
|
|
1560
1651
|
return path;
|
|
1561
1652
|
}
|
|
@@ -1650,7 +1741,7 @@ async function generateContextFile(server) {
|
|
|
1650
1741
|
);
|
|
1651
1742
|
const distContextPath = slash(`/@fs/${resolve(__dirname, "context.js")}`);
|
|
1652
1743
|
return `
|
|
1653
|
-
import { page, userEvent as __userEvent_CDP__ } from '${distContextPath}'
|
|
1744
|
+
import { page, userEvent as __userEvent_CDP__, cdp } from '${distContextPath}'
|
|
1654
1745
|
${userEventNonProviderImport}
|
|
1655
1746
|
const filepath = () => ${filepathCode}
|
|
1656
1747
|
const rpc = () => __vitest_worker__.rpc
|
|
@@ -1667,7 +1758,7 @@ export const server = {
|
|
|
1667
1758
|
}
|
|
1668
1759
|
export const commands = server.commands
|
|
1669
1760
|
export const userEvent = ${getUserEvent(provider)}
|
|
1670
|
-
export { page }
|
|
1761
|
+
export { page, cdp }
|
|
1671
1762
|
`;
|
|
1672
1763
|
}
|
|
1673
1764
|
function getUserEvent(provider) {
|
|
@@ -1713,11 +1804,13 @@ ${err.message}`);
|
|
|
1713
1804
|
onImportMeta() {
|
|
1714
1805
|
},
|
|
1715
1806
|
onDynamicImport(node) {
|
|
1716
|
-
const
|
|
1807
|
+
const replaceString = "__vitest_browser_runner__.wrapModule(() => import(";
|
|
1808
|
+
const importSubstring = code.substring(node.start, node.end);
|
|
1809
|
+
const hasIgnore = importSubstring.includes("/* @vite-ignore */");
|
|
1717
1810
|
s.overwrite(
|
|
1718
1811
|
node.start,
|
|
1719
1812
|
node.source.start,
|
|
1720
|
-
|
|
1813
|
+
replaceString + (hasIgnore ? "/* @vite-ignore */ " : "")
|
|
1721
1814
|
);
|
|
1722
1815
|
s.overwrite(node.end - 1, node.end, "))");
|
|
1723
1816
|
}
|
|
@@ -1848,6 +1941,7 @@ var BrowserPlugin = (browserServer, base = "/") => {
|
|
|
1848
1941
|
const pkgRoot = resolve(fileURLToPath(import.meta.url), "../..");
|
|
1849
1942
|
const distRoot = resolve(pkgRoot, "dist");
|
|
1850
1943
|
const project = browserServer.project;
|
|
1944
|
+
let loupePath;
|
|
1851
1945
|
return [
|
|
1852
1946
|
{
|
|
1853
1947
|
enforce: "pre",
|
|
@@ -1926,16 +2020,45 @@ var BrowserPlugin = (browserServer, base = "/") => {
|
|
|
1926
2020
|
(file) => getFilePoolName(project, file) === "browser"
|
|
1927
2021
|
);
|
|
1928
2022
|
const setupFiles = toArray(project.config.setupFiles);
|
|
2023
|
+
const define = {};
|
|
2024
|
+
for (const env in project.config.env || {}) {
|
|
2025
|
+
const stringValue = JSON.stringify(project.config.env[env]);
|
|
2026
|
+
define[`process.env.${env}`] = stringValue;
|
|
2027
|
+
define[`import.meta.env.${env}`] = stringValue;
|
|
2028
|
+
}
|
|
2029
|
+
const entries = [
|
|
2030
|
+
...browserTestFiles,
|
|
2031
|
+
...setupFiles,
|
|
2032
|
+
resolve(distDir, "index.js"),
|
|
2033
|
+
resolve(distDir, "browser.js"),
|
|
2034
|
+
resolve(distDir, "runners.js"),
|
|
2035
|
+
resolve(distDir, "utils.js"),
|
|
2036
|
+
...project.config.snapshotSerializers || []
|
|
2037
|
+
];
|
|
2038
|
+
if (project.config.diff) {
|
|
2039
|
+
entries.push(project.config.diff);
|
|
2040
|
+
}
|
|
2041
|
+
if (project.ctx.coverageProvider) {
|
|
2042
|
+
const coverage = project.ctx.config.coverage;
|
|
2043
|
+
const provider = coverage.provider;
|
|
2044
|
+
if (provider === "v8") {
|
|
2045
|
+
const path = tryResolve("@vitest/coverage-v8", [project.ctx.config.root]);
|
|
2046
|
+
if (path) {
|
|
2047
|
+
entries.push(path);
|
|
2048
|
+
}
|
|
2049
|
+
} else if (provider === "istanbul") {
|
|
2050
|
+
const path = tryResolve("@vitest/coverage-istanbul", [project.ctx.config.root]);
|
|
2051
|
+
if (path) {
|
|
2052
|
+
entries.push(path);
|
|
2053
|
+
}
|
|
2054
|
+
} else if (provider === "custom" && coverage.customProviderModule) {
|
|
2055
|
+
entries.push(coverage.customProviderModule);
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
1929
2058
|
return {
|
|
2059
|
+
define,
|
|
1930
2060
|
optimizeDeps: {
|
|
1931
|
-
entries
|
|
1932
|
-
...browserTestFiles,
|
|
1933
|
-
...setupFiles,
|
|
1934
|
-
resolve(distDir, "index.js"),
|
|
1935
|
-
resolve(distDir, "browser.js"),
|
|
1936
|
-
resolve(distDir, "runners.js"),
|
|
1937
|
-
resolve(distDir, "utils.js")
|
|
1938
|
-
],
|
|
2061
|
+
entries,
|
|
1939
2062
|
exclude: [
|
|
1940
2063
|
"vitest",
|
|
1941
2064
|
"vitest/utils",
|
|
@@ -1966,6 +2089,7 @@ var BrowserPlugin = (browserServer, base = "/") => {
|
|
|
1966
2089
|
"vitest > chai > loupe",
|
|
1967
2090
|
"vitest > @vitest/runner > p-limit",
|
|
1968
2091
|
"vitest > @vitest/utils > diff-sequences",
|
|
2092
|
+
"vitest > @vitest/utils > loupe",
|
|
1969
2093
|
"@vitest/browser > @testing-library/user-event",
|
|
1970
2094
|
"@vitest/browser > @testing-library/dom"
|
|
1971
2095
|
]
|
|
@@ -1992,7 +2116,7 @@ var BrowserPlugin = (browserServer, base = "/") => {
|
|
|
1992
2116
|
if (rawId.startsWith("/__virtual_vitest__")) {
|
|
1993
2117
|
const url = new URL(rawId, "http://localhost");
|
|
1994
2118
|
if (!url.searchParams.has("id")) {
|
|
1995
|
-
|
|
2119
|
+
return;
|
|
1996
2120
|
}
|
|
1997
2121
|
const id = decodeURIComponent(url.searchParams.get("id"));
|
|
1998
2122
|
const resolved = await this.resolve(id, distRoot, {
|
|
@@ -2013,6 +2137,15 @@ var BrowserPlugin = (browserServer, base = "/") => {
|
|
|
2013
2137
|
if (id.startsWith("/__vitest_browser__/") || id.startsWith("/__vitest__/")) {
|
|
2014
2138
|
return resolve(distRoot, "client", id.slice(1));
|
|
2015
2139
|
}
|
|
2140
|
+
},
|
|
2141
|
+
configResolved(config) {
|
|
2142
|
+
loupePath = resolve(config.cacheDir, "deps/loupe.js");
|
|
2143
|
+
},
|
|
2144
|
+
transform(code, id) {
|
|
2145
|
+
if (id.startsWith(loupePath)) {
|
|
2146
|
+
const utilRequire = "nodeUtil = require_util();";
|
|
2147
|
+
return code.replace(utilRequire, " ".repeat(utilRequire.length));
|
|
2148
|
+
}
|
|
2016
2149
|
}
|
|
2017
2150
|
},
|
|
2018
2151
|
BrowserContext(browserServer),
|
|
@@ -2022,10 +2155,8 @@ var BrowserPlugin = (browserServer, base = "/") => {
|
|
|
2022
2155
|
enforce: "post",
|
|
2023
2156
|
async config(viteConfig) {
|
|
2024
2157
|
// Enables using ignore hint for coverage providers with @preserve keyword
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
viteConfig.esbuild.legalComments = "inline";
|
|
2028
|
-
}
|
|
2158
|
+
viteConfig.esbuild ||= {};
|
|
2159
|
+
viteConfig.esbuild.legalComments = "inline";
|
|
2029
2160
|
const server = resolveApiServerConfig(
|
|
2030
2161
|
viteConfig.test?.browser || {},
|
|
2031
2162
|
defaultBrowserPort
|
|
@@ -2055,18 +2186,31 @@ var BrowserPlugin = (browserServer, base = "/") => {
|
|
|
2055
2186
|
},
|
|
2056
2187
|
// TODO: remove this when @testing-library/vue supports ESM
|
|
2057
2188
|
{
|
|
2058
|
-
name: "vitest:browser:support-
|
|
2189
|
+
name: "vitest:browser:support-testing-library",
|
|
2059
2190
|
config() {
|
|
2060
2191
|
return {
|
|
2192
|
+
define: {
|
|
2193
|
+
// testing-library/preact
|
|
2194
|
+
"process.env.PTL_SKIP_AUTO_CLEANUP": !!process.env.PTL_SKIP_AUTO_CLEANUP,
|
|
2195
|
+
// testing-library/react
|
|
2196
|
+
"process.env.RTL_SKIP_AUTO_CLEANUP": !!process.env.RTL_SKIP_AUTO_CLEANUP,
|
|
2197
|
+
"process.env?.RTL_SKIP_AUTO_CLEANUP": !!process.env.RTL_SKIP_AUTO_CLEANUP,
|
|
2198
|
+
// testing-library/svelte, testing-library/solid
|
|
2199
|
+
"process.env.STL_SKIP_AUTO_CLEANUP": !!process.env.STL_SKIP_AUTO_CLEANUP,
|
|
2200
|
+
// testing-library/vue
|
|
2201
|
+
"process.env.VTL_SKIP_AUTO_CLEANUP": !!process.env.VTL_SKIP_AUTO_CLEANUP,
|
|
2202
|
+
// dom.debug()
|
|
2203
|
+
"process.env.DEBUG_PRINT_LIMIT": process.env.DEBUG_PRINT_LIMIT || 7e3
|
|
2204
|
+
},
|
|
2061
2205
|
optimizeDeps: {
|
|
2062
2206
|
esbuildOptions: {
|
|
2063
2207
|
plugins: [
|
|
2064
2208
|
{
|
|
2065
2209
|
name: "test-utils-rewrite",
|
|
2066
2210
|
setup(build) {
|
|
2067
|
-
const _require = createRequire(import.meta.url);
|
|
2068
2211
|
build.onResolve({ filter: /@vue\/test-utils/ }, (args) => {
|
|
2069
|
-
const
|
|
2212
|
+
const _require2 = getRequire();
|
|
2213
|
+
const resolved = _require2.resolve(args.path, {
|
|
2070
2214
|
paths: [args.importer]
|
|
2071
2215
|
});
|
|
2072
2216
|
return { path: resolved };
|
|
@@ -2081,6 +2225,21 @@ var BrowserPlugin = (browserServer, base = "/") => {
|
|
|
2081
2225
|
}
|
|
2082
2226
|
];
|
|
2083
2227
|
};
|
|
2228
|
+
function tryResolve(path, paths) {
|
|
2229
|
+
try {
|
|
2230
|
+
const _require2 = getRequire();
|
|
2231
|
+
return _require2.resolve(path, { paths });
|
|
2232
|
+
} catch {
|
|
2233
|
+
return void 0;
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
let _require;
|
|
2237
|
+
function getRequire() {
|
|
2238
|
+
if (!_require) {
|
|
2239
|
+
_require = createRequire(import.meta.url);
|
|
2240
|
+
}
|
|
2241
|
+
return _require;
|
|
2242
|
+
}
|
|
2084
2243
|
function resolveCoverageFolder(project) {
|
|
2085
2244
|
const options = project.ctx.config;
|
|
2086
2245
|
const htmlReporter = options.coverage?.enabled ? toArray(options.coverage.reporter).find((reporter) => {
|
|
@@ -2172,7 +2331,14 @@ function createBrowserPool(ctx) {
|
|
|
2172
2331
|
files.push(file);
|
|
2173
2332
|
groupedFiles.set(project, files);
|
|
2174
2333
|
}
|
|
2334
|
+
let isCancelled = false;
|
|
2335
|
+
ctx.onCancel(() => {
|
|
2336
|
+
isCancelled = true;
|
|
2337
|
+
});
|
|
2175
2338
|
for (const [project, files] of groupedFiles.entries()) {
|
|
2339
|
+
if (isCancelled) {
|
|
2340
|
+
break;
|
|
2341
|
+
}
|
|
2176
2342
|
await runTests(project, files);
|
|
2177
2343
|
}
|
|
2178
2344
|
};
|
|
@@ -2206,14 +2372,13 @@ async function createBrowserServer(project, configFile, prePlugins = [], postPlu
|
|
|
2206
2372
|
...project.options,
|
|
2207
2373
|
// spread project config inlined in root workspace config
|
|
2208
2374
|
base: "/",
|
|
2209
|
-
logLevel: "
|
|
2375
|
+
logLevel: process.env.VITEST_BROWSER_DEBUG ?? "info",
|
|
2210
2376
|
mode: project.config.mode,
|
|
2211
2377
|
configFile: configPath,
|
|
2212
2378
|
// watch is handled by Vitest
|
|
2213
2379
|
server: {
|
|
2214
2380
|
hmr: false,
|
|
2215
|
-
watch: null
|
|
2216
|
-
preTransformRequests: false
|
|
2381
|
+
watch: null
|
|
2217
2382
|
},
|
|
2218
2383
|
plugins: [
|
|
2219
2384
|
...prePlugins,
|
package/dist/providers.js
CHANGED
package/dist/state.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const{parse:$parse,stringify:$stringify}=JSON;const{keys}=Object;const Primitive=String;const primitive="string";const ignore={};const object="object";const noop=(_,value)=>value;const primitives=value=>value instanceof Primitive?Primitive(value):value;const Primitives=(_,value)=>typeof value===primitive?new Primitive(value):value;const revive=(input,parsed,output,$)=>{const lazy=[];for(let ke=keys(output),{length}=ke,y=0;y<length;y++){const k=ke[y];const value=output[k];if(value instanceof Primitive){const tmp=input[value];if(typeof tmp===object&&!parsed.has(tmp)){parsed.add(tmp);output[k]=ignore;lazy.push({k,a:[input,parsed,tmp,$]})}else output[k]=$.call(output,k,tmp)}else if(output[k]!==ignore)output[k]=$.call(output,k,value)}for(let{length}=lazy,i=0;i<length;i++){const{k,a}=lazy[i];output[k]=$.call(output,k,revive.apply(null,a))}return output};const parse=(text,reviver)=>{const input=$parse(text,Primitives).map(primitives);const value=input[0];const $=noop;const tmp=typeof value===object&&value?revive(input,new Set,value,$):value;return $.call({"":tmp},"",tmp)};function getBrowserState(){return window.__vitest_browser_runner__}const config=getBrowserState().config;const providedContext=parse(getBrowserState().providedContext);const state={ctx:{pool:"browser",worker:"./browser.js",workerId:1,config,projectName:config.name||"",files:[],environment:{name:"browser",options:null},providedContext,invalidates:[]},onCancel:null,mockMap:new Map,config,environment:{name:"browser",transformMode:"web",setup(){throw new Error("Not called in the browser")}},moduleCache:getBrowserState().moduleCache,rpc:null,durations:{environment:0,prepare:performance.now()},providedContext};globalThis.__vitest_browser__=true;globalThis.__vitest_worker__=state;
|
|
1
|
+
const{parse:$parse,stringify:$stringify}=JSON;const{keys}=Object;const Primitive=String;const primitive="string";const ignore={};const object="object";const noop=(_,value)=>value;const primitives=value=>value instanceof Primitive?Primitive(value):value;const Primitives=(_,value)=>typeof value===primitive?new Primitive(value):value;const revive=(input,parsed,output,$)=>{const lazy=[];for(let ke=keys(output),{length}=ke,y=0;y<length;y++){const k=ke[y];const value=output[k];if(value instanceof Primitive){const tmp=input[value];if(typeof tmp===object&&!parsed.has(tmp)){parsed.add(tmp);output[k]=ignore;lazy.push({k,a:[input,parsed,tmp,$]})}else output[k]=$.call(output,k,tmp)}else if(output[k]!==ignore)output[k]=$.call(output,k,value)}for(let{length}=lazy,i=0;i<length;i++){const{k,a}=lazy[i];output[k]=$.call(output,k,revive.apply(null,a))}return output};const parse=(text,reviver)=>{const input=$parse(text,Primitives).map(primitives);const value=input[0];const $=noop;const tmp=typeof value===object&&value?revive(input,new Set,value,$):value;return $.call({"":tmp},"",tmp)};function getBrowserState(){return window.__vitest_browser_runner__}const config=getBrowserState().config;const contextId=getBrowserState().contextId;const providedContext=parse(getBrowserState().providedContext);const state={ctx:{pool:"browser",worker:"./browser.js",workerId:1,config,projectName:config.name||"",files:[],environment:{name:"browser",options:null},providedContext,invalidates:[]},onCancel:null,mockMap:new Map,config,environment:{name:"browser",transformMode:"web",setup(){throw new Error("Not called in the browser")}},moduleCache:getBrowserState().moduleCache,rpc:null,durations:{environment:0,prepare:performance.now()},providedContext};globalThis.__vitest_browser__=true;globalThis.__vitest_worker__=state;getBrowserState().cdp=createCdp();function rpc(){return state.rpc}function createCdp(){const listenersMap=new WeakMap;function getId(listener){const id=listenersMap.get(listener)||crypto.randomUUID();listenersMap.set(listener,id);return id}const listeners={};const error=err=>{window.dispatchEvent(new ErrorEvent("error",{error:err}))};const cdp={send(method,params){return rpc().sendCdpEvent(contextId,method,params)},on(event,listener){const listenerId=getId(listener);listeners[event]=listeners[event]||[];listeners[event].push(listener);rpc().trackCdpEvent(contextId,"on",event,listenerId).catch(error);return cdp},once(event,listener){const listenerId=getId(listener);const handler=data=>{listener(data);cdp.off(event,listener)};listeners[event]=listeners[event]||[];listeners[event].push(handler);rpc().trackCdpEvent(contextId,"once",event,listenerId).catch(error);return cdp},off(event,listener){const listenerId=getId(listener);if(listeners[event]){listeners[event]=listeners[event].filter(l=>l!==listener)}rpc().trackCdpEvent(contextId,"off",event,listenerId).catch(error);return cdp},emit(event,payload){if(listeners[event]){listeners[event].forEach(l=>{try{l(payload)}catch(err){error(err)}})}}};return cdp}
|