@vitest/browser 4.0.16 → 4.1.0-beta.1
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 +89 -0
- package/dist/client/.vite/manifest.json +2 -2
- package/dist/client/__vitest__/assets/index-DHXSWiHD.js +57 -0
- package/dist/client/__vitest__/index.html +1 -1
- package/dist/client/__vitest_browser__/{orchestrator-8U3FyXSU.js → orchestrator-S_3e_uzt.js} +40 -8
- package/dist/client/__vitest_browser__/{tester-g_x0OsgY.js → tester-cVWT4Xmu.js} +62 -25
- package/dist/client/error-catcher.js +5 -1
- package/dist/client/esm-client-injector.js +2 -1
- package/dist/client/orchestrator.html +1 -1
- package/dist/client/tester/tester.html +1 -1
- package/dist/context.js +53 -0
- package/dist/expect-element.js +4 -4
- package/dist/{index-CEutxZap.js → index-5ZLDAkrH.js} +1 -1
- package/dist/index.js +214 -109
- package/dist/locators.d.ts +2 -1
- package/dist/locators.js +1 -1
- package/dist/shared/screenshotMatcher/types.d.ts +1 -1
- package/package.json +10 -9
- package/dist/client/__vitest__/assets/index-CLLxNdKA.js +0 -57
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
})();
|
|
24
24
|
</script>
|
|
25
25
|
<!-- !LOAD_METADATA! -->
|
|
26
|
-
<script type="module" src="./assets/index-
|
|
26
|
+
<script type="module" src="./assets/index-DHXSWiHD.js"></script>
|
|
27
27
|
<link rel="stylesheet" href="./assets/index-DlhE0rqZ.css">
|
|
28
28
|
</head>
|
|
29
29
|
<body>
|
package/dist/client/__vitest_browser__/{orchestrator-8U3FyXSU.js → orchestrator-S_3e_uzt.js}
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { g as getBrowserState, a as getConfig, r as relative, b as generateFileHash } from "./utils-uxqdqUz8.js";
|
|
2
2
|
import { channel, globalChannel, client } from "@vitest/browser/client";
|
|
3
|
+
import { Traces } from "vitest/internal/browser";
|
|
3
4
|
// @__NO_SIDE_EFFECTS__
|
|
4
5
|
function getUiAPI() {
|
|
5
6
|
return window.__vitest_ui_api__;
|
|
@@ -10,8 +11,14 @@ class IframeOrchestrator {
|
|
|
10
11
|
recreateNonIsolatedIframe = false;
|
|
11
12
|
iframes = /* @__PURE__ */ new Map();
|
|
12
13
|
eventTarget = new EventTarget();
|
|
14
|
+
traces;
|
|
13
15
|
constructor() {
|
|
14
16
|
debug("init orchestrator", getBrowserState().sessionId);
|
|
17
|
+
const otelConfig = getBrowserState().config.experimental.openTelemetry;
|
|
18
|
+
this.traces = new Traces({
|
|
19
|
+
enabled: !!((otelConfig == null ? void 0 : otelConfig.enabled) && otelConfig.browserSdkPath),
|
|
20
|
+
sdkPath: `/@fs/${otelConfig == null ? void 0 : otelConfig.browserSdkPath}`
|
|
21
|
+
});
|
|
15
22
|
channel.addEventListener(
|
|
16
23
|
"message",
|
|
17
24
|
(e) => this.onIframeEvent(e)
|
|
@@ -22,6 +29,21 @@ class IframeOrchestrator {
|
|
|
22
29
|
);
|
|
23
30
|
}
|
|
24
31
|
async createTesters(options) {
|
|
32
|
+
await this.traces.waitInit();
|
|
33
|
+
this.traces.recordInitSpan(
|
|
34
|
+
this.traces.getContextFromCarrier(getBrowserState().otelCarrier)
|
|
35
|
+
);
|
|
36
|
+
const orchestratorSpan = this.traces.startContextSpan(
|
|
37
|
+
"vitest.browser.orchestrator.run",
|
|
38
|
+
this.traces.getContextFromCarrier(options.otelCarrier)
|
|
39
|
+
);
|
|
40
|
+
orchestratorSpan.span.setAttributes({
|
|
41
|
+
"vitest.browser.files": options.files.map((f) => f.filepath)
|
|
42
|
+
});
|
|
43
|
+
const endSpan = async () => {
|
|
44
|
+
orchestratorSpan.span.end();
|
|
45
|
+
await this.traces.flush();
|
|
46
|
+
};
|
|
25
47
|
const startTime = performance.now();
|
|
26
48
|
this.cancelled = false;
|
|
27
49
|
const config = getConfig();
|
|
@@ -35,13 +57,15 @@ class IframeOrchestrator {
|
|
|
35
57
|
}
|
|
36
58
|
}
|
|
37
59
|
if (config.browser.isolate === false) {
|
|
38
|
-
await this.runNonIsolatedTests(container, options, startTime);
|
|
60
|
+
await this.runNonIsolatedTests(container, options, startTime, orchestratorSpan.context);
|
|
61
|
+
await endSpan();
|
|
39
62
|
return;
|
|
40
63
|
}
|
|
41
64
|
this.iframes.forEach((iframe) => iframe.remove());
|
|
42
65
|
this.iframes.clear();
|
|
43
66
|
for (let i = 0; i < options.files.length; i++) {
|
|
44
67
|
if (this.cancelled) {
|
|
68
|
+
await endSpan();
|
|
45
69
|
return;
|
|
46
70
|
}
|
|
47
71
|
const file = options.files[i];
|
|
@@ -50,9 +74,11 @@ class IframeOrchestrator {
|
|
|
50
74
|
container,
|
|
51
75
|
file,
|
|
52
76
|
options,
|
|
53
|
-
startTime
|
|
77
|
+
startTime,
|
|
78
|
+
orchestratorSpan.context
|
|
54
79
|
);
|
|
55
80
|
}
|
|
81
|
+
await endSpan();
|
|
56
82
|
}
|
|
57
83
|
async cleanupTesters() {
|
|
58
84
|
const config = getConfig();
|
|
@@ -75,7 +101,7 @@ class IframeOrchestrator {
|
|
|
75
101
|
});
|
|
76
102
|
this.recreateNonIsolatedIframe = true;
|
|
77
103
|
}
|
|
78
|
-
async runNonIsolatedTests(container, options, startTime) {
|
|
104
|
+
async runNonIsolatedTests(container, options, startTime, otelContext) {
|
|
79
105
|
if (this.recreateNonIsolatedIframe) {
|
|
80
106
|
this.recreateNonIsolatedIframe = false;
|
|
81
107
|
this.iframes.get(ID_ALL).remove();
|
|
@@ -84,7 +110,7 @@ class IframeOrchestrator {
|
|
|
84
110
|
}
|
|
85
111
|
if (!this.iframes.has(ID_ALL)) {
|
|
86
112
|
debug("preparing non-isolated iframe");
|
|
87
|
-
await this.prepareIframe(container, ID_ALL, startTime);
|
|
113
|
+
await this.prepareIframe(container, ID_ALL, startTime, otelContext);
|
|
88
114
|
}
|
|
89
115
|
const config = getConfig();
|
|
90
116
|
const { width, height } = config.browser.viewport;
|
|
@@ -100,7 +126,7 @@ class IframeOrchestrator {
|
|
|
100
126
|
});
|
|
101
127
|
debug("finished running tests", options.files.join(", "));
|
|
102
128
|
}
|
|
103
|
-
async runIsolatedTestInIframe(container, spec, options, startTime) {
|
|
129
|
+
async runIsolatedTestInIframe(container, spec, options, startTime, otelContext) {
|
|
104
130
|
const config = getConfig();
|
|
105
131
|
const { width, height } = config.browser.viewport;
|
|
106
132
|
const file = spec.filepath;
|
|
@@ -108,7 +134,12 @@ class IframeOrchestrator {
|
|
|
108
134
|
this.iframes.get(file).remove();
|
|
109
135
|
this.iframes.delete(file);
|
|
110
136
|
}
|
|
111
|
-
const iframe = await this.prepareIframe(
|
|
137
|
+
const iframe = await this.prepareIframe(
|
|
138
|
+
container,
|
|
139
|
+
file,
|
|
140
|
+
startTime,
|
|
141
|
+
otelContext
|
|
142
|
+
);
|
|
112
143
|
await setIframeViewport(iframe, width, height);
|
|
113
144
|
await sendEventToIframe({
|
|
114
145
|
event: "execute",
|
|
@@ -127,7 +158,7 @@ class IframeOrchestrator {
|
|
|
127
158
|
this.eventTarget.dispatchEvent(event);
|
|
128
159
|
return error;
|
|
129
160
|
}
|
|
130
|
-
async prepareIframe(container, iframeId, startTime) {
|
|
161
|
+
async prepareIframe(container, iframeId, startTime, otelContext) {
|
|
131
162
|
const iframe = this.createTestIframe(iframeId);
|
|
132
163
|
container.appendChild(iframe);
|
|
133
164
|
await new Promise((resolve, reject) => {
|
|
@@ -146,7 +177,8 @@ Expected: ${iframe.src}`
|
|
|
146
177
|
sendEventToIframe({
|
|
147
178
|
event: "prepare",
|
|
148
179
|
iframeId,
|
|
149
|
-
startTime
|
|
180
|
+
startTime,
|
|
181
|
+
otelCarrier: this.traces.getContextCarrier(otelContext)
|
|
150
182
|
}).then(resolve, (error) => reject(this.dispatchIframeError(error)));
|
|
151
183
|
}
|
|
152
184
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { c as resolve, m as moduleRunner, d as getWorkerState, g as getBrowserState, e as getTestName, a as getConfig } from "./utils-uxqdqUz8.js";
|
|
2
2
|
import { onCancel, globalChannel, channel, client } from "@vitest/browser/client";
|
|
3
3
|
import { userEvent, page, server } from "vitest/browser";
|
|
4
|
-
import { getSafeTimers, DecodedMap as DecodedMap$1, getOriginalPosition as getOriginalPosition$1, loadDiffConfig, loadSnapshotSerializers, takeCoverageInsideWorker, browserFormat, setupCommonEnv, startCoverageInsideWorker, stopCoverageInsideWorker, startTests, collectTests, SpyModule } from "vitest/internal/browser";
|
|
5
|
-
import {
|
|
4
|
+
import { getSafeTimers, DecodedMap as DecodedMap$1, getOriginalPosition as getOriginalPosition$1, loadDiffConfig, loadSnapshotSerializers, takeCoverageInsideWorker, browserFormat, Traces, setupCommonEnv, startCoverageInsideWorker, stopCoverageInsideWorker, startTests, collectTests, SpyModule } from "vitest/internal/browser";
|
|
5
|
+
import { TestRunner, BenchmarkRunner } from "vitest";
|
|
6
6
|
const scriptRel = "modulepreload";
|
|
7
7
|
const assetsURL = function(dep) {
|
|
8
8
|
return "/" + dep;
|
|
@@ -811,11 +811,13 @@ function createBrowserRunner(runnerClass, mocker, state, coverageModule) {
|
|
|
811
811
|
sourceMapCache = /* @__PURE__ */ new Map();
|
|
812
812
|
method = "run";
|
|
813
813
|
commands;
|
|
814
|
+
_otel;
|
|
814
815
|
constructor(options) {
|
|
815
816
|
super(options.config);
|
|
816
817
|
this.config = options.config;
|
|
817
818
|
this.commands = getBrowserState().commands;
|
|
818
819
|
this.viteEnvironment = "__browser__";
|
|
820
|
+
this._otel = getBrowserState().traces;
|
|
819
821
|
}
|
|
820
822
|
setMethod(method) {
|
|
821
823
|
this.method = method;
|
|
@@ -865,28 +867,28 @@ function createBrowserRunner(runnerClass, mocker, state, coverageModule) {
|
|
|
865
867
|
if (!this.traces.has(test.id)) {
|
|
866
868
|
this.traces.set(test.id, []);
|
|
867
869
|
}
|
|
868
|
-
const
|
|
870
|
+
const traces2 = this.traces.get(test.id);
|
|
869
871
|
const { tracePath } = await this.commands.triggerCommand(
|
|
870
872
|
"__vitest_stopChunkTrace",
|
|
871
873
|
[{ name }]
|
|
872
874
|
);
|
|
873
|
-
|
|
875
|
+
traces2.push(tracePath);
|
|
874
876
|
};
|
|
875
877
|
onAfterRunTask = async (task) => {
|
|
876
878
|
var _a, _b, _c;
|
|
877
879
|
await ((_a = super.onAfterRunTask) == null ? void 0 : _a.call(this, task));
|
|
878
880
|
const trace = this.config.browser.trace;
|
|
879
|
-
const
|
|
880
|
-
if (
|
|
881
|
+
const traces2 = this.traces.get(task.id) || [];
|
|
882
|
+
if (traces2.length) {
|
|
881
883
|
if (trace === "retain-on-failure" && ((_b = task.result) == null ? void 0 : _b.state) === "pass") {
|
|
882
884
|
await this.commands.triggerCommand(
|
|
883
885
|
"__vitest_deleteTracing",
|
|
884
|
-
[{ traces }]
|
|
886
|
+
[{ traces: traces2 }]
|
|
885
887
|
);
|
|
886
888
|
} else {
|
|
887
889
|
await this.commands.triggerCommand(
|
|
888
890
|
"__vitest_annotateTraces",
|
|
889
|
-
[{ testId: task.id, traces }]
|
|
891
|
+
[{ testId: task.id, traces: traces2 }]
|
|
890
892
|
);
|
|
891
893
|
}
|
|
892
894
|
}
|
|
@@ -1024,9 +1026,10 @@ function createBrowserRunner(runnerClass, mocker, state, coverageModule) {
|
|
|
1024
1026
|
throw new Error(`Failed to import test file ${filepath}`, { cause: err });
|
|
1025
1027
|
}
|
|
1026
1028
|
};
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1029
|
+
trace = (name, attributes, cb) => {
|
|
1030
|
+
const options = typeof attributes === "object" ? { attributes } : {};
|
|
1031
|
+
return this._otel.$(`vitest.test.runner.${name}`, options, cb || attributes);
|
|
1032
|
+
};
|
|
1030
1033
|
};
|
|
1031
1034
|
}
|
|
1032
1035
|
let cachedRunner = null;
|
|
@@ -1037,7 +1040,7 @@ async function initiateRunner(state, mocker, config) {
|
|
|
1037
1040
|
if (cachedRunner) {
|
|
1038
1041
|
return cachedRunner;
|
|
1039
1042
|
}
|
|
1040
|
-
const runnerClass = config.mode === "test" ?
|
|
1043
|
+
const runnerClass = config.mode === "test" ? TestRunner : BenchmarkRunner;
|
|
1041
1044
|
const BrowserRunner = createBrowserRunner(runnerClass, mocker, state, {
|
|
1042
1045
|
takeCoverage: () => takeCoverageInsideWorker(config.coverage, moduleRunner)
|
|
1043
1046
|
});
|
|
@@ -1931,19 +1934,28 @@ class CommandsManager {
|
|
|
1931
1934
|
var _a, _b;
|
|
1932
1935
|
const state = getWorkerState();
|
|
1933
1936
|
const rpc2 = state.rpc;
|
|
1934
|
-
const { sessionId } = getBrowserState();
|
|
1937
|
+
const { sessionId, traces: traces2 } = getBrowserState();
|
|
1935
1938
|
const filepath = state.filepath || ((_b = (_a = state.current) == null ? void 0 : _a.file) == null ? void 0 : _b.filepath);
|
|
1936
1939
|
args = args.filter((arg) => arg !== void 0);
|
|
1937
1940
|
if (this._listeners.length) {
|
|
1938
1941
|
await Promise.all(this._listeners.map((listener) => listener(command, args)));
|
|
1939
1942
|
}
|
|
1940
|
-
return
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1943
|
+
return traces2.$(
|
|
1944
|
+
"vitest.browser.tester.command",
|
|
1945
|
+
{
|
|
1946
|
+
attributes: {
|
|
1947
|
+
"vitest.browser.command": command,
|
|
1948
|
+
"code.file.path": filepath
|
|
1949
|
+
}
|
|
1950
|
+
},
|
|
1951
|
+
() => rpc2.triggerCommand(sessionId, command, filepath, args).catch((err) => {
|
|
1952
|
+
var _a2;
|
|
1953
|
+
clientError.message = err.message;
|
|
1954
|
+
clientError.name = err.name;
|
|
1955
|
+
clientError.stack = (_a2 = clientError.stack) == null ? void 0 : _a2.replace(clientError.message, err.message);
|
|
1956
|
+
throw clientError;
|
|
1957
|
+
})
|
|
1958
|
+
);
|
|
1947
1959
|
}
|
|
1948
1960
|
}
|
|
1949
1961
|
const debugVar = getConfig().env.VITEST_BROWSER_DEBUG;
|
|
@@ -1951,6 +1963,13 @@ const debug = debugVar && debugVar !== "false" ? (...args) => {
|
|
|
1951
1963
|
var _a, _b;
|
|
1952
1964
|
return (_b = (_a = client.rpc).debug) == null ? void 0 : _b.call(_a, ...args.map(String));
|
|
1953
1965
|
} : void 0;
|
|
1966
|
+
const otelConfig = getConfig().experimental.openTelemetry;
|
|
1967
|
+
const traces = new Traces({
|
|
1968
|
+
enabled: !!((otelConfig == null ? void 0 : otelConfig.enabled) && (otelConfig == null ? void 0 : otelConfig.browserSdkPath)),
|
|
1969
|
+
sdkPath: `/@fs/${otelConfig == null ? void 0 : otelConfig.browserSdkPath}`
|
|
1970
|
+
});
|
|
1971
|
+
let rootTesterSpan;
|
|
1972
|
+
getBrowserState().traces = traces;
|
|
1954
1973
|
channel.addEventListener("message", async (e) => {
|
|
1955
1974
|
await client.waitForConnection();
|
|
1956
1975
|
const data = e.data;
|
|
@@ -1979,9 +1998,19 @@ channel.addEventListener("message", async (e) => {
|
|
|
1979
1998
|
}
|
|
1980
1999
|
case "cleanup": {
|
|
1981
2000
|
await cleanup().catch((err) => unhandledError(err, "Cleanup Error"));
|
|
2001
|
+
rootTesterSpan == null ? void 0 : rootTesterSpan.span.end();
|
|
2002
|
+
await traces.finish();
|
|
1982
2003
|
break;
|
|
1983
2004
|
}
|
|
1984
2005
|
case "prepare": {
|
|
2006
|
+
await traces.waitInit();
|
|
2007
|
+
const tracesContext = traces.getContextFromCarrier(data.otelCarrier);
|
|
2008
|
+
traces.recordInitSpan(tracesContext);
|
|
2009
|
+
rootTesterSpan = traces.startContextSpan(
|
|
2010
|
+
`vitest.browser.tester.run`,
|
|
2011
|
+
tracesContext
|
|
2012
|
+
);
|
|
2013
|
+
traces.bind(rootTesterSpan.context);
|
|
1985
2014
|
await prepare(data).catch((err) => unhandledError(err, "Prepare Error"));
|
|
1986
2015
|
break;
|
|
1987
2016
|
}
|
|
@@ -2070,11 +2099,19 @@ async function executeTests(method, specifications) {
|
|
|
2070
2099
|
for (const file of specifications) {
|
|
2071
2100
|
state.filepath = file.filepath;
|
|
2072
2101
|
debug == null ? void 0 : debug("running test file", file.filepath);
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2102
|
+
await traces.$(
|
|
2103
|
+
`vitest.test.runner.${method}.module`,
|
|
2104
|
+
{
|
|
2105
|
+
attributes: { "code.file.path": file.filepath }
|
|
2106
|
+
},
|
|
2107
|
+
async () => {
|
|
2108
|
+
if (method === "run") {
|
|
2109
|
+
await startTests([file], runner);
|
|
2110
|
+
} else {
|
|
2111
|
+
await collectTests([file], runner);
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
);
|
|
2078
2115
|
}
|
|
2079
2116
|
}
|
|
2080
2117
|
async function prepare(options) {
|
|
@@ -31,7 +31,11 @@ function catchWindowErrors(errorEvent, prop, cb) {
|
|
|
31
31
|
cb(e)
|
|
32
32
|
}
|
|
33
33
|
else {
|
|
34
|
-
|
|
34
|
+
// `ErrorEvent` doesn't necessary have `ErrotEvent.error` defined
|
|
35
|
+
// but some has `ErrorEvent.message` defined, e.g. ResizeObserver error.
|
|
36
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent/error
|
|
37
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors
|
|
38
|
+
console.error(e.message ? new Error(e.message) : e)
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
const addEventListener = window.addEventListener.bind(window)
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const { evaluatedModules } = __vitest_worker__
|
|
12
|
-
const moduleId =
|
|
12
|
+
const moduleId = `${Math.random()}`
|
|
13
13
|
const viteModule = evaluatedModules.ensureModule(moduleId, moduleId)
|
|
14
14
|
|
|
15
15
|
viteModule.evaluated = false
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
type: { __VITEST_TYPE__ },
|
|
39
39
|
sessionId: { __VITEST_SESSION_ID__ },
|
|
40
40
|
testerId: { __VITEST_TESTER_ID__ },
|
|
41
|
+
otelCarrier: { __VITEST_OTEL_CARRIER__ },
|
|
41
42
|
provider: { __VITEST_PROVIDER__ },
|
|
42
43
|
method: { __VITEST_METHOD__ },
|
|
43
44
|
providedContext: { __VITEST_PROVIDED_CONTEXT__ },
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
{__VITEST_INJECTOR__}
|
|
27
27
|
{__VITEST_ERROR_CATCHER__}
|
|
28
28
|
{__VITEST_SCRIPTS__}
|
|
29
|
-
<script type="module" crossorigin src="/__vitest_browser__/orchestrator-
|
|
29
|
+
<script type="module" crossorigin src="/__vitest_browser__/orchestrator-S_3e_uzt.js"></script>
|
|
30
30
|
<link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-uxqdqUz8.js">
|
|
31
31
|
</head>
|
|
32
32
|
<body>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<link rel="icon" href="{__VITEST_FAVICON__}" type="image/svg+xml">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Vitest Browser Tester</title>
|
|
8
|
-
<script type="module" crossorigin src="/__vitest_browser__/tester-
|
|
8
|
+
<script type="module" crossorigin src="/__vitest_browser__/tester-cVWT4Xmu.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-uxqdqUz8.js">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/dist/context.js
CHANGED
|
@@ -165,6 +165,36 @@ const kLocator = Symbol.for("$$vitest:locator");
|
|
|
165
165
|
function isLocator(element) {
|
|
166
166
|
return !!element && typeof element === "object" && kLocator in element;
|
|
167
167
|
}
|
|
168
|
+
const DEFAULT_WHEEL_DELTA = 100;
|
|
169
|
+
function resolveUserEventWheelOptions(options) {
|
|
170
|
+
let delta;
|
|
171
|
+
if (options.delta) {
|
|
172
|
+
delta = options.delta;
|
|
173
|
+
} else {
|
|
174
|
+
switch (options.direction) {
|
|
175
|
+
case "up": {
|
|
176
|
+
delta = { y: -DEFAULT_WHEEL_DELTA };
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
case "down": {
|
|
180
|
+
delta = { y: DEFAULT_WHEEL_DELTA };
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
case "left": {
|
|
184
|
+
delta = { x: -DEFAULT_WHEEL_DELTA };
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
case "right": {
|
|
188
|
+
delta = { x: DEFAULT_WHEEL_DELTA };
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
delta,
|
|
195
|
+
times: options.times
|
|
196
|
+
};
|
|
197
|
+
}
|
|
168
198
|
|
|
169
199
|
// this file should not import anything directly, only types and utils
|
|
170
200
|
// @ts-expect-error not typed global
|
|
@@ -205,6 +235,9 @@ function createUserEvent(__tl_user_event_base__, options) {
|
|
|
205
235
|
tripleClick(element, options) {
|
|
206
236
|
return convertToLocator(element).tripleClick(options);
|
|
207
237
|
},
|
|
238
|
+
wheel(elementOrOptions, options) {
|
|
239
|
+
return convertToLocator(elementOrOptions).wheel(options);
|
|
240
|
+
},
|
|
208
241
|
selectOptions(element, value, options) {
|
|
209
242
|
return convertToLocator(element).selectOptions(value, options);
|
|
210
243
|
},
|
|
@@ -339,6 +372,26 @@ function createPreviewUserEvent(userEventBase, options) {
|
|
|
339
372
|
},
|
|
340
373
|
async paste() {
|
|
341
374
|
await userEvent.paste(clipboardData);
|
|
375
|
+
},
|
|
376
|
+
async wheel(element, options) {
|
|
377
|
+
const resolvedElement = isLocator(element) ? element.element() : element;
|
|
378
|
+
const resolvedOptions = resolveUserEventWheelOptions(options);
|
|
379
|
+
const rect = resolvedElement.getBoundingClientRect();
|
|
380
|
+
const centerX = rect.left + rect.width / 2;
|
|
381
|
+
const centerY = rect.top + rect.height / 2;
|
|
382
|
+
const wheelEvent = new WheelEvent("wheel", {
|
|
383
|
+
clientX: centerX,
|
|
384
|
+
clientY: centerY,
|
|
385
|
+
deltaY: resolvedOptions.delta.y ?? 0,
|
|
386
|
+
deltaX: resolvedOptions.delta.x ?? 0,
|
|
387
|
+
deltaMode: 0,
|
|
388
|
+
bubbles: true,
|
|
389
|
+
cancelable: true
|
|
390
|
+
});
|
|
391
|
+
const times = options.times ?? 1;
|
|
392
|
+
for (let count = 0; count < times; count += 1) {
|
|
393
|
+
resolvedElement.dispatchEvent(wheelEvent);
|
|
394
|
+
}
|
|
342
395
|
}
|
|
343
396
|
};
|
|
344
397
|
for (const [name, fn] of Object.entries(vitestUserEvent)) {
|
package/dist/expect-element.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{recordArtifact,expect,chai}from"vitest";import{getType}from"vitest/internal/browser";import{k as kAriaCheckedRoles,L as Locator,g as getAriaChecked,a as getAriaRole,b as getAriaDisabled,c as beginAriaCaches,e as endAriaCaches,i as isElementVisible$1,d as getElementAccessibleDescription,f as getElementAccessibleErrorMessage,h as getElementAccessibleName,j as cssEscape,l as convertToSelector,m as getBrowserState,p as processTimeoutOptions}from"./index-
|
|
1
|
+
import{recordArtifact,expect,chai}from"vitest";import{getType}from"vitest/internal/browser";import{k as kAriaCheckedRoles,L as Locator,g as getAriaChecked,a as getAriaRole,b as getAriaDisabled,c as beginAriaCaches,e as endAriaCaches,i as isElementVisible$1,d as getElementAccessibleDescription,f as getElementAccessibleErrorMessage,h as getElementAccessibleName,j as cssEscape,l as convertToSelector,m as getBrowserState,p as processTimeoutOptions}from"./index-5ZLDAkrH.js";import{server}from"vitest/browser";function getAriaCheckedRoles(){return[...kAriaCheckedRoles]}function queryElementFromUserInput(_,K,q){return _ instanceof Locator&&(_=_.query()),_==null?null:getElementFromUserInput(_,K,q)}function getElementFromUserInput(_,K,q){_ instanceof Locator&&(_=_.element());let J=_?.ownerDocument?.defaultView||window;if(_ instanceof J.HTMLElement||_ instanceof J.SVGElement)return _;throw new UserInputElementTypeError(_,K,q)}function getNodeFromUserInput(_,K,q){_ instanceof Locator&&(_=_.element());let J=_.ownerDocument?.defaultView||window;if(_ instanceof J.Node)return _;throw new UserInputNodeTypeError(_,K,q)}function getMessage(_,K,q,J,Y,X){return[`${K}\n`,`${q}:\n${_.utils.EXPECTED_COLOR(redent(display(_,J),2))}`,`${Y}:\n${_.utils.RECEIVED_COLOR(redent(display(_,X),2))}`].join(`
|
|
2
2
|
`)}function redent(_,K){return indentString(stripIndent(_),K)}function indentString(_,K){return _.replace(/^(?!\s*$)/gm,` `.repeat(K))}function minIndent(_){let K=_.match(/^[ \t]*(?=\S)/gm);return K?K.reduce((_,K)=>Math.min(_,K.length),1/0):0}function stripIndent(_){let K=minIndent(_);if(K===0)return _;let q=RegExp(`^[ \\t]{${K}}`,`gm`);return _.replace(q,``)}function display(_,K){return typeof K==`string`?K:_.utils.stringify(K)}function toSentence(_,{wordConnector:K=`, `,lastWordConnector:q=` and `}={}){return[_.slice(0,-1).join(K),_.at(-1)].join(_.length>1?q:``)}class GenericTypeError extends Error{constructor(_,K,q,J){super(),Error.captureStackTrace&&Error.captureStackTrace(this,q);let Y=``;try{Y=J.utils.printWithType(`Received`,K,J.utils.printReceived)}catch{}this.message=[J.utils.matcherHint(`${J.isNot?`.not`:``}.${q.name}`,`received`,``),``,`${J.utils.RECEIVED_COLOR(`received`)} value must ${_} or a Locator that returns ${_}.`,Y].join(`
|
|
3
|
-
`)}}class UserInputElementTypeError extends GenericTypeError{constructor(_,K,q){super(`an HTMLElement or an SVGElement`,_,K,q)}}class UserInputNodeTypeError extends GenericTypeError{constructor(_,K,q){super(`a Node`,_,K,q)}}function getTag(_){return _ instanceof HTMLFormElement?`FORM`:_.tagName.toUpperCase()}function isInputElement(_){return getTag(_)===`INPUT`}function getSingleElementValue(_){if(_)switch(getTag(_)){case`INPUT`:return getInputValue(_);case`SELECT`:return getSelectValue(_);default:return _.value??getAccessibleValue(_)}}function getSelectValue({multiple:_,options:K}){let q=[...K].filter(_=>_.selected);if(_)return[...q].map(_=>_.value);if(q.length!==0)return q[0].value}function getInputValue(_){switch(_.type){case`number`:return _.value===``?null:Number(_.value);case`checkbox`:return _.checked;default:return _.value}}const rolesSupportingValues=[`meter`,`progressbar`,`slider`,`spinbutton`];function getAccessibleValue(_){if(rolesSupportingValues.includes(_.getAttribute(`role`)||``))return Number(_.getAttribute(`aria-valuenow`))}function normalize(_){return _.replace(/\s+/g,` `).trim()}function matches(_,K){return K instanceof RegExp?K.test(_):_.includes(String(K))}function arrayAsSetComparison(_,K){if(Array.isArray(_)&&Array.isArray(K)){let q=new Set(K);for(let K of new Set(_))if(!q.has(K))return!1;return!0}}const supportedRoles=getAriaCheckedRoles();function toBeChecked(_){let K=getElementFromUserInput(_,toBeChecked,this);if(!(
|
|
3
|
+
`)}}class UserInputElementTypeError extends GenericTypeError{constructor(_,K,q){super(`an HTMLElement or an SVGElement`,_,K,q)}}class UserInputNodeTypeError extends GenericTypeError{constructor(_,K,q){super(`a Node`,_,K,q)}}function getTag(_){return _ instanceof HTMLFormElement?`FORM`:_.tagName.toUpperCase()}function isInputElement(_){return getTag(_)===`INPUT`}function getSingleElementValue(_){if(_)switch(getTag(_)){case`INPUT`:return getInputValue(_);case`SELECT`:return getSelectValue(_);default:return _.value??getAccessibleValue(_)}}function getSelectValue({multiple:_,options:K}){let q=[...K].filter(_=>_.selected);if(_)return[...q].map(_=>_.value);if(q.length!==0)return q[0].value}function getInputValue(_){switch(_.type){case`number`:return _.value===``?null:Number(_.value);case`checkbox`:return _.checked;default:return _.value}}const rolesSupportingValues=[`meter`,`progressbar`,`slider`,`spinbutton`];function getAccessibleValue(_){if(rolesSupportingValues.includes(_.getAttribute(`role`)||``))return Number(_.getAttribute(`aria-valuenow`))}function normalize(_){return _.replace(/\s+/g,` `).trim()}function matches(_,K){return K instanceof RegExp?K.test(_):_.includes(String(K))}function arrayAsSetComparison(_,K){if(Array.isArray(_)&&Array.isArray(K)){let q=new Set(K);for(let K of new Set(_))if(!q.has(K))return!1;return!0}}const supportedRoles=getAriaCheckedRoles();function toBeChecked(_){let K=getElementFromUserInput(_,toBeChecked,this);if(!(isInputElement(K)&&[`checkbox`,`radio`].includes(K.type))&&!(supportedRoles.includes(getAriaRole(K)||``)&&[`true`,`false`].includes(K.getAttribute(`aria-checked`)||``)))return{pass:!1,message:()=>`only inputs with type="checkbox" or type="radio" or elements with ${supportedRolesSentence()} and a valid aria-checked attribute can be used with .toBeChecked(). Use .toHaveValue() instead`};let q=getAriaChecked(K)===!0;return{pass:q,message:()=>{let _=q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeChecked`,`element`,``),``,`Received element ${_} checked:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
|
|
4
4
|
`)}}}function supportedRolesSentence(){return toSentence(supportedRoles.map(_=>`role="${_}"`),{lastWordConnector:` or `})}function toBeEmptyDOMElement(_){let K=getElementFromUserInput(_,toBeEmptyDOMElement,this);return{pass:isEmptyElement(K),message:()=>[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeEmptyDOMElement`,`element`,``),``,`Received:`,` ${this.utils.printReceived(K.innerHTML)}`].join(`
|
|
5
5
|
`)}}function isEmptyElement(_){return[..._.childNodes].filter(_=>_.nodeType!==Node.COMMENT_NODE).length===0}function toBeDisabled(_){let K=getElementFromUserInput(_,toBeDisabled,this),q=isElementDisabled(K);return{pass:q,message:()=>{let _=q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeDisabled`,`element`,``),``,`Received element ${_} disabled:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
|
|
6
6
|
`)}}}function toBeEnabled(_){let K=getElementFromUserInput(_,toBeEnabled,this),q=isElementDisabled(K);return{pass:!q,message:()=>{let _=q?`is not`:`is`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeEnabled`,`element`,``),``,`Received element ${_} enabled:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
|
|
@@ -8,7 +8,7 @@ import{recordArtifact,expect,chai}from"vitest";import{getType}from"vitest/intern
|
|
|
8
8
|
`)}}const FORM_TAGS$1=[`FORM`,`INPUT`,`SELECT`,`TEXTAREA`];function isElementHavingAriaInvalid(_){return _.hasAttribute(`aria-invalid`)&&_.getAttribute(`aria-invalid`)!==`false`}function isSupportsValidityMethod(_){return FORM_TAGS$1.includes(getTag(_))}function isElementInvalid(_){let K=isElementHavingAriaInvalid(_);return isSupportsValidityMethod(_)?K||!_.checkValidity():K}function toBeInvalid(_){let K=getElementFromUserInput(_,toBeInvalid,this),q=isElementInvalid(K);return{pass:q,message:()=>{let _=q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeInvalid`,`element`,``),``,`Received element ${_} currently invalid:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
|
|
9
9
|
`)}}}function toBeValid(_){let K=getElementFromUserInput(_,toBeInvalid,this),q=!isElementInvalid(K);return{pass:q,message:()=>{let _=q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeValid`,`element`,``),``,`Received element ${_} currently valid:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
|
|
10
10
|
`)}}}function toBeInViewport(_,K){let q=getElementFromUserInput(_,toBeInViewport,this),J=K?.ratio??0;return getViewportIntersection(q,J).then(({pass:_,ratio:K})=>({pass:_,message:()=>{let Y=_?`is`:`is not`,X=J>0?` with ratio ${J}`:``,Z=K===void 0?``:` (actual ratio: ${K.toFixed(3)})`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeInViewport`,`element`,``),``,`Received element ${Y} in viewport${X}${Z}:`,` ${this.utils.printReceived(q.cloneNode(!1))}`].join(`
|
|
11
|
-
`)}}))}async function getViewportIntersection(_,K){let q=await new Promise(K=>{let q=new IntersectionObserver(_=>{_.length>0?K(_[0].intersectionRatio):K(0),q.disconnect()});q.observe(_),requestAnimationFrame(()=>{})});return{pass:q>0&&q>K-1e-9,ratio:q}}function toBePartiallyChecked(_){let K=getElementFromUserInput(_,toBePartiallyChecked,this);if(!(
|
|
11
|
+
`)}}))}async function getViewportIntersection(_,K){let q=await new Promise(K=>{let q=new IntersectionObserver(_=>{_.length>0?K(_[0].intersectionRatio):K(0),q.disconnect()});q.observe(_),requestAnimationFrame(()=>{})});return{pass:q>0&&q>K-1e-9,ratio:q}}function toBePartiallyChecked(_){let K=getElementFromUserInput(_,toBePartiallyChecked,this);if(!(isInputElement(K)&&K.type===`checkbox`)&&K.getAttribute(`role`)!==`checkbox`)return{pass:!1,message:()=>`only inputs with type="checkbox" or elements with role="checkbox" and a valid aria-checked attribute can be used with .toBePartiallyChecked(). Use .toHaveValue() instead`};let q=isAriaMixed(K);return{pass:q,message:()=>{let _=q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBePartiallyChecked`,`element`,``),``,`Received element ${_} partially checked:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
|
|
12
12
|
`)}}}function isAriaMixed(_){let K=getAriaChecked(_)===`mixed`;return!K&&isInputElement(_)&&[`checkbox`,`radio`].includes(_.type)&&_.getAttribute(`aria-checked`)===`mixed`?!0:K}const FORM_TAGS=[`SELECT`,`TEXTAREA`],ARIA_FORM_TAGS=[`INPUT`,`SELECT`,`TEXTAREA`],UNSUPPORTED_INPUT_TYPES=[`color`,`hidden`,`range`,`submit`,`image`,`reset`],SUPPORTED_ARIA_ROLES=[`checkbox`,`combobox`,`gridcell`,`listbox`,`radiogroup`,`spinbutton`,`textbox`,`tree`];function isRequiredOnFormTagsExceptInput(_){return FORM_TAGS.includes(getTag(_))&&_.hasAttribute(`required`)}function isRequiredOnSupportedInput(_){return getTag(_)===`INPUT`&&_.hasAttribute(`required`)&&(_.hasAttribute(`type`)&&!UNSUPPORTED_INPUT_TYPES.includes(_.getAttribute(`type`)||``)||!_.hasAttribute(`type`))}function isElementRequiredByARIA(_){return _.hasAttribute(`aria-required`)&&_.getAttribute(`aria-required`)===`true`&&(ARIA_FORM_TAGS.includes(getTag(_))||_.hasAttribute(`role`)&&SUPPORTED_ARIA_ROLES.includes(_.getAttribute(`role`)||``))}function toBeRequired(_){let K=getElementFromUserInput(_,toBeRequired,this),q=isRequiredOnFormTagsExceptInput(K)||isRequiredOnSupportedInput(K)||isElementRequiredByARIA(K);return{pass:q,message:()=>{let _=q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeRequired`,`element`,``),``,`Received element ${_} required:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
|
|
13
13
|
`)}}}function toBeVisible(_){let K=getElementFromUserInput(_,toBeVisible,this),q=K.ownerDocument===K.getRootNode({composed:!0});beginAriaCaches();let J=q&&isElementVisible(K);return endAriaCaches(),{pass:J,message:()=>{let _=J?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeVisible`,`element`,``),``,`Received element ${_} visible${q?``:` (element is not in the document)`}:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
|
|
14
14
|
`)}}}function isElementVisible(_){let K=isElementVisible$1(_);if(server.browser!==`webkit`)return K;let q=_.closest(`details`);return!q||_===q?K:isElementVisibleInDetails(_)}function isElementVisibleInDetails(_){let K=_;for(;K;){if(K.tagName===`DETAILS`){let q=K.querySelector(`summary`)===_;if(!K.open&&!q)return!1}K=K.parentElement}return _.offsetParent!==null}function toContainElement(_,K){let q=getElementFromUserInput(_,toContainElement,this),J=K===null?null:getElementFromUserInput(K,toContainElement,this);return{pass:q.contains(J),message:()=>[this.utils.matcherHint(`${this.isNot?`.not`:``}.toContainElement`,`element`,`element`),``,this.utils.RECEIVED_COLOR(`${this.utils.stringify(q.cloneNode(!1))} ${this.isNot?`contains:`:`does not contain:`} ${this.utils.stringify(J?J.cloneNode(!1):null)}
|
|
@@ -23,5 +23,5 @@ import{recordArtifact,expect,chai}from"vitest";import{getType}from"vitest/intern
|
|
|
23
23
|
`)}}}function getMultiElementValue(_){let K=``;for(let q of _){if(K&&K!==q.type)throw Error(`Multiple form elements with the same name must be of the same type`);K=q.type}switch(K){case`radio`:{let K=_.find(_=>_.checked);return K?K.value:void 0}case`checkbox`:return _.filter(_=>_.checked).map(_=>_.value);default:return _.map(_=>_.value)}}function getFormValue(_,K){let q=[..._.querySelectorAll(`[name="${cssEscape(K)}"]`)];if(q.length!==0)switch(q.length){case 1:return getSingleElementValue(q[0]);default:return getMultiElementValue(q)}}function getPureName(_){return/\[\]$/.test(_)?_.slice(0,-2):_}function getAllFormValues(_){let K={};for(let q of _.elements){if(!(`name`in q))continue;let J=q.name;K[getPureName(J)]=getFormValue(_,J)}return K}function toHaveRole(_,K){let q=getElementFromUserInput(_,toHaveRole,this);beginAriaCaches();let J=getAriaRole(q);return endAriaCaches(),{pass:J===K,message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveRole`,`element`,``),`Expected element ${_} have role`,K,`Received`,J)}}}function toHaveSelection(_,K){let q=getElementFromUserInput(_,toHaveSelection,this),J=K!==void 0;if(J&&typeof K!=`string`)throw Error(`expected selection must be a string or undefined`);let Y=getSelection(q);return{pass:J?this.equals(Y,K,[arrayAsSetComparison,...this.customTesters]):!!Y,message:()=>{let _=this.isNot?`not to`:`to`,q=this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveSelection`,`element`,K);return getMessage(this,q,`Expected the element ${_} have selection`,J?K:`(any)`,`Received`,Y)}}}function getSelection(_){let K=_.ownerDocument.getSelection();if(!K)return``;if([`INPUT`,`TEXTAREA`].includes(getTag(_))){let K=_;return[`radio`,`checkbox`].includes(K.type)||K.selectionStart==null||K.selectionEnd==null?``:K.value.toString().substring(K.selectionStart,K.selectionEnd)}if(K.anchorNode===null||K.focusNode===null)return``;let q=K.getRangeAt(0),J=_.ownerDocument.createRange();if(K.containsNode(_,!1))J.selectNodeContents(_),K.removeAllRanges(),K.addRange(J);else if(!(_.contains(K.anchorNode)&&_.contains(K.focusNode))){let Y=_===q.startContainer||_.contains(q.startContainer),X=_===q.endContainer||_.contains(q.endContainer);K.removeAllRanges(),(Y||X)&&(J.selectNodeContents(_),Y&&J.setStart(q.startContainer,q.startOffset),X&&J.setEnd(q.endContainer,q.endOffset),K.addRange(J))}let Y=K.toString();return K.removeAllRanges(),K.addRange(q),Y}const browser=server.config.browser.name,usedValuesProps=new Set(`backgroundPosition.background-position.bottom.left.right.top.height.width.margin-bottom.marginBottom.margin-left.marginLeft.margin-right.marginRight.margin-top.marginTop.min-height.minHeight.min-width.minWidth.padding-bottom.padding-left.padding-right.padding-top.text-indent.paddingBottom.paddingLeft.paddingRight.paddingTop.textIndent`.split(`.`));function toHaveStyle(_,K){let q=getElementFromUserInput(_,toHaveStyle,this),{getComputedStyle:J}=q.ownerDocument.defaultView,Y=typeof K==`object`?getStyleFromObjectCSS(K):computeCSSStyleDeclaration(K),X=J(q),Z=new Set(Array.from(q.style));return{pass:isSubset(Y,q,X,Z),message:()=>{let _=`${this.isNot?`.not`:``}.toHaveStyle`,K=new Set(Object.keys(Y)),J=printoutObjectStyles(Array.from(X).filter(_=>K.has(_)).reduce((_,K)=>(_[K]=(Z.has(K)&&usedValuesProps.has(K)?q.style:X)[K],_),{})),Q=J===``?`Expected styles could not be parsed by the browser. Did you make a typo?`:this.utils.diff(printoutObjectStyles(Y),J);return[this.utils.matcherHint(_,`element`,``),Q].join(`
|
|
24
24
|
|
|
25
25
|
`)}}}function getStyleFromObjectCSS(_){let K=browser===`chrome`||browser===`chromium`?document:document.implementation.createHTMLDocument(``),q=K.createElement(`div`);K.body.appendChild(q);let J=Object.keys(_);J.forEach(K=>{q.style[K]=_[K]});let Y={},X=window.getComputedStyle(q);return J.forEach(_=>{let K=(usedValuesProps.has(_)?q.style:X)[_];K!=null&&(Y[_]=K)}),q.remove(),Y}function computeCSSStyleDeclaration(_){let K=browser===`chrome`||browser===`chromium`||browser===`webkit`?document:document.implementation.createHTMLDocument(``),q=K.createElement(`div`);q.setAttribute(`style`,_.replace(/\n/g,``)),K.body.appendChild(q);let J=window.getComputedStyle(q),Y=Array.from(q.style).reduce((_,K)=>(_[K]=usedValuesProps.has(K)?q.style.getPropertyValue(K):J.getPropertyValue(K),_),{});return q.remove(),Y}function printoutObjectStyles(_){return Object.keys(_).sort().map(K=>`${K}: ${_[K]};`).join(`
|
|
26
|
-
`)}function isSubset(_,K,q,J){let Y=Object.keys(_);return Y.length?Y.every(Y=>{let X=_[Y],Z=Y.startsWith(`--`),Q=[Y];return Z||Q.push(Y.toLowerCase()),Q.some(_=>{let Z=J.has(Y)&&usedValuesProps.has(Y)?K.style:q;return Z[_]===X||Z.getPropertyValue(_)===X})}):!1}function toHaveTextContent(_,K,q={normalizeWhitespace:!0}){let J=getNodeFromUserInput(_,toHaveTextContent,this),Y=q.normalizeWhitespace?normalize(J.textContent||``):(J.textContent||``).replace(/\u00A0/g,` `),X=Y!==``&&K===``;return{pass:!X&&matches(Y,K),message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveTextContent`,`element`,``),X?`Checking with empty string will always match, use .toBeEmptyDOMElement() instead`:`Expected element ${_} have text content`,K,`Received`,Y)}}}function toHaveValue(_,K){let q=getElementFromUserInput(_,toHaveValue,this);if(isInputElement(q)&&[`checkbox`,`radio`].includes(q.type))throw Error(`input with type=checkbox or type=radio cannot be used with .toHaveValue(). Use .toBeChecked() for type=checkbox or .toHaveFormValues() instead`);let J=getSingleElementValue(q),Y=K!==void 0,X=K,Z=J;return K==J&&K!==J&&(X=`${K} (${typeof K})`,Z=`${J} (${typeof J})`),{pass:Y?this.equals(J,K,[arrayAsSetComparison,...this.customTesters]):!!J,message:()=>{let _=this.isNot?`not to`:`to`,q=this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveValue`,`element`,K);return getMessage(this,q,`Expected the element ${_} have value`,Y?X:`(any)`,`Received`,Z)}}}const counters=new Map([]);async function toMatchScreenshot(K,q,J=typeof q==`object`?q:{}){if(this.isNot)throw Error(`'toMatchScreenshot' cannot be used with "not"`);if(this.task===void 0||this.currentTestName===void 0)throw Error(`'toMatchScreenshot' cannot be used without test context`);let Y=`${this.task.result?.repeatCount??0}${this.testPath}${this.currentTestName}`,X=counters.get(Y);X===void 0&&(X={current:0},counters.set(Y,X)),X.current+=1;let Z=typeof q==`string`?q:`${this.currentTestName} ${X.current}`,Q=J.screenshotOptions&&`mask`in J.screenshotOptions?{...J,screenshotOptions:{...J.screenshotOptions,mask:J.screenshotOptions.mask.map(convertToSelector)}}:J,$=await getBrowserState().commands.triggerCommand(`__vitest_screenshotMatcher`,[Z,this.currentTestName,{element:convertToSelector(K),...Q}]);if($.pass===!1){let K=[];$.reference&&K.push({name:`reference`,...$.reference}),$.actual&&K.push({name:`actual`,...$.actual}),$.diff&&K.push({name:`diff
|
|
26
|
+
`)}function isSubset(_,K,q,J){let Y=Object.keys(_);return Y.length?Y.every(Y=>{let X=_[Y],Z=Y.startsWith(`--`),Q=[Y];return Z||Q.push(Y.toLowerCase()),Q.some(_=>{let Z=J.has(Y)&&usedValuesProps.has(Y)?K.style:q;return Z[_]===X||Z.getPropertyValue(_)===X})}):!1}function toHaveTextContent(_,K,q={normalizeWhitespace:!0}){let J=getNodeFromUserInput(_,toHaveTextContent,this),Y=q.normalizeWhitespace?normalize(J.textContent||``):(J.textContent||``).replace(/\u00A0/g,` `),X=Y!==``&&K===``;return{pass:!X&&matches(Y,K),message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveTextContent`,`element`,``),X?`Checking with empty string will always match, use .toBeEmptyDOMElement() instead`:`Expected element ${_} have text content`,K,`Received`,Y)}}}function toHaveValue(_,K){let q=getElementFromUserInput(_,toHaveValue,this);if(isInputElement(q)&&[`checkbox`,`radio`].includes(q.type))throw Error(`input with type=checkbox or type=radio cannot be used with .toHaveValue(). Use .toBeChecked() for type=checkbox or .toHaveFormValues() instead`);let J=getSingleElementValue(q),Y=K!==void 0,X=K,Z=J;return K==J&&K!==J&&(X=`${K} (${typeof K})`,Z=`${J} (${typeof J})`),{pass:Y?this.equals(J,K,[arrayAsSetComparison,...this.customTesters]):!!J,message:()=>{let _=this.isNot?`not to`:`to`,q=this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveValue`,`element`,K);return getMessage(this,q,`Expected the element ${_} have value`,Y?X:`(any)`,`Received`,Z)}}}const counters=new Map([]);async function toMatchScreenshot(K,q,J=typeof q==`object`?q:{}){if(this.isNot)throw Error(`'toMatchScreenshot' cannot be used with "not"`);if(this.task===void 0||this.currentTestName===void 0)throw Error(`'toMatchScreenshot' cannot be used without test context`);let Y=`${this.task.result?.repeatCount??0}${this.testPath}${this.currentTestName}`,X=counters.get(Y);X===void 0&&(X={current:0},counters.set(Y,X)),X.current+=1;let Z=typeof q==`string`?q:`${this.currentTestName} ${X.current}`,Q=J.screenshotOptions&&`mask`in J.screenshotOptions?{...J,screenshotOptions:{...J.screenshotOptions,mask:J.screenshotOptions.mask.map(convertToSelector)}}:J,$=await getBrowserState().commands.triggerCommand(`__vitest_screenshotMatcher`,[Z,this.currentTestName,{element:convertToSelector(K),...Q}]);if($.pass===!1){let K=[];$.reference&&K.push({name:`reference`,...$.reference}),$.actual&&K.push({name:`actual`,...$.actual}),$.diff&&K.push({name:`diff`,...$.diff}),K.length>0&&await recordArtifact(this.task,{type:`internal:toMatchScreenshot`,kind:`visual-regression`,message:$.message,attachments:K})}return{pass:$.pass,message:()=>$.pass?``:[this.utils.matcherHint(`toMatchScreenshot`,`element`,``),``,$.message,$.reference?`\nReference screenshot:\n ${this.utils.EXPECTED_COLOR($.reference.path)}`:null,$.actual?`\nActual screenshot:\n ${this.utils.RECEIVED_COLOR($.actual.path)}`:null,$.diff?this.utils.DIM_COLOR(`\nDiff image:\n ${$.diff.path}`):null,``].filter(_=>_!==null).join(`
|
|
27
27
|
`)}}const matchers={toBeDisabled,toBeEnabled,toBeEmptyDOMElement,toBeInTheDocument,toBeInViewport,toBeInvalid,toBeRequired,toBeValid,toBeVisible,toContainElement,toContainHTML,toHaveAccessibleDescription,toHaveAccessibleErrorMessage,toHaveAccessibleName,toHaveAttribute,toHaveClass,toHaveFocus,toHaveFormValues,toHaveStyle,toHaveTextContent,toHaveValue,toHaveDisplayValue,toBeChecked,toBePartiallyChecked,toHaveRole,toHaveSelection,toMatchScreenshot},kLocator=Symbol.for(`$$vitest:locator`);function element(_,Y){if(_!=null&&!(_ instanceof HTMLElement)&&!(_ instanceof SVGElement)&&!(kLocator in _))throw Error(`Invalid element or locator: ${_}. Expected an instance of HTMLElement, SVGElement or Locator, received ${getType(_)}`);let X=expect.poll(function(){if(_ instanceof Element||_==null)return _;let K=chai.util.flag(this,`negate`),J=chai.util.flag(this,`_name`);if(K&&J===`toBeInTheDocument`)return _.query();if(J===`toHaveLength`)return _.elements();if(J===`toMatchScreenshot`&&!chai.util.flag(this,`_poll.assert_once`)&&chai.util.flag(this,`_poll.assert_once`,!0),chai.util.flag(this,`_isLastPollAttempt`))return _.element();let Y=_.query();if(!Y)throw Error(`Cannot find element with locator: ${JSON.stringify(_)}`);return Y},processTimeoutOptions(Y));return chai.util.flag(X,`_poll.element`,!0),X}expect.extend(matchers),expect.element=element;
|