@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.
Files changed (46) hide show
  1. package/lib/cli.js +12 -34
  2. package/lib/common/compilationCache.js +4 -2
  3. package/lib/common/configLoader.js +4 -1
  4. package/lib/common/fixtures.js +31 -2
  5. package/lib/common/globals.js +9 -0
  6. package/lib/common/process.js +15 -3
  7. package/lib/common/testType.js +2 -1
  8. package/lib/common/transform.js +0 -1
  9. package/lib/index.js +95 -56
  10. package/lib/isomorphic/folders.js +25 -0
  11. package/lib/isomorphic/teleReceiver.js +368 -0
  12. package/lib/matchers/expect.js +35 -16
  13. package/lib/matchers/matchers.js +48 -48
  14. package/lib/matchers/toBeTruthy.js +1 -1
  15. package/lib/matchers/toEqual.js +1 -4
  16. package/lib/matchers/toMatchSnapshot.js +3 -4
  17. package/lib/matchers/toMatchText.js +1 -1
  18. package/lib/plugins/vitePlugin.js +3 -2
  19. package/lib/reporters/base.js +6 -9
  20. package/lib/reporters/html.js +7 -2
  21. package/lib/reporters/json.js +2 -2
  22. package/lib/reporters/junit.js +2 -2
  23. package/lib/reporters/teleEmitter.js +209 -0
  24. package/lib/runner/dispatcher.js +15 -2
  25. package/lib/runner/loadUtils.js +168 -96
  26. package/lib/runner/loaderHost.js +2 -2
  27. package/lib/runner/processHost.js +16 -4
  28. package/lib/runner/reporters.js +3 -2
  29. package/lib/runner/runner.js +9 -1
  30. package/lib/runner/taskRunner.js +6 -8
  31. package/lib/runner/tasks.js +55 -46
  32. package/lib/runner/testGroups.js +15 -10
  33. package/lib/runner/uiMode.js +279 -0
  34. package/lib/runner/workerHost.js +7 -6
  35. package/lib/store.js +99 -0
  36. package/lib/util.js +23 -39
  37. package/lib/worker/fixtureRunner.js +3 -3
  38. package/lib/worker/testInfo.js +8 -3
  39. package/lib/worker/timeoutManager.js +11 -5
  40. package/lib/worker/workerMain.js +6 -3
  41. package/package.json +2 -2
  42. package/types/component.d.ts +1 -1
  43. package/types/reporterPrivate.ts +22 -0
  44. package/types/test.d.ts +18 -22
  45. package/types/testReporter.d.ts +5 -1
  46. package/lib/common/profiler.js +0 -53
package/lib/store.js ADDED
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.store = void 0;
7
+ var _fs = _interopRequireDefault(require("fs"));
8
+ var _path = _interopRequireDefault(require("path"));
9
+ var _globals = require("./common/globals");
10
+ var _utilsBundle = require("playwright-core/lib/utilsBundle");
11
+ var _utils = require("playwright-core/lib/utils");
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+ /**
14
+ * Copyright Microsoft Corporation. All rights reserved.
15
+ *
16
+ * Licensed under the Apache License, Version 2.0 (the "License");
17
+ * you may not use this file except in compliance with the License.
18
+ * You may obtain a copy of the License at
19
+ *
20
+ * http://www.apache.org/licenses/LICENSE-2.0
21
+ *
22
+ * Unless required by applicable law or agreed to in writing, software
23
+ * distributed under the License is distributed on an "AS IS" BASIS,
24
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25
+ * See the License for the specific language governing permissions and
26
+ * limitations under the License.
27
+ */
28
+
29
+ class JsonStore {
30
+ async delete(name) {
31
+ const file = this.path(name);
32
+ await _fs.default.promises.rm(file, {
33
+ force: true
34
+ });
35
+ }
36
+ async get(name) {
37
+ const file = this.path(name);
38
+ try {
39
+ const type = contentType(name);
40
+ if (type === 'binary') return await _fs.default.promises.readFile(file);
41
+ const text = await _fs.default.promises.readFile(file, 'utf-8');
42
+ if (type === 'json') return JSON.parse(text);
43
+ return text;
44
+ } catch (e) {
45
+ return undefined;
46
+ }
47
+ }
48
+ path(name) {
49
+ return _path.default.join(this.root(), name);
50
+ }
51
+ root() {
52
+ const config = (0, _globals.currentConfig)();
53
+ if (!config) throw new Error('Cannot access store before config is loaded');
54
+ return config._internal.storeDir;
55
+ }
56
+ async set(name, value) {
57
+ const file = this.path(name);
58
+ if (value === undefined) {
59
+ await _fs.default.promises.rm(file, {
60
+ force: true
61
+ });
62
+ return;
63
+ }
64
+ let data = '';
65
+ switch (contentType(name)) {
66
+ case 'json':
67
+ {
68
+ if (Buffer.isBuffer(value)) throw new Error('JSON value must be an Object');
69
+ data = JSON.stringify(value, undefined, 2);
70
+ break;
71
+ }
72
+ case 'text':
73
+ {
74
+ if (!(0, _utils.isString)(value)) throw new Error('Textual value must be a string');
75
+ data = value;
76
+ break;
77
+ }
78
+ case 'binary':
79
+ {
80
+ if (!Buffer.isBuffer(value)) throw new Error('Binary value must be a Buffer');
81
+ data = value;
82
+ break;
83
+ }
84
+ }
85
+ await _fs.default.promises.mkdir(_path.default.dirname(file), {
86
+ recursive: true
87
+ });
88
+ await _fs.default.promises.writeFile(file, data);
89
+ }
90
+ }
91
+ function contentType(name) {
92
+ var _mime$getType;
93
+ const mimeType = (_mime$getType = _utilsBundle.mime.getType(_path.default.basename(name))) !== null && _mime$getType !== void 0 ? _mime$getType : 'application/octet-string';
94
+ if ((0, _utils.isJsonMimeType)(mimeType)) return 'json';
95
+ if ((0, _utils.isTextualMimeType)(mimeType)) return 'text';
96
+ return 'binary';
97
+ }
98
+ const store = new JsonStore();
99
+ exports.store = store;
package/lib/util.js CHANGED
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.addSuffixToFilePath = addSuffixToFilePath;
7
7
  exports.callLogText = callLogText;
8
- exports.captureStackTrace = captureStackTrace;
9
8
  exports.createFileFiltersFromArguments = createFileFiltersFromArguments;
10
9
  exports.createFileMatcher = createFileMatcher;
11
10
  exports.createFileMatcherFromArguments = createFileMatcherFromArguments;
@@ -16,6 +15,8 @@ exports.errorWithFile = errorWithFile;
16
15
  exports.expectTypes = expectTypes;
17
16
  exports.experimentalLoaderOption = experimentalLoaderOption;
18
17
  exports.fileIsModule = fileIsModule;
18
+ exports.filterStackTrace = filterStackTrace;
19
+ exports.filteredStackTrace = filteredStackTrace;
19
20
  exports.folderIsModule = folderIsModule;
20
21
  exports.forceRegExp = forceRegExp;
21
22
  exports.formatLocation = formatLocation;
@@ -26,6 +27,7 @@ exports.normalizeAndSaveAttachment = normalizeAndSaveAttachment;
26
27
  exports.relativeFilePath = relativeFilePath;
27
28
  exports.sanitizeForFilePath = sanitizeForFilePath;
28
29
  exports.serializeError = serializeError;
30
+ exports.stringifyStackFrames = stringifyStackFrames;
29
31
  exports.trimLongString = trimLongString;
30
32
  var _fs = _interopRequireDefault(require("fs"));
31
33
  var _utilsBundle = require("playwright-core/lib/utilsBundle");
@@ -50,51 +52,33 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
50
52
  * limitations under the License.
51
53
  */
52
54
 
53
- const PLAYWRIGHT_CORE_PATH = _path.default.dirname(require.resolve('playwright-core'));
54
- const EXPECT_PATH = require.resolve('./common/expectBundle');
55
- const EXPECT_PATH_IMPL = require.resolve('./common/expectBundleImpl');
56
55
  const PLAYWRIGHT_TEST_PATH = _path.default.join(__dirname, '..');
56
+ const PLAYWRIGHT_CORE_PATH = _path.default.dirname(require.resolve('playwright-core/package.json'));
57
57
  function filterStackTrace(e) {
58
+ var _e$stack;
58
59
  if (process.env.PWDEBUGIMPL) return;
59
-
60
- // This method filters internal stack frames using Error.prepareStackTrace
61
- // hook. Read more about the hook: https://v8.dev/docs/stack-trace-api
62
- //
63
- // NOTE: Error.prepareStackTrace will only be called if `e.stack` has not
64
- // been accessed before. This is the case for Jest Expect and simple throw
65
- // statements.
66
- //
67
- // If `e.stack` has been accessed, this method will be NOOP.
68
- const oldPrepare = Error.prepareStackTrace;
69
- const stackFormatter = oldPrepare || ((error, structuredStackTrace) => [`${error.name}: ${error.message}`, ...structuredStackTrace.map(callSite => ' at ' + callSite.toString())].join('\n'));
70
- Error.prepareStackTrace = (error, structuredStackTrace) => {
71
- return stackFormatter(error, structuredStackTrace.filter(callSite => {
72
- const fileName = callSite.getFileName();
73
- const functionName = callSite.getFunctionName() || undefined;
74
- if (!fileName) return true;
75
- return !fileName.startsWith(PLAYWRIGHT_TEST_PATH) && !fileName.startsWith(PLAYWRIGHT_CORE_PATH) && !(0, _utils.isInternalFileName)(fileName, functionName);
76
- }));
77
- };
78
- // eslint-disable-next-line
79
- e.stack; // trigger Error.prepareStackTrace
80
- Error.prepareStackTrace = oldPrepare;
60
+ const stackLines = stringifyStackFrames(filteredStackTrace(((_e$stack = e.stack) === null || _e$stack === void 0 ? void 0 : _e$stack.split('\n')) || []));
61
+ const message = e.message;
62
+ e.stack = `${e.name}: ${e.message}\n${stackLines.join('\n')}`;
63
+ e.message = message;
81
64
  }
82
- function captureStackTrace(customApiName) {
83
- const stackTrace = (0, _utils.captureStackTrace)();
65
+ function filteredStackTrace(rawStack) {
84
66
  const frames = [];
85
- const frameTexts = [];
86
- for (let i = 0; i < stackTrace.frames.length; ++i) {
87
- const frame = stackTrace.frames[i];
88
- if (frame.file === EXPECT_PATH || frame.file === EXPECT_PATH_IMPL) continue;
67
+ for (const line of rawStack) {
68
+ const frame = (0, _utilsBundle.parseStackTraceLine)(line);
69
+ if (!frame || !frame.file) continue;
70
+ if (!process.env.PWDEBUGIMPL && frame.file.startsWith(PLAYWRIGHT_TEST_PATH)) continue;
71
+ if (!process.env.PWDEBUGIMPL && frame.file.startsWith(PLAYWRIGHT_CORE_PATH)) continue;
89
72
  frames.push(frame);
90
- frameTexts.push(stackTrace.frameTexts[i]);
91
73
  }
92
- return {
93
- allFrames: stackTrace.allFrames,
94
- frames,
95
- frameTexts,
96
- apiName: customApiName !== null && customApiName !== void 0 ? customApiName : stackTrace.apiName
97
- };
74
+ return frames;
75
+ }
76
+ function stringifyStackFrames(frames) {
77
+ const stackLines = [];
78
+ for (const frame of frames) {
79
+ if (frame.function) stackLines.push(` at ${frame.function} (${frame.file}:${frame.line}:${frame.column})`);else stackLines.push(` at ${frame.file}:${frame.line}:${frame.column}`);
80
+ }
81
+ return stackLines;
98
82
  }
99
83
  function serializeError(error) {
100
84
  if (error instanceof Error) {
@@ -40,7 +40,8 @@ class Fixture {
40
40
  this.value = null;
41
41
  const title = this.registration.customTitle || this.registration.name;
42
42
  this._runnableDescription = {
43
- title: this.registration.timeout !== undefined ? `Fixture "${title}"` : `setting up "${title}"`,
43
+ title,
44
+ phase: 'setup',
44
45
  location: registration.location,
45
46
  slot: this.registration.timeout === undefined ? undefined : {
46
47
  timeout: this.registration.timeout,
@@ -109,8 +110,7 @@ class Fixture {
109
110
  await this._teardownWithDepsComplete;
110
111
  }
111
112
  _setTeardownDescription(timeoutManager) {
112
- const title = this.registration.customTitle || this.registration.name;
113
- this._runnableDescription.title = this.registration.timeout !== undefined ? `Fixture "${title}"` : `tearing down "${title}"`;
113
+ this._runnableDescription.phase = 'teardown';
114
114
  timeoutManager.setCurrentFixture(this._runnableDescription);
115
115
  }
116
116
  async _teardownInternal(timeoutManager) {
@@ -52,9 +52,11 @@ class TestInfoImpl {
52
52
  this._startTime = void 0;
53
53
  this._startWallTime = void 0;
54
54
  this._hasHardError = false;
55
+ this._traceEvents = [];
55
56
  this._onTestFailureImmediateCallbacks = new Map();
56
57
  this._didTimeout = false;
57
58
  this._lastStepId = 0;
59
+ this.testId = void 0;
58
60
  this.repeatEachIndex = void 0;
59
61
  this.retry = void 0;
60
62
  this.workerIndex = void 0;
@@ -80,6 +82,7 @@ class TestInfoImpl {
80
82
  this.errors = [];
81
83
  this.currentStep = void 0;
82
84
  this._test = test;
85
+ this.testId = test.id;
83
86
  this._onStepBegin = onStepBegin;
84
87
  this._onStepEnd = onStepEnd;
85
88
  this._startTime = (0, _utils.monotonicTime)();
@@ -199,8 +202,7 @@ class TestInfoImpl {
199
202
  testId: this._test.id,
200
203
  stepId,
201
204
  ...data,
202
- location,
203
- wallTime: Date.now()
205
+ location
204
206
  };
205
207
  this._onStepBegin(payload);
206
208
  return step;
@@ -228,7 +230,10 @@ class TestInfoImpl {
228
230
  this._hasHardError = state.hasHardError;
229
231
  }
230
232
  async _runAsStep(cb, stepInfo) {
231
- const step = this._addStep(stepInfo);
233
+ const step = this._addStep({
234
+ ...stepInfo,
235
+ wallTime: Date.now()
236
+ });
232
237
  try {
233
238
  const result = await cb();
234
239
  step.complete({});
@@ -93,8 +93,15 @@ class TimeoutManager {
93
93
  switch (this._runnable.type) {
94
94
  case 'test':
95
95
  {
96
- const fixtureSuffix = this._fixture ? ` while ${this._fixture.title}` : '';
97
- message = `Test timeout of ${timeout}ms exceeded${fixtureSuffix}.`;
96
+ if (this._fixture) {
97
+ if (this._fixture.phase === 'setup') {
98
+ message = `Test timeout of ${timeout}ms exceeded while setting up "${this._fixture.title}".`;
99
+ } else {
100
+ message = [`Test finished within timeout of ${timeout}ms, but tearing down "${this._fixture.title}" ran out of time.`, `Please allow more time for the test, since teardown is attributed towards the test timeout budget.`].join('\n');
101
+ }
102
+ } else {
103
+ message = `Test timeout of ${timeout}ms exceeded.`;
104
+ }
98
105
  break;
99
106
  }
100
107
  case 'afterEach':
@@ -107,8 +114,7 @@ class TimeoutManager {
107
114
  break;
108
115
  case 'teardown':
109
116
  {
110
- const fixtureSuffix = this._fixture ? ` while ${this._fixture.title}` : '';
111
- message = `Worker teardown timeout of ${timeout}ms exceeded${fixtureSuffix}.`;
117
+ if (this._fixture) message = `Worker teardown timeout of ${timeout}ms exceeded while ${this._fixture.phase === 'setup' ? 'setting up' : 'tearing down'} "${this._fixture.title}".`;else message = `Worker teardown timeout of ${timeout}ms exceeded.`;
112
118
  break;
113
119
  }
114
120
  case 'skip':
@@ -119,7 +125,7 @@ class TimeoutManager {
119
125
  break;
120
126
  }
121
127
  const fixtureWithSlot = (_this$_fixture2 = this._fixture) !== null && _this$_fixture2 !== void 0 && _this$_fixture2.slot ? this._fixture : undefined;
122
- if (fixtureWithSlot) message = `${fixtureWithSlot.title} timeout of ${timeout}ms exceeded.`;
128
+ if (fixtureWithSlot) message = `Fixture "${fixtureWithSlot.title}" timeout of ${timeout}ms exceeded during ${fixtureWithSlot.phase}.`;
123
129
  message = _utilsBundle.colors.red(message);
124
130
  const location = (fixtureWithSlot || this._runnable).location;
125
131
  return {
@@ -221,7 +221,8 @@ class WorkerMain extends _process.ProcessRunner {
221
221
  // In theory, we should run above code without any errors.
222
222
  // However, in the case we screwed up, or loadTestFile failed in the worker
223
223
  // but not in the runner, let's do a fatal error.
224
- this.unhandledError(e);
224
+ this._fatalErrors.push((0, _util2.serializeError)(e));
225
+ this._stop();
225
226
  } finally {
226
227
  const donePayload = {
227
228
  fatalErrors: this._fatalErrors,
@@ -299,7 +300,8 @@ class WorkerMain extends _process.ProcessRunner {
299
300
  category: 'hook',
300
301
  title: 'Before Hooks',
301
302
  canHaveChildren: true,
302
- forceNoParent: true
303
+ forceNoParent: true,
304
+ wallTime: Date.now()
303
305
  });
304
306
 
305
307
  // Note: wrap all preparation steps together, because failure/skip in any of them
@@ -367,7 +369,8 @@ class WorkerMain extends _process.ProcessRunner {
367
369
  category: 'hook',
368
370
  title: 'After Hooks',
369
371
  canHaveChildren: true,
370
- forceNoParent: true
372
+ forceNoParent: true,
373
+ wallTime: Date.now()
371
374
  });
372
375
  let firstAfterHooksError;
373
376
  let afterHooksSlot;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playwright/test",
3
- "version": "1.31.2",
3
+ "version": "1.32.0",
4
4
  "description": "A high-level API to automate web browsers",
5
5
  "repository": "github:Microsoft/playwright",
6
6
  "homepage": "https://playwright.dev",
@@ -34,7 +34,7 @@
34
34
  "license": "Apache-2.0",
35
35
  "dependencies": {
36
36
  "@types/node": "*",
37
- "playwright-core": "1.31.2"
37
+ "playwright-core": "1.32.0"
38
38
  },
39
39
  "optionalDependencies": {
40
40
  "fsevents": "2.3.2"
@@ -34,7 +34,7 @@ export type ObjectComponent = {
34
34
  options?: MountOptions
35
35
  };
36
36
 
37
- export type Component = JsxComponent | ObjectComponent;
37
+ export type Component = JsxComponent | ObjectComponent | number | string | Array<any>;
38
38
 
39
39
  declare global {
40
40
  interface Window {
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import type { Suite } from './testReporter';
18
+
19
+ export interface SuitePrivate extends Suite {
20
+ _fileId: string | undefined;
21
+ _parallelMode: 'default' | 'serial' | 'parallel';
22
+ }
package/types/test.d.ts CHANGED
@@ -1782,19 +1782,8 @@ export interface FullConfig<TestArgs = {}, WorkerArgs = {}> {
1782
1782
  export type TestStatus = 'passed' | 'failed' | 'timedOut' | 'skipped' | 'interrupted';
1783
1783
 
1784
1784
  /**
1785
- * `WorkerInfo` contains information about the worker that is running tests. It is available to
1786
- * [test.beforeAll(hookFunction)](https://playwright.dev/docs/api/class-test#test-before-all) and
1787
- * [test.afterAll(hookFunction)](https://playwright.dev/docs/api/class-test#test-after-all) hooks and worker-scoped
1788
- * fixtures.
1789
- *
1790
- * ```js
1791
- * import { test, expect } from '@playwright/test';
1792
- *
1793
- * test.beforeAll(async ({ browserName }, workerInfo) => {
1794
- * console.log(`Running ${browserName} in worker #${workerInfo.workerIndex}`);
1795
- * });
1796
- * ```
1797
- *
1785
+ * `WorkerInfo` contains information about the worker that is running tests and is available to worker-scoped
1786
+ * fixtures. `WorkerInfo` is a subset of [TestInfo] that is available in many other places.
1798
1787
  */
1799
1788
  export interface WorkerInfo {
1800
1789
  /**
@@ -1826,9 +1815,11 @@ export interface WorkerInfo {
1826
1815
  }
1827
1816
 
1828
1817
  /**
1829
- * `TestInfo` contains information about currently running test. It is available to any test function,
1830
- * [test.beforeEach(hookFunction)](https://playwright.dev/docs/api/class-test#test-before-each) and
1831
- * [test.afterEach(hookFunction)](https://playwright.dev/docs/api/class-test#test-after-each) hooks and test-scoped
1818
+ * `TestInfo` contains information about currently running test. It is available to test functions,
1819
+ * [test.beforeEach(hookFunction)](https://playwright.dev/docs/api/class-test#test-before-each),
1820
+ * [test.afterEach(hookFunction)](https://playwright.dev/docs/api/class-test#test-after-each),
1821
+ * [test.beforeAll(hookFunction)](https://playwright.dev/docs/api/class-test#test-before-all) and
1822
+ * [test.afterAll(hookFunction)](https://playwright.dev/docs/api/class-test#test-after-all) hooks, and test-scoped
1832
1823
  * fixtures. `TestInfo` provides utilities to control test execution: attach files, update test timeout, determine
1833
1824
  * which test is currently running and whether it was retried, etc.
1834
1825
  *
@@ -1871,9 +1862,9 @@ export interface TestInfo {
1871
1862
  *
1872
1863
  * ```js
1873
1864
  * import { test, expect } from '@playwright/test';
1865
+ * import { download } from './my-custom-helpers';
1874
1866
  *
1875
1867
  * test('basic test', async ({}, testInfo) => {
1876
- * const { download } = require('./my-custom-helpers');
1877
1868
  * const tmpPath = await download('a');
1878
1869
  * await testInfo.attach('downloaded', { path: tmpPath });
1879
1870
  * });
@@ -2226,6 +2217,11 @@ export interface TestInfo {
2226
2217
  */
2227
2218
  stdout: Array<string|Buffer>;
2228
2219
 
2220
+ /**
2221
+ * Test id matching the test case id in the reporter API.
2222
+ */
2223
+ testId: string;
2224
+
2229
2225
  /**
2230
2226
  * Timeout in milliseconds for the currently running test. Zero means no timeout. Learn more about
2231
2227
  * [various timeouts](https://playwright.dev/docs/test-timeouts).
@@ -3166,7 +3162,7 @@ export interface TestType<TestArgs extends KeyValue, WorkerArgs extends KeyValue
3166
3162
  * @param title Step name.
3167
3163
  * @param body Step body.
3168
3164
  */
3169
- step<T>(title: string, body: () => Promise<T>): Promise<T>;
3165
+ step<T>(title: string, body: () => T | Promise<T>): Promise<T>;
3170
3166
  /**
3171
3167
  * `expect` function can be used to create test assertions. Read more about [test assertions](https://playwright.dev/docs/test-assertions).
3172
3168
  *
@@ -3312,7 +3308,7 @@ type ConnectOptions = {
3312
3308
  * [testProject.use](https://playwright.dev/docs/api/class-testproject#test-project-use).
3313
3309
  *
3314
3310
  * ```js
3315
- * import type { PlaywrightTestConfig } from '@playwright/test';
3311
+ * import { defineConfig } from '@playwright/test';
3316
3312
  * export default defineConfig({
3317
3313
  * use: {
3318
3314
  * headless: false,
@@ -3439,7 +3435,7 @@ export type VideoMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry';
3439
3435
  * [testProject.use](https://playwright.dev/docs/api/class-testproject#test-project-use).
3440
3436
  *
3441
3437
  * ```js
3442
- * import type { PlaywrightTestConfig } from '@playwright/test';
3438
+ * import { defineConfig } from '@playwright/test';
3443
3439
  * export default defineConfig({
3444
3440
  * use: {
3445
3441
  * headless: false,
@@ -4090,12 +4086,12 @@ interface GenericAssertions<R> {
4090
4086
  *
4091
4087
  * ```js
4092
4088
  * const value = 'Is 42 enough?';
4093
- * expect(value).toMatches(/Is \d+ enough/);
4089
+ * expect(value).toMatch(/Is \d+ enough/);
4094
4090
  * ```
4095
4091
  *
4096
4092
  * @param expected Regular expression to match against.
4097
4093
  */
4098
- toMatch(expected: RegExp): R;
4094
+ toMatch(expected: RegExp | string): R;
4099
4095
  /**
4100
4096
  * Compares contents of the value with contents of `expected`, performing "deep equality" check. Allows extra
4101
4097
  * properties to be present in the value, unlike
@@ -319,6 +319,10 @@ export interface FullResult {
319
319
  * import { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';
320
320
  *
321
321
  * class MyReporter implements Reporter {
322
+ * constructor(options: { customOption?: string } = {}) {
323
+ * console.log(`my-awesome-reporter setup with customOption set to ${options.customOption}`);
324
+ * }
325
+ *
322
326
  * onBegin(config: FullConfig, suite: Suite) {
323
327
  * console.log(`Starting the run with ${suite.allTests().length} tests`);
324
328
  * }
@@ -347,7 +351,7 @@ export interface FullResult {
347
351
  * import { defineConfig } from '@playwright/test';
348
352
  *
349
353
  * export default defineConfig({
350
- * reporter: './my-awesome-reporter.ts',
354
+ * reporter: ['./my-awesome-reporter.ts', { customOption: 'some value' }],
351
355
  * });
352
356
  * ```
353
357
  *
@@ -1,53 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.startProfiling = startProfiling;
7
- exports.stopProfiling = stopProfiling;
8
- var fs = _interopRequireWildcard(require("fs"));
9
- var path = _interopRequireWildcard(require("path"));
10
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
11
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
12
- /**
13
- * Copyright Microsoft Corporation. All rights reserved.
14
- *
15
- * Licensed under the Apache License, Version 2.0 (the "License");
16
- * you may not use this file except in compliance with the License.
17
- * You may obtain a copy of the License at
18
- *
19
- * http://www.apache.org/licenses/LICENSE-2.0
20
- *
21
- * Unless required by applicable law or agreed to in writing, software
22
- * distributed under the License is distributed on an "AS IS" BASIS,
23
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24
- * See the License for the specific language governing permissions and
25
- * limitations under the License.
26
- */
27
-
28
- const profileDir = process.env.PWTEST_PROFILE_DIR || '';
29
- let session;
30
- async function startProfiling() {
31
- if (!profileDir) return;
32
- session = new (require('inspector').Session)();
33
- session.connect();
34
- await new Promise(f => {
35
- session.post('Profiler.enable', () => {
36
- session.post('Profiler.start', f);
37
- });
38
- });
39
- }
40
- async function stopProfiling(processName) {
41
- if (!profileDir) return;
42
- await new Promise(f => session.post('Profiler.stop', (err, {
43
- profile
44
- }) => {
45
- if (!err) {
46
- fs.mkdirSync(profileDir, {
47
- recursive: true
48
- });
49
- fs.writeFileSync(path.join(profileDir, (processName || 'runner') + '.json'), JSON.stringify(profile));
50
- }
51
- f();
52
- }));
53
- }