ScuttleBot

Blame History Raw 312 lines
1
"use strict";
2
var __defProp = Object.defineProperty;
3
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
var __getOwnPropNames = Object.getOwnPropertyNames;
5
var __hasOwnProp = Object.prototype.hasOwnProperty;
6
var __export = (target, all) => {
7
for (var name in all)
8
__defProp(target, name, { get: all[name], enumerable: true });
9
};
10
var __copyProps = (to, from, except, desc) => {
11
if (from && typeof from === "object" || typeof from === "function") {
12
for (let key of __getOwnPropNames(from))
13
if (!__hasOwnProp.call(to, key) && key !== except)
14
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
}
16
return to;
17
};
18
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
var expect_exports = {};
20
__export(expect_exports, {
21
expect: () => expect,
22
mergeExpects: () => mergeExpects
23
});
24
module.exports = __toCommonJS(expect_exports);
25
var import_utils = require("playwright-core/lib/utils");
26
var import_matcherHint = require("./matcherHint");
27
var import_matchers = require("./matchers");
28
var import_toMatchAriaSnapshot = require("./toMatchAriaSnapshot");
29
var import_toMatchSnapshot = require("./toMatchSnapshot");
30
var import_expectBundle = require("../common/expectBundle");
31
var import_globals = require("../common/globals");
32
var import_util = require("../util");
33
var import_testInfo = require("../worker/testInfo");
34
function createMatchers(actual, info, prefix) {
35
return new Proxy((0, import_expectBundle.expect)(actual), new ExpectMetaInfoProxyHandler(actual, info, prefix));
36
}
37
const userMatchersSymbol = Symbol("userMatchers");
38
function qualifiedMatcherName(qualifier, matcherName) {
39
return qualifier.join(":") + "$" + matcherName;
40
}
41
function createExpect(info, prefix, userMatchers) {
42
const expectInstance = new Proxy(import_expectBundle.expect, {
43
apply: function(target, thisArg, argumentsList) {
44
const [actual, messageOrOptions] = argumentsList;
45
const message = (0, import_utils.isString)(messageOrOptions) ? messageOrOptions : messageOrOptions?.message || info.message;
46
const newInfo = { ...info, message };
47
if (newInfo.poll) {
48
if (typeof actual !== "function")
49
throw new Error("`expect.poll()` accepts only function as a first argument");
50
newInfo.poll.generator = actual;
51
}
52
return createMatchers(actual, newInfo, prefix);
53
},
54
get: function(target, property) {
55
if (property === "configure")
56
return configure;
57
if (property === "extend") {
58
return (matchers) => {
59
const qualifier = [...prefix, (0, import_utils.createGuid)()];
60
const wrappedMatchers = {};
61
for (const [name, matcher] of Object.entries(matchers)) {
62
wrappedMatchers[name] = wrapPlaywrightMatcherToPassNiceThis(matcher);
63
const key = qualifiedMatcherName(qualifier, name);
64
wrappedMatchers[key] = wrappedMatchers[name];
65
Object.defineProperty(wrappedMatchers[key], "name", { value: name });
66
}
67
import_expectBundle.expect.extend(wrappedMatchers);
68
return createExpect(info, qualifier, { ...userMatchers, ...matchers });
69
};
70
}
71
if (property === "soft") {
72
return (actual, messageOrOptions) => {
73
return configure({ soft: true })(actual, messageOrOptions);
74
};
75
}
76
if (property === userMatchersSymbol)
77
return userMatchers;
78
if (property === "poll") {
79
return (actual, messageOrOptions) => {
80
const poll = (0, import_utils.isString)(messageOrOptions) ? {} : messageOrOptions || {};
81
return configure({ _poll: poll })(actual, messageOrOptions);
82
};
83
}
84
return import_expectBundle.expect[property];
85
}
86
});
87
const configure = (configuration) => {
88
const newInfo = { ...info };
89
if ("message" in configuration)
90
newInfo.message = configuration.message;
91
if ("timeout" in configuration)
92
newInfo.timeout = configuration.timeout;
93
if ("soft" in configuration)
94
newInfo.isSoft = configuration.soft;
95
if ("_poll" in configuration) {
96
newInfo.poll = configuration._poll ? { ...info.poll, generator: () => {
97
} } : void 0;
98
if (typeof configuration._poll === "object") {
99
newInfo.poll.timeout = configuration._poll.timeout ?? newInfo.poll.timeout;
100
newInfo.poll.intervals = configuration._poll.intervals ?? newInfo.poll.intervals;
101
}
102
}
103
return createExpect(newInfo, prefix, userMatchers);
104
};
105
return expectInstance;
106
}
107
let matcherCallContext;
108
function setMatcherCallContext(context) {
109
matcherCallContext = context;
110
}
111
function takeMatcherCallContext() {
112
try {
113
return matcherCallContext;
114
} finally {
115
matcherCallContext = void 0;
116
}
117
}
118
const defaultExpectTimeout = 5e3;
119
function wrapPlaywrightMatcherToPassNiceThis(matcher) {
120
return function(...args) {
121
const { isNot, promise, utils } = this;
122
const context = takeMatcherCallContext();
123
const timeout = context?.expectInfo.timeout ?? context?.testInfo?._projectInternal?.expect?.timeout ?? defaultExpectTimeout;
124
const newThis = {
125
isNot,
126
promise,
127
utils,
128
timeout,
129
_stepInfo: context?.step
130
};
131
newThis.equals = throwUnsupportedExpectMatcherError;
132
return matcher.call(newThis, ...args);
133
};
134
}
135
function throwUnsupportedExpectMatcherError() {
136
throw new Error("It looks like you are using custom expect matchers that are not compatible with Playwright. See https://aka.ms/playwright/expect-compatibility");
137
}
138
import_expectBundle.expect.setState({ expand: false });
139
const customAsyncMatchers = {
140
toBeAttached: import_matchers.toBeAttached,
141
toBeChecked: import_matchers.toBeChecked,
142
toBeDisabled: import_matchers.toBeDisabled,
143
toBeEditable: import_matchers.toBeEditable,
144
toBeEmpty: import_matchers.toBeEmpty,
145
toBeEnabled: import_matchers.toBeEnabled,
146
toBeFocused: import_matchers.toBeFocused,
147
toBeHidden: import_matchers.toBeHidden,
148
toBeInViewport: import_matchers.toBeInViewport,
149
toBeOK: import_matchers.toBeOK,
150
toBeVisible: import_matchers.toBeVisible,
151
toContainText: import_matchers.toContainText,
152
toContainClass: import_matchers.toContainClass,
153
toHaveAccessibleDescription: import_matchers.toHaveAccessibleDescription,
154
toHaveAccessibleName: import_matchers.toHaveAccessibleName,
155
toHaveAccessibleErrorMessage: import_matchers.toHaveAccessibleErrorMessage,
156
toHaveAttribute: import_matchers.toHaveAttribute,
157
toHaveClass: import_matchers.toHaveClass,
158
toHaveCount: import_matchers.toHaveCount,
159
toHaveCSS: import_matchers.toHaveCSS,
160
toHaveId: import_matchers.toHaveId,
161
toHaveJSProperty: import_matchers.toHaveJSProperty,
162
toHaveRole: import_matchers.toHaveRole,
163
toHaveText: import_matchers.toHaveText,
164
toHaveTitle: import_matchers.toHaveTitle,
165
toHaveURL: import_matchers.toHaveURL,
166
toHaveValue: import_matchers.toHaveValue,
167
toHaveValues: import_matchers.toHaveValues,
168
toHaveScreenshot: import_toMatchSnapshot.toHaveScreenshot,
169
toMatchAriaSnapshot: import_toMatchAriaSnapshot.toMatchAriaSnapshot,
170
toPass: import_matchers.toPass
171
};
172
const customMatchers = {
173
...customAsyncMatchers,
174
toMatchSnapshot: import_toMatchSnapshot.toMatchSnapshot
175
};
176
class ExpectMetaInfoProxyHandler {
177
constructor(actual, info, prefix) {
178
this._actual = actual;
179
this._info = { ...info };
180
this._prefix = prefix;
181
}
182
get(target, matcherName, receiver) {
183
if (matcherName === "toThrowError")
184
matcherName = "toThrow";
185
let matcher = Reflect.get(target, matcherName, receiver);
186
if (typeof matcherName !== "string")
187
return matcher;
188
let resolvedMatcherName = matcherName;
189
for (let i = this._prefix.length; i > 0; i--) {
190
const qualifiedName = qualifiedMatcherName(this._prefix.slice(0, i), matcherName);
191
if (Reflect.has(target, qualifiedName)) {
192
matcher = Reflect.get(target, qualifiedName, receiver);
193
resolvedMatcherName = qualifiedName;
194
break;
195
}
196
}
197
if (matcher === void 0)
198
throw new Error(`expect: Property '${matcherName}' not found.`);
199
if (typeof matcher !== "function") {
200
if (matcherName === "not")
201
this._info.isNot = !this._info.isNot;
202
return new Proxy(matcher, this);
203
}
204
if (this._info.poll) {
205
if (customAsyncMatchers[matcherName] || matcherName === "resolves" || matcherName === "rejects")
206
throw new Error(`\`expect.poll()\` does not support "${matcherName}" matcher.`);
207
matcher = (...args) => pollMatcher(resolvedMatcherName, this._info, this._prefix, ...args);
208
}
209
return (...args) => {
210
const testInfo = (0, import_globals.currentTestInfo)();
211
setMatcherCallContext({ expectInfo: this._info, testInfo });
212
if (!testInfo)
213
return matcher.call(target, ...args);
214
const customMessage = this._info.message || "";
215
const suffixes = (0, import_matchers.computeMatcherTitleSuffix)(matcherName, this._actual, args);
216
const defaultTitle = `${this._info.poll ? "poll " : ""}${this._info.isSoft ? "soft " : ""}${this._info.isNot ? "not " : ""}${matcherName}${suffixes.short || ""}`;
217
const shortTitle = customMessage || `Expect ${(0, import_utils.escapeWithQuotes)(defaultTitle, '"')}`;
218
const longTitle = shortTitle + (suffixes.long || "");
219
const apiName = `expect${this._info.poll ? ".poll " : ""}${this._info.isSoft ? ".soft " : ""}${this._info.isNot ? ".not" : ""}.${matcherName}${suffixes.short || ""}`;
220
const stackFrames = (0, import_util.filteredStackTrace)((0, import_utils.captureRawStack)());
221
const stepInfo = {
222
category: "expect",
223
apiName,
224
title: longTitle,
225
shortTitle,
226
params: args[0] ? { expected: args[0] } : void 0,
227
infectParentStepsWithError: this._info.isSoft
228
};
229
const step = testInfo._addStep(stepInfo);
230
const reportStepError = (e) => {
231
const jestError = (0, import_matcherHint.isJestError)(e) ? e : null;
232
const expectError = jestError ? new import_matcherHint.ExpectError(jestError, customMessage, stackFrames) : void 0;
233
if (jestError?.matcherResult.suggestedRebaseline) {
234
step.complete({ suggestedRebaseline: jestError?.matcherResult.suggestedRebaseline });
235
return;
236
}
237
const error = expectError ?? e;
238
step.complete({ error });
239
if (this._info.isSoft)
240
testInfo._failWithError(error);
241
else
242
throw error;
243
};
244
const finalizer = () => {
245
step.complete({});
246
};
247
try {
248
setMatcherCallContext({ expectInfo: this._info, testInfo, step: step.info });
249
const callback = () => matcher.call(target, ...args);
250
const result = (0, import_utils.currentZone)().with("stepZone", step).run(callback);
251
if (result instanceof Promise)
252
return result.then(finalizer).catch(reportStepError);
253
finalizer();
254
return result;
255
} catch (e) {
256
void reportStepError(e);
257
}
258
};
259
}
260
}
261
async function pollMatcher(qualifiedMatcherName2, info, prefix, ...args) {
262
const testInfo = (0, import_globals.currentTestInfo)();
263
const poll = info.poll;
264
const timeout = poll.timeout ?? info.timeout ?? testInfo?._projectInternal?.expect?.timeout ?? defaultExpectTimeout;
265
const { deadline, timeoutMessage } = testInfo ? testInfo._deadlineForMatcher(timeout) : import_testInfo.TestInfoImpl._defaultDeadlineForMatcher(timeout);
266
const result = await (0, import_utils.pollAgainstDeadline)(async () => {
267
if (testInfo && (0, import_globals.currentTestInfo)() !== testInfo)
268
return { continuePolling: false, result: void 0 };
269
const innerInfo = {
270
...info,
271
isSoft: false,
272
// soft is outside of poll, not inside
273
poll: void 0
274
};
275
const value = await poll.generator();
276
try {
277
let matchers = createMatchers(value, innerInfo, prefix);
278
if (info.isNot)
279
matchers = matchers.not;
280
matchers[qualifiedMatcherName2](...args);
281
return { continuePolling: false, result: void 0 };
282
} catch (error) {
283
return { continuePolling: true, result: error };
284
}
285
}, deadline, poll.intervals ?? [100, 250, 500, 1e3]);
286
if (result.timedOut) {
287
const message = result.result ? [
288
result.result.message,
289
"",
290
`Call Log:`,
291
`- ${timeoutMessage}`
292
].join("\n") : timeoutMessage;
293
throw new Error(message);
294
}
295
}
296
const expect = createExpect({}, [], {}).extend(customMatchers);
297
function mergeExpects(...expects) {
298
let merged = expect;
299
for (const e of expects) {
300
const internals = e[userMatchersSymbol];
301
if (!internals)
302
continue;
303
merged = merged.extend(internals);
304
}
305
return merged;
306
}
307
// Annotate the CommonJS export names for ESM import in node:
308
0 && (module.exports = {
309
expect,
310
mergeExpects
311
});
312

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button