@playwright/test 1.31.2 → 1.32.0
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/lib/cli.js +12 -34
- package/lib/common/compilationCache.js +4 -2
- package/lib/common/configLoader.js +4 -1
- package/lib/common/fixtures.js +31 -2
- package/lib/common/globals.js +9 -0
- package/lib/common/process.js +15 -3
- package/lib/common/testType.js +2 -1
- package/lib/common/transform.js +0 -1
- package/lib/index.js +95 -56
- package/lib/isomorphic/folders.js +25 -0
- package/lib/isomorphic/teleReceiver.js +368 -0
- package/lib/matchers/expect.js +35 -16
- package/lib/matchers/matchers.js +48 -48
- package/lib/matchers/toBeTruthy.js +1 -1
- package/lib/matchers/toEqual.js +1 -4
- package/lib/matchers/toMatchSnapshot.js +3 -4
- package/lib/matchers/toMatchText.js +1 -1
- package/lib/plugins/vitePlugin.js +3 -2
- package/lib/reporters/base.js +6 -9
- package/lib/reporters/html.js +7 -2
- package/lib/reporters/json.js +2 -2
- package/lib/reporters/junit.js +2 -2
- package/lib/reporters/teleEmitter.js +209 -0
- package/lib/runner/dispatcher.js +15 -2
- package/lib/runner/loadUtils.js +168 -96
- package/lib/runner/loaderHost.js +2 -2
- package/lib/runner/processHost.js +16 -4
- package/lib/runner/reporters.js +3 -2
- package/lib/runner/runner.js +9 -1
- package/lib/runner/taskRunner.js +6 -8
- package/lib/runner/tasks.js +55 -46
- package/lib/runner/testGroups.js +15 -10
- package/lib/runner/uiMode.js +279 -0
- package/lib/runner/workerHost.js +7 -6
- package/lib/store.js +99 -0
- package/lib/util.js +23 -39
- package/lib/worker/fixtureRunner.js +3 -3
- package/lib/worker/testInfo.js +8 -3
- package/lib/worker/timeoutManager.js +11 -5
- package/lib/worker/workerMain.js +6 -3
- package/package.json +2 -2
- package/types/component.d.ts +1 -1
- package/types/reporterPrivate.ts +22 -0
- package/types/test.d.ts +18 -22
- package/types/testReporter.d.ts +5 -1
- package/lib/common/profiler.js +0 -53
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.baseFullConfig = exports.TeleTestCase = exports.TeleSuite = exports.TeleReporterReceiver = void 0;
|
|
7
|
+
exports.parseRegexPatterns = parseRegexPatterns;
|
|
8
|
+
exports.serializeRegexPatterns = serializeRegexPatterns;
|
|
9
|
+
/**
|
|
10
|
+
* Copyright (c) Microsoft Corporation.
|
|
11
|
+
*
|
|
12
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
13
|
+
* you may not use this file except in compliance with the License.
|
|
14
|
+
* You may obtain a copy of the License at
|
|
15
|
+
*
|
|
16
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
+
*
|
|
18
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
19
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
+
* See the License for the specific language governing permissions and
|
|
22
|
+
* limitations under the License.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
class TeleReporterReceiver {
|
|
26
|
+
constructor(reporter) {
|
|
27
|
+
this._rootSuite = void 0;
|
|
28
|
+
this._reporter = void 0;
|
|
29
|
+
this._tests = new Map();
|
|
30
|
+
this._rootSuite = new TeleSuite('', 'root');
|
|
31
|
+
this._reporter = reporter;
|
|
32
|
+
}
|
|
33
|
+
dispatch(message) {
|
|
34
|
+
const {
|
|
35
|
+
method,
|
|
36
|
+
params
|
|
37
|
+
} = message;
|
|
38
|
+
if (method === 'onBegin') {
|
|
39
|
+
this._onBegin(params.config, params.projects);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (method === 'onTestBegin') {
|
|
43
|
+
this._onTestBegin(params.testId, params.result);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (method === 'onTestEnd') {
|
|
47
|
+
this._onTestEnd(params.testId, params.result);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (method === 'onStepBegin') {
|
|
51
|
+
this._onStepBegin(params.testId, params.resultId, params.step);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (method === 'onStepEnd') {
|
|
55
|
+
this._onStepEnd(params.testId, params.resultId, params.step);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (method === 'onError') {
|
|
59
|
+
this._onError(params.error);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (method === 'onStdIO') {
|
|
63
|
+
this._onStdIO(params.type, params.testId, params.resultId, params.data, params.isBase64);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (method === 'onEnd') {
|
|
67
|
+
this._onEnd(params.result);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
_onBegin(config, projects) {
|
|
72
|
+
var _this$_reporter$onBeg, _this$_reporter;
|
|
73
|
+
const removeMissing = config.listOnly;
|
|
74
|
+
for (const project of projects) {
|
|
75
|
+
let projectSuite = this._rootSuite.suites.find(suite => suite.project().id === project.id);
|
|
76
|
+
if (!projectSuite) {
|
|
77
|
+
projectSuite = new TeleSuite(project.name, 'project');
|
|
78
|
+
this._rootSuite.suites.push(projectSuite);
|
|
79
|
+
projectSuite.parent = this._rootSuite;
|
|
80
|
+
}
|
|
81
|
+
const p = this._parseProject(project);
|
|
82
|
+
projectSuite.project = () => p;
|
|
83
|
+
this._mergeSuitesInto(project.suites, projectSuite, removeMissing);
|
|
84
|
+
}
|
|
85
|
+
(_this$_reporter$onBeg = (_this$_reporter = this._reporter).onBegin) === null || _this$_reporter$onBeg === void 0 ? void 0 : _this$_reporter$onBeg.call(_this$_reporter, this._parseConfig(config), this._rootSuite);
|
|
86
|
+
}
|
|
87
|
+
_onTestBegin(testId, payload) {
|
|
88
|
+
var _this$_reporter$onTes, _this$_reporter2;
|
|
89
|
+
const test = this._tests.get(testId);
|
|
90
|
+
const testResult = test._createTestResult(payload.id);
|
|
91
|
+
testResult.retry = payload.retry;
|
|
92
|
+
testResult.workerIndex = payload.workerIndex;
|
|
93
|
+
testResult.parallelIndex = payload.parallelIndex;
|
|
94
|
+
testResult.startTime = new Date(payload.startTime);
|
|
95
|
+
(_this$_reporter$onTes = (_this$_reporter2 = this._reporter).onTestBegin) === null || _this$_reporter$onTes === void 0 ? void 0 : _this$_reporter$onTes.call(_this$_reporter2, test, testResult);
|
|
96
|
+
}
|
|
97
|
+
_onTestEnd(testId, payload) {
|
|
98
|
+
var _this$_reporter$onTes2, _this$_reporter3;
|
|
99
|
+
const test = this._tests.get(testId);
|
|
100
|
+
const result = test.resultsMap.get(payload.id);
|
|
101
|
+
result.duration = payload.duration;
|
|
102
|
+
result.status = payload.status;
|
|
103
|
+
result.errors = payload.errors;
|
|
104
|
+
result.attachments = payload.attachments;
|
|
105
|
+
(_this$_reporter$onTes2 = (_this$_reporter3 = this._reporter).onTestEnd) === null || _this$_reporter$onTes2 === void 0 ? void 0 : _this$_reporter$onTes2.call(_this$_reporter3, test, result);
|
|
106
|
+
}
|
|
107
|
+
_onStepBegin(testId, resultId, payload) {
|
|
108
|
+
var _this$_reporter$onSte, _this$_reporter4;
|
|
109
|
+
const test = this._tests.get(testId);
|
|
110
|
+
const result = test.resultsMap.get(resultId);
|
|
111
|
+
const step = {
|
|
112
|
+
titlePath: () => [],
|
|
113
|
+
title: payload.title,
|
|
114
|
+
category: payload.category,
|
|
115
|
+
location: payload.location,
|
|
116
|
+
startTime: new Date(payload.startTime),
|
|
117
|
+
duration: 0,
|
|
118
|
+
steps: []
|
|
119
|
+
};
|
|
120
|
+
// TODO: implement nested steps.
|
|
121
|
+
result.stepMap.set(payload.id, step);
|
|
122
|
+
result.stepStack[result.stepStack.length - 1].steps.push(step);
|
|
123
|
+
result.stepStack.push(step);
|
|
124
|
+
(_this$_reporter$onSte = (_this$_reporter4 = this._reporter).onStepBegin) === null || _this$_reporter$onSte === void 0 ? void 0 : _this$_reporter$onSte.call(_this$_reporter4, test, result, step);
|
|
125
|
+
}
|
|
126
|
+
_onStepEnd(testId, resultId, payload) {
|
|
127
|
+
var _this$_reporter$onSte2, _this$_reporter5;
|
|
128
|
+
const test = this._tests.get(testId);
|
|
129
|
+
const result = test.resultsMap.get(resultId);
|
|
130
|
+
const step = result.stepMap.get(payload.id);
|
|
131
|
+
const i = result.stepStack.indexOf(step);
|
|
132
|
+
if (i !== -1) result.stepStack.splice(i, 1);
|
|
133
|
+
step.duration = payload.duration;
|
|
134
|
+
step.error = payload.error;
|
|
135
|
+
(_this$_reporter$onSte2 = (_this$_reporter5 = this._reporter).onStepEnd) === null || _this$_reporter$onSte2 === void 0 ? void 0 : _this$_reporter$onSte2.call(_this$_reporter5, test, result, step);
|
|
136
|
+
}
|
|
137
|
+
_onError(error) {
|
|
138
|
+
var _this$_reporter$onErr, _this$_reporter6;
|
|
139
|
+
(_this$_reporter$onErr = (_this$_reporter6 = this._reporter).onError) === null || _this$_reporter$onErr === void 0 ? void 0 : _this$_reporter$onErr.call(_this$_reporter6, error);
|
|
140
|
+
}
|
|
141
|
+
_onStdIO(type, testId, resultId, data, isBase64) {
|
|
142
|
+
var _this$_reporter$onStd, _this$_reporter7, _this$_reporter$onStd2, _this$_reporter8;
|
|
143
|
+
const chunk = isBase64 ? Buffer.from(data, 'base64') : data;
|
|
144
|
+
const test = testId ? this._tests.get(testId) : undefined;
|
|
145
|
+
const result = test && resultId ? test.resultsMap.get(resultId) : undefined;
|
|
146
|
+
if (type === 'stdout') (_this$_reporter$onStd = (_this$_reporter7 = this._reporter).onStdOut) === null || _this$_reporter$onStd === void 0 ? void 0 : _this$_reporter$onStd.call(_this$_reporter7, chunk, test, result);else (_this$_reporter$onStd2 = (_this$_reporter8 = this._reporter).onStdErr) === null || _this$_reporter$onStd2 === void 0 ? void 0 : _this$_reporter$onStd2.call(_this$_reporter8, chunk, test, result);
|
|
147
|
+
}
|
|
148
|
+
_onEnd(result) {
|
|
149
|
+
var _this$_reporter$onEnd, _this$_reporter9;
|
|
150
|
+
(_this$_reporter$onEnd = (_this$_reporter9 = this._reporter).onEnd) === null || _this$_reporter$onEnd === void 0 ? void 0 : _this$_reporter$onEnd.call(_this$_reporter9, result);
|
|
151
|
+
}
|
|
152
|
+
_parseConfig(config) {
|
|
153
|
+
const fullConfig = baseFullConfig;
|
|
154
|
+
fullConfig.rootDir = config.rootDir;
|
|
155
|
+
fullConfig.configFile = config.configFile;
|
|
156
|
+
return fullConfig;
|
|
157
|
+
}
|
|
158
|
+
_parseProject(project) {
|
|
159
|
+
return {
|
|
160
|
+
id: project.id,
|
|
161
|
+
metadata: project.metadata,
|
|
162
|
+
name: project.name,
|
|
163
|
+
outputDir: project.outputDir,
|
|
164
|
+
repeatEach: project.repeatEach,
|
|
165
|
+
retries: project.retries,
|
|
166
|
+
testDir: project.testDir,
|
|
167
|
+
testIgnore: parseRegexPatterns(project.testIgnore),
|
|
168
|
+
testMatch: parseRegexPatterns(project.testMatch),
|
|
169
|
+
timeout: project.timeout,
|
|
170
|
+
grep: parseRegexPatterns(project.grep),
|
|
171
|
+
grepInvert: parseRegexPatterns(project.grepInvert),
|
|
172
|
+
dependencies: project.dependencies,
|
|
173
|
+
snapshotDir: project.snapshotDir,
|
|
174
|
+
use: {}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
_mergeSuitesInto(jsonSuites, parent, removeMissing) {
|
|
178
|
+
for (const jsonSuite of jsonSuites) {
|
|
179
|
+
let targetSuite = parent.suites.find(s => s.title === jsonSuite.title);
|
|
180
|
+
if (!targetSuite) {
|
|
181
|
+
targetSuite = new TeleSuite(jsonSuite.title, jsonSuite.type);
|
|
182
|
+
targetSuite.parent = parent;
|
|
183
|
+
parent.suites.push(targetSuite);
|
|
184
|
+
}
|
|
185
|
+
targetSuite.location = jsonSuite.location;
|
|
186
|
+
targetSuite._fileId = jsonSuite.fileId;
|
|
187
|
+
targetSuite._parallelMode = jsonSuite.parallelMode;
|
|
188
|
+
this._mergeSuitesInto(jsonSuite.suites, targetSuite, removeMissing);
|
|
189
|
+
this._mergeTestsInto(jsonSuite.tests, targetSuite, removeMissing);
|
|
190
|
+
}
|
|
191
|
+
if (removeMissing) {
|
|
192
|
+
const suiteMap = new Map(parent.suites.map(p => [p.title, p]));
|
|
193
|
+
parent.suites = jsonSuites.map(s => suiteMap.get(s.title)).filter(Boolean);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
_mergeTestsInto(jsonTests, parent, removeMissing) {
|
|
197
|
+
for (const jsonTest of jsonTests) {
|
|
198
|
+
let targetTest = parent.tests.find(s => s.title === jsonTest.title);
|
|
199
|
+
if (!targetTest) {
|
|
200
|
+
targetTest = new TeleTestCase(jsonTest.testId, jsonTest.title, jsonTest.location);
|
|
201
|
+
targetTest.parent = parent;
|
|
202
|
+
parent.tests.push(targetTest);
|
|
203
|
+
this._tests.set(targetTest.id, targetTest);
|
|
204
|
+
}
|
|
205
|
+
this._updateTest(jsonTest, targetTest);
|
|
206
|
+
}
|
|
207
|
+
if (removeMissing) {
|
|
208
|
+
const testMap = new Map(parent.tests.map(p => [p.title, p]));
|
|
209
|
+
parent.tests = jsonTests.map(s => testMap.get(s.title)).filter(Boolean);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
_updateTest(payload, test) {
|
|
213
|
+
test.id = payload.testId;
|
|
214
|
+
test.expectedStatus = payload.expectedStatus;
|
|
215
|
+
test.timeout = payload.timeout;
|
|
216
|
+
test.location = payload.location;
|
|
217
|
+
test.annotations = payload.annotations;
|
|
218
|
+
test.retries = payload.retries;
|
|
219
|
+
return test;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
exports.TeleReporterReceiver = TeleReporterReceiver;
|
|
223
|
+
class TeleSuite {
|
|
224
|
+
constructor(title, type) {
|
|
225
|
+
this.title = void 0;
|
|
226
|
+
this.location = void 0;
|
|
227
|
+
this.parent = void 0;
|
|
228
|
+
this._requireFile = '';
|
|
229
|
+
this.suites = [];
|
|
230
|
+
this.tests = [];
|
|
231
|
+
this._timeout = void 0;
|
|
232
|
+
this._retries = void 0;
|
|
233
|
+
this._fileId = void 0;
|
|
234
|
+
this._parallelMode = 'default';
|
|
235
|
+
this._type = void 0;
|
|
236
|
+
this.title = title;
|
|
237
|
+
this._type = type;
|
|
238
|
+
}
|
|
239
|
+
allTests() {
|
|
240
|
+
const result = [];
|
|
241
|
+
const visit = suite => {
|
|
242
|
+
for (const entry of [...suite.suites, ...suite.tests]) {
|
|
243
|
+
if (entry instanceof TeleSuite) visit(entry);else result.push(entry);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
visit(this);
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
titlePath() {
|
|
250
|
+
const titlePath = this.parent ? this.parent.titlePath() : [];
|
|
251
|
+
// Ignore anonymous describe blocks.
|
|
252
|
+
if (this.title || this._type !== 'describe') titlePath.push(this.title);
|
|
253
|
+
return titlePath;
|
|
254
|
+
}
|
|
255
|
+
project() {
|
|
256
|
+
return undefined;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
exports.TeleSuite = TeleSuite;
|
|
260
|
+
class TeleTestCase {
|
|
261
|
+
constructor(id, title, location) {
|
|
262
|
+
this.title = void 0;
|
|
263
|
+
this.fn = () => {};
|
|
264
|
+
this.results = [];
|
|
265
|
+
this.location = void 0;
|
|
266
|
+
this.parent = void 0;
|
|
267
|
+
this.expectedStatus = 'passed';
|
|
268
|
+
this.timeout = 0;
|
|
269
|
+
this.annotations = [];
|
|
270
|
+
this.retries = 0;
|
|
271
|
+
this.repeatEachIndex = 0;
|
|
272
|
+
this.id = void 0;
|
|
273
|
+
this.resultsMap = new Map();
|
|
274
|
+
this.id = id;
|
|
275
|
+
this.title = title;
|
|
276
|
+
this.location = location;
|
|
277
|
+
}
|
|
278
|
+
titlePath() {
|
|
279
|
+
const titlePath = this.parent ? this.parent.titlePath() : [];
|
|
280
|
+
titlePath.push(this.title);
|
|
281
|
+
return titlePath;
|
|
282
|
+
}
|
|
283
|
+
outcome() {
|
|
284
|
+
const nonSkipped = this.results.filter(result => result.status !== 'skipped' && result.status !== 'interrupted');
|
|
285
|
+
if (!nonSkipped.length) return 'skipped';
|
|
286
|
+
if (nonSkipped.every(result => result.status === this.expectedStatus)) return 'expected';
|
|
287
|
+
if (nonSkipped.some(result => result.status === this.expectedStatus)) return 'flaky';
|
|
288
|
+
return 'unexpected';
|
|
289
|
+
}
|
|
290
|
+
ok() {
|
|
291
|
+
const status = this.outcome();
|
|
292
|
+
return status === 'expected' || status === 'flaky' || status === 'skipped';
|
|
293
|
+
}
|
|
294
|
+
_clearResults() {
|
|
295
|
+
this.results = [];
|
|
296
|
+
this.resultsMap.clear();
|
|
297
|
+
}
|
|
298
|
+
_createTestResult(id) {
|
|
299
|
+
this._clearResults();
|
|
300
|
+
const result = {
|
|
301
|
+
retry: this.results.length,
|
|
302
|
+
parallelIndex: -1,
|
|
303
|
+
workerIndex: -1,
|
|
304
|
+
duration: -1,
|
|
305
|
+
startTime: new Date(),
|
|
306
|
+
stdout: [],
|
|
307
|
+
stderr: [],
|
|
308
|
+
attachments: [],
|
|
309
|
+
status: 'skipped',
|
|
310
|
+
steps: [],
|
|
311
|
+
errors: [],
|
|
312
|
+
stepMap: new Map(),
|
|
313
|
+
stepStack: []
|
|
314
|
+
};
|
|
315
|
+
result.stepStack.push(result);
|
|
316
|
+
this.results.push(result);
|
|
317
|
+
this.resultsMap.set(id, result);
|
|
318
|
+
return result;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
exports.TeleTestCase = TeleTestCase;
|
|
322
|
+
const baseFullConfig = {
|
|
323
|
+
forbidOnly: false,
|
|
324
|
+
fullyParallel: false,
|
|
325
|
+
globalSetup: null,
|
|
326
|
+
globalTeardown: null,
|
|
327
|
+
globalTimeout: 0,
|
|
328
|
+
grep: /.*/,
|
|
329
|
+
grepInvert: null,
|
|
330
|
+
maxFailures: 0,
|
|
331
|
+
metadata: {},
|
|
332
|
+
preserveOutput: 'always',
|
|
333
|
+
projects: [],
|
|
334
|
+
reporter: [[process.env.CI ? 'dot' : 'list']],
|
|
335
|
+
reportSlowTests: {
|
|
336
|
+
max: 5,
|
|
337
|
+
threshold: 15000
|
|
338
|
+
},
|
|
339
|
+
configFile: '',
|
|
340
|
+
rootDir: '',
|
|
341
|
+
quiet: false,
|
|
342
|
+
shard: null,
|
|
343
|
+
updateSnapshots: 'missing',
|
|
344
|
+
version: '',
|
|
345
|
+
workers: 0,
|
|
346
|
+
webServer: null
|
|
347
|
+
};
|
|
348
|
+
exports.baseFullConfig = baseFullConfig;
|
|
349
|
+
function serializeRegexPatterns(patterns) {
|
|
350
|
+
if (!Array.isArray(patterns)) patterns = [patterns];
|
|
351
|
+
return patterns.map(s => {
|
|
352
|
+
if (typeof s === 'string') return {
|
|
353
|
+
s
|
|
354
|
+
};
|
|
355
|
+
return {
|
|
356
|
+
r: {
|
|
357
|
+
source: s.source,
|
|
358
|
+
flags: s.flags
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
function parseRegexPatterns(patterns) {
|
|
364
|
+
return patterns.map(p => {
|
|
365
|
+
if (p.s) return p.s;
|
|
366
|
+
return new RegExp(p.r.source, p.r.flags);
|
|
367
|
+
});
|
|
368
|
+
}
|
package/lib/matchers/expect.js
CHANGED
|
@@ -5,13 +5,11 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.printReceivedStringContainExpectedSubstring = exports.printReceivedStringContainExpectedResult = exports.expect = void 0;
|
|
7
7
|
var _utils = require("playwright-core/lib/utils");
|
|
8
|
-
var _path = _interopRequireDefault(require("path"));
|
|
9
8
|
var _matchers = require("./matchers");
|
|
10
9
|
var _toMatchSnapshot = require("./toMatchSnapshot");
|
|
11
10
|
var _globals = require("../common/globals");
|
|
12
11
|
var _util = require("../util");
|
|
13
12
|
var _expectBundle = require("../common/expectBundle");
|
|
14
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
13
|
/**
|
|
16
14
|
* Copyright Microsoft Corporation. All rights reserved.
|
|
17
15
|
*
|
|
@@ -40,6 +38,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
40
38
|
// Format substring but do not enclose in double quote marks.
|
|
41
39
|
// The replacement is compatible with pretty-format package.
|
|
42
40
|
const printSubstring = val => val.replace(/"|\\/g, '\\$&');
|
|
41
|
+
let lastCallId = 0;
|
|
43
42
|
const printReceivedStringContainExpectedSubstring = (received, start, length // not end
|
|
44
43
|
) => (0, _expectBundle.RECEIVED_COLOR)('"' + printSubstring(received.slice(0, start)) + (0, _expectBundle.INVERTED_COLOR)(printSubstring(received.slice(start, start + length))) + printSubstring(received.slice(start + length)) + '"');
|
|
45
44
|
exports.printReceivedStringContainExpectedSubstring = printReceivedStringContainExpectedSubstring;
|
|
@@ -102,7 +101,8 @@ class ExpectMetaInfoProxyHandler {
|
|
|
102
101
|
isSoft,
|
|
103
102
|
isPoll,
|
|
104
103
|
generator,
|
|
105
|
-
isNot: false
|
|
104
|
+
isNot: false,
|
|
105
|
+
nameTokens: []
|
|
106
106
|
};
|
|
107
107
|
if (typeof messageOrOptions === 'string') {
|
|
108
108
|
this._info.message = messageOrOptions;
|
|
@@ -114,6 +114,7 @@ class ExpectMetaInfoProxyHandler {
|
|
|
114
114
|
}
|
|
115
115
|
get(target, matcherName, receiver) {
|
|
116
116
|
let matcher = Reflect.get(target, matcherName, receiver);
|
|
117
|
+
if (typeof matcherName !== 'string') return matcher;
|
|
117
118
|
if (matcher === undefined) throw new Error(`expect: Property '${matcherName}' not found.`);
|
|
118
119
|
if (typeof matcher !== 'function') {
|
|
119
120
|
if (matcherName === 'not') this._info.isNot = !this._info.isNot;
|
|
@@ -128,23 +129,23 @@ class ExpectMetaInfoProxyHandler {
|
|
|
128
129
|
return (...args) => {
|
|
129
130
|
const testInfo = (0, _globals.currentTestInfo)();
|
|
130
131
|
if (!testInfo) return matcher.call(target, ...args);
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
const frame = stackTrace.frames[0];
|
|
132
|
+
const rawStack = (0, _utils.captureRawStack)();
|
|
133
|
+
const stackFrames = (0, _util.filteredStackTrace)(rawStack);
|
|
134
134
|
const customMessage = this._info.message || '';
|
|
135
135
|
const defaultTitle = `expect${this._info.isPoll ? '.poll' : ''}${this._info.isSoft ? '.soft' : ''}${this._info.isNot ? '.not' : ''}.${matcherName}`;
|
|
136
|
+
const wallTime = Date.now();
|
|
136
137
|
const step = testInfo._addStep({
|
|
137
|
-
location:
|
|
138
|
-
file: _path.default.resolve(process.cwd(), frame.file),
|
|
139
|
-
line: frame.line || 0,
|
|
140
|
-
column: frame.column || 0
|
|
141
|
-
} : undefined,
|
|
138
|
+
location: stackFrames[0],
|
|
142
139
|
category: 'expect',
|
|
143
140
|
title: (0, _util.trimLongString)(customMessage || defaultTitle, 1024),
|
|
144
141
|
canHaveChildren: true,
|
|
145
|
-
forceNoParent: false
|
|
142
|
+
forceNoParent: false,
|
|
143
|
+
wallTime
|
|
146
144
|
});
|
|
147
145
|
testInfo.currentStep = step;
|
|
146
|
+
const generateTraceEvent = matcherName !== 'poll' && matcherName !== 'toPass';
|
|
147
|
+
const callId = ++lastCallId;
|
|
148
|
+
if (generateTraceEvent) testInfo._traceEvents.push((0, _utils.createBeforeActionTraceEventForExpect)(`expect@${callId}`, defaultTitle, args[0], stackFrames));
|
|
148
149
|
const reportStepError = jestError => {
|
|
149
150
|
const message = jestError.message;
|
|
150
151
|
if (customMessage) {
|
|
@@ -156,19 +157,37 @@ class ExpectMetaInfoProxyHandler {
|
|
|
156
157
|
// if there's a newline after the matcher text, then remove it as well.
|
|
157
158
|
if (uselessMatcherLineIndex + 1 < messageLines.length && messageLines[uselessMatcherLineIndex + 1].trim() === '') messageLines.splice(uselessMatcherLineIndex, 2);else messageLines.splice(uselessMatcherLineIndex, 1);
|
|
158
159
|
}
|
|
159
|
-
const newMessage = [
|
|
160
|
+
const newMessage = [customMessage, '', ...messageLines].join('\n');
|
|
160
161
|
jestError.message = newMessage;
|
|
161
|
-
jestError.stack = newMessage + '\n' +
|
|
162
|
+
jestError.stack = jestError.name + ': ' + newMessage + '\n' + (0, _util.stringifyStackFrames)(stackFrames).join('\n');
|
|
162
163
|
}
|
|
163
164
|
const serializerError = (0, _util.serializeError)(jestError);
|
|
165
|
+
if (generateTraceEvent) {
|
|
166
|
+
const error = {
|
|
167
|
+
name: jestError.name,
|
|
168
|
+
message: jestError.message,
|
|
169
|
+
stack: jestError.stack
|
|
170
|
+
};
|
|
171
|
+
testInfo._traceEvents.push((0, _utils.createAfterActionTraceEventForExpect)(`expect@${callId}`, error));
|
|
172
|
+
}
|
|
164
173
|
step.complete({
|
|
165
174
|
error: serializerError
|
|
166
175
|
});
|
|
167
176
|
if (this._info.isSoft) testInfo._failWithError(serializerError, false /* isHardError */);else throw jestError;
|
|
168
177
|
};
|
|
178
|
+
const finalizer = () => {
|
|
179
|
+
if (generateTraceEvent) testInfo._traceEvents.push((0, _utils.createAfterActionTraceEventForExpect)(`expect@${callId}`));
|
|
180
|
+
step.complete({});
|
|
181
|
+
};
|
|
169
182
|
try {
|
|
170
|
-
const
|
|
171
|
-
|
|
183
|
+
const expectZone = {
|
|
184
|
+
title: defaultTitle,
|
|
185
|
+
wallTime
|
|
186
|
+
};
|
|
187
|
+
const result = _utils.zones.run('expectZone', expectZone, () => {
|
|
188
|
+
return matcher.call(target, ...args);
|
|
189
|
+
});
|
|
190
|
+
if (result instanceof Promise) return result.then(() => finalizer()).catch(reportStepError);else finalizer();
|
|
172
191
|
} catch (e) {
|
|
173
192
|
reportStepError(e);
|
|
174
193
|
}
|