build: push tvapp v2 docker files

This commit is contained in:
2025-02-20 13:10:51 -07:00
parent bee45668cc
commit 9e79e42d09
536 changed files with 142093 additions and 5531 deletions

6
node_modules/playwright/.eslintrc.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
extends: '../../.eslintrc-with-ts-config.js',
rules: {
'@typescript-eslint/no-floating-promises': 'error',
},
};

202
node_modules/playwright/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Portions Copyright (c) Microsoft Corporation.
Portions Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

5
node_modules/playwright/NOTICE generated vendored Normal file
View File

@@ -0,0 +1,5 @@
Playwright
Copyright (c) Microsoft Corporation
This software contains code derived from the Puppeteer project (https://github.com/puppeteer/puppeteer),
available under the Apache 2.0 license (https://github.com/puppeteer/puppeteer/blob/master/LICENSE).

168
node_modules/playwright/README.md generated vendored Normal file
View File

@@ -0,0 +1,168 @@
# 🎭 Playwright
[![npm version](https://img.shields.io/npm/v/playwright.svg)](https://www.npmjs.com/package/playwright) <!-- GEN:chromium-version-badge -->[![Chromium version](https://img.shields.io/badge/chromium-131.0.6778.33-blue.svg?logo=google-chrome)](https://www.chromium.org/Home)<!-- GEN:stop --> <!-- GEN:firefox-version-badge -->[![Firefox version](https://img.shields.io/badge/firefox-132.0-blue.svg?logo=firefoxbrowser)](https://www.mozilla.org/en-US/firefox/new/)<!-- GEN:stop --> <!-- GEN:webkit-version-badge -->[![WebKit version](https://img.shields.io/badge/webkit-18.2-blue.svg?logo=safari)](https://webkit.org/)<!-- GEN:stop --> [![Join Discord](https://img.shields.io/badge/join-discord-infomational)](https://aka.ms/playwright/discord)
## [Documentation](https://playwright.dev) | [API reference](https://playwright.dev/docs/api/class-playwright)
Playwright is a framework for Web Testing and Automation. It allows testing [Chromium](https://www.chromium.org/Home), [Firefox](https://www.mozilla.org/en-US/firefox/new/) and [WebKit](https://webkit.org/) with a single API. Playwright is built to enable cross-browser web automation that is **ever-green**, **capable**, **reliable** and **fast**.
| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->131.0.6778.33<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->18.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->132.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Headless execution is supported for all browsers on all platforms. Check out [system requirements](https://playwright.dev/docs/intro#system-requirements) for details.
Looking for Playwright for [Python](https://playwright.dev/python/docs/intro), [.NET](https://playwright.dev/dotnet/docs/intro), or [Java](https://playwright.dev/java/docs/intro)?
## Installation
Playwright has its own test runner for end-to-end tests, we call it Playwright Test.
### Using init command
The easiest way to get started with Playwright Test is to run the init command.
```Shell
# Run from your project's root directory
npm init playwright@latest
# Or create a new project
npm init playwright@latest new-project
```
This will create a configuration file, optionally add examples, a GitHub Action workflow and a first test example.spec.ts. You can now jump directly to writing assertions section.
### Manually
Add dependency and install browsers.
```Shell
npm i -D @playwright/test
# install supported browsers
npx playwright install
```
You can optionally install only selected browsers, see [install browsers](https://playwright.dev/docs/cli#install-browsers) for more details. Or you can install no browsers at all and use existing [browser channels](https://playwright.dev/docs/browsers).
* [Getting started](https://playwright.dev/docs/intro)
* [API reference](https://playwright.dev/docs/api/class-playwright)
## Capabilities
### Resilient • No flaky tests
**Auto-wait**. Playwright waits for elements to be actionable prior to performing actions. It also has a rich set of introspection events. The combination of the two eliminates the need for artificial timeouts - a primary cause of flaky tests.
**Web-first assertions**. Playwright assertions are created specifically for the dynamic web. Checks are automatically retried until the necessary conditions are met.
**Tracing**. Configure test retry strategy, capture execution trace, videos and screenshots to eliminate flakes.
### No trade-offs • No limits
Browsers run web content belonging to different origins in different processes. Playwright is aligned with the architecture of the modern browsers and runs tests out-of-process. This makes Playwright free of the typical in-process test runner limitations.
**Multiple everything**. Test scenarios that span multiple tabs, multiple origins and multiple users. Create scenarios with different contexts for different users and run them against your server, all in one test.
**Trusted events**. Hover elements, interact with dynamic controls and produce trusted events. Playwright uses real browser input pipeline indistinguishable from the real user.
Test frames, pierce Shadow DOM. Playwright selectors pierce shadow DOM and allow entering frames seamlessly.
### Full isolation • Fast execution
**Browser contexts**. Playwright creates a browser context for each test. Browser context is equivalent to a brand new browser profile. This delivers full test isolation with zero overhead. Creating a new browser context only takes a handful of milliseconds.
**Log in once**. Save the authentication state of the context and reuse it in all the tests. This bypasses repetitive log-in operations in each test, yet delivers full isolation of independent tests.
### Powerful Tooling
**[Codegen](https://playwright.dev/docs/codegen)**. Generate tests by recording your actions. Save them into any language.
**[Playwright inspector](https://playwright.dev/docs/inspector)**. Inspect page, generate selectors, step through the test execution, see click points and explore execution logs.
**[Trace Viewer](https://playwright.dev/docs/trace-viewer)**. Capture all the information to investigate the test failure. Playwright trace contains test execution screencast, live DOM snapshots, action explorer, test source and many more.
Looking for Playwright for [TypeScript](https://playwright.dev/docs/intro), [JavaScript](https://playwright.dev/docs/intro), [Python](https://playwright.dev/python/docs/intro), [.NET](https://playwright.dev/dotnet/docs/intro), or [Java](https://playwright.dev/java/docs/intro)?
## Examples
To learn how to run these Playwright Test examples, check out our [getting started docs](https://playwright.dev/docs/intro).
#### Page screenshot
This code snippet navigates to Playwright homepage and saves a screenshot.
```TypeScript
import { test } from '@playwright/test';
test('Page Screenshot', async ({ page }) => {
await page.goto('https://playwright.dev/');
await page.screenshot({ path: `example.png` });
});
```
#### Mobile and geolocation
This snippet emulates Mobile Safari on a device at given geolocation, navigates to maps.google.com, performs the action and takes a screenshot.
```TypeScript
import { test, devices } from '@playwright/test';
test.use({
...devices['iPhone 13 Pro'],
locale: 'en-US',
geolocation: { longitude: 12.492507, latitude: 41.889938 },
permissions: ['geolocation'],
})
test('Mobile and geolocation', async ({ page }) => {
await page.goto('https://maps.google.com');
await page.getByText('Your location').click();
await page.waitForRequest(/.*preview\/pwa/);
await page.screenshot({ path: 'colosseum-iphone.png' });
});
```
#### Evaluate in browser context
This code snippet navigates to example.com, and executes a script in the page context.
```TypeScript
import { test } from '@playwright/test';
test('Evaluate in browser context', async ({ page }) => {
await page.goto('https://www.example.com/');
const dimensions = await page.evaluate(() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio
}
});
console.log(dimensions);
});
```
#### Intercept network requests
This code snippet sets up request routing for a page to log all network requests.
```TypeScript
import { test } from '@playwright/test';
test('Intercept network requests', async ({ page }) => {
// Log and continue all network requests
await page.route('**', route => {
console.log(route.request().url());
route.continue();
});
await page.goto('http://todomvc.com');
});
```
## Resources
* [Documentation](https://playwright.dev)
* [API reference](https://playwright.dev/docs/api/class-playwright/)
* [Contribution guide](CONTRIBUTING.md)
* [Changelog](https://github.com/microsoft/playwright/releases)

19
node_modules/playwright/cli.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env node
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { program } = require('./lib/program');
program.parse(process.argv);

17
node_modules/playwright/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,17 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from 'playwright-core';

17
node_modules/playwright/index.js generated vendored Normal file
View File

@@ -0,0 +1,17 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module.exports = require('playwright-core');

18
node_modules/playwright/index.mjs generated vendored Normal file
View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from 'playwright-core';
import playwright from 'playwright-core';
export default playwright;

42
node_modules/playwright/jsx-runtime.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function jsx(type, props, key) {
return {
__pw_type: 'jsx',
type,
props,
key,
};
}
function jsxs(type, props, key) {
return {
__pw_type: 'jsx',
type,
props,
key,
};
}
// this is used in <></> notation
const Fragment = { __pw_jsx_fragment: true };
module.exports = {
Fragment,
jsx,
jsxs,
};

21
node_modules/playwright/jsx-runtime.mjs generated vendored Normal file
View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import jsxRuntime from './jsx-runtime.js';
export const jsx = jsxRuntime.jsx;
export const jsxs = jsxRuntime.jsxs;
export const Fragment = jsxRuntime.Fragment;

264
node_modules/playwright/lib/common/config.js generated vendored Normal file
View File

@@ -0,0 +1,264 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.defaultTimeout = exports.defaultReporter = exports.defaultGrep = exports.builtInReporters = exports.FullProjectInternal = exports.FullConfigInternal = void 0;
exports.getProjectId = getProjectId;
exports.takeFirst = takeFirst;
exports.toReporters = toReporters;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _os = _interopRequireDefault(require("os"));
var _util = require("../util");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const defaultTimeout = exports.defaultTimeout = 30000;
class FullConfigInternal {
constructor(location, userConfig, configCLIOverrides) {
var _this$globalSetups$, _this$globalTeardowns;
this.config = void 0;
this.configDir = void 0;
this.configCLIOverrides = void 0;
this.webServers = void 0;
this.plugins = void 0;
this.projects = [];
this.singleTSConfigPath = void 0;
this.cliArgs = [];
this.cliGrep = void 0;
this.cliGrepInvert = void 0;
this.cliOnlyChanged = void 0;
this.cliProjectFilter = void 0;
this.cliListOnly = false;
this.cliPassWithNoTests = void 0;
this.cliFailOnFlakyTests = void 0;
this.cliLastFailed = void 0;
this.testIdMatcher = void 0;
this.defineConfigWasUsed = false;
this.globalSetups = [];
this.globalTeardowns = [];
if (configCLIOverrides.projects && userConfig.projects) throw new Error(`Cannot use --browser option when configuration file defines projects. Specify browserName in the projects instead.`);
const {
resolvedConfigFile,
configDir
} = location;
const packageJsonPath = (0, _util.getPackageJsonPath)(configDir);
const packageJsonDir = packageJsonPath ? _path.default.dirname(packageJsonPath) : process.cwd();
this.configDir = configDir;
this.configCLIOverrides = configCLIOverrides;
const privateConfiguration = userConfig['@playwright/test'];
this.plugins = ((privateConfiguration === null || privateConfiguration === void 0 ? void 0 : privateConfiguration.plugins) || []).map(p => ({
factory: p
}));
this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig);
this.globalSetups = (Array.isArray(userConfig.globalSetup) ? userConfig.globalSetup : [userConfig.globalSetup]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined);
this.globalTeardowns = (Array.isArray(userConfig.globalTeardown) ? userConfig.globalTeardown : [userConfig.globalTeardown]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined);
this.config = {
configFile: resolvedConfigFile,
rootDir: pathResolve(configDir, userConfig.testDir) || configDir,
forbidOnly: takeFirst(configCLIOverrides.forbidOnly, userConfig.forbidOnly, false),
fullyParallel: takeFirst(configCLIOverrides.fullyParallel, userConfig.fullyParallel, false),
globalSetup: (_this$globalSetups$ = this.globalSetups[0]) !== null && _this$globalSetups$ !== void 0 ? _this$globalSetups$ : null,
globalTeardown: (_this$globalTeardowns = this.globalTeardowns[0]) !== null && _this$globalTeardowns !== void 0 ? _this$globalTeardowns : null,
globalTimeout: takeFirst(configCLIOverrides.globalTimeout, userConfig.globalTimeout, 0),
grep: takeFirst(userConfig.grep, defaultGrep),
grepInvert: takeFirst(userConfig.grepInvert, null),
maxFailures: takeFirst(configCLIOverrides.debug ? 1 : undefined, configCLIOverrides.maxFailures, userConfig.maxFailures, 0),
metadata: takeFirst(userConfig.metadata, {}),
preserveOutput: takeFirst(userConfig.preserveOutput, 'always'),
reporter: takeFirst(configCLIOverrides.reporter, resolveReporters(userConfig.reporter, configDir), [[defaultReporter]]),
reportSlowTests: takeFirst(userConfig.reportSlowTests, {
max: 5,
threshold: 15000
}),
quiet: takeFirst(configCLIOverrides.quiet, userConfig.quiet, false),
projects: [],
shard: takeFirst(configCLIOverrides.shard, userConfig.shard, null),
updateSnapshots: takeFirst(configCLIOverrides.updateSnapshots, userConfig.updateSnapshots, 'missing'),
version: require('../../package.json').version,
workers: 0,
webServer: null
};
for (const key in userConfig) {
if (key.startsWith('@')) this.config[key] = userConfig[key];
}
this.config[configInternalSymbol] = this;
const workers = takeFirst(configCLIOverrides.debug ? 1 : undefined, configCLIOverrides.workers, userConfig.workers, '50%');
if (typeof workers === 'string') {
if (workers.endsWith('%')) {
const cpus = _os.default.cpus().length;
this.config.workers = Math.max(1, Math.floor(cpus * (parseInt(workers, 10) / 100)));
} else {
this.config.workers = parseWorkers(workers);
}
} else {
this.config.workers = workers;
}
const webServers = takeFirst(userConfig.webServer, null);
if (Array.isArray(webServers)) {
// multiple web server mode
// Due to previous choices, this value shows up to the user in globalSetup as part of FullConfig. Arrays are not supported by the old type.
this.config.webServer = null;
this.webServers = webServers;
} else if (webServers) {
// legacy singleton mode
this.config.webServer = webServers;
this.webServers = [webServers];
} else {
this.webServers = [];
}
const projectConfigs = configCLIOverrides.projects || userConfig.projects || [userConfig];
this.projects = projectConfigs.map(p => new FullProjectInternal(configDir, userConfig, this, p, this.configCLIOverrides, packageJsonDir));
resolveProjectDependencies(this.projects);
this._assignUniqueProjectIds(this.projects);
this.config.projects = this.projects.map(p => p.project);
}
_assignUniqueProjectIds(projects) {
const usedNames = new Set();
for (const p of projects) {
const name = p.project.name || '';
for (let i = 0; i < projects.length; ++i) {
const candidate = name + (i ? i : '');
if (usedNames.has(candidate)) continue;
p.id = candidate;
p.project.__projectId = p.id;
usedNames.add(candidate);
break;
}
}
}
}
exports.FullConfigInternal = FullConfigInternal;
class FullProjectInternal {
constructor(configDir, config, fullConfig, projectConfig, configCLIOverrides, packageJsonDir) {
var _this$expect$toHaveSc;
this.project = void 0;
this.fullConfig = void 0;
this.fullyParallel = void 0;
this.expect = void 0;
this.respectGitIgnore = void 0;
this.snapshotPathTemplate = void 0;
this.ignoreSnapshots = void 0;
this.id = '';
this.deps = [];
this.teardown = void 0;
this.fullConfig = fullConfig;
const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir);
const defaultSnapshotPathTemplate = '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{-projectName}{-snapshotSuffix}{ext}';
this.snapshotPathTemplate = takeFirst(projectConfig.snapshotPathTemplate, config.snapshotPathTemplate, defaultSnapshotPathTemplate);
this.project = {
grep: takeFirst(projectConfig.grep, config.grep, defaultGrep),
grepInvert: takeFirst(projectConfig.grepInvert, config.grepInvert, null),
outputDir: takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, projectConfig.outputDir), pathResolve(configDir, config.outputDir), _path.default.join(packageJsonDir, 'test-results')),
// Note: we either apply the cli override for repeatEach or not, depending on whether the
// project is top-level vs dependency. See collectProjectsAndTestFiles in loadUtils.
repeatEach: takeFirst(projectConfig.repeatEach, config.repeatEach, 1),
retries: takeFirst(configCLIOverrides.retries, projectConfig.retries, config.retries, 0),
metadata: takeFirst(projectConfig.metadata, config.metadata, {}),
name: takeFirst(projectConfig.name, config.name, ''),
testDir,
snapshotDir: takeFirst(pathResolve(configDir, projectConfig.snapshotDir), pathResolve(configDir, config.snapshotDir), testDir),
testIgnore: takeFirst(projectConfig.testIgnore, config.testIgnore, []),
testMatch: takeFirst(projectConfig.testMatch, config.testMatch, '**/*.@(spec|test).?(c|m)[jt]s?(x)'),
timeout: takeFirst(configCLIOverrides.debug ? 0 : undefined, configCLIOverrides.timeout, projectConfig.timeout, config.timeout, defaultTimeout),
use: (0, _util.mergeObjects)(config.use, projectConfig.use, configCLIOverrides.use),
dependencies: projectConfig.dependencies || [],
teardown: projectConfig.teardown
};
this.fullyParallel = takeFirst(configCLIOverrides.fullyParallel, projectConfig.fullyParallel, config.fullyParallel, undefined);
this.expect = takeFirst(projectConfig.expect, config.expect, {});
if ((_this$expect$toHaveSc = this.expect.toHaveScreenshot) !== null && _this$expect$toHaveSc !== void 0 && _this$expect$toHaveSc.stylePath) {
const stylePaths = Array.isArray(this.expect.toHaveScreenshot.stylePath) ? this.expect.toHaveScreenshot.stylePath : [this.expect.toHaveScreenshot.stylePath];
this.expect.toHaveScreenshot.stylePath = stylePaths.map(stylePath => _path.default.resolve(configDir, stylePath));
}
this.respectGitIgnore = takeFirst(projectConfig.respectGitIgnore, config.respectGitIgnore, !projectConfig.testDir && !config.testDir);
this.ignoreSnapshots = takeFirst(configCLIOverrides.ignoreSnapshots, projectConfig.ignoreSnapshots, config.ignoreSnapshots, false);
}
}
exports.FullProjectInternal = FullProjectInternal;
function takeFirst(...args) {
for (const arg of args) {
if (arg !== undefined) return arg;
}
return undefined;
}
function pathResolve(baseDir, relative) {
if (!relative) return undefined;
return _path.default.resolve(baseDir, relative);
}
function resolveReporters(reporters, rootDir) {
var _toReporters;
return (_toReporters = toReporters(reporters)) === null || _toReporters === void 0 ? void 0 : _toReporters.map(([id, arg]) => {
if (builtInReporters.includes(id)) return [id, arg];
return [require.resolve(id, {
paths: [rootDir]
}), arg];
});
}
function parseWorkers(workers) {
const parsedWorkers = parseInt(workers, 10);
if (isNaN(parsedWorkers)) throw new Error(`Workers ${workers} must be a number or percentage.`);
return parsedWorkers;
}
function resolveProjectDependencies(projects) {
const teardownSet = new Set();
for (const project of projects) {
for (const dependencyName of project.project.dependencies) {
const dependencies = projects.filter(p => p.project.name === dependencyName);
if (!dependencies.length) throw new Error(`Project '${project.project.name}' depends on unknown project '${dependencyName}'`);
if (dependencies.length > 1) throw new Error(`Project dependencies should have unique names, reading ${dependencyName}`);
project.deps.push(...dependencies);
}
if (project.project.teardown) {
const teardowns = projects.filter(p => p.project.name === project.project.teardown);
if (!teardowns.length) throw new Error(`Project '${project.project.name}' has unknown teardown project '${project.project.teardown}'`);
if (teardowns.length > 1) throw new Error(`Project teardowns should have unique names, reading ${project.project.teardown}`);
const teardown = teardowns[0];
project.teardown = teardown;
teardownSet.add(teardown);
}
}
for (const teardown of teardownSet) {
if (teardown.deps.length) throw new Error(`Teardown project ${teardown.project.name} must not have dependencies`);
}
for (const project of projects) {
for (const dep of project.deps) {
if (teardownSet.has(dep)) throw new Error(`Project ${project.project.name} must not depend on a teardown project ${dep.project.name}`);
}
}
}
function toReporters(reporters) {
if (!reporters) return;
if (typeof reporters === 'string') return [[reporters]];
return reporters;
}
const builtInReporters = exports.builtInReporters = ['list', 'line', 'dot', 'json', 'junit', 'null', 'github', 'html', 'blob'];
function resolveScript(id, rootDir) {
if (!id) return undefined;
const localPath = _path.default.resolve(rootDir, id);
if (_fs.default.existsSync(localPath)) return localPath;
return require.resolve(id, {
paths: [rootDir]
});
}
const defaultGrep = exports.defaultGrep = /.*/;
const defaultReporter = exports.defaultReporter = process.env.CI ? 'dot' : 'list';
const configInternalSymbol = Symbol('configInternalSymbol');
function getProjectId(project) {
return project.__projectId;
}

330
node_modules/playwright/lib/common/configLoader.js generated vendored Normal file
View File

@@ -0,0 +1,330 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.defineConfig = void 0;
exports.deserializeConfig = deserializeConfig;
exports.loadConfig = loadConfig;
exports.loadConfigFromFileRestartIfNeeded = loadConfigFromFileRestartIfNeeded;
exports.loadEmptyConfigForMergeReports = loadEmptyConfigForMergeReports;
exports.resolveConfigLocation = resolveConfigLocation;
exports.restartWithExperimentalTsEsm = restartWithExperimentalTsEsm;
var fs = _interopRequireWildcard(require("fs"));
var path = _interopRequireWildcard(require("path"));
var _utils = require("playwright-core/lib/utils");
var _transform = require("../transform/transform");
var _util = require("../util");
var _config = require("./config");
var _compilationCache = require("../transform/compilationCache");
var _esmLoaderHost = require("./esmLoaderHost");
var _esmUtils = require("../transform/esmUtils");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const kDefineConfigWasUsed = Symbol('defineConfigWasUsed');
const defineConfig = (...configs) => {
let result = configs[0];
for (let i = 1; i < configs.length; ++i) {
const config = configs[i];
result = {
...result,
...config,
expect: {
...result.expect,
...config.expect
},
use: {
...result.use,
...config.use
},
build: {
...result.build,
...config.build
},
webServer: [...(Array.isArray(result.webServer) ? result.webServer : result.webServer ? [result.webServer] : []), ...(Array.isArray(config.webServer) ? config.webServer : config.webServer ? [config.webServer] : [])]
};
if (!result.projects && !config.projects) continue;
const projectOverrides = new Map();
for (const project of config.projects || []) projectOverrides.set(project.name, project);
const projects = [];
for (const project of result.projects || []) {
const projectOverride = projectOverrides.get(project.name);
if (projectOverride) {
projects.push({
...project,
...projectOverride,
use: {
...project.use,
...projectOverride.use
}
});
projectOverrides.delete(project.name);
} else {
projects.push(project);
}
}
projects.push(...projectOverrides.values());
result.projects = projects;
}
result[kDefineConfigWasUsed] = true;
return result;
};
exports.defineConfig = defineConfig;
async function deserializeConfig(data) {
if (data.compilationCache) (0, _compilationCache.addToCompilationCache)(data.compilationCache);
return await loadConfig(data.location, data.configCLIOverrides);
}
async function loadUserConfig(location) {
let object = location.resolvedConfigFile ? await (0, _transform.requireOrImport)(location.resolvedConfigFile) : {};
if (object && typeof object === 'object' && 'default' in object) object = object['default'];
return object;
}
async function loadConfig(location, overrides, ignoreProjectDependencies = false) {
var _playwrightTest, _userConfig$build;
// 1. Setup tsconfig; configure ESM loader with tsconfig and compilation cache.
(0, _transform.setSingleTSConfig)(overrides === null || overrides === void 0 ? void 0 : overrides.tsconfig);
await (0, _esmLoaderHost.configureESMLoader)();
// 2. Load and validate playwright config.
const userConfig = await loadUserConfig(location);
validateConfig(location.resolvedConfigFile || '<default config>', userConfig);
const fullConfig = new _config.FullConfigInternal(location, userConfig, overrides || {});
fullConfig.defineConfigWasUsed = !!userConfig[kDefineConfigWasUsed];
if (ignoreProjectDependencies) {
for (const project of fullConfig.projects) {
project.deps = [];
project.teardown = undefined;
}
}
// 3. Load transform options from the playwright config.
const babelPlugins = ((_playwrightTest = userConfig['@playwright/test']) === null || _playwrightTest === void 0 ? void 0 : _playwrightTest.babelPlugins) || [];
const external = ((_userConfig$build = userConfig.build) === null || _userConfig$build === void 0 ? void 0 : _userConfig$build.external) || [];
(0, _transform.setTransformConfig)({
babelPlugins,
external
});
if (!(overrides !== null && overrides !== void 0 && overrides.tsconfig)) (0, _transform.setSingleTSConfig)(fullConfig === null || fullConfig === void 0 ? void 0 : fullConfig.singleTSConfigPath);
// 4. Send transform options to ESM loader.
await (0, _esmLoaderHost.configureESMLoaderTransformConfig)();
return fullConfig;
}
function validateConfig(file, config) {
if (typeof config !== 'object' || !config) throw (0, _util.errorWithFile)(file, `Configuration file must export a single object`);
validateProject(file, config, 'config');
if ('forbidOnly' in config && config.forbidOnly !== undefined) {
if (typeof config.forbidOnly !== 'boolean') throw (0, _util.errorWithFile)(file, `config.forbidOnly must be a boolean`);
}
if ('globalSetup' in config && config.globalSetup !== undefined) {
if (Array.isArray(config.globalSetup)) {
config.globalSetup.forEach((item, index) => {
if (typeof item !== 'string') throw (0, _util.errorWithFile)(file, `config.globalSetup[${index}] must be a string`);
});
} else if (typeof config.globalSetup !== 'string') {
throw (0, _util.errorWithFile)(file, `config.globalSetup must be a string`);
}
}
if ('globalTeardown' in config && config.globalTeardown !== undefined) {
if (Array.isArray(config.globalTeardown)) {
config.globalTeardown.forEach((item, index) => {
if (typeof item !== 'string') throw (0, _util.errorWithFile)(file, `config.globalTeardown[${index}] must be a string`);
});
} else if (typeof config.globalTeardown !== 'string') {
throw (0, _util.errorWithFile)(file, `config.globalTeardown must be a string`);
}
}
if ('globalTimeout' in config && config.globalTimeout !== undefined) {
if (typeof config.globalTimeout !== 'number' || config.globalTimeout < 0) throw (0, _util.errorWithFile)(file, `config.globalTimeout must be a non-negative number`);
}
if ('grep' in config && config.grep !== undefined) {
if (Array.isArray(config.grep)) {
config.grep.forEach((item, index) => {
if (!(0, _utils.isRegExp)(item)) throw (0, _util.errorWithFile)(file, `config.grep[${index}] must be a RegExp`);
});
} else if (!(0, _utils.isRegExp)(config.grep)) {
throw (0, _util.errorWithFile)(file, `config.grep must be a RegExp`);
}
}
if ('grepInvert' in config && config.grepInvert !== undefined) {
if (Array.isArray(config.grepInvert)) {
config.grepInvert.forEach((item, index) => {
if (!(0, _utils.isRegExp)(item)) throw (0, _util.errorWithFile)(file, `config.grepInvert[${index}] must be a RegExp`);
});
} else if (!(0, _utils.isRegExp)(config.grepInvert)) {
throw (0, _util.errorWithFile)(file, `config.grepInvert must be a RegExp`);
}
}
if ('maxFailures' in config && config.maxFailures !== undefined) {
if (typeof config.maxFailures !== 'number' || config.maxFailures < 0) throw (0, _util.errorWithFile)(file, `config.maxFailures must be a non-negative number`);
}
if ('preserveOutput' in config && config.preserveOutput !== undefined) {
if (typeof config.preserveOutput !== 'string' || !['always', 'never', 'failures-only'].includes(config.preserveOutput)) throw (0, _util.errorWithFile)(file, `config.preserveOutput must be one of "always", "never" or "failures-only"`);
}
if ('projects' in config && config.projects !== undefined) {
if (!Array.isArray(config.projects)) throw (0, _util.errorWithFile)(file, `config.projects must be an array`);
config.projects.forEach((project, index) => {
validateProject(file, project, `config.projects[${index}]`);
});
}
if ('quiet' in config && config.quiet !== undefined) {
if (typeof config.quiet !== 'boolean') throw (0, _util.errorWithFile)(file, `config.quiet must be a boolean`);
}
if ('reporter' in config && config.reporter !== undefined) {
if (Array.isArray(config.reporter)) {
config.reporter.forEach((item, index) => {
if (!Array.isArray(item) || item.length <= 0 || item.length > 2 || typeof item[0] !== 'string') throw (0, _util.errorWithFile)(file, `config.reporter[${index}] must be a tuple [name, optionalArgument]`);
});
} else if (typeof config.reporter !== 'string') {
throw (0, _util.errorWithFile)(file, `config.reporter must be a string`);
}
}
if ('reportSlowTests' in config && config.reportSlowTests !== undefined && config.reportSlowTests !== null) {
if (!config.reportSlowTests || typeof config.reportSlowTests !== 'object') throw (0, _util.errorWithFile)(file, `config.reportSlowTests must be an object`);
if (!('max' in config.reportSlowTests) || typeof config.reportSlowTests.max !== 'number' || config.reportSlowTests.max < 0) throw (0, _util.errorWithFile)(file, `config.reportSlowTests.max must be a non-negative number`);
if (!('threshold' in config.reportSlowTests) || typeof config.reportSlowTests.threshold !== 'number' || config.reportSlowTests.threshold < 0) throw (0, _util.errorWithFile)(file, `config.reportSlowTests.threshold must be a non-negative number`);
}
if ('shard' in config && config.shard !== undefined && config.shard !== null) {
if (!config.shard || typeof config.shard !== 'object') throw (0, _util.errorWithFile)(file, `config.shard must be an object`);
if (!('total' in config.shard) || typeof config.shard.total !== 'number' || config.shard.total < 1) throw (0, _util.errorWithFile)(file, `config.shard.total must be a positive number`);
if (!('current' in config.shard) || typeof config.shard.current !== 'number' || config.shard.current < 1 || config.shard.current > config.shard.total) throw (0, _util.errorWithFile)(file, `config.shard.current must be a positive number, not greater than config.shard.total`);
}
if ('updateSnapshots' in config && config.updateSnapshots !== undefined) {
if (typeof config.updateSnapshots !== 'string' || !['all', 'none', 'missing'].includes(config.updateSnapshots)) throw (0, _util.errorWithFile)(file, `config.updateSnapshots must be one of "all", "none" or "missing"`);
}
if ('workers' in config && config.workers !== undefined) {
if (typeof config.workers === 'number' && config.workers <= 0) throw (0, _util.errorWithFile)(file, `config.workers must be a positive number`);else if (typeof config.workers === 'string' && !config.workers.endsWith('%')) throw (0, _util.errorWithFile)(file, `config.workers must be a number or percentage`);
}
}
function validateProject(file, project, title) {
if (typeof project !== 'object' || !project) throw (0, _util.errorWithFile)(file, `${title} must be an object`);
if ('name' in project && project.name !== undefined) {
if (typeof project.name !== 'string') throw (0, _util.errorWithFile)(file, `${title}.name must be a string`);
}
if ('outputDir' in project && project.outputDir !== undefined) {
if (typeof project.outputDir !== 'string') throw (0, _util.errorWithFile)(file, `${title}.outputDir must be a string`);
}
if ('repeatEach' in project && project.repeatEach !== undefined) {
if (typeof project.repeatEach !== 'number' || project.repeatEach < 0) throw (0, _util.errorWithFile)(file, `${title}.repeatEach must be a non-negative number`);
}
if ('retries' in project && project.retries !== undefined) {
if (typeof project.retries !== 'number' || project.retries < 0) throw (0, _util.errorWithFile)(file, `${title}.retries must be a non-negative number`);
}
if ('testDir' in project && project.testDir !== undefined) {
if (typeof project.testDir !== 'string') throw (0, _util.errorWithFile)(file, `${title}.testDir must be a string`);
}
for (const prop of ['testIgnore', 'testMatch']) {
if (prop in project && project[prop] !== undefined) {
const value = project[prop];
if (Array.isArray(value)) {
value.forEach((item, index) => {
if (typeof item !== 'string' && !(0, _utils.isRegExp)(item)) throw (0, _util.errorWithFile)(file, `${title}.${prop}[${index}] must be a string or a RegExp`);
});
} else if (typeof value !== 'string' && !(0, _utils.isRegExp)(value)) {
throw (0, _util.errorWithFile)(file, `${title}.${prop} must be a string or a RegExp`);
}
}
}
if ('timeout' in project && project.timeout !== undefined) {
if (typeof project.timeout !== 'number' || project.timeout < 0) throw (0, _util.errorWithFile)(file, `${title}.timeout must be a non-negative number`);
}
if ('use' in project && project.use !== undefined) {
if (!project.use || typeof project.use !== 'object') throw (0, _util.errorWithFile)(file, `${title}.use must be an object`);
}
if ('ignoreSnapshots' in project && project.ignoreSnapshots !== undefined) {
if (typeof project.ignoreSnapshots !== 'boolean') throw (0, _util.errorWithFile)(file, `${title}.ignoreSnapshots must be a boolean`);
}
}
function resolveConfigLocation(configFile) {
const configFileOrDirectory = configFile ? path.resolve(process.cwd(), configFile) : process.cwd();
const resolvedConfigFile = resolveConfigFile(configFileOrDirectory);
return {
resolvedConfigFile,
configDir: resolvedConfigFile ? path.dirname(resolvedConfigFile) : configFileOrDirectory
};
}
function resolveConfigFile(configFileOrDirectory) {
const resolveConfig = configFile => {
if (fs.existsSync(configFile)) return configFile;
};
const resolveConfigFileFromDirectory = directory => {
for (const ext of ['.ts', '.js', '.mts', '.mjs', '.cts', '.cjs']) {
const configFile = resolveConfig(path.resolve(directory, 'playwright.config' + ext));
if (configFile) return configFile;
}
};
if (!fs.existsSync(configFileOrDirectory)) throw new Error(`${configFileOrDirectory} does not exist`);
if (fs.statSync(configFileOrDirectory).isDirectory()) {
// When passed a directory, look for a config file inside.
const configFile = resolveConfigFileFromDirectory(configFileOrDirectory);
if (configFile) return configFile;
// If there is no config, assume this as a root testing directory.
return undefined;
}
// When passed a file, it must be a config file.
return configFileOrDirectory;
}
async function loadConfigFromFileRestartIfNeeded(configFile, overrides, ignoreDeps) {
const location = resolveConfigLocation(configFile);
if (restartWithExperimentalTsEsm(location.resolvedConfigFile)) return null;
return await loadConfig(location, overrides, ignoreDeps);
}
async function loadEmptyConfigForMergeReports() {
// Merge reports is "different" for no good reason. It should not pick up local config from the cwd.
return await loadConfig({
configDir: process.cwd()
});
}
function restartWithExperimentalTsEsm(configFile, force = false) {
// Opt-out switch.
if (process.env.PW_DISABLE_TS_ESM) return false;
// There are two esm loader APIs:
// - Older API that needs a process restart. Available in Node 16, 17, and non-latest 18, 19 and 20.
// - Newer API that works in-process. Available in Node 21+ and latest 18, 19 and 20.
// First check whether we have already restarted with the ESM loader from the older API.
if (globalThis.__esmLoaderPortPreV20) {
// clear execArgv after restart, so that childProcess.fork in user code does not inherit our loader.
process.execArgv = (0, _esmUtils.execArgvWithoutExperimentalLoaderOptions)();
return false;
}
// Now check for the newer API presence.
if (!require('node:module').register) {
// With older API requiring a process restart, do so conditionally on the config.
const configIsModule = !!configFile && (0, _util.fileIsModule)(configFile);
if (!force && !configIsModule) return false;
const innerProcess = require('child_process').fork(require.resolve('../../cli'), process.argv.slice(2), {
env: {
...process.env,
PW_TS_ESM_LEGACY_LOADER_ON: '1'
},
execArgv: (0, _esmUtils.execArgvWithExperimentalLoaderOptions)()
});
innerProcess.on('close', code => {
if (code !== 0 && code !== null) (0, _utils.gracefullyProcessExitDoNotHang)(code);
});
return true;
}
// With the newer API, always enable the ESM loader, because it does not need a restart.
(0, _esmLoaderHost.registerESMLoader)();
return false;
}

96
node_modules/playwright/lib/common/esmLoaderHost.js generated vendored Normal file
View File

@@ -0,0 +1,96 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.configureESMLoader = configureESMLoader;
exports.configureESMLoaderTransformConfig = configureESMLoaderTransformConfig;
exports.esmLoaderRegistered = void 0;
exports.incorporateCompilationCache = incorporateCompilationCache;
exports.registerESMLoader = registerESMLoader;
exports.startCollectingFileDeps = startCollectingFileDeps;
exports.stopCollectingFileDeps = stopCollectingFileDeps;
var _url = _interopRequireDefault(require("url"));
var _compilationCache = require("../transform/compilationCache");
var _transform = require("../transform/transform");
var _portTransport = require("../transform/portTransport");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
let loaderChannel;
// Node.js < 20
if (globalThis.__esmLoaderPortPreV20) loaderChannel = createPortTransport(globalThis.__esmLoaderPortPreV20);
// Node.js >= 20
let esmLoaderRegistered = exports.esmLoaderRegistered = false;
function registerESMLoader() {
const {
port1,
port2
} = new MessageChannel();
// register will wait until the loader is initialized.
require('node:module').register(_url.default.pathToFileURL(require.resolve('../transform/esmLoader')), {
parentURL: _url.default.pathToFileURL(__filename),
data: {
port: port2
},
transferList: [port2]
});
loaderChannel = createPortTransport(port1);
exports.esmLoaderRegistered = esmLoaderRegistered = true;
}
function createPortTransport(port) {
return new _portTransport.PortTransport(port, async (method, params) => {
if (method === 'pushToCompilationCache') (0, _compilationCache.addToCompilationCache)(params.cache);
});
}
async function startCollectingFileDeps() {
if (!loaderChannel) return;
await loaderChannel.send('startCollectingFileDeps', {});
}
async function stopCollectingFileDeps(file) {
if (!loaderChannel) return;
await loaderChannel.send('stopCollectingFileDeps', {
file
});
}
async function incorporateCompilationCache() {
if (!loaderChannel) return;
// This is needed to gather dependency information from the esm loader
// that is populated from the resolve hook. We do not need to push
// this information proactively during load, but gather it at the end.
const result = await loaderChannel.send('getCompilationCache', {});
(0, _compilationCache.addToCompilationCache)(result.cache);
}
async function configureESMLoader() {
if (!loaderChannel) return;
await loaderChannel.send('setSingleTSConfig', {
tsconfig: (0, _transform.singleTSConfig)()
});
await loaderChannel.send('addToCompilationCache', {
cache: (0, _compilationCache.serializeCompilationCache)()
});
}
async function configureESMLoaderTransformConfig() {
if (!loaderChannel) return;
await loaderChannel.send('setSingleTSConfig', {
tsconfig: (0, _transform.singleTSConfig)()
});
await loaderChannel.send('setTransformConfig', {
config: (0, _transform.transformConfig)()
});
}

30
node_modules/playwright/lib/common/expectBundle.js generated vendored Normal file
View File

@@ -0,0 +1,30 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.printReceived = exports.mock = exports.matcherUtils = exports.expect = exports.asymmetricMatchers = exports.RECEIVED_COLOR = exports.INVERTED_COLOR = exports.EXPECTED_COLOR = void 0;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const expect = exports.expect = require('./expectBundleImpl').expect;
const mock = exports.mock = require('./expectBundleImpl').mock;
const asymmetricMatchers = exports.asymmetricMatchers = require('./expectBundleImpl').asymmetricMatchers;
const matcherUtils = exports.matcherUtils = require('./expectBundleImpl').matcherUtils;
const EXPECTED_COLOR = exports.EXPECTED_COLOR = require('./expectBundleImpl').EXPECTED_COLOR;
const INVERTED_COLOR = exports.INVERTED_COLOR = require('./expectBundleImpl').INVERTED_COLOR;
const RECEIVED_COLOR = exports.RECEIVED_COLOR = require('./expectBundleImpl').RECEIVED_COLOR;
const printReceived = exports.printReceived = require('./expectBundleImpl').printReceived;

389
node_modules/playwright/lib/common/expectBundleImpl.js generated vendored Normal file

File diff suppressed because one or more lines are too long

323
node_modules/playwright/lib/common/fixtures.js generated vendored Normal file
View File

@@ -0,0 +1,323 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FixturePool = void 0;
exports.fixtureParameterNames = fixtureParameterNames;
exports.formatPotentiallyInternalLocation = formatPotentiallyInternalLocation;
exports.inheritFixtureNames = inheritFixtureNames;
var _util = require("../util");
var crypto = _interopRequireWildcard(require("crypto"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const kScopeOrder = ['test', 'worker'];
function isFixtureTuple(value) {
return Array.isArray(value) && typeof value[1] === 'object';
}
function isFixtureOption(value) {
return isFixtureTuple(value) && !!value[1].option;
}
class FixturePool {
constructor(fixturesList, onLoadError, parentPool, disallowWorkerFixtures, optionOverrides) {
var _optionOverrides$over;
this.digest = void 0;
this._registrations = void 0;
this._onLoadError = void 0;
this._registrations = new Map(parentPool ? parentPool._registrations : []);
this._onLoadError = onLoadError;
const allOverrides = (_optionOverrides$over = optionOverrides === null || optionOverrides === void 0 ? void 0 : optionOverrides.overrides) !== null && _optionOverrides$over !== void 0 ? _optionOverrides$over : {};
const overrideKeys = new Set(Object.keys(allOverrides));
for (const list of fixturesList) {
this._appendFixtureList(list, !!disallowWorkerFixtures, false);
// Process option overrides immediately after original option definitions,
// so that any test.use() override it.
const selectedOverrides = {};
for (const [key, value] of Object.entries(list.fixtures)) {
if (isFixtureOption(value) && overrideKeys.has(key)) selectedOverrides[key] = [allOverrides[key], value[1]];
}
if (Object.entries(selectedOverrides).length) this._appendFixtureList({
fixtures: selectedOverrides,
location: optionOverrides.location
}, !!disallowWorkerFixtures, true);
}
this.digest = this.validate();
}
_appendFixtureList(list, disallowWorkerFixtures, isOptionsOverride) {
const {
fixtures,
location
} = list;
for (const entry of Object.entries(fixtures)) {
const name = entry[0];
let value = entry[1];
let options;
if (isFixtureTuple(value)) {
var _value$1$auto;
options = {
auto: (_value$1$auto = value[1].auto) !== null && _value$1$auto !== void 0 ? _value$1$auto : false,
scope: value[1].scope || 'test',
option: !!value[1].option,
timeout: value[1].timeout,
customTitle: value[1].title,
box: value[1].box
};
value = value[0];
}
let fn = value;
const previous = this._registrations.get(name);
if (previous && options) {
if (previous.scope !== options.scope) {
this._addLoadError(`Fixture "${name}" has already been registered as a { scope: '${previous.scope}' } fixture defined in ${(0, _util.formatLocation)(previous.location)}.`, location);
continue;
}
if (previous.auto !== options.auto) {
this._addLoadError(`Fixture "${name}" has already been registered as a { auto: '${previous.scope}' } fixture defined in ${(0, _util.formatLocation)(previous.location)}.`, location);
continue;
}
} else if (previous) {
options = {
auto: previous.auto,
scope: previous.scope,
option: previous.option,
timeout: previous.timeout,
customTitle: previous.customTitle,
box: previous.box
};
} else if (!options) {
options = {
auto: false,
scope: 'test',
option: false,
timeout: undefined
};
}
if (!kScopeOrder.includes(options.scope)) {
this._addLoadError(`Fixture "${name}" has unknown { scope: '${options.scope}' }.`, location);
continue;
}
if (options.scope === 'worker' && disallowWorkerFixtures) {
this._addLoadError(`Cannot use({ ${name} }) in a describe group, because it forces a new worker.\nMake it top-level in the test file or put in the configuration file.`, location);
continue;
}
// Overriding option with "undefined" value means setting it to the default value
// from the config or from the original declaration of the option.
if (fn === undefined && options.option && previous) {
let original = previous;
while (!original.optionOverride && original.super) original = original.super;
fn = original.fn;
}
const deps = fixtureParameterNames(fn, location, e => this._onLoadError(e));
const registration = {
id: '',
name,
location,
scope: options.scope,
fn,
auto: options.auto,
option: options.option,
timeout: options.timeout,
customTitle: options.customTitle,
box: options.box,
deps,
super: previous,
optionOverride: isOptionsOverride
};
registrationId(registration);
this._registrations.set(name, registration);
}
}
validate() {
const markers = new Map();
const stack = [];
let hasDependencyErrors = false;
const addDependencyError = (message, location) => {
hasDependencyErrors = true;
this._addLoadError(message, location);
};
const visit = (registration, boxedOnly) => {
markers.set(registration, 'visiting');
stack.push(registration);
for (const name of registration.deps) {
const dep = this.resolve(name, registration);
if (!dep) {
if (name === registration.name) addDependencyError(`Fixture "${registration.name}" references itself, but does not have a base implementation.`, registration.location);else addDependencyError(`Fixture "${registration.name}" has unknown parameter "${name}".`, registration.location);
continue;
}
if (kScopeOrder.indexOf(registration.scope) > kScopeOrder.indexOf(dep.scope)) {
addDependencyError(`${registration.scope} fixture "${registration.name}" cannot depend on a ${dep.scope} fixture "${name}" defined in ${formatPotentiallyInternalLocation(dep.location)}.`, registration.location);
continue;
}
if (!markers.has(dep)) {
visit(dep, boxedOnly);
} else if (markers.get(dep) === 'visiting') {
const index = stack.indexOf(dep);
const allRegs = stack.slice(index, stack.length);
const filteredRegs = allRegs.filter(r => !r.box);
const regs = boxedOnly ? filteredRegs : allRegs;
const names = regs.map(r => `"${r.name}"`);
addDependencyError(`Fixtures ${names.join(' -> ')} -> "${dep.name}" form a dependency cycle: ${regs.map(r => formatPotentiallyInternalLocation(r.location)).join(' -> ')} -> ${formatPotentiallyInternalLocation(dep.location)}`, dep.location);
continue;
}
}
markers.set(registration, 'visited');
stack.pop();
};
const names = Array.from(this._registrations.keys()).sort();
// First iterate over non-boxed fixtures to provide clear error messages.
for (const name of names) {
const registration = this._registrations.get(name);
if (!registration.box) visit(registration, true);
}
// If no errors found, iterate over boxed fixtures
if (!hasDependencyErrors) {
for (const name of names) {
const registration = this._registrations.get(name);
if (registration.box) visit(registration, false);
}
}
const hash = crypto.createHash('sha1');
for (const name of names) {
const registration = this._registrations.get(name);
if (registration.scope === 'worker') hash.update(registration.id + ';');
}
return hash.digest('hex');
}
validateFunction(fn, prefix, location) {
for (const name of fixtureParameterNames(fn, location, e => this._onLoadError(e))) {
const registration = this._registrations.get(name);
if (!registration) this._addLoadError(`${prefix} has unknown parameter "${name}".`, location);
}
}
resolve(name, forFixture) {
if (name === (forFixture === null || forFixture === void 0 ? void 0 : forFixture.name)) return forFixture.super;
return this._registrations.get(name);
}
autoFixtures() {
return [...this._registrations.values()].filter(r => r.auto !== false);
}
_addLoadError(message, location) {
this._onLoadError({
message,
location
});
}
}
exports.FixturePool = FixturePool;
const signatureSymbol = Symbol('signature');
function formatPotentiallyInternalLocation(location) {
const isUserFixture = location && (0, _util.filterStackFile)(location.file);
return isUserFixture ? (0, _util.formatLocation)(location) : '<builtin>';
}
function fixtureParameterNames(fn, location, onError) {
if (typeof fn !== 'function') return [];
if (!fn[signatureSymbol]) fn[signatureSymbol] = innerFixtureParameterNames(fn, location, onError);
return fn[signatureSymbol];
}
function inheritFixtureNames(from, to) {
to[signatureSymbol] = from[signatureSymbol];
}
function innerFixtureParameterNames(fn, location, onError) {
const text = filterOutComments(fn.toString());
const match = text.match(/(?:async)?(?:\s+function)?[^(]*\(([^)]*)/);
if (!match) return [];
const trimmedParams = match[1].trim();
if (!trimmedParams) return [];
const [firstParam] = splitByComma(trimmedParams);
if (firstParam[0] !== '{' || firstParam[firstParam.length - 1] !== '}') {
onError({
message: 'First argument must use the object destructuring pattern: ' + firstParam,
location
});
return [];
}
const props = splitByComma(firstParam.substring(1, firstParam.length - 1)).map(prop => {
const colon = prop.indexOf(':');
return colon === -1 ? prop.trim() : prop.substring(0, colon).trim();
});
const restProperty = props.find(prop => prop.startsWith('...'));
if (restProperty) {
onError({
message: `Rest property "${restProperty}" is not supported. List all used fixtures explicitly, separated by comma.`,
location
});
return [];
}
return props;
}
function filterOutComments(s) {
const result = [];
let commentState = 'none';
for (let i = 0; i < s.length; ++i) {
if (commentState === 'singleline') {
if (s[i] === '\n') commentState = 'none';
} else if (commentState === 'multiline') {
if (s[i - 1] === '*' && s[i] === '/') commentState = 'none';
} else if (commentState === 'none') {
if (s[i] === '/' && s[i + 1] === '/') {
commentState = 'singleline';
} else if (s[i] === '/' && s[i + 1] === '*') {
commentState = 'multiline';
i += 2;
} else {
result.push(s[i]);
}
}
}
return result.join('');
}
function splitByComma(s) {
const result = [];
const stack = [];
let start = 0;
for (let i = 0; i < s.length; i++) {
if (s[i] === '{' || s[i] === '[') {
stack.push(s[i] === '{' ? '}' : ']');
} else if (s[i] === stack[stack.length - 1]) {
stack.pop();
} else if (!stack.length && s[i] === ',') {
const token = s.substring(start, i).trim();
if (token) result.push(token);
start = i + 1;
}
}
const lastToken = s.substring(start).trim();
if (lastToken) result.push(lastToken);
return result;
}
// name + superId, fn -> id
const registrationIdMap = new Map();
let lastId = 0;
function registrationId(registration) {
if (registration.id) return registration.id;
const key = registration.name + '@@@' + (registration.super ? registrationId(registration.super) : '');
let map = registrationIdMap.get(key);
if (!map) {
map = new Map();
registrationIdMap.set(key, map);
}
if (!map.has(registration.fn)) map.set(registration.fn, String(lastId++));
registration.id = map.get(registration.fn);
return registration.id;
}

48
node_modules/playwright/lib/common/globals.js generated vendored Normal file
View File

@@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.currentTestInfo = currentTestInfo;
exports.currentlyLoadingFileSuite = currentlyLoadingFileSuite;
exports.isWorkerProcess = isWorkerProcess;
exports.setCurrentTestInfo = setCurrentTestInfo;
exports.setCurrentlyLoadingFileSuite = setCurrentlyLoadingFileSuite;
exports.setIsWorkerProcess = setIsWorkerProcess;
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
let currentTestInfoValue = null;
function setCurrentTestInfo(testInfo) {
currentTestInfoValue = testInfo;
}
function currentTestInfo() {
return currentTestInfoValue;
}
let currentFileSuite;
function setCurrentlyLoadingFileSuite(suite) {
currentFileSuite = suite;
}
function currentlyLoadingFileSuite() {
return currentFileSuite;
}
let _isWorkerProcess = false;
function setIsWorkerProcess() {
_isWorkerProcess = true;
}
function isWorkerProcess() {
return _isWorkerProcess;
}

48
node_modules/playwright/lib/common/ipc.js generated vendored Normal file
View File

@@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.serializeConfig = serializeConfig;
exports.stdioChunkToParams = stdioChunkToParams;
var _util = _interopRequireDefault(require("util"));
var _compilationCache = require("../transform/compilationCache");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function serializeConfig(config, passCompilationCache) {
const result = {
location: {
configDir: config.configDir,
resolvedConfigFile: config.config.configFile
},
configCLIOverrides: config.configCLIOverrides,
compilationCache: passCompilationCache ? (0, _compilationCache.serializeCompilationCache)() : undefined
};
return result;
}
function stdioChunkToParams(chunk) {
if (chunk instanceof Uint8Array) return {
buffer: Buffer.from(chunk).toString('base64')
};
if (typeof chunk !== 'string') return {
text: _util.default.inspect(chunk)
};
return {
text: chunk
};
}

79
node_modules/playwright/lib/common/poolBuilder.js generated vendored Normal file
View File

@@ -0,0 +1,79 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PoolBuilder = void 0;
var _fixtures = require("./fixtures");
var _util = require("../util");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PoolBuilder {
static createForLoader() {
return new PoolBuilder('loader');
}
static createForWorker(project) {
return new PoolBuilder('worker', project);
}
constructor(type, project) {
this._project = void 0;
this._testTypePools = new Map();
this._type = void 0;
this._type = type;
this._project = project;
}
buildPools(suite, testErrors) {
suite.forEachTest(test => {
const pool = this._buildPoolForTest(test, testErrors);
if (this._type === 'loader') test._poolDigest = pool.digest;
if (this._type === 'worker') test._pool = pool;
});
}
_buildPoolForTest(test, testErrors) {
let pool = this._buildTestTypePool(test._testType, testErrors);
const parents = [];
for (let parent = test.parent; parent; parent = parent.parent) parents.push(parent);
parents.reverse();
for (const parent of parents) {
if (parent._use.length) pool = new _fixtures.FixturePool(parent._use, e => this._handleLoadError(e, testErrors), pool, parent._type === 'describe');
for (const hook of parent._hooks) pool.validateFunction(hook.fn, hook.type + ' hook', hook.location);
for (const modifier of parent._modifiers) pool.validateFunction(modifier.fn, modifier.type + ' modifier', modifier.location);
}
pool.validateFunction(test.fn, 'Test', test.location);
return pool;
}
_buildTestTypePool(testType, testErrors) {
if (!this._testTypePools.has(testType)) {
var _this$_project$projec, _this$_project, _this$_project2;
const optionOverrides = {
overrides: (_this$_project$projec = (_this$_project = this._project) === null || _this$_project === void 0 || (_this$_project = _this$_project.project) === null || _this$_project === void 0 ? void 0 : _this$_project.use) !== null && _this$_project$projec !== void 0 ? _this$_project$projec : {},
location: {
file: `project#${(_this$_project2 = this._project) === null || _this$_project2 === void 0 ? void 0 : _this$_project2.id}`,
line: 1,
column: 1
}
};
const pool = new _fixtures.FixturePool(testType.fixtures, e => this._handleLoadError(e, testErrors), undefined, undefined, optionOverrides);
this._testTypePools.set(testType, pool);
}
return this._testTypePools.get(testType);
}
_handleLoadError(e, testErrors) {
if (testErrors) testErrors.push(e);else throw new Error(`${(0, _util.formatLocation)(e.location)}: ${e.message}`);
}
}
exports.PoolBuilder = PoolBuilder;

140
node_modules/playwright/lib/common/process.js generated vendored Normal file
View File

@@ -0,0 +1,140 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ProcessRunner = void 0;
var _utils = require("playwright-core/lib/utils");
var _util = require("../util");
var _esmLoaderHost = require("./esmLoaderHost");
var _esmUtils = require("../transform/esmUtils");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ProcessRunner {
async gracefullyClose() {}
dispatchEvent(method, params) {
const response = {
method,
params
};
sendMessageToParent({
method: '__dispatch__',
params: response
});
}
}
exports.ProcessRunner = ProcessRunner;
let gracefullyCloseCalled = false;
let forceExitInitiated = false;
sendMessageToParent({
method: 'ready'
});
process.on('disconnect', () => gracefullyCloseAndExit(true));
process.on('SIGINT', () => {});
process.on('SIGTERM', () => {});
// Clear execArgv immediately, so that the user-code does not inherit our loader.
process.execArgv = (0, _esmUtils.execArgvWithoutExperimentalLoaderOptions)();
// Node.js >= 20
if (process.env.PW_TS_ESM_LOADER_ON) (0, _esmLoaderHost.registerESMLoader)();
let processRunner;
let processName;
const startingEnv = {
...process.env
};
process.on('message', async message => {
if (message.method === '__init__') {
const {
processParams,
runnerParams,
runnerScript
} = message.params;
void (0, _utils.startProfiling)();
const {
create
} = require(runnerScript);
processRunner = create(runnerParams);
processName = processParams.processName;
return;
}
if (message.method === '__stop__') {
const keys = new Set([...Object.keys(process.env), ...Object.keys(startingEnv)]);
const producedEnv = [...keys].filter(key => startingEnv[key] !== process.env[key]).map(key => {
var _process$env$key;
return [key, (_process$env$key = process.env[key]) !== null && _process$env$key !== void 0 ? _process$env$key : null];
});
sendMessageToParent({
method: '__env_produced__',
params: producedEnv
});
await gracefullyCloseAndExit(false);
return;
}
if (message.method === '__dispatch__') {
const {
id,
method,
params
} = message.params;
try {
const result = await processRunner[method](params);
const response = {
id,
result
};
sendMessageToParent({
method: '__dispatch__',
params: response
});
} catch (e) {
const response = {
id,
error: (0, _util.serializeError)(e)
};
sendMessageToParent({
method: '__dispatch__',
params: response
});
}
}
});
const kForceExitTimeout = +(process.env.PWTEST_FORCE_EXIT_TIMEOUT || 30000);
async function gracefullyCloseAndExit(forceExit) {
if (forceExit && !forceExitInitiated) {
forceExitInitiated = true;
// Force exit after 30 seconds.
// eslint-disable-next-line no-restricted-properties
setTimeout(() => process.exit(0), kForceExitTimeout);
}
if (!gracefullyCloseCalled) {
var _processRunner;
gracefullyCloseCalled = true;
// Meanwhile, try to gracefully shutdown.
await ((_processRunner = processRunner) === null || _processRunner === void 0 ? void 0 : _processRunner.gracefullyClose().catch(() => {}));
if (processName) await (0, _utils.stopProfiling)(processName).catch(() => {});
// eslint-disable-next-line no-restricted-properties
process.exit(0);
}
}
function sendMessageToParent(message) {
try {
process.send(message);
} catch (e) {
// Can throw when closing.
}
}

133
node_modules/playwright/lib/common/suiteUtils.js generated vendored Normal file
View File

@@ -0,0 +1,133 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.applyRepeatEachIndex = applyRepeatEachIndex;
exports.bindFileSuiteToProject = bindFileSuiteToProject;
exports.filterByFocusedLine = filterByFocusedLine;
exports.filterByTestIds = filterByTestIds;
exports.filterOnly = filterOnly;
exports.filterSuite = filterSuite;
exports.filterSuiteWithOnlySemantics = filterSuiteWithOnlySemantics;
exports.filterTestsRemoveEmptySuites = filterTestsRemoveEmptySuites;
var _path = _interopRequireDefault(require("path"));
var _utils = require("playwright-core/lib/utils");
var _util = require("../util");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function filterSuite(suite, suiteFilter, testFilter) {
for (const child of suite.suites) {
if (!suiteFilter(child)) filterSuite(child, suiteFilter, testFilter);
}
const filteredTests = suite.tests.filter(testFilter);
const entries = new Set([...suite.suites, ...filteredTests]);
suite._entries = suite._entries.filter(e => entries.has(e)); // Preserve the order.
}
function filterTestsRemoveEmptySuites(suite, filter) {
const filteredSuites = suite.suites.filter(child => filterTestsRemoveEmptySuites(child, filter));
const filteredTests = suite.tests.filter(filter);
const entries = new Set([...filteredSuites, ...filteredTests]);
suite._entries = suite._entries.filter(e => entries.has(e)); // Preserve the order.
return !!suite._entries.length;
}
function bindFileSuiteToProject(project, suite) {
const relativeFile = _path.default.relative(project.project.testDir, suite.location.file);
const fileId = (0, _utils.calculateSha1)((0, _utils.toPosixPath)(relativeFile)).slice(0, 20);
// Clone suite.
const result = suite._deepClone();
result._fileId = fileId;
// Assign test properties with project-specific values.
result.forEachTest((test, suite) => {
var _inheritedRetries, _inheritedTimeout;
suite._fileId = fileId;
// At the point of the query, suite is not yet attached to the project, so we only get file, describe and test titles.
const [file, ...titles] = test.titlePath();
const testIdExpression = `[project=${project.id}]${(0, _utils.toPosixPath)(file)}\x1e${titles.join('\x1e')}`;
const testId = fileId + '-' + (0, _utils.calculateSha1)(testIdExpression).slice(0, 20);
test.id = testId;
test._projectId = project.id;
// Inherit properties from parent suites.
let inheritedRetries;
let inheritedTimeout;
test.annotations = [];
for (let parentSuite = suite; parentSuite; parentSuite = parentSuite.parent) {
if (parentSuite._staticAnnotations.length) test.annotations = [...parentSuite._staticAnnotations, ...test.annotations];
if (inheritedRetries === undefined && parentSuite._retries !== undefined) inheritedRetries = parentSuite._retries;
if (inheritedTimeout === undefined && parentSuite._timeout !== undefined) inheritedTimeout = parentSuite._timeout;
}
test.retries = (_inheritedRetries = inheritedRetries) !== null && _inheritedRetries !== void 0 ? _inheritedRetries : project.project.retries;
test.timeout = (_inheritedTimeout = inheritedTimeout) !== null && _inheritedTimeout !== void 0 ? _inheritedTimeout : project.project.timeout;
test.annotations.push(...test._staticAnnotations);
// Skip annotations imply skipped expectedStatus.
if (test.annotations.some(a => a.type === 'skip' || a.type === 'fixme')) test.expectedStatus = 'skipped';
// We only compute / set digest in the runner.
if (test._poolDigest) test._workerHash = `${project.id}-${test._poolDigest}-0`;
});
return result;
}
function applyRepeatEachIndex(project, fileSuite, repeatEachIndex) {
// Assign test properties with project-specific values.
fileSuite.forEachTest((test, suite) => {
if (repeatEachIndex) {
const [file, ...titles] = test.titlePath();
const testIdExpression = `[project=${project.id}]${(0, _utils.toPosixPath)(file)}\x1e${titles.join('\x1e')} (repeat:${repeatEachIndex})`;
const testId = suite._fileId + '-' + (0, _utils.calculateSha1)(testIdExpression).slice(0, 20);
test.id = testId;
test.repeatEachIndex = repeatEachIndex;
if (test._poolDigest) test._workerHash = `${project.id}-${test._poolDigest}-${repeatEachIndex}`;
}
});
}
function filterOnly(suite) {
if (!suite._getOnlyItems().length) return;
const suiteFilter = suite => suite._only;
const testFilter = test => test._only;
return filterSuiteWithOnlySemantics(suite, suiteFilter, testFilter);
}
function filterSuiteWithOnlySemantics(suite, suiteFilter, testFilter) {
const onlySuites = suite.suites.filter(child => filterSuiteWithOnlySemantics(child, suiteFilter, testFilter) || suiteFilter(child));
const onlyTests = suite.tests.filter(testFilter);
const onlyEntries = new Set([...onlySuites, ...onlyTests]);
if (onlyEntries.size) {
suite._entries = suite._entries.filter(e => onlyEntries.has(e)); // Preserve the order.
return true;
}
return false;
}
function filterByFocusedLine(suite, focusedTestFileLines) {
if (!focusedTestFileLines.length) return;
const matchers = focusedTestFileLines.map(createFileMatcherFromFilter);
const testFileLineMatches = (testFileName, testLine, testColumn) => matchers.some(m => m(testFileName, testLine, testColumn));
const suiteFilter = suite => !!suite.location && testFileLineMatches(suite.location.file, suite.location.line, suite.location.column);
const testFilter = test => testFileLineMatches(test.location.file, test.location.line, test.location.column);
return filterSuite(suite, suiteFilter, testFilter);
}
function filterByTestIds(suite, testIdMatcher) {
if (!testIdMatcher) return;
filterTestsRemoveEmptySuites(suite, test => testIdMatcher(test.id));
}
function createFileMatcherFromFilter(filter) {
const fileMatcher = (0, _util.createFileMatcher)(filter.re || filter.exact || '');
return (testFileName, testLine, testColumn) => fileMatcher(testFileName) && (filter.line === testLine || filter.line === null) && (filter.column === testColumn || filter.column === null);
}

309
node_modules/playwright/lib/common/test.js generated vendored Normal file
View File

@@ -0,0 +1,309 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TestCase = exports.Suite = void 0;
var _testType = require("./testType");
var _teleReceiver = require("../isomorphic/teleReceiver");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Base {
constructor(title) {
this.title = void 0;
this._only = false;
this._requireFile = '';
this.title = title;
}
}
class Suite extends Base {
constructor(title, type) {
super(title);
this.location = void 0;
this.parent = void 0;
this._use = [];
this._entries = [];
this._hooks = [];
this._timeout = void 0;
this._retries = void 0;
// Annotations known statically before running the test, e.g. `test.describe.skip()` or `test.describe({ annotation }, body)`.
this._staticAnnotations = [];
// Explicitly declared tags that are not a part of the title.
this._tags = [];
this._modifiers = [];
this._parallelMode = 'none';
this._fullProject = void 0;
this._fileId = void 0;
this._type = void 0;
this._type = type;
}
get type() {
return this._type;
}
entries() {
return this._entries;
}
get suites() {
return this._entries.filter(entry => entry instanceof Suite);
}
get tests() {
return this._entries.filter(entry => entry instanceof TestCase);
}
_addTest(test) {
test.parent = this;
this._entries.push(test);
}
_addSuite(suite) {
suite.parent = this;
this._entries.push(suite);
}
_prependSuite(suite) {
suite.parent = this;
this._entries.unshift(suite);
}
allTests() {
const result = [];
const visit = suite => {
for (const entry of suite._entries) {
if (entry instanceof Suite) visit(entry);else result.push(entry);
}
};
visit(this);
return result;
}
_hasTests() {
let result = false;
const visit = suite => {
for (const entry of suite._entries) {
if (result) return;
if (entry instanceof Suite) visit(entry);else result = true;
}
};
visit(this);
return result;
}
titlePath() {
const titlePath = this.parent ? this.parent.titlePath() : [];
// Ignore anonymous describe blocks.
if (this.title || this._type !== 'describe') titlePath.push(this.title);
return titlePath;
}
_collectGrepTitlePath(path) {
if (this.parent) this.parent._collectGrepTitlePath(path);
if (this.title || this._type !== 'describe') path.push(this.title);
path.push(...this._tags);
}
_getOnlyItems() {
const items = [];
if (this._only) items.push(this);
for (const suite of this.suites) items.push(...suite._getOnlyItems());
items.push(...this.tests.filter(test => test._only));
return items;
}
_deepClone() {
const suite = this._clone();
for (const entry of this._entries) {
if (entry instanceof Suite) suite._addSuite(entry._deepClone());else suite._addTest(entry._clone());
}
return suite;
}
_deepSerialize() {
const suite = this._serialize();
suite.entries = [];
for (const entry of this._entries) {
if (entry instanceof Suite) suite.entries.push(entry._deepSerialize());else suite.entries.push(entry._serialize());
}
return suite;
}
static _deepParse(data) {
const suite = Suite._parse(data);
for (const entry of data.entries) {
if (entry.kind === 'suite') suite._addSuite(Suite._deepParse(entry));else suite._addTest(TestCase._parse(entry));
}
return suite;
}
forEachTest(visitor) {
for (const entry of this._entries) {
if (entry instanceof Suite) entry.forEachTest(visitor);else visitor(entry, this);
}
}
_serialize() {
return {
kind: 'suite',
title: this.title,
type: this._type,
location: this.location,
only: this._only,
requireFile: this._requireFile,
timeout: this._timeout,
retries: this._retries,
staticAnnotations: this._staticAnnotations.slice(),
tags: this._tags.slice(),
modifiers: this._modifiers.slice(),
parallelMode: this._parallelMode,
hooks: this._hooks.map(h => ({
type: h.type,
location: h.location,
title: h.title
})),
fileId: this._fileId
};
}
static _parse(data) {
const suite = new Suite(data.title, data.type);
suite.location = data.location;
suite._only = data.only;
suite._requireFile = data.requireFile;
suite._timeout = data.timeout;
suite._retries = data.retries;
suite._staticAnnotations = data.staticAnnotations;
suite._tags = data.tags;
suite._modifiers = data.modifiers;
suite._parallelMode = data.parallelMode;
suite._hooks = data.hooks.map(h => ({
type: h.type,
location: h.location,
title: h.title,
fn: () => {}
}));
suite._fileId = data.fileId;
return suite;
}
_clone() {
const data = this._serialize();
const suite = Suite._parse(data);
suite._use = this._use.slice();
suite._hooks = this._hooks.slice();
suite._fullProject = this._fullProject;
return suite;
}
project() {
var _this$_fullProject, _this$parent;
return ((_this$_fullProject = this._fullProject) === null || _this$_fullProject === void 0 ? void 0 : _this$_fullProject.project) || ((_this$parent = this.parent) === null || _this$parent === void 0 ? void 0 : _this$parent.project());
}
}
exports.Suite = Suite;
class TestCase extends Base {
constructor(title, fn, testType, location) {
super(title);
this.fn = void 0;
this.results = [];
this.location = void 0;
this.parent = void 0;
this.type = 'test';
this.expectedStatus = 'passed';
this.timeout = 0;
this.annotations = [];
this.retries = 0;
this.repeatEachIndex = 0;
this._testType = void 0;
this.id = '';
this._pool = void 0;
this._poolDigest = '';
this._workerHash = '';
this._projectId = '';
// Annotations known statically before running the test, e.g. `test.skip()` or `test(title, { annotation }, body)`.
this._staticAnnotations = [];
// Explicitly declared tags that are not a part of the title.
this._tags = [];
this.fn = fn;
this._testType = testType;
this.location = location;
}
titlePath() {
const titlePath = this.parent ? this.parent.titlePath() : [];
titlePath.push(this.title);
return titlePath;
}
outcome() {
return (0, _teleReceiver.computeTestCaseOutcome)(this);
}
ok() {
const status = this.outcome();
return status === 'expected' || status === 'flaky' || status === 'skipped';
}
get tags() {
return this._grepTitle().match(/@[\S]+/g) || [];
}
_serialize() {
return {
kind: 'test',
id: this.id,
title: this.title,
retries: this.retries,
timeout: this.timeout,
expectedStatus: this.expectedStatus,
location: this.location,
only: this._only,
requireFile: this._requireFile,
poolDigest: this._poolDigest,
workerHash: this._workerHash,
staticAnnotations: this._staticAnnotations.slice(),
annotations: this.annotations.slice(),
tags: this._tags.slice(),
projectId: this._projectId
};
}
static _parse(data) {
const test = new TestCase(data.title, () => {}, _testType.rootTestType, data.location);
test.id = data.id;
test.retries = data.retries;
test.timeout = data.timeout;
test.expectedStatus = data.expectedStatus;
test._only = data.only;
test._requireFile = data.requireFile;
test._poolDigest = data.poolDigest;
test._workerHash = data.workerHash;
test._staticAnnotations = data.staticAnnotations;
test.annotations = data.annotations;
test._tags = data.tags;
test._projectId = data.projectId;
return test;
}
_clone() {
const data = this._serialize();
const test = TestCase._parse(data);
test._testType = this._testType;
test.fn = this.fn;
return test;
}
_appendTestResult() {
const result = {
retry: this.results.length,
parallelIndex: -1,
workerIndex: -1,
duration: 0,
startTime: new Date(),
stdout: [],
stderr: [],
attachments: [],
status: 'skipped',
steps: [],
errors: []
};
this.results.push(result);
return result;
}
_grepTitle() {
const path = [];
this.parent._collectGrepTitlePath(path);
path.push(this.title);
path.push(...this._tags);
return path.join(' ');
}
}
exports.TestCase = TestCase;

102
node_modules/playwright/lib/common/testLoader.js generated vendored Normal file
View File

@@ -0,0 +1,102 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.defaultTimeout = void 0;
exports.loadTestFile = loadTestFile;
var _path = _interopRequireDefault(require("path"));
var _util = _interopRequireDefault(require("util"));
var _globals = require("./globals");
var _test = require("./test");
var _transform = require("../transform/transform");
var _util2 = require("../util");
var _compilationCache = require("../transform/compilationCache");
var esmLoaderHost = _interopRequireWildcard(require("./esmLoaderHost"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const defaultTimeout = exports.defaultTimeout = 30000;
// To allow multiple loaders in the same process without clearing require cache,
// we make these maps global.
const cachedFileSuites = new Map();
async function loadTestFile(file, rootDir, testErrors) {
if (cachedFileSuites.has(file)) return cachedFileSuites.get(file);
const suite = new _test.Suite(_path.default.relative(rootDir, file) || _path.default.basename(file), 'file');
suite._requireFile = file;
suite.location = {
file,
line: 0,
column: 0
};
(0, _globals.setCurrentlyLoadingFileSuite)(suite);
if (!(0, _globals.isWorkerProcess)()) {
(0, _compilationCache.startCollectingFileDeps)();
await esmLoaderHost.startCollectingFileDeps();
}
try {
await (0, _transform.requireOrImport)(file);
cachedFileSuites.set(file, suite);
} catch (e) {
if (!testErrors) throw e;
testErrors.push(serializeLoadError(file, e));
} finally {
(0, _globals.setCurrentlyLoadingFileSuite)(undefined);
if (!(0, _globals.isWorkerProcess)()) {
(0, _compilationCache.stopCollectingFileDeps)(file);
await esmLoaderHost.stopCollectingFileDeps(file);
}
}
{
// Test locations that we discover potentially have different file name.
// This could be due to either
// a) use of source maps or due to
// b) require of one file from another.
// Try fixing (a) w/o regressing (b).
const files = new Set();
suite.allTests().map(t => files.add(t.location.file));
if (files.size === 1) {
// All tests point to one file.
const mappedFile = files.values().next().value;
if (suite.location.file !== mappedFile) {
// The file is different, check for a likely source map case.
if (_path.default.extname(mappedFile) !== _path.default.extname(suite.location.file)) suite.location.file = mappedFile;
}
}
}
return suite;
}
function serializeLoadError(file, error) {
if (error instanceof Error) {
const result = (0, _util2.filterStackTrace)(error);
// Babel parse errors have location.
const loc = error.loc;
result.location = loc ? {
file,
line: loc.line || 0,
column: loc.column || 0
} : undefined;
return result;
}
return {
value: _util.default.inspect(error)
};
}

285
node_modules/playwright/lib/common/testType.js generated vendored Normal file
View File

@@ -0,0 +1,285 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TestTypeImpl = void 0;
exports.mergeTests = mergeTests;
exports.rootTestType = void 0;
var _expect = require("../matchers/expect");
var _globals = require("./globals");
var _test = require("./test");
var _transform = require("../transform/transform");
var _utils = require("playwright-core/lib/utils");
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const testTypeSymbol = Symbol('testType');
class TestTypeImpl {
constructor(fixtures) {
this.fixtures = void 0;
this.test = void 0;
this.fixtures = fixtures;
const test = (0, _transform.wrapFunctionWithLocation)(this._createTest.bind(this, 'default'));
test[testTypeSymbol] = this;
test.expect = _expect.expect;
test.only = (0, _transform.wrapFunctionWithLocation)(this._createTest.bind(this, 'only'));
test.describe = (0, _transform.wrapFunctionWithLocation)(this._describe.bind(this, 'default'));
test.describe.only = (0, _transform.wrapFunctionWithLocation)(this._describe.bind(this, 'only'));
test.describe.configure = (0, _transform.wrapFunctionWithLocation)(this._configure.bind(this));
test.describe.fixme = (0, _transform.wrapFunctionWithLocation)(this._describe.bind(this, 'fixme'));
test.describe.parallel = (0, _transform.wrapFunctionWithLocation)(this._describe.bind(this, 'parallel'));
test.describe.parallel.only = (0, _transform.wrapFunctionWithLocation)(this._describe.bind(this, 'parallel.only'));
test.describe.serial = (0, _transform.wrapFunctionWithLocation)(this._describe.bind(this, 'serial'));
test.describe.serial.only = (0, _transform.wrapFunctionWithLocation)(this._describe.bind(this, 'serial.only'));
test.describe.skip = (0, _transform.wrapFunctionWithLocation)(this._describe.bind(this, 'skip'));
test.beforeEach = (0, _transform.wrapFunctionWithLocation)(this._hook.bind(this, 'beforeEach'));
test.afterEach = (0, _transform.wrapFunctionWithLocation)(this._hook.bind(this, 'afterEach'));
test.beforeAll = (0, _transform.wrapFunctionWithLocation)(this._hook.bind(this, 'beforeAll'));
test.afterAll = (0, _transform.wrapFunctionWithLocation)(this._hook.bind(this, 'afterAll'));
test.skip = (0, _transform.wrapFunctionWithLocation)(this._modifier.bind(this, 'skip'));
test.fixme = (0, _transform.wrapFunctionWithLocation)(this._modifier.bind(this, 'fixme'));
test.fail = (0, _transform.wrapFunctionWithLocation)(this._modifier.bind(this, 'fail'));
test.fail.only = (0, _transform.wrapFunctionWithLocation)(this._createTest.bind(this, 'fail.only'));
test.slow = (0, _transform.wrapFunctionWithLocation)(this._modifier.bind(this, 'slow'));
test.setTimeout = (0, _transform.wrapFunctionWithLocation)(this._setTimeout.bind(this));
test.step = this._step.bind(this);
test.use = (0, _transform.wrapFunctionWithLocation)(this._use.bind(this));
test.extend = (0, _transform.wrapFunctionWithLocation)(this._extend.bind(this));
test.info = () => {
const result = (0, _globals.currentTestInfo)();
if (!result) throw new Error('test.info() can only be called while test is running');
return result;
};
this.test = test;
}
_currentSuite(location, title) {
const suite = (0, _globals.currentlyLoadingFileSuite)();
if (!suite) {
throw new Error([`Playwright Test did not expect ${title} to be called here.`, `Most common reasons include:`, `- You are calling ${title} in a configuration file.`, `- You are calling ${title} in a file that is imported by the configuration file.`, `- You have two different versions of @playwright/test. This usually happens`, ` when one of the dependencies in your package.json depends on @playwright/test.`].join('\n'));
}
return suite;
}
_createTest(type, location, title, fnOrDetails, fn) {
throwIfRunningInsideJest();
const suite = this._currentSuite(location, 'test()');
if (!suite) return;
let details;
let body;
if (typeof fnOrDetails === 'function') {
body = fnOrDetails;
details = {};
} else {
body = fn;
details = fnOrDetails;
}
const validatedDetails = validateTestDetails(details);
const test = new _test.TestCase(title, body, this, location);
test._requireFile = suite._requireFile;
test._staticAnnotations.push(...validatedDetails.annotations);
test._tags.push(...validatedDetails.tags);
suite._addTest(test);
if (type === 'only' || type === 'fail.only') test._only = true;
if (type === 'skip' || type === 'fixme' || type === 'fail') test._staticAnnotations.push({
type
});else if (type === 'fail.only') test._staticAnnotations.push({
type: 'fail'
});
}
_describe(type, location, titleOrFn, fnOrDetails, fn) {
throwIfRunningInsideJest();
const suite = this._currentSuite(location, 'test.describe()');
if (!suite) return;
let title;
let body;
let details;
if (typeof titleOrFn === 'function') {
title = '';
details = {};
body = titleOrFn;
} else if (typeof fnOrDetails === 'function') {
title = titleOrFn;
details = {};
body = fnOrDetails;
} else {
title = titleOrFn;
details = fnOrDetails;
body = fn;
}
const validatedDetails = validateTestDetails(details);
const child = new _test.Suite(title, 'describe');
child._requireFile = suite._requireFile;
child.location = location;
child._staticAnnotations.push(...validatedDetails.annotations);
child._tags.push(...validatedDetails.tags);
suite._addSuite(child);
if (type === 'only' || type === 'serial.only' || type === 'parallel.only') child._only = true;
if (type === 'serial' || type === 'serial.only') child._parallelMode = 'serial';
if (type === 'parallel' || type === 'parallel.only') child._parallelMode = 'parallel';
if (type === 'skip' || type === 'fixme') child._staticAnnotations.push({
type
});
for (let parent = suite; parent; parent = parent.parent) {
if (parent._parallelMode === 'serial' && child._parallelMode === 'parallel') throw new Error('describe.parallel cannot be nested inside describe.serial');
if (parent._parallelMode === 'default' && child._parallelMode === 'parallel') throw new Error('describe.parallel cannot be nested inside describe with default mode');
}
(0, _globals.setCurrentlyLoadingFileSuite)(child);
body();
(0, _globals.setCurrentlyLoadingFileSuite)(suite);
}
_hook(name, location, title, fn) {
const suite = this._currentSuite(location, `test.${name}()`);
if (!suite) return;
if (typeof title === 'function') {
fn = title;
title = `${name} hook`;
}
suite._hooks.push({
type: name,
fn: fn,
title,
location
});
}
_configure(location, options) {
throwIfRunningInsideJest();
const suite = this._currentSuite(location, `test.describe.configure()`);
if (!suite) return;
if (options.timeout !== undefined) suite._timeout = options.timeout;
if (options.retries !== undefined) suite._retries = options.retries;
if (options.mode !== undefined) {
if (suite._parallelMode !== 'none') throw new Error(`"${suite._parallelMode}" mode is already assigned for the enclosing scope.`);
suite._parallelMode = options.mode;
for (let parent = suite.parent; parent; parent = parent.parent) {
if (parent._parallelMode === 'serial' && suite._parallelMode === 'parallel') throw new Error('describe with parallel mode cannot be nested inside describe with serial mode');
if (parent._parallelMode === 'default' && suite._parallelMode === 'parallel') throw new Error('describe with parallel mode cannot be nested inside describe with default mode');
}
}
}
_modifier(type, location, ...modifierArgs) {
const suite = (0, _globals.currentlyLoadingFileSuite)();
if (suite) {
if (typeof modifierArgs[0] === 'string' && typeof modifierArgs[1] === 'function' && (type === 'skip' || type === 'fixme' || type === 'fail')) {
// Support for test.{skip,fixme,fail}(title, body)
this._createTest(type, location, modifierArgs[0], modifierArgs[1]);
return;
}
if (typeof modifierArgs[0] === 'string' && typeof modifierArgs[1] === 'object' && typeof modifierArgs[2] === 'function' && (type === 'skip' || type === 'fixme' || type === 'fail')) {
// Support for test.{skip,fixme,fail}(title, details, body)
this._createTest(type, location, modifierArgs[0], modifierArgs[1], modifierArgs[2]);
return;
}
if (typeof modifierArgs[0] === 'function') {
suite._modifiers.push({
type,
fn: modifierArgs[0],
location,
description: modifierArgs[1]
});
} else {
if (modifierArgs.length >= 1 && !modifierArgs[0]) return;
const description = modifierArgs[1];
suite._staticAnnotations.push({
type,
description
});
}
return;
}
const testInfo = (0, _globals.currentTestInfo)();
if (!testInfo) throw new Error(`test.${type}() can only be called inside test, describe block or fixture`);
if (typeof modifierArgs[0] === 'function') throw new Error(`test.${type}() with a function can only be called inside describe block`);
testInfo[type](...modifierArgs);
}
_setTimeout(location, timeout) {
const suite = (0, _globals.currentlyLoadingFileSuite)();
if (suite) {
suite._timeout = timeout;
return;
}
const testInfo = (0, _globals.currentTestInfo)();
if (!testInfo) throw new Error(`test.setTimeout() can only be called from a test`);
testInfo.setTimeout(timeout);
}
_use(location, fixtures) {
const suite = this._currentSuite(location, `test.use()`);
if (!suite) return;
suite._use.push({
fixtures,
location
});
}
async _step(title, body, options = {}) {
const testInfo = (0, _globals.currentTestInfo)();
if (!testInfo) throw new Error(`test.step() can only be called from a test`);
const step = testInfo._addStep({
category: 'test.step',
title,
location: options.location,
box: options.box
});
return await _utils.zones.run('stepZone', step, async () => {
try {
const result = await body();
step.complete({});
return result;
} catch (error) {
step.complete({
error
});
throw error;
}
});
}
_extend(location, fixtures) {
if (fixtures[testTypeSymbol]) throw new Error(`test.extend() accepts fixtures object, not a test object.\nDid you mean to call mergeTests()?`);
const fixturesWithLocation = {
fixtures,
location
};
return new TestTypeImpl([...this.fixtures, fixturesWithLocation]).test;
}
}
exports.TestTypeImpl = TestTypeImpl;
function throwIfRunningInsideJest() {
if (process.env.JEST_WORKER_ID) {
const packageManagerCommand = (0, _utils.getPackageManagerExecCommand)();
throw new Error(`Playwright Test needs to be invoked via '${packageManagerCommand} playwright test' and excluded from Jest test runs.\n` + `Creating one directory for Playwright tests and one for Jest is the recommended way of doing it.\n` + `See https://playwright.dev/docs/intro for more information about Playwright Test.`);
}
}
function validateTestDetails(details) {
const annotations = Array.isArray(details.annotation) ? details.annotation : details.annotation ? [details.annotation] : [];
const tags = Array.isArray(details.tag) ? details.tag : details.tag ? [details.tag] : [];
for (const tag of tags) {
if (tag[0] !== '@') throw new Error(`Tag must start with "@" symbol, got "${tag}" instead.`);
}
return {
annotations,
tags
};
}
const rootTestType = exports.rootTestType = new TestTypeImpl([]);
function mergeTests(...tests) {
let result = rootTestType;
for (const t of tests) {
const testTypeImpl = t[testTypeSymbol];
if (!testTypeImpl) throw new Error(`mergeTests() accepts "test" functions as parameters.\nDid you mean to call test.extend() with fixtures instead?`);
// Filter out common ancestor fixtures.
const newFixtures = testTypeImpl.fixtures.filter(theirs => !result.fixtures.find(ours => ours.fixtures === theirs.fixtures));
result = new TestTypeImpl([...result.fixtures, ...newFixtures]);
}
return result.test;
}

69
node_modules/playwright/lib/fsWatcher.js generated vendored Normal file
View File

@@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Watcher = void 0;
var _utilsBundle = require("./utilsBundle");
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Watcher {
constructor(onChange) {
this._onChange = void 0;
this._watchedPaths = [];
this._ignoredFolders = [];
this._collector = [];
this._fsWatcher = void 0;
this._throttleTimer = void 0;
this._onChange = onChange;
}
async update(watchedPaths, ignoredFolders, reportPending) {
var _this$_fsWatcher;
if (JSON.stringify([this._watchedPaths, this._ignoredFolders]) === JSON.stringify(watchedPaths, ignoredFolders)) return;
if (reportPending) this._reportEventsIfAny();
this._watchedPaths = watchedPaths;
this._ignoredFolders = ignoredFolders;
void ((_this$_fsWatcher = this._fsWatcher) === null || _this$_fsWatcher === void 0 ? void 0 : _this$_fsWatcher.close());
this._fsWatcher = undefined;
this._collector.length = 0;
clearTimeout(this._throttleTimer);
this._throttleTimer = undefined;
if (!this._watchedPaths.length) return;
const ignored = [...this._ignoredFolders, '**/node_modules/**'];
this._fsWatcher = _utilsBundle.chokidar.watch(watchedPaths, {
ignoreInitial: true,
ignored
}).on('all', async (event, file) => {
if (this._throttleTimer) clearTimeout(this._throttleTimer);
this._collector.push({
event,
file
});
this._throttleTimer = setTimeout(() => this._reportEventsIfAny(), 250);
});
await new Promise((resolve, reject) => this._fsWatcher.once('ready', resolve).once('error', reject));
}
async close() {
var _this$_fsWatcher2;
await ((_this$_fsWatcher2 = this._fsWatcher) === null || _this$_fsWatcher2 === void 0 ? void 0 : _this$_fsWatcher2.close());
}
_reportEventsIfAny() {
if (this._collector.length) this._onChange(this._collector.slice());
this._collector.length = 0;
}
}
exports.Watcher = Watcher;

903
node_modules/playwright/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,903 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports._baseTest = void 0;
Object.defineProperty(exports, "defineConfig", {
enumerable: true,
get: function () {
return _configLoader.defineConfig;
}
});
Object.defineProperty(exports, "expect", {
enumerable: true,
get: function () {
return _expect.expect;
}
});
Object.defineProperty(exports, "mergeExpects", {
enumerable: true,
get: function () {
return _expect.mergeExpects;
}
});
Object.defineProperty(exports, "mergeTests", {
enumerable: true,
get: function () {
return _testType.mergeTests;
}
});
exports.test = void 0;
var fs = _interopRequireWildcard(require("fs"));
var path = _interopRequireWildcard(require("path"));
var playwrightLibrary = _interopRequireWildcard(require("playwright-core"));
var _utils = require("playwright-core/lib/utils");
var _testType = require("./common/testType");
var _globals = require("./common/globals");
var _expect = require("./matchers/expect");
var _configLoader = require("./common/configLoader");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the 'License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const _baseTest = exports._baseTest = _testType.rootTestType.test;
(0, _utils.addInternalStackPrefix)(path.dirname(require.resolve('../package.json')));
if (process['__pw_initiator__']) {
const originalStackTraceLimit = Error.stackTraceLimit;
Error.stackTraceLimit = 200;
try {
throw new Error('Requiring @playwright/test second time, \nFirst:\n' + process['__pw_initiator__'] + '\n\nSecond: ');
} finally {
Error.stackTraceLimit = originalStackTraceLimit;
}
} else {
process['__pw_initiator__'] = new Error().stack;
}
const playwrightFixtures = {
defaultBrowserType: ['chromium', {
scope: 'worker',
option: true
}],
browserName: [({
defaultBrowserType
}, use) => use(defaultBrowserType), {
scope: 'worker',
option: true
}],
playwright: [async ({}, use) => {
await use(require('playwright-core'));
}, {
scope: 'worker',
box: true
}],
headless: [({
launchOptions
}, use) => {
var _launchOptions$headle;
return use((_launchOptions$headle = launchOptions.headless) !== null && _launchOptions$headle !== void 0 ? _launchOptions$headle : true);
}, {
scope: 'worker',
option: true
}],
channel: [({
launchOptions
}, use) => use(launchOptions.channel), {
scope: 'worker',
option: true
}],
launchOptions: [{}, {
scope: 'worker',
option: true
}],
connectOptions: [async ({
_optionConnectOptions
}, use) => {
await use(connectOptionsFromEnv() || _optionConnectOptions);
}, {
scope: 'worker',
option: true
}],
screenshot: ['off', {
scope: 'worker',
option: true
}],
video: ['off', {
scope: 'worker',
option: true
}],
trace: ['off', {
scope: 'worker',
option: true
}],
_browserOptions: [async ({
playwright,
headless,
channel,
launchOptions
}, use) => {
const options = {
handleSIGINT: false,
...launchOptions
};
if (headless !== undefined) options.headless = headless;
if (channel !== undefined) options.channel = channel;
options.tracesDir = tracing().tracesDir();
for (const browserType of [playwright.chromium, playwright.firefox, playwright.webkit, playwright._bidiChromium, playwright._bidiFirefox]) browserType._defaultLaunchOptions = options;
await use(options);
for (const browserType of [playwright.chromium, playwright.firefox, playwright.webkit, playwright._bidiChromium, playwright._bidiFirefox]) browserType._defaultLaunchOptions = undefined;
}, {
scope: 'worker',
auto: true,
box: true
}],
browser: [async ({
playwright,
browserName,
_browserOptions,
connectOptions,
_reuseContext
}, use, testInfo) => {
if (!['chromium', 'firefox', 'webkit', '_bidiChromium', '_bidiFirefox'].includes(browserName)) throw new Error(`Unexpected browserName "${browserName}", must be one of "chromium", "firefox" or "webkit"`);
if (connectOptions) {
var _connectOptions$expos;
const browser = await playwright[browserName].connect({
...connectOptions,
exposeNetwork: (_connectOptions$expos = connectOptions.exposeNetwork) !== null && _connectOptions$expos !== void 0 ? _connectOptions$expos : connectOptions._exposeNetwork,
headers: {
...(_reuseContext ? {
'x-playwright-reuse-context': '1'
} : {}),
// HTTP headers are ASCII only (not UTF-8).
'x-playwright-launch-options': (0, _utils.jsonStringifyForceASCII)(_browserOptions),
...connectOptions.headers
}
});
await use(browser);
await browser._wrapApiCall(async () => {
await browser.close({
reason: 'Test ended.'
});
}, true);
return;
}
const browser = await playwright[browserName].launch();
await use(browser);
await browser._wrapApiCall(async () => {
await browser.close({
reason: 'Test ended.'
});
}, true);
}, {
scope: 'worker',
timeout: 0
}],
acceptDownloads: [({
contextOptions
}, use) => {
var _contextOptions$accep;
return use((_contextOptions$accep = contextOptions.acceptDownloads) !== null && _contextOptions$accep !== void 0 ? _contextOptions$accep : true);
}, {
option: true
}],
bypassCSP: [({
contextOptions
}, use) => {
var _contextOptions$bypas;
return use((_contextOptions$bypas = contextOptions.bypassCSP) !== null && _contextOptions$bypas !== void 0 ? _contextOptions$bypas : false);
}, {
option: true
}],
colorScheme: [({
contextOptions
}, use) => use(contextOptions.colorScheme === undefined ? 'light' : contextOptions.colorScheme), {
option: true
}],
deviceScaleFactor: [({
contextOptions
}, use) => use(contextOptions.deviceScaleFactor), {
option: true
}],
extraHTTPHeaders: [({
contextOptions
}, use) => use(contextOptions.extraHTTPHeaders), {
option: true
}],
geolocation: [({
contextOptions
}, use) => use(contextOptions.geolocation), {
option: true
}],
hasTouch: [({
contextOptions
}, use) => {
var _contextOptions$hasTo;
return use((_contextOptions$hasTo = contextOptions.hasTouch) !== null && _contextOptions$hasTo !== void 0 ? _contextOptions$hasTo : false);
}, {
option: true
}],
httpCredentials: [({
contextOptions
}, use) => use(contextOptions.httpCredentials), {
option: true
}],
ignoreHTTPSErrors: [({
contextOptions
}, use) => {
var _contextOptions$ignor;
return use((_contextOptions$ignor = contextOptions.ignoreHTTPSErrors) !== null && _contextOptions$ignor !== void 0 ? _contextOptions$ignor : false);
}, {
option: true
}],
isMobile: [({
contextOptions
}, use) => {
var _contextOptions$isMob;
return use((_contextOptions$isMob = contextOptions.isMobile) !== null && _contextOptions$isMob !== void 0 ? _contextOptions$isMob : false);
}, {
option: true
}],
javaScriptEnabled: [({
contextOptions
}, use) => {
var _contextOptions$javaS;
return use((_contextOptions$javaS = contextOptions.javaScriptEnabled) !== null && _contextOptions$javaS !== void 0 ? _contextOptions$javaS : true);
}, {
option: true
}],
locale: [({
contextOptions
}, use) => {
var _contextOptions$local;
return use((_contextOptions$local = contextOptions.locale) !== null && _contextOptions$local !== void 0 ? _contextOptions$local : 'en-US');
}, {
option: true
}],
offline: [({
contextOptions
}, use) => {
var _contextOptions$offli;
return use((_contextOptions$offli = contextOptions.offline) !== null && _contextOptions$offli !== void 0 ? _contextOptions$offli : false);
}, {
option: true
}],
permissions: [({
contextOptions
}, use) => use(contextOptions.permissions), {
option: true
}],
proxy: [({
contextOptions
}, use) => use(contextOptions.proxy), {
option: true
}],
storageState: [({
contextOptions
}, use) => use(contextOptions.storageState), {
option: true
}],
clientCertificates: [({
contextOptions
}, use) => use(contextOptions.clientCertificates), {
option: true
}],
timezoneId: [({
contextOptions
}, use) => use(contextOptions.timezoneId), {
option: true
}],
userAgent: [({
contextOptions
}, use) => use(contextOptions.userAgent), {
option: true
}],
viewport: [({
contextOptions
}, use) => use(contextOptions.viewport === undefined ? {
width: 1280,
height: 720
} : contextOptions.viewport), {
option: true
}],
actionTimeout: [0, {
option: true
}],
testIdAttribute: ['data-testid', {
option: true
}],
navigationTimeout: [0, {
option: true
}],
baseURL: [async ({}, use) => {
await use(process.env.PLAYWRIGHT_TEST_BASE_URL);
}, {
option: true
}],
serviceWorkers: [({
contextOptions
}, use) => {
var _contextOptions$servi;
return use((_contextOptions$servi = contextOptions.serviceWorkers) !== null && _contextOptions$servi !== void 0 ? _contextOptions$servi : 'allow');
}, {
option: true
}],
contextOptions: [{}, {
option: true
}],
_combinedContextOptions: [async ({
acceptDownloads,
bypassCSP,
clientCertificates,
colorScheme,
deviceScaleFactor,
extraHTTPHeaders,
hasTouch,
geolocation,
httpCredentials,
ignoreHTTPSErrors,
isMobile,
javaScriptEnabled,
locale,
offline,
permissions,
proxy,
storageState,
viewport,
timezoneId,
userAgent,
baseURL,
contextOptions,
serviceWorkers
}, use) => {
const options = {};
if (acceptDownloads !== undefined) options.acceptDownloads = acceptDownloads;
if (bypassCSP !== undefined) options.bypassCSP = bypassCSP;
if (colorScheme !== undefined) options.colorScheme = colorScheme;
if (deviceScaleFactor !== undefined) options.deviceScaleFactor = deviceScaleFactor;
if (extraHTTPHeaders !== undefined) options.extraHTTPHeaders = extraHTTPHeaders;
if (geolocation !== undefined) options.geolocation = geolocation;
if (hasTouch !== undefined) options.hasTouch = hasTouch;
if (httpCredentials !== undefined) options.httpCredentials = httpCredentials;
if (ignoreHTTPSErrors !== undefined) options.ignoreHTTPSErrors = ignoreHTTPSErrors;
if (isMobile !== undefined) options.isMobile = isMobile;
if (javaScriptEnabled !== undefined) options.javaScriptEnabled = javaScriptEnabled;
if (locale !== undefined) options.locale = locale;
if (offline !== undefined) options.offline = offline;
if (permissions !== undefined) options.permissions = permissions;
if (proxy !== undefined) options.proxy = proxy;
if (storageState !== undefined) options.storageState = storageState;
if (clientCertificates !== null && clientCertificates !== void 0 && clientCertificates.length) options.clientCertificates = resolveClientCerticates(clientCertificates);
if (timezoneId !== undefined) options.timezoneId = timezoneId;
if (userAgent !== undefined) options.userAgent = userAgent;
if (viewport !== undefined) options.viewport = viewport;
if (baseURL !== undefined) options.baseURL = baseURL;
if (serviceWorkers !== undefined) options.serviceWorkers = serviceWorkers;
await use({
...contextOptions,
...options
});
}, {
box: true
}],
_setupContextOptions: [async ({
playwright,
_combinedContextOptions,
actionTimeout,
navigationTimeout,
testIdAttribute
}, use, testInfo) => {
if (testIdAttribute) playwrightLibrary.selectors.setTestIdAttribute(testIdAttribute);
testInfo.snapshotSuffix = process.platform;
if ((0, _utils.debugMode)()) testInfo._setDebugMode();
for (const browserType of [playwright.chromium, playwright.firefox, playwright.webkit]) {
browserType._defaultContextOptions = _combinedContextOptions;
browserType._defaultContextTimeout = actionTimeout || 0;
browserType._defaultContextNavigationTimeout = navigationTimeout || 0;
}
playwright.request._defaultContextOptions = {
..._combinedContextOptions
};
playwright.request._defaultContextOptions.tracesDir = tracing().tracesDir();
playwright.request._defaultContextOptions.timeout = actionTimeout || 0;
await use();
playwright.request._defaultContextOptions = undefined;
for (const browserType of [playwright.chromium, playwright.firefox, playwright.webkit]) {
browserType._defaultContextOptions = undefined;
browserType._defaultContextTimeout = undefined;
browserType._defaultContextNavigationTimeout = undefined;
}
}, {
auto: 'all-hooks-included',
title: 'context configuration',
box: true
}],
_setupArtifacts: [async ({
playwright,
screenshot
}, use, testInfo) => {
// This fixture has a separate zero-timeout slot to ensure that artifact collection
// happens even after some fixtures or hooks time out.
// Now that default test timeout is known, we can replace zero with an actual value.
testInfo.setTimeout(testInfo.project.timeout);
const artifactsRecorder = new ArtifactsRecorder(playwright, tracing().artifactsDir(), screenshot);
await artifactsRecorder.willStartTest(testInfo);
const tracingGroupSteps = [];
const csiListener = {
onApiCallBegin: (apiName, params, frames, userData, out) => {
userData.apiName = apiName;
const testInfo = (0, _globals.currentTestInfo)();
if (!testInfo || apiName.includes('setTestIdAttribute') || apiName === 'tracing.groupEnd') return;
const step = testInfo._addStep({
location: frames[0],
category: 'pw:api',
title: renderApiCall(apiName, params),
apiName,
params
}, tracingGroupSteps[tracingGroupSteps.length - 1]);
userData.step = step;
out.stepId = step.stepId;
if (apiName === 'tracing.group') tracingGroupSteps.push(step);
},
onApiCallEnd: (userData, error) => {
// "tracing.group" step will end later, when "tracing.groupEnd" finishes.
if (userData.apiName === 'tracing.group') return;
if (userData.apiName === 'tracing.groupEnd') {
const step = tracingGroupSteps.pop();
step === null || step === void 0 || step.complete({
error
});
return;
}
const step = userData.step;
step === null || step === void 0 || step.complete({
error
});
},
onWillPause: ({
keepTestTimeout
}) => {
var _currentTestInfo;
if (!keepTestTimeout) (_currentTestInfo = (0, _globals.currentTestInfo)()) === null || _currentTestInfo === void 0 || _currentTestInfo._setDebugMode();
},
runAfterCreateBrowserContext: async context => {
await (artifactsRecorder === null || artifactsRecorder === void 0 ? void 0 : artifactsRecorder.didCreateBrowserContext(context));
const testInfo = (0, _globals.currentTestInfo)();
if (testInfo) attachConnectedHeaderIfNeeded(testInfo, context.browser());
},
runAfterCreateRequestContext: async context => {
await (artifactsRecorder === null || artifactsRecorder === void 0 ? void 0 : artifactsRecorder.didCreateRequestContext(context));
},
runBeforeCloseBrowserContext: async context => {
await (artifactsRecorder === null || artifactsRecorder === void 0 ? void 0 : artifactsRecorder.willCloseBrowserContext(context));
},
runBeforeCloseRequestContext: async context => {
await (artifactsRecorder === null || artifactsRecorder === void 0 ? void 0 : artifactsRecorder.willCloseRequestContext(context));
}
};
const clientInstrumentation = playwright._instrumentation;
clientInstrumentation.addListener(csiListener);
await use();
clientInstrumentation.removeListener(csiListener);
await artifactsRecorder.didFinishTest();
}, {
auto: 'all-hooks-included',
title: 'trace recording',
box: true,
timeout: 0
}],
_contextFactory: [async ({
browser,
video,
_reuseContext,
_combinedContextOptions /** mitigate dep-via-auto lack of traceability */
}, use, testInfo) => {
const testInfoImpl = testInfo;
const videoMode = normalizeVideoMode(video);
const captureVideo = shouldCaptureVideo(videoMode, testInfo) && !_reuseContext;
const contexts = new Map();
await use(async options => {
const hook = testInfoImpl._currentHookType();
if (hook === 'beforeAll' || hook === 'afterAll') {
throw new Error([`"context" and "page" fixtures are not supported in "${hook}" since they are created on a per-test basis.`, `If you would like to reuse a single page between tests, create context manually with browser.newContext(). See https://aka.ms/playwright/reuse-page for details.`, `If you would like to configure your page before each test, do that in beforeEach hook instead.`].join('\n'));
}
const videoOptions = captureVideo ? {
recordVideo: {
dir: tracing().artifactsDir(),
size: typeof video === 'string' ? undefined : video.size
}
} : {};
const context = await browser.newContext({
...videoOptions,
...options
});
const contextData = {
pagesWithVideo: []
};
contexts.set(context, contextData);
if (captureVideo) context.on('page', page => contextData.pagesWithVideo.push(page));
if (process.env.PW_CLOCK === 'frozen') {
await context._wrapApiCall(async () => {
await context.clock.install({
time: 0
});
await context.clock.pauseAt(1000);
}, true);
} else if (process.env.PW_CLOCK === 'realtime') {
await context._wrapApiCall(async () => {
await context.clock.install({
time: 0
});
}, true);
}
return context;
});
let counter = 0;
const closeReason = testInfo.status === 'timedOut' ? 'Test timeout of ' + testInfo.timeout + 'ms exceeded.' : 'Test ended.';
await Promise.all([...contexts.keys()].map(async context => {
await context._wrapApiCall(async () => {
await context.close({
reason: closeReason
});
}, true);
const testFailed = testInfo.status !== testInfo.expectedStatus;
const preserveVideo = captureVideo && (videoMode === 'on' || testFailed && videoMode === 'retain-on-failure' || videoMode === 'on-first-retry' && testInfo.retry === 1);
if (preserveVideo) {
const {
pagesWithVideo: pagesForVideo
} = contexts.get(context);
const videos = pagesForVideo.map(p => p.video()).filter(Boolean);
await Promise.all(videos.map(async v => {
try {
const savedPath = testInfo.outputPath(`video${counter ? '-' + counter : ''}.webm`);
++counter;
await v.saveAs(savedPath);
testInfo.attachments.push({
name: 'video',
path: savedPath,
contentType: 'video/webm'
});
} catch (e) {
// Silent catch empty videos.
}
}));
}
}));
}, {
scope: 'test',
title: 'context',
box: true
}],
_optionContextReuseMode: ['none', {
scope: 'worker',
option: true
}],
_optionConnectOptions: [undefined, {
scope: 'worker',
option: true
}],
_reuseContext: [async ({
video,
_optionContextReuseMode
}, use) => {
let mode = _optionContextReuseMode;
if (process.env.PW_TEST_REUSE_CONTEXT) mode = 'when-possible';
const reuse = mode === 'when-possible' && normalizeVideoMode(video) === 'off';
await use(reuse);
}, {
scope: 'worker',
title: 'context',
box: true
}],
context: async ({
playwright,
browser,
_reuseContext,
_contextFactory
}, use, testInfo) => {
attachConnectedHeaderIfNeeded(testInfo, browser);
if (!_reuseContext) {
await use(await _contextFactory());
return;
}
const defaultContextOptions = playwright.chromium._defaultContextOptions;
const context = await browser._newContextForReuse(defaultContextOptions);
context[kIsReusedContext] = true;
await use(context);
const closeReason = testInfo.status === 'timedOut' ? 'Test timeout of ' + testInfo.timeout + 'ms exceeded.' : 'Test ended.';
await browser._stopPendingOperations(closeReason);
},
page: async ({
context,
_reuseContext
}, use) => {
if (!_reuseContext) {
await use(await context.newPage());
return;
}
// First time we are reusing the context, we should create the page.
let [page] = context.pages();
if (!page) page = await context.newPage();
await use(page);
},
request: async ({
playwright
}, use) => {
const request = await playwright.request.newContext();
await use(request);
const hook = test.info()._currentHookType();
if (hook === 'beforeAll') {
await request.dispose({
reason: [`Fixture { request } from beforeAll cannot be reused in a test.`, ` - Recommended fix: use a separate { request } in the test.`, ` - Alternatively, manually create APIRequestContext in beforeAll and dispose it in afterAll.`, `See https://playwright.dev/docs/api-testing#sending-api-requests-from-ui-tests for more details.`].join('\n')
});
} else {
await request.dispose();
}
}
};
function normalizeVideoMode(video) {
if (!video) return 'off';
let videoMode = typeof video === 'string' ? video : video.mode;
if (videoMode === 'retry-with-video') videoMode = 'on-first-retry';
return videoMode;
}
function shouldCaptureVideo(videoMode, testInfo) {
return videoMode === 'on' || videoMode === 'retain-on-failure' || videoMode === 'on-first-retry' && testInfo.retry === 1;
}
function normalizeScreenshotMode(screenshot) {
if (!screenshot) return 'off';
return typeof screenshot === 'string' ? screenshot : screenshot.mode;
}
function attachConnectedHeaderIfNeeded(testInfo, browser) {
const connectHeaders = browser === null || browser === void 0 ? void 0 : browser._connectHeaders;
if (!connectHeaders) return;
for (const header of connectHeaders) {
if (header.name !== 'x-playwright-attachment') continue;
const [name, value] = header.value.split('=');
if (!name || !value) continue;
if (testInfo.attachments.some(attachment => attachment.name === name)) continue;
testInfo.attachments.push({
name,
contentType: 'text/plain',
body: Buffer.from(value)
});
}
}
function resolveFileToConfig(file) {
const config = test.info().config.configFile;
if (!config || !file) return file;
if (path.isAbsolute(file)) return file;
return path.resolve(path.dirname(config), file);
}
function resolveClientCerticates(clientCertificates) {
for (const cert of clientCertificates) {
cert.certPath = resolveFileToConfig(cert.certPath);
cert.keyPath = resolveFileToConfig(cert.keyPath);
cert.pfxPath = resolveFileToConfig(cert.pfxPath);
}
return clientCertificates;
}
const kTracingStarted = Symbol('kTracingStarted');
const kIsReusedContext = Symbol('kReusedContext');
function connectOptionsFromEnv() {
const wsEndpoint = process.env.PW_TEST_CONNECT_WS_ENDPOINT;
if (!wsEndpoint) return undefined;
const headers = process.env.PW_TEST_CONNECT_HEADERS ? JSON.parse(process.env.PW_TEST_CONNECT_HEADERS) : undefined;
return {
wsEndpoint,
headers,
exposeNetwork: process.env.PW_TEST_CONNECT_EXPOSE_NETWORK
};
}
class ArtifactsRecorder {
constructor(playwright, artifactsDir, screenshot) {
this._testInfo = void 0;
this._playwright = void 0;
this._artifactsDir = void 0;
this._screenshotMode = void 0;
this._screenshotOptions = void 0;
this._temporaryScreenshots = [];
this._temporaryArtifacts = [];
this._reusedContexts = new Set();
this._screenshotOrdinal = 0;
this._screenshottedSymbol = void 0;
this._startedCollectingArtifacts = void 0;
this._playwright = playwright;
this._artifactsDir = artifactsDir;
this._screenshotMode = normalizeScreenshotMode(screenshot);
this._screenshotOptions = typeof screenshot === 'string' ? undefined : screenshot;
this._screenshottedSymbol = Symbol('screenshotted');
this._startedCollectingArtifacts = Symbol('startedCollectingArtifacts');
}
_createTemporaryArtifact(...name) {
const file = path.join(this._artifactsDir, ...name);
this._temporaryArtifacts.push(file);
return file;
}
async willStartTest(testInfo) {
this._testInfo = testInfo;
testInfo._onDidFinishTestFunction = () => this.didFinishTestFunction();
// Since beforeAll(s), test and afterAll(s) reuse the same TestInfo, make sure we do not
// overwrite previous screenshots.
this._screenshotOrdinal = testInfo.attachments.filter(a => a.name === 'screenshot').length;
// Process existing contexts.
for (const browserType of [this._playwright.chromium, this._playwright.firefox, this._playwright.webkit]) {
const promises = [];
const existingContexts = Array.from(browserType._contexts);
for (const context of existingContexts) {
if (context[kIsReusedContext]) this._reusedContexts.add(context);else promises.push(this.didCreateBrowserContext(context));
}
await Promise.all(promises);
}
{
const existingApiRequests = Array.from(this._playwright.request._contexts);
await Promise.all(existingApiRequests.map(c => this.didCreateRequestContext(c)));
}
}
async didCreateBrowserContext(context) {
await this._startTraceChunkOnContextCreation(context.tracing);
}
async willCloseBrowserContext(context) {
// When reusing context, we get all previous contexts closed at the start of next test.
// Do not record empty traces and useless screenshots for them.
if (this._reusedContexts.has(context)) return;
await this._stopTracing(context.tracing);
if (this._screenshotMode === 'on' || this._screenshotMode === 'only-on-failure' || this._screenshotMode === 'on-first-failure' && this._testInfo.retry === 0) {
// Capture screenshot for now. We'll know whether we have to preserve them
// after the test finishes.
await Promise.all(context.pages().map(page => this._screenshotPage(page, true)));
}
}
async didCreateRequestContext(context) {
const tracing = context._tracing;
await this._startTraceChunkOnContextCreation(tracing);
}
async willCloseRequestContext(context) {
const tracing = context._tracing;
await this._stopTracing(tracing);
}
_shouldCaptureScreenshotUponFinish() {
return this._screenshotMode === 'on' || this._screenshotMode === 'only-on-failure' && this._testInfo._isFailure() || this._screenshotMode === 'on-first-failure' && this._testInfo._isFailure() && this._testInfo.retry === 0;
}
async didFinishTestFunction() {
if (this._shouldCaptureScreenshotUponFinish()) await this._screenshotOnTestFailure();
}
async didFinishTest() {
const captureScreenshots = this._shouldCaptureScreenshotUponFinish();
if (captureScreenshots) await this._screenshotOnTestFailure();
const leftoverContexts = [];
for (const browserType of [this._playwright.chromium, this._playwright.firefox, this._playwright.webkit]) leftoverContexts.push(...browserType._contexts);
const leftoverApiRequests = Array.from(this._playwright.request._contexts);
// Collect traces/screenshots for remaining contexts.
await Promise.all(leftoverContexts.map(async context => {
await this._stopTracing(context.tracing);
}).concat(leftoverApiRequests.map(async context => {
const tracing = context._tracing;
await this._stopTracing(tracing);
})));
// Attach temporary screenshots for contexts closed before collecting the test trace.
if (captureScreenshots) {
for (const file of this._temporaryScreenshots) {
try {
const screenshotPath = this._createScreenshotAttachmentPath();
await fs.promises.rename(file, screenshotPath);
this._attachScreenshot(screenshotPath);
} catch {}
}
}
}
_createScreenshotAttachmentPath() {
const testFailed = this._testInfo._isFailure();
const index = this._screenshotOrdinal + 1;
++this._screenshotOrdinal;
const screenshotPath = this._testInfo.outputPath(`test-${testFailed ? 'failed' : 'finished'}-${index}.png`);
return screenshotPath;
}
async _screenshotPage(page, temporary) {
if (page[this._screenshottedSymbol]) return;
page[this._screenshottedSymbol] = true;
try {
const screenshotPath = temporary ? this._createTemporaryArtifact((0, _utils.createGuid)() + '.png') : this._createScreenshotAttachmentPath();
// Pass caret=initial to avoid any evaluations that might slow down the screenshot
// and let the page modify itself from the problematic state it had at the moment of failure.
await page.screenshot({
...this._screenshotOptions,
timeout: 5000,
path: screenshotPath,
caret: 'initial'
});
if (temporary) this._temporaryScreenshots.push(screenshotPath);else this._attachScreenshot(screenshotPath);
} catch {
// Screenshot may fail, just ignore.
}
}
_attachScreenshot(screenshotPath) {
this._testInfo.attachments.push({
name: 'screenshot',
path: screenshotPath,
contentType: 'image/png'
});
}
async _screenshotOnTestFailure() {
const contexts = [];
for (const browserType of [this._playwright.chromium, this._playwright.firefox, this._playwright.webkit]) contexts.push(...browserType._contexts);
const pages = contexts.map(ctx => ctx.pages()).flat();
await Promise.all(pages.map(page => this._screenshotPage(page, false)));
}
async _startTraceChunkOnContextCreation(tracing) {
const options = this._testInfo._tracing.traceOptions();
if (options) {
const title = this._testInfo._tracing.traceTitle();
const name = this._testInfo._tracing.generateNextTraceRecordingName();
if (!tracing[kTracingStarted]) {
await tracing.start({
...options,
title,
name
});
tracing[kTracingStarted] = true;
} else {
await tracing.startChunk({
title,
name
});
}
} else {
if (tracing[kTracingStarted]) {
tracing[kTracingStarted] = false;
await tracing.stop();
}
}
}
async _stopTracing(tracing) {
if (tracing[this._startedCollectingArtifacts]) return;
tracing[this._startedCollectingArtifacts] = true;
if (this._testInfo._tracing.traceOptions() && tracing[kTracingStarted]) await tracing.stopChunk({
path: this._testInfo._tracing.generateNextTraceRecordingPath()
});
}
}
const paramsToRender = ['url', 'selector', 'text', 'key'];
function renderApiCall(apiName, params) {
if (apiName === 'tracing.group') return params.name;
const paramsArray = [];
if (params) {
for (const name of paramsToRender) {
if (!(name in params)) continue;
let value;
if (name === 'selector' && (0, _utils.isString)(params[name]) && params[name].startsWith('internal:')) {
const getter = (0, _utils.asLocator)('javascript', params[name]);
apiName = apiName.replace(/^locator\./, 'locator.' + getter + '.');
apiName = apiName.replace(/^page\./, 'page.' + getter + '.');
apiName = apiName.replace(/^frame\./, 'frame.' + getter + '.');
} else {
value = params[name];
paramsArray.push(value);
}
}
}
const paramsText = paramsArray.length ? '(' + paramsArray.join(', ') + ')' : '';
return apiName + paramsText;
}
function tracing() {
return test.info()._tracing;
}
const test = exports.test = _baseTest.extend(playwrightFixtures);

28
node_modules/playwright/lib/internalsForTest.js generated vendored Normal file
View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fileDependencies = fileDependencies;
var _path = _interopRequireDefault(require("path"));
var _compilationCache = require("./transform/compilationCache");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function fileDependencies() {
return Object.fromEntries([...(0, _compilationCache.fileDependenciesForTest)().entries()].map(entry => [_path.default.basename(entry[0]), [...entry[1]].map(f => _path.default.basename(f)).sort()]));
}

72
node_modules/playwright/lib/isomorphic/events.js generated vendored Normal file
View File

@@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.EventEmitter = exports.Disposable = void 0;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
let Disposable = exports.Disposable = void 0;
(function (_Disposable) {
function disposeAll(disposables) {
for (const disposable of disposables.splice(0)) disposable.dispose();
}
_Disposable.disposeAll = disposeAll;
})(Disposable || (exports.Disposable = Disposable = {}));
class EventEmitter {
constructor() {
this.event = void 0;
this._deliveryQueue = void 0;
this._listeners = new Set();
this.event = (listener, disposables) => {
this._listeners.add(listener);
let disposed = false;
const self = this;
const result = {
dispose() {
if (!disposed) {
disposed = true;
self._listeners.delete(listener);
}
}
};
if (disposables) disposables.push(result);
return result;
};
}
fire(event) {
const dispatch = !this._deliveryQueue;
if (!this._deliveryQueue) this._deliveryQueue = [];
for (const listener of this._listeners) this._deliveryQueue.push({
listener,
event
});
if (!dispatch) return;
for (let index = 0; index < this._deliveryQueue.length; index++) {
const {
listener,
event
} = this._deliveryQueue[index];
listener.call(null, event);
}
this._deliveryQueue = undefined;
}
dispose() {
this._listeners.clear();
if (this._deliveryQueue) this._deliveryQueue = [];
}
}
exports.EventEmitter = EventEmitter;

25
node_modules/playwright/lib/isomorphic/folders.js generated vendored Normal file
View File

@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.artifactsFolderName = artifactsFolderName;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function artifactsFolderName(workerIndex) {
return `.playwright-artifacts-${workerIndex}`;
}

View File

@@ -0,0 +1,58 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.StringInternPool = exports.JsonStringInternalizer = void 0;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class StringInternPool {
constructor() {
this._stringCache = new Map();
}
internString(s) {
let result = this._stringCache.get(s);
if (!result) {
this._stringCache.set(s, s);
result = s;
}
return result;
}
}
exports.StringInternPool = StringInternPool;
class JsonStringInternalizer {
constructor(pool) {
this._pool = void 0;
this._pool = pool;
}
traverse(value) {
if (typeof value !== 'object') return;
if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
if (typeof value[i] === 'string') value[i] = this.intern(value[i]);else this.traverse(value[i]);
}
} else {
for (const name in value) {
if (typeof value[name] === 'string') value[name] = this.intern(value[name]);else this.traverse(value[name]);
}
}
}
intern(value) {
return this._pool.internString(value);
}
}
exports.JsonStringInternalizer = JsonStringInternalizer;

504
node_modules/playwright/lib/isomorphic/teleReceiver.js generated vendored Normal file
View File

@@ -0,0 +1,504 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.baseFullConfig = exports.TeleTestResult = exports.TeleTestCase = exports.TeleSuite = exports.TeleReporterReceiver = void 0;
exports.computeTestCaseOutcome = computeTestCaseOutcome;
exports.parseRegexPatterns = parseRegexPatterns;
exports.serializeRegexPatterns = serializeRegexPatterns;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class TeleReporterReceiver {
constructor(reporter, options = {}) {
this.isListing = false;
this._rootSuite = void 0;
this._options = void 0;
this._reporter = void 0;
this._tests = new Map();
this._rootDir = void 0;
this._config = void 0;
this._rootSuite = new TeleSuite('', 'root');
this._options = options;
this._reporter = reporter;
}
reset() {
this._rootSuite._entries = [];
this._tests.clear();
}
dispatch(message) {
const {
method,
params
} = message;
if (method === 'onConfigure') {
this._onConfigure(params.config);
return;
}
if (method === 'onProject') {
this._onProject(params.project);
return;
}
if (method === 'onBegin') {
this._onBegin();
return;
}
if (method === 'onTestBegin') {
this._onTestBegin(params.testId, params.result);
return;
}
if (method === 'onTestEnd') {
this._onTestEnd(params.test, params.result);
return;
}
if (method === 'onStepBegin') {
this._onStepBegin(params.testId, params.resultId, params.step);
return;
}
if (method === 'onStepEnd') {
this._onStepEnd(params.testId, params.resultId, params.step);
return;
}
if (method === 'onError') {
this._onError(params.error);
return;
}
if (method === 'onStdIO') {
this._onStdIO(params.type, params.testId, params.resultId, params.data, params.isBase64);
return;
}
if (method === 'onEnd') return this._onEnd(params.result);
if (method === 'onExit') return this._onExit();
}
_onConfigure(config) {
var _this$_reporter$onCon, _this$_reporter;
this._rootDir = config.rootDir;
this._config = this._parseConfig(config);
(_this$_reporter$onCon = (_this$_reporter = this._reporter).onConfigure) === null || _this$_reporter$onCon === void 0 || _this$_reporter$onCon.call(_this$_reporter, this._config);
}
_onProject(project) {
let projectSuite = this._options.mergeProjects ? this._rootSuite.suites.find(suite => suite.project().name === project.name) : undefined;
if (!projectSuite) {
projectSuite = new TeleSuite(project.name, 'project');
this._rootSuite._addSuite(projectSuite);
}
// Always update project in watch mode.
projectSuite._project = this._parseProject(project);
for (const suite of project.suites) this._mergeSuiteInto(suite, projectSuite);
}
_onBegin() {
var _this$_reporter$onBeg, _this$_reporter2;
(_this$_reporter$onBeg = (_this$_reporter2 = this._reporter).onBegin) === null || _this$_reporter$onBeg === void 0 || _this$_reporter$onBeg.call(_this$_reporter2, this._rootSuite);
}
_onTestBegin(testId, payload) {
var _this$_reporter$onTes, _this$_reporter3;
const test = this._tests.get(testId);
if (this._options.clearPreviousResultsWhenTestBegins) test.results = [];
const testResult = test._createTestResult(payload.id);
testResult.retry = payload.retry;
testResult.workerIndex = payload.workerIndex;
testResult.parallelIndex = payload.parallelIndex;
testResult.setStartTimeNumber(payload.startTime);
(_this$_reporter$onTes = (_this$_reporter3 = this._reporter).onTestBegin) === null || _this$_reporter$onTes === void 0 || _this$_reporter$onTes.call(_this$_reporter3, test, testResult);
}
_onTestEnd(testEndPayload, payload) {
var _result$errors, _this$_reporter$onTes2, _this$_reporter4;
const test = this._tests.get(testEndPayload.testId);
test.timeout = testEndPayload.timeout;
test.expectedStatus = testEndPayload.expectedStatus;
test.annotations = testEndPayload.annotations;
const result = test.results.find(r => r._id === payload.id);
result.duration = payload.duration;
result.status = payload.status;
result.errors = payload.errors;
result.error = (_result$errors = result.errors) === null || _result$errors === void 0 ? void 0 : _result$errors[0];
result.attachments = this._parseAttachments(payload.attachments);
(_this$_reporter$onTes2 = (_this$_reporter4 = this._reporter).onTestEnd) === null || _this$_reporter$onTes2 === void 0 || _this$_reporter$onTes2.call(_this$_reporter4, test, result);
// Free up the memory as won't see these step ids.
result._stepMap = new Map();
}
_onStepBegin(testId, resultId, payload) {
var _this$_reporter$onSte, _this$_reporter5;
const test = this._tests.get(testId);
const result = test.results.find(r => r._id === resultId);
const parentStep = payload.parentStepId ? result._stepMap.get(payload.parentStepId) : undefined;
const location = this._absoluteLocation(payload.location);
const step = new TeleTestStep(payload, parentStep, location);
if (parentStep) parentStep.steps.push(step);else result.steps.push(step);
result._stepMap.set(payload.id, step);
(_this$_reporter$onSte = (_this$_reporter5 = this._reporter).onStepBegin) === null || _this$_reporter$onSte === void 0 || _this$_reporter$onSte.call(_this$_reporter5, test, result, step);
}
_onStepEnd(testId, resultId, payload) {
var _this$_reporter$onSte2, _this$_reporter6;
const test = this._tests.get(testId);
const result = test.results.find(r => r._id === resultId);
const step = result._stepMap.get(payload.id);
step.duration = payload.duration;
step.error = payload.error;
(_this$_reporter$onSte2 = (_this$_reporter6 = this._reporter).onStepEnd) === null || _this$_reporter$onSte2 === void 0 || _this$_reporter$onSte2.call(_this$_reporter6, test, result, step);
}
_onError(error) {
var _this$_reporter$onErr, _this$_reporter7;
(_this$_reporter$onErr = (_this$_reporter7 = this._reporter).onError) === null || _this$_reporter$onErr === void 0 || _this$_reporter$onErr.call(_this$_reporter7, error);
}
_onStdIO(type, testId, resultId, data, isBase64) {
const chunk = isBase64 ? globalThis.Buffer ? Buffer.from(data, 'base64') : atob(data) : data;
const test = testId ? this._tests.get(testId) : undefined;
const result = test && resultId ? test.results.find(r => r._id === resultId) : undefined;
if (type === 'stdout') {
var _this$_reporter$onStd, _this$_reporter8;
result === null || result === void 0 || result.stdout.push(chunk);
(_this$_reporter$onStd = (_this$_reporter8 = this._reporter).onStdOut) === null || _this$_reporter$onStd === void 0 || _this$_reporter$onStd.call(_this$_reporter8, chunk, test, result);
} else {
var _this$_reporter$onStd2, _this$_reporter9;
result === null || result === void 0 || result.stderr.push(chunk);
(_this$_reporter$onStd2 = (_this$_reporter9 = this._reporter).onStdErr) === null || _this$_reporter$onStd2 === void 0 || _this$_reporter$onStd2.call(_this$_reporter9, chunk, test, result);
}
}
async _onEnd(result) {
var _this$_reporter$onEnd, _this$_reporter10;
await ((_this$_reporter$onEnd = (_this$_reporter10 = this._reporter).onEnd) === null || _this$_reporter$onEnd === void 0 ? void 0 : _this$_reporter$onEnd.call(_this$_reporter10, {
status: result.status,
startTime: new Date(result.startTime),
duration: result.duration
}));
}
_onExit() {
var _this$_reporter$onExi, _this$_reporter11;
return (_this$_reporter$onExi = (_this$_reporter11 = this._reporter).onExit) === null || _this$_reporter$onExi === void 0 ? void 0 : _this$_reporter$onExi.call(_this$_reporter11);
}
_parseConfig(config) {
const result = {
...baseFullConfig,
...config
};
if (this._options.configOverrides) {
result.configFile = this._options.configOverrides.configFile;
result.reportSlowTests = this._options.configOverrides.reportSlowTests;
result.quiet = this._options.configOverrides.quiet;
result.reporter = [...this._options.configOverrides.reporter];
}
return result;
}
_parseProject(project) {
return {
metadata: project.metadata,
name: project.name,
outputDir: this._absolutePath(project.outputDir),
repeatEach: project.repeatEach,
retries: project.retries,
testDir: this._absolutePath(project.testDir),
testIgnore: parseRegexPatterns(project.testIgnore),
testMatch: parseRegexPatterns(project.testMatch),
timeout: project.timeout,
grep: parseRegexPatterns(project.grep),
grepInvert: parseRegexPatterns(project.grepInvert),
dependencies: project.dependencies,
teardown: project.teardown,
snapshotDir: this._absolutePath(project.snapshotDir),
use: {}
};
}
_parseAttachments(attachments) {
return attachments.map(a => {
return {
...a,
body: a.base64 && globalThis.Buffer ? Buffer.from(a.base64, 'base64') : undefined
};
});
}
_mergeSuiteInto(jsonSuite, parent) {
let targetSuite = parent.suites.find(s => s.title === jsonSuite.title);
if (!targetSuite) {
targetSuite = new TeleSuite(jsonSuite.title, parent.type === 'project' ? 'file' : 'describe');
parent._addSuite(targetSuite);
}
targetSuite.location = this._absoluteLocation(jsonSuite.location);
jsonSuite.entries.forEach(e => {
if ('testId' in e) this._mergeTestInto(e, targetSuite);else this._mergeSuiteInto(e, targetSuite);
});
}
_mergeTestInto(jsonTest, parent) {
let targetTest = this._options.mergeTestCases ? parent.tests.find(s => s.title === jsonTest.title && s.repeatEachIndex === jsonTest.repeatEachIndex) : undefined;
if (!targetTest) {
targetTest = new TeleTestCase(jsonTest.testId, jsonTest.title, this._absoluteLocation(jsonTest.location), jsonTest.repeatEachIndex);
parent._addTest(targetTest);
this._tests.set(targetTest.id, targetTest);
}
this._updateTest(jsonTest, targetTest);
}
_updateTest(payload, test) {
var _payload$tags, _payload$annotations;
test.id = payload.testId;
test.location = this._absoluteLocation(payload.location);
test.retries = payload.retries;
test.tags = (_payload$tags = payload.tags) !== null && _payload$tags !== void 0 ? _payload$tags : [];
test.annotations = (_payload$annotations = payload.annotations) !== null && _payload$annotations !== void 0 ? _payload$annotations : [];
return test;
}
_absoluteLocation(location) {
if (!location) return location;
return {
...location,
file: this._absolutePath(location.file)
};
}
_absolutePath(relativePath) {
if (relativePath === undefined) return;
return this._options.resolvePath ? this._options.resolvePath(this._rootDir, relativePath) : this._rootDir + '/' + relativePath;
}
}
exports.TeleReporterReceiver = TeleReporterReceiver;
class TeleSuite {
constructor(title, type) {
this.title = void 0;
this.location = void 0;
this.parent = void 0;
this._entries = [];
this._requireFile = '';
this._timeout = void 0;
this._retries = void 0;
this._project = void 0;
this._parallelMode = 'none';
this._type = void 0;
this.title = title;
this._type = type;
}
get type() {
return this._type;
}
get suites() {
return this._entries.filter(e => e.type !== 'test');
}
get tests() {
return this._entries.filter(e => e.type === 'test');
}
entries() {
return this._entries;
}
allTests() {
const result = [];
const visit = suite => {
for (const entry of suite.entries()) {
if (entry.type === 'test') result.push(entry);else visit(entry);
}
};
visit(this);
return result;
}
titlePath() {
const titlePath = this.parent ? this.parent.titlePath() : [];
// Ignore anonymous describe blocks.
if (this.title || this._type !== 'describe') titlePath.push(this.title);
return titlePath;
}
project() {
var _this$_project, _this$parent;
return (_this$_project = this._project) !== null && _this$_project !== void 0 ? _this$_project : (_this$parent = this.parent) === null || _this$parent === void 0 ? void 0 : _this$parent.project();
}
_addTest(test) {
test.parent = this;
this._entries.push(test);
}
_addSuite(suite) {
suite.parent = this;
this._entries.push(suite);
}
}
exports.TeleSuite = TeleSuite;
class TeleTestCase {
constructor(id, title, location, repeatEachIndex) {
this.title = void 0;
this.fn = () => {};
this.results = [];
this.location = void 0;
this.parent = void 0;
this.type = 'test';
this.expectedStatus = 'passed';
this.timeout = 0;
this.annotations = [];
this.retries = 0;
this.tags = [];
this.repeatEachIndex = 0;
this.id = void 0;
this.id = id;
this.title = title;
this.location = location;
this.repeatEachIndex = repeatEachIndex;
}
titlePath() {
const titlePath = this.parent ? this.parent.titlePath() : [];
titlePath.push(this.title);
return titlePath;
}
outcome() {
return computeTestCaseOutcome(this);
}
ok() {
const status = this.outcome();
return status === 'expected' || status === 'flaky' || status === 'skipped';
}
_createTestResult(id) {
const result = new TeleTestResult(this.results.length, id);
this.results.push(result);
return result;
}
}
exports.TeleTestCase = TeleTestCase;
class TeleTestStep {
constructor(payload, parentStep, location) {
this.title = void 0;
this.category = void 0;
this.location = void 0;
this.parent = void 0;
this.duration = -1;
this.steps = [];
this._startTime = 0;
this.title = payload.title;
this.category = payload.category;
this.location = location;
this.parent = parentStep;
this._startTime = payload.startTime;
}
titlePath() {
var _this$parent2;
const parentPath = ((_this$parent2 = this.parent) === null || _this$parent2 === void 0 ? void 0 : _this$parent2.titlePath()) || [];
return [...parentPath, this.title];
}
get startTime() {
return new Date(this._startTime);
}
set startTime(value) {
this._startTime = +value;
}
}
class TeleTestResult {
constructor(retry, id) {
this.retry = void 0;
this.parallelIndex = -1;
this.workerIndex = -1;
this.duration = -1;
this.stdout = [];
this.stderr = [];
this.attachments = [];
this.status = 'skipped';
this.steps = [];
this.errors = [];
this.error = void 0;
this._stepMap = new Map();
this._id = void 0;
this._startTime = 0;
this.retry = retry;
this._id = id;
}
setStartTimeNumber(startTime) {
this._startTime = startTime;
}
get startTime() {
return new Date(this._startTime);
}
set startTime(value) {
this._startTime = +value;
}
}
exports.TeleTestResult = TeleTestResult;
const baseFullConfig = exports.baseFullConfig = {
forbidOnly: false,
fullyParallel: false,
globalSetup: null,
globalTeardown: null,
globalTimeout: 0,
grep: /.*/,
grepInvert: null,
maxFailures: 0,
metadata: {},
preserveOutput: 'always',
projects: [],
reporter: [[process.env.CI ? 'dot' : 'list']],
reportSlowTests: {
max: 5,
threshold: 15000
},
configFile: '',
rootDir: '',
quiet: false,
shard: null,
updateSnapshots: 'missing',
version: '',
workers: 0,
webServer: null
};
function serializeRegexPatterns(patterns) {
if (!Array.isArray(patterns)) patterns = [patterns];
return patterns.map(s => {
if (typeof s === 'string') return {
s
};
return {
r: {
source: s.source,
flags: s.flags
}
};
});
}
function parseRegexPatterns(patterns) {
return patterns.map(p => {
if (p.s !== undefined) return p.s;
return new RegExp(p.r.source, p.r.flags);
});
}
function computeTestCaseOutcome(test) {
let skipped = 0;
let didNotRun = 0;
let expected = 0;
let interrupted = 0;
let unexpected = 0;
for (const result of test.results) {
if (result.status === 'interrupted') {
++interrupted; // eslint-disable-line @typescript-eslint/no-unused-vars
} else if (result.status === 'skipped' && test.expectedStatus === 'skipped') {
// Only tests "expected to be skipped" are skipped. These were specifically
// marked with test.skip or test.fixme.
++skipped;
} else if (result.status === 'skipped') {
// Tests that were expected to run, but were skipped are "did not run".
// This happens when:
// - testing finished early;
// - test failure prevented other tests in the serial suite to run;
// - probably more cases!
++didNotRun; // eslint-disable-line @typescript-eslint/no-unused-vars
} else if (result.status === test.expectedStatus) {
// Either passed and expected to pass, or failed and expected to fail.
++expected;
} else {
++unexpected;
}
}
// Tests that were "skipped as expected" are considered equal to "expected" below,
// because that's the expected outcome.
//
// However, we specifically differentiate the case of "only skipped"
// and show it as "skipped" in all reporters.
//
// More exotic cases like "failed on first run and skipped on retry" are flaky.
if (expected === 0 && unexpected === 0) return 'skipped'; // all results were skipped or interrupted
if (unexpected === 0) return 'expected'; // no failures, just expected+skipped
if (expected === 0 && skipped === 0) return 'unexpected'; // only failures
return 'flaky'; // expected+unexpected or skipped+unexpected
}

View File

@@ -0,0 +1,144 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TeleSuiteUpdater = void 0;
var _teleReceiver = require("./teleReceiver");
var _testTree = require("./testTree");
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class TeleSuiteUpdater {
constructor(options) {
this.rootSuite = void 0;
this.config = void 0;
this.loadErrors = [];
this.progress = {
total: 0,
passed: 0,
failed: 0,
skipped: 0
};
this._receiver = void 0;
this._lastRunReceiver = void 0;
this._lastRunTestCount = 0;
this._options = void 0;
this._testResultsSnapshot = void 0;
this._receiver = new _teleReceiver.TeleReporterReceiver(this._createReporter(), {
mergeProjects: true,
mergeTestCases: true,
resolvePath: (rootDir, relativePath) => rootDir + options.pathSeparator + relativePath,
clearPreviousResultsWhenTestBegins: true
});
this._options = options;
}
_createReporter() {
return {
version: () => 'v2',
onConfigure: c => {
this.config = c;
// TeleReportReceiver is merging everything into a single suite, so when we
// run one test, we still get many tests via rootSuite.allTests().length.
// To work around that, have a dedicated per-run receiver that will only have
// suite for a single test run, and hence will have correct total.
this._lastRunReceiver = new _teleReceiver.TeleReporterReceiver({
version: () => 'v2',
onBegin: suite => {
this._lastRunTestCount = suite.allTests().length;
this._lastRunReceiver = undefined;
}
}, {
mergeProjects: true,
mergeTestCases: false,
resolvePath: (rootDir, relativePath) => rootDir + this._options.pathSeparator + relativePath
});
},
onBegin: suite => {
if (!this.rootSuite) this.rootSuite = suite;
// As soon as new test tree is built add previous results, before calling onUpdate
// to avoid flashing empty results in the UI.
if (this._testResultsSnapshot) {
for (const test of this.rootSuite.allTests()) {
var _this$_testResultsSna;
test.results = ((_this$_testResultsSna = this._testResultsSnapshot) === null || _this$_testResultsSna === void 0 ? void 0 : _this$_testResultsSna.get(test.id)) || test.results;
}
this._testResultsSnapshot = undefined;
}
this.progress.total = this._lastRunTestCount;
this.progress.passed = 0;
this.progress.failed = 0;
this.progress.skipped = 0;
this._options.onUpdate(true);
},
onEnd: () => {
this._options.onUpdate(true);
},
onTestBegin: (test, testResult) => {
testResult[_testTree.statusEx] = 'running';
this._options.onUpdate();
},
onTestEnd: (test, testResult) => {
if (test.outcome() === 'skipped') ++this.progress.skipped;else if (test.outcome() === 'unexpected') ++this.progress.failed;else ++this.progress.passed;
testResult[_testTree.statusEx] = testResult.status;
this._options.onUpdate();
},
onError: error => this._handleOnError(error),
printsToStdio: () => false
};
}
processGlobalReport(report) {
const receiver = new _teleReceiver.TeleReporterReceiver({
version: () => 'v2',
onConfigure: c => {
this.config = c;
},
onError: error => this._handleOnError(error)
});
for (const message of report) void receiver.dispatch(message);
}
processListReport(report) {
var _this$rootSuite;
// Save test results and reset all projects, the results will be restored after
// new project structure is built.
const tests = ((_this$rootSuite = this.rootSuite) === null || _this$rootSuite === void 0 ? void 0 : _this$rootSuite.allTests()) || [];
this._testResultsSnapshot = new Map(tests.map(test => [test.id, test.results]));
this._receiver.reset();
for (const message of report) void this._receiver.dispatch(message);
}
processTestReportEvent(message) {
var _this$_lastRunReceive, _this$_receiver$dispa;
// The order of receiver dispatches matters here, we want to assign `lastRunTestCount`
// before we use it.
(_this$_lastRunReceive = this._lastRunReceiver) === null || _this$_lastRunReceive === void 0 || (_this$_lastRunReceive = _this$_lastRunReceive.dispatch(message)) === null || _this$_lastRunReceive === void 0 || _this$_lastRunReceive.catch(() => {});
(_this$_receiver$dispa = this._receiver.dispatch(message)) === null || _this$_receiver$dispa === void 0 || _this$_receiver$dispa.catch(() => {});
}
_handleOnError(error) {
var _this$_options$onErro, _this$_options;
this.loadErrors.push(error);
(_this$_options$onErro = (_this$_options = this._options).onError) === null || _this$_options$onErro === void 0 || _this$_options$onErro.call(_this$_options, error);
this._options.onUpdate();
}
asModel() {
return {
rootSuite: this.rootSuite || new _teleReceiver.TeleSuite('', 'root'),
config: this.config,
loadErrors: this.loadErrors,
progress: this.progress
};
}
}
exports.TeleSuiteUpdater = TeleSuiteUpdater;

View File

@@ -0,0 +1,210 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WebSocketTestServerTransport = exports.TestServerConnection = void 0;
var events = _interopRequireWildcard(require("./events"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// -- Reuse boundary -- Everything below this line is reused in the vscode extension.
class WebSocketTestServerTransport {
constructor(url) {
this._ws = void 0;
this._ws = new WebSocket(url);
}
onmessage(listener) {
this._ws.addEventListener('message', event => listener(event.data));
}
onopen(listener) {
this._ws.addEventListener('open', listener);
}
onerror(listener) {
this._ws.addEventListener('error', listener);
}
onclose(listener) {
this._ws.addEventListener('close', listener);
}
send(data) {
this._ws.send(data);
}
close() {
this._ws.close();
}
}
exports.WebSocketTestServerTransport = WebSocketTestServerTransport;
class TestServerConnection {
constructor(transport) {
this.onClose = void 0;
this.onReport = void 0;
this.onStdio = void 0;
this.onTestFilesChanged = void 0;
this.onLoadTraceRequested = void 0;
this._onCloseEmitter = new events.EventEmitter();
this._onReportEmitter = new events.EventEmitter();
this._onStdioEmitter = new events.EventEmitter();
this._onTestFilesChangedEmitter = new events.EventEmitter();
this._onLoadTraceRequestedEmitter = new events.EventEmitter();
this._lastId = 0;
this._transport = void 0;
this._callbacks = new Map();
this._connectedPromise = void 0;
this._isClosed = false;
this.onClose = this._onCloseEmitter.event;
this.onReport = this._onReportEmitter.event;
this.onStdio = this._onStdioEmitter.event;
this.onTestFilesChanged = this._onTestFilesChangedEmitter.event;
this.onLoadTraceRequested = this._onLoadTraceRequestedEmitter.event;
this._transport = transport;
this._transport.onmessage(data => {
const message = JSON.parse(data);
const {
id,
result,
error,
method,
params
} = message;
if (id) {
const callback = this._callbacks.get(id);
if (!callback) return;
this._callbacks.delete(id);
if (error) callback.reject(new Error(error));else callback.resolve(result);
} else {
this._dispatchEvent(method, params);
}
});
const pingInterval = setInterval(() => this._sendMessage('ping').catch(() => {}), 30000);
this._connectedPromise = new Promise((f, r) => {
this._transport.onopen(f);
this._transport.onerror(r);
});
this._transport.onclose(() => {
this._isClosed = true;
this._onCloseEmitter.fire();
clearInterval(pingInterval);
});
}
isClosed() {
return this._isClosed;
}
async _sendMessage(method, params) {
const logForTest = globalThis.__logForTest;
logForTest === null || logForTest === void 0 || logForTest({
method,
params
});
await this._connectedPromise;
const id = ++this._lastId;
const message = {
id,
method,
params
};
this._transport.send(JSON.stringify(message));
return new Promise((resolve, reject) => {
this._callbacks.set(id, {
resolve,
reject
});
});
}
_sendMessageNoReply(method, params) {
this._sendMessage(method, params).catch(() => {});
}
_dispatchEvent(method, params) {
if (method === 'report') this._onReportEmitter.fire(params);else if (method === 'stdio') this._onStdioEmitter.fire(params);else if (method === 'testFilesChanged') this._onTestFilesChangedEmitter.fire(params);else if (method === 'loadTraceRequested') this._onLoadTraceRequestedEmitter.fire(params);
}
async initialize(params) {
await this._sendMessage('initialize', params);
}
async ping(params) {
await this._sendMessage('ping', params);
}
async pingNoReply(params) {
this._sendMessageNoReply('ping', params);
}
async watch(params) {
await this._sendMessage('watch', params);
}
watchNoReply(params) {
this._sendMessageNoReply('watch', params);
}
async open(params) {
await this._sendMessage('open', params);
}
openNoReply(params) {
this._sendMessageNoReply('open', params);
}
async resizeTerminal(params) {
await this._sendMessage('resizeTerminal', params);
}
resizeTerminalNoReply(params) {
this._sendMessageNoReply('resizeTerminal', params);
}
async checkBrowsers(params) {
return await this._sendMessage('checkBrowsers', params);
}
async installBrowsers(params) {
await this._sendMessage('installBrowsers', params);
}
async runGlobalSetup(params) {
return await this._sendMessage('runGlobalSetup', params);
}
async runGlobalTeardown(params) {
return await this._sendMessage('runGlobalTeardown', params);
}
async startDevServer(params) {
return await this._sendMessage('startDevServer', params);
}
async stopDevServer(params) {
return await this._sendMessage('stopDevServer', params);
}
async clearCache(params) {
return await this._sendMessage('clearCache', params);
}
async listFiles(params) {
return await this._sendMessage('listFiles', params);
}
async listTests(params) {
return await this._sendMessage('listTests', params);
}
async runTests(params) {
return await this._sendMessage('runTests', params);
}
async findRelatedTestFiles(params) {
return await this._sendMessage('findRelatedTestFiles', params);
}
async stopTests(params) {
await this._sendMessage('stopTests', params);
}
stopTestsNoReply(params) {
this._sendMessageNoReply('stopTests', params);
}
async closeGracefully(params) {
await this._sendMessage('closeGracefully', params);
}
close() {
try {
this._transport.close();
} catch {}
}
}
exports.TestServerConnection = TestServerConnection;

View File

@@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});

272
node_modules/playwright/lib/isomorphic/testTree.js generated vendored Normal file
View File

@@ -0,0 +1,272 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TestTree = void 0;
exports.collectTestIds = collectTestIds;
exports.sortAndPropagateStatus = sortAndPropagateStatus;
exports.statusEx = void 0;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// -- Reuse boundary -- Everything below this line is reused in the vscode extension.
class TestTree {
constructor(rootFolder, rootSuite, loadErrors, projectFilters, pathSeparator) {
this.rootItem = void 0;
this._treeItemById = new Map();
this._treeItemByTestId = new Map();
this.pathSeparator = void 0;
const filterProjects = projectFilters && [...projectFilters.values()].some(Boolean);
this.pathSeparator = pathSeparator;
this.rootItem = {
kind: 'group',
subKind: 'folder',
id: rootFolder,
title: '',
location: {
file: '',
line: 0,
column: 0
},
duration: 0,
parent: undefined,
children: [],
status: 'none',
hasLoadErrors: false
};
this._treeItemById.set(rootFolder, this.rootItem);
const visitSuite = (project, parentSuite, parentGroup) => {
for (const suite of parentSuite.suites) {
const title = suite.title || '<anonymous>';
let group = parentGroup.children.find(item => item.kind === 'group' && item.title === title);
if (!group) {
group = {
kind: 'group',
subKind: 'describe',
id: 'suite:' + parentSuite.titlePath().join('\x1e') + '\x1e' + title,
// account for anonymous suites
title,
location: suite.location,
duration: 0,
parent: parentGroup,
children: [],
status: 'none',
hasLoadErrors: false
};
this._addChild(parentGroup, group);
}
visitSuite(project, suite, group);
}
for (const test of parentSuite.tests) {
const title = test.title;
let testCaseItem = parentGroup.children.find(t => t.kind !== 'group' && t.title === title);
if (!testCaseItem) {
testCaseItem = {
kind: 'case',
id: 'test:' + test.titlePath().join('\x1e'),
title,
parent: parentGroup,
children: [],
tests: [],
location: test.location,
duration: 0,
status: 'none',
project: undefined,
test: undefined,
tags: test.tags
};
this._addChild(parentGroup, testCaseItem);
}
const result = test.results[0];
let status = 'none';
if ((result === null || result === void 0 ? void 0 : result[statusEx]) === 'scheduled') status = 'scheduled';else if ((result === null || result === void 0 ? void 0 : result[statusEx]) === 'running') status = 'running';else if ((result === null || result === void 0 ? void 0 : result.status) === 'skipped') status = 'skipped';else if ((result === null || result === void 0 ? void 0 : result.status) === 'interrupted') status = 'none';else if (result && test.outcome() !== 'expected') status = 'failed';else if (result && test.outcome() === 'expected') status = 'passed';
testCaseItem.tests.push(test);
const testItem = {
kind: 'test',
id: test.id,
title: project.name,
location: test.location,
test,
parent: testCaseItem,
children: [],
status,
duration: test.results.length ? Math.max(0, test.results[0].duration) : 0,
project
};
this._addChild(testCaseItem, testItem);
this._treeItemByTestId.set(test.id, testItem);
testCaseItem.duration = testCaseItem.children.reduce((a, b) => a + b.duration, 0);
}
};
for (const projectSuite of (rootSuite === null || rootSuite === void 0 ? void 0 : rootSuite.suites) || []) {
if (filterProjects && !projectFilters.get(projectSuite.title)) continue;
for (const fileSuite of projectSuite.suites) {
const fileItem = this._fileItem(fileSuite.location.file.split(pathSeparator), true);
visitSuite(projectSuite.project(), fileSuite, fileItem);
}
}
for (const loadError of loadErrors) {
if (!loadError.location) continue;
const fileItem = this._fileItem(loadError.location.file.split(pathSeparator), true);
fileItem.hasLoadErrors = true;
}
}
_addChild(parent, child) {
parent.children.push(child);
child.parent = parent;
this._treeItemById.set(child.id, child);
}
filterTree(filterText, statusFilters, runningTestIds) {
const tokens = filterText.trim().toLowerCase().split(' ');
const filtersStatuses = [...statusFilters.values()].some(Boolean);
const filter = testCase => {
const titleWithTags = [...testCase.tests[0].titlePath(), ...testCase.tests[0].tags].join(' ').toLowerCase();
if (!tokens.every(token => titleWithTags.includes(token)) && !testCase.tests.some(t => runningTestIds === null || runningTestIds === void 0 ? void 0 : runningTestIds.has(t.id))) return false;
testCase.children = testCase.children.filter(test => {
return !filtersStatuses || (runningTestIds === null || runningTestIds === void 0 ? void 0 : runningTestIds.has(test.test.id)) || statusFilters.get(test.status);
});
testCase.tests = testCase.children.map(c => c.test);
return !!testCase.children.length;
};
const visit = treeItem => {
const newChildren = [];
for (const child of treeItem.children) {
if (child.kind === 'case') {
if (filter(child)) newChildren.push(child);
} else {
visit(child);
if (child.children.length || child.hasLoadErrors) newChildren.push(child);
}
}
treeItem.children = newChildren;
};
visit(this.rootItem);
}
_fileItem(filePath, isFile) {
if (filePath.length === 0) return this.rootItem;
const fileName = filePath.join(this.pathSeparator);
const existingFileItem = this._treeItemById.get(fileName);
if (existingFileItem) return existingFileItem;
const parentFileItem = this._fileItem(filePath.slice(0, filePath.length - 1), false);
const fileItem = {
kind: 'group',
subKind: isFile ? 'file' : 'folder',
id: fileName,
title: filePath[filePath.length - 1],
location: {
file: fileName,
line: 0,
column: 0
},
duration: 0,
parent: parentFileItem,
children: [],
status: 'none',
hasLoadErrors: false
};
this._addChild(parentFileItem, fileItem);
return fileItem;
}
sortAndPropagateStatus() {
sortAndPropagateStatus(this.rootItem);
}
flattenForSingleProject() {
const visit = treeItem => {
if (treeItem.kind === 'case' && treeItem.children.length === 1) {
treeItem.project = treeItem.children[0].project;
treeItem.test = treeItem.children[0].test;
treeItem.children = [];
this._treeItemByTestId.set(treeItem.test.id, treeItem);
} else {
treeItem.children.forEach(visit);
}
};
visit(this.rootItem);
}
shortenRoot() {
let shortRoot = this.rootItem;
while (shortRoot.children.length === 1 && shortRoot.children[0].kind === 'group' && shortRoot.children[0].subKind === 'folder') shortRoot = shortRoot.children[0];
shortRoot.location = this.rootItem.location;
this.rootItem = shortRoot;
}
testIds() {
const result = new Set();
const visit = treeItem => {
if (treeItem.kind === 'case') treeItem.tests.forEach(t => result.add(t.id));
treeItem.children.forEach(visit);
};
visit(this.rootItem);
return result;
}
fileNames() {
const result = new Set();
const visit = treeItem => {
if (treeItem.kind === 'group' && treeItem.subKind === 'file') result.add(treeItem.id);else treeItem.children.forEach(visit);
};
visit(this.rootItem);
return [...result];
}
flatTreeItems() {
const result = [];
const visit = treeItem => {
result.push(treeItem);
treeItem.children.forEach(visit);
};
visit(this.rootItem);
return result;
}
treeItemById(id) {
return this._treeItemById.get(id);
}
collectTestIds(treeItem) {
return treeItem ? collectTestIds(treeItem) : new Set();
}
}
exports.TestTree = TestTree;
function sortAndPropagateStatus(treeItem) {
for (const child of treeItem.children) sortAndPropagateStatus(child);
if (treeItem.kind === 'group') {
treeItem.children.sort((a, b) => {
const fc = a.location.file.localeCompare(b.location.file);
return fc || a.location.line - b.location.line;
});
}
let allPassed = treeItem.children.length > 0;
let allSkipped = treeItem.children.length > 0;
let hasFailed = false;
let hasRunning = false;
let hasScheduled = false;
for (const child of treeItem.children) {
allSkipped = allSkipped && child.status === 'skipped';
allPassed = allPassed && (child.status === 'passed' || child.status === 'skipped');
hasFailed = hasFailed || child.status === 'failed';
hasRunning = hasRunning || child.status === 'running';
hasScheduled = hasScheduled || child.status === 'scheduled';
}
if (hasRunning) treeItem.status = 'running';else if (hasScheduled) treeItem.status = 'scheduled';else if (hasFailed) treeItem.status = 'failed';else if (allSkipped) treeItem.status = 'skipped';else if (allPassed) treeItem.status = 'passed';
}
function collectTestIds(treeItem) {
const testIds = new Set();
const visit = treeItem => {
var _treeItem$children;
if (treeItem.kind === 'case') treeItem.tests.map(t => t.id).forEach(id => testIds.add(id));else if (treeItem.kind === 'test') testIds.add(treeItem.id);else (_treeItem$children = treeItem.children) === null || _treeItem$children === void 0 || _treeItem$children.forEach(visit);
};
visit(treeItem);
return testIds;
}
const statusEx = exports.statusEx = Symbol('statusEx');

58
node_modules/playwright/lib/loader/loaderMain.js generated vendored Normal file
View File

@@ -0,0 +1,58 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.create = exports.LoaderMain = void 0;
var _configLoader = require("../common/configLoader");
var _process = require("../common/process");
var _testLoader = require("../common/testLoader");
var _compilationCache = require("../transform/compilationCache");
var _poolBuilder = require("../common/poolBuilder");
var _esmLoaderHost = require("../common/esmLoaderHost");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class LoaderMain extends _process.ProcessRunner {
constructor(serializedConfig) {
super();
this._serializedConfig = void 0;
this._configPromise = void 0;
this._poolBuilder = _poolBuilder.PoolBuilder.createForLoader();
this._serializedConfig = serializedConfig;
}
_config() {
if (!this._configPromise) this._configPromise = (0, _configLoader.deserializeConfig)(this._serializedConfig);
return this._configPromise;
}
async loadTestFile(params) {
const testErrors = [];
const config = await this._config();
const fileSuite = await (0, _testLoader.loadTestFile)(params.file, config.config.rootDir, testErrors);
this._poolBuilder.buildPools(fileSuite);
return {
fileSuite: fileSuite._deepSerialize(),
testErrors
};
}
async getCompilationCacheFromLoader() {
await (0, _esmLoaderHost.incorporateCompilationCache)();
return (0, _compilationCache.serializeCompilationCache)();
}
}
exports.LoaderMain = LoaderMain;
const create = config => new LoaderMain(config);
exports.create = create;

350
node_modules/playwright/lib/matchers/expect.js generated vendored Normal file
View File

@@ -0,0 +1,350 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.expect = void 0;
exports.mergeExpects = mergeExpects;
exports.printReceivedStringContainExpectedSubstring = exports.printReceivedStringContainExpectedResult = void 0;
var _utils = require("playwright-core/lib/utils");
var _matchers = require("./matchers");
var _toMatchSnapshot = require("./toMatchSnapshot");
var _globals = require("../common/globals");
var _util = require("../util");
var _expectBundle = require("../common/expectBundle");
var _testInfo = require("../worker/testInfo");
var _matcherHint = require("./matcherHint");
var _toMatchAriaSnapshot = require("./toMatchAriaSnapshot");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// #region
// Mirrored from https://github.com/facebook/jest/blob/f13abff8df9a0e1148baf3584bcde6d1b479edc7/packages/expect/src/print.ts
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found here
* https://github.com/facebook/jest/blob/1547740bbc26400d69f4576bf35645163e942829/LICENSE
*/
// Format substring but do not enclose in double quote marks.
// The replacement is compatible with pretty-format package.
const printSubstring = val => val.replace(/"|\\/g, '\\$&');
const printReceivedStringContainExpectedSubstring = (received, start, length // not end
) => (0, _expectBundle.RECEIVED_COLOR)('"' + printSubstring(received.slice(0, start)) + (0, _expectBundle.INVERTED_COLOR)(printSubstring(received.slice(start, start + length))) + printSubstring(received.slice(start + length)) + '"');
exports.printReceivedStringContainExpectedSubstring = printReceivedStringContainExpectedSubstring;
const printReceivedStringContainExpectedResult = (received, result) => result === null ? (0, _expectBundle.printReceived)(received) : printReceivedStringContainExpectedSubstring(received, result.index, result[0].length);
// #endregion
exports.printReceivedStringContainExpectedResult = printReceivedStringContainExpectedResult;
function createMatchers(actual, info, prefix) {
return new Proxy((0, _expectBundle.expect)(actual), new ExpectMetaInfoProxyHandler(info, prefix));
}
const getCustomMatchersSymbol = Symbol('get custom matchers');
function qualifiedMatcherName(qualifier, matcherName) {
return qualifier.join(':') + '$' + matcherName;
}
function createExpect(info, prefix, customMatchers) {
const expectInstance = new Proxy(_expectBundle.expect, {
apply: function (target, thisArg, argumentsList) {
const [actual, messageOrOptions] = argumentsList;
const message = (0, _utils.isString)(messageOrOptions) ? messageOrOptions : (messageOrOptions === null || messageOrOptions === void 0 ? void 0 : messageOrOptions.message) || info.message;
const newInfo = {
...info,
message
};
if (newInfo.poll) {
if (typeof actual !== 'function') throw new Error('`expect.poll()` accepts only function as a first argument');
newInfo.poll.generator = actual;
}
return createMatchers(actual, newInfo, prefix);
},
get: function (target, property) {
if (property === 'configure') return configure;
if (property === 'extend') {
return matchers => {
const qualifier = [...prefix, (0, _utils.createGuid)()];
const wrappedMatchers = {};
const extendedMatchers = {
...customMatchers
};
for (const [name, matcher] of Object.entries(matchers)) {
wrappedMatchers[name] = function (...args) {
const {
isNot,
promise,
utils
} = this;
const newThis = {
isNot,
promise,
utils,
timeout: currentExpectTimeout()
};
newThis.equals = throwUnsupportedExpectMatcherError;
return matcher.call(newThis, ...args);
};
const key = qualifiedMatcherName(qualifier, name);
wrappedMatchers[key] = wrappedMatchers[name];
Object.defineProperty(wrappedMatchers[key], 'name', {
value: name
});
extendedMatchers[name] = wrappedMatchers[key];
}
_expectBundle.expect.extend(wrappedMatchers);
return createExpect(info, qualifier, extendedMatchers);
};
}
if (property === 'soft') {
return (actual, messageOrOptions) => {
return configure({
soft: true
})(actual, messageOrOptions);
};
}
if (property === getCustomMatchersSymbol) return customMatchers;
if (property === 'poll') {
return (actual, messageOrOptions) => {
const poll = (0, _utils.isString)(messageOrOptions) ? {} : messageOrOptions || {};
return configure({
_poll: poll
})(actual, messageOrOptions);
};
}
return _expectBundle.expect[property];
}
});
const configure = configuration => {
const newInfo = {
...info
};
if ('message' in configuration) newInfo.message = configuration.message;
if ('timeout' in configuration) newInfo.timeout = configuration.timeout;
if ('soft' in configuration) newInfo.isSoft = configuration.soft;
if ('_poll' in configuration) {
newInfo.poll = configuration._poll ? {
...info.poll,
generator: () => {}
} : undefined;
if (typeof configuration._poll === 'object') {
var _configuration$_poll$, _configuration$_poll$2;
newInfo.poll.timeout = (_configuration$_poll$ = configuration._poll.timeout) !== null && _configuration$_poll$ !== void 0 ? _configuration$_poll$ : newInfo.poll.timeout;
newInfo.poll.intervals = (_configuration$_poll$2 = configuration._poll.intervals) !== null && _configuration$_poll$2 !== void 0 ? _configuration$_poll$2 : newInfo.poll.intervals;
}
}
return createExpect(newInfo, prefix, customMatchers);
};
return expectInstance;
}
function throwUnsupportedExpectMatcherError() {
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');
}
_expectBundle.expect.setState({
expand: false
});
const customAsyncMatchers = {
toBeAttached: _matchers.toBeAttached,
toBeChecked: _matchers.toBeChecked,
toBeDisabled: _matchers.toBeDisabled,
toBeEditable: _matchers.toBeEditable,
toBeEmpty: _matchers.toBeEmpty,
toBeEnabled: _matchers.toBeEnabled,
toBeFocused: _matchers.toBeFocused,
toBeHidden: _matchers.toBeHidden,
toBeInViewport: _matchers.toBeInViewport,
toBeOK: _matchers.toBeOK,
toBeVisible: _matchers.toBeVisible,
toContainText: _matchers.toContainText,
toHaveAccessibleDescription: _matchers.toHaveAccessibleDescription,
toHaveAccessibleName: _matchers.toHaveAccessibleName,
toHaveAttribute: _matchers.toHaveAttribute,
toHaveClass: _matchers.toHaveClass,
toHaveCount: _matchers.toHaveCount,
toHaveCSS: _matchers.toHaveCSS,
toHaveId: _matchers.toHaveId,
toHaveJSProperty: _matchers.toHaveJSProperty,
toHaveRole: _matchers.toHaveRole,
toHaveText: _matchers.toHaveText,
toHaveTitle: _matchers.toHaveTitle,
toHaveURL: _matchers.toHaveURL,
toHaveValue: _matchers.toHaveValue,
toHaveValues: _matchers.toHaveValues,
toHaveScreenshot: _toMatchSnapshot.toHaveScreenshot,
toMatchAriaSnapshot: _toMatchAriaSnapshot.toMatchAriaSnapshot,
toPass: _matchers.toPass
};
const customMatchers = {
...customAsyncMatchers,
toMatchSnapshot: _toMatchSnapshot.toMatchSnapshot
};
class ExpectMetaInfoProxyHandler {
constructor(info, prefix) {
this._info = void 0;
this._prefix = void 0;
this._info = {
...info
};
this._prefix = prefix;
}
get(target, matcherName, receiver) {
let matcher = Reflect.get(target, matcherName, receiver);
if (typeof matcherName !== 'string') return matcher;
let resolvedMatcherName = matcherName;
for (let i = this._prefix.length; i > 0; i--) {
const qualifiedName = qualifiedMatcherName(this._prefix.slice(0, i), matcherName);
if (Reflect.has(target, qualifiedName)) {
matcher = Reflect.get(target, qualifiedName, receiver);
resolvedMatcherName = qualifiedName;
break;
}
}
if (matcher === undefined) throw new Error(`expect: Property '${matcherName}' not found.`);
if (typeof matcher !== 'function') {
if (matcherName === 'not') this._info.isNot = !this._info.isNot;
return new Proxy(matcher, this);
}
if (this._info.poll) {
if (customAsyncMatchers[matcherName] || matcherName === 'resolves' || matcherName === 'rejects') throw new Error(`\`expect.poll()\` does not support "${matcherName}" matcher.`);
matcher = (...args) => pollMatcher(resolvedMatcherName, this._info, this._prefix, ...args);
}
return (...args) => {
const testInfo = (0, _globals.currentTestInfo)();
// We assume that the matcher will read the current expect timeout the first thing.
setCurrentExpectConfigureTimeout(this._info.timeout);
if (!testInfo) return matcher.call(target, ...args);
const customMessage = this._info.message || '';
const argsSuffix = computeArgsSuffix(matcherName, args);
const defaultTitle = `expect${this._info.poll ? '.poll' : ''}${this._info.isSoft ? '.soft' : ''}${this._info.isNot ? '.not' : ''}.${matcherName}${argsSuffix}`;
const title = customMessage || defaultTitle;
// This looks like it is unnecessary, but it isn't - we need to filter
// out all the frames that belong to the test runner from caught runtime errors.
const stackFrames = (0, _util.filteredStackTrace)((0, _utils.captureRawStack)());
// Enclose toPass in a step to maintain async stacks, toPass matcher is always async.
const stepInfo = {
category: 'expect',
title: (0, _util.trimLongString)(title, 1024),
params: args[0] ? {
expected: args[0]
} : undefined,
infectParentStepsWithError: this._info.isSoft
};
const step = testInfo._addStep(stepInfo);
const reportStepError = e => {
const jestError = (0, _matcherHint.isJestError)(e) ? e : null;
const error = jestError ? new _matcherHint.ExpectError(jestError, customMessage, stackFrames) : e;
if (jestError !== null && jestError !== void 0 && jestError.matcherResult.suggestedRebaseline) {
step.complete({
suggestedRebaseline: jestError === null || jestError === void 0 ? void 0 : jestError.matcherResult.suggestedRebaseline
});
return;
}
step.complete({
error
});
if (this._info.isSoft) testInfo._failWithError(error);else throw error;
};
const finalizer = () => {
step.complete({});
};
try {
const callback = () => matcher.call(target, ...args);
// toPass and poll matchers can contain other steps, expects and API calls,
// so they behave like a retriable step.
const result = matcherName === 'toPass' || this._info.poll ? _utils.zones.run('stepZone', step, callback) : _utils.zones.run('expectZone', {
title,
stepId: step.stepId
}, callback);
if (result instanceof Promise) return result.then(finalizer).catch(reportStepError);
finalizer();
return result;
} catch (e) {
reportStepError(e);
}
};
}
}
async function pollMatcher(qualifiedMatcherName, info, prefix, ...args) {
var _poll$timeout, _poll$intervals;
const testInfo = (0, _globals.currentTestInfo)();
const poll = info.poll;
const timeout = (_poll$timeout = poll.timeout) !== null && _poll$timeout !== void 0 ? _poll$timeout : currentExpectTimeout();
const {
deadline,
timeoutMessage
} = testInfo ? testInfo._deadlineForMatcher(timeout) : _testInfo.TestInfoImpl._defaultDeadlineForMatcher(timeout);
const result = await (0, _utils.pollAgainstDeadline)(async () => {
if (testInfo && (0, _globals.currentTestInfo)() !== testInfo) return {
continuePolling: false,
result: undefined
};
const innerInfo = {
...info,
isSoft: false,
// soft is outside of poll, not inside
poll: undefined
};
const value = await poll.generator();
try {
let matchers = createMatchers(value, innerInfo, prefix);
if (info.isNot) matchers = matchers.not;
matchers[qualifiedMatcherName](...args);
return {
continuePolling: false,
result: undefined
};
} catch (error) {
return {
continuePolling: true,
result: error
};
}
}, deadline, (_poll$intervals = poll.intervals) !== null && _poll$intervals !== void 0 ? _poll$intervals : [100, 250, 500, 1000]);
if (result.timedOut) {
const message = result.result ? [result.result.message, '', `Call Log:`, `- ${timeoutMessage}`].join('\n') : timeoutMessage;
throw new Error(message);
}
}
let currentExpectConfigureTimeout;
function setCurrentExpectConfigureTimeout(timeout) {
currentExpectConfigureTimeout = timeout;
}
function currentExpectTimeout() {
var _testInfo$_projectInt;
if (currentExpectConfigureTimeout !== undefined) return currentExpectConfigureTimeout;
const testInfo = (0, _globals.currentTestInfo)();
let defaultExpectTimeout = testInfo === null || testInfo === void 0 || (_testInfo$_projectInt = testInfo._projectInternal) === null || _testInfo$_projectInt === void 0 || (_testInfo$_projectInt = _testInfo$_projectInt.expect) === null || _testInfo$_projectInt === void 0 ? void 0 : _testInfo$_projectInt.timeout;
if (typeof defaultExpectTimeout === 'undefined') defaultExpectTimeout = 5000;
return defaultExpectTimeout;
}
function computeArgsSuffix(matcherName, args) {
let value = '';
if (matcherName === 'toHaveScreenshot') value = (0, _toMatchSnapshot.toHaveScreenshotStepTitle)(...args);
return value ? `(${value})` : '';
}
const expect = exports.expect = createExpect({}, [], {}).extend(customMatchers);
function mergeExpects(...expects) {
let merged = expect;
for (const e of expects) {
const internals = e[getCustomMatchersSymbol];
if (!internals)
// non-playwright expects mutate the global expect, so we don't need to do anything special
continue;
merged = merged.extend(internals);
}
return merged;
}

50
node_modules/playwright/lib/matchers/matcherHint.js generated vendored Normal file
View File

@@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ExpectError = void 0;
exports.isJestError = isJestError;
exports.kNoElementsFoundError = void 0;
exports.matcherHint = matcherHint;
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _utils = require("playwright-core/lib/utils");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const kNoElementsFoundError = exports.kNoElementsFoundError = '<element(s) not found>';
function matcherHint(state, locator, matcherName, expression, actual, matcherOptions, timeout) {
let header = state.utils.matcherHint(matcherName, expression, actual, matcherOptions).replace(/ \/\/ deep equality/, '') + '\n\n';
if (timeout) header = _utilsBundle.colors.red(`Timed out ${timeout}ms waiting for `) + header;
if (locator) header += `Locator: ${String(locator)}\n`;
return header;
}
class ExpectError extends Error {
constructor(jestError, customMessage, stackFrames) {
super('');
// Copy to erase the JestMatcherError constructor name from the console.log(error).
this.matcherResult = void 0;
this.name = jestError.name;
this.message = jestError.message;
this.matcherResult = jestError.matcherResult;
if (customMessage) this.message = customMessage + '\n\n' + this.message;
this.stack = this.name + ': ' + this.message + '\n' + (0, _utils.stringifyStackFrames)(stackFrames).join('\n');
}
}
exports.ExpectError = ExpectError;
function isJestError(e) {
return e instanceof Error && 'matcherResult' in e;
}

451
node_modules/playwright/lib/matchers/matchers.js generated vendored Normal file
View File

@@ -0,0 +1,451 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBeAttached = toBeAttached;
exports.toBeChecked = toBeChecked;
exports.toBeDisabled = toBeDisabled;
exports.toBeEditable = toBeEditable;
exports.toBeEmpty = toBeEmpty;
exports.toBeEnabled = toBeEnabled;
exports.toBeFocused = toBeFocused;
exports.toBeHidden = toBeHidden;
exports.toBeInViewport = toBeInViewport;
exports.toBeOK = toBeOK;
exports.toBeVisible = toBeVisible;
exports.toContainText = toContainText;
exports.toHaveAccessibleDescription = toHaveAccessibleDescription;
exports.toHaveAccessibleName = toHaveAccessibleName;
exports.toHaveAttribute = toHaveAttribute;
exports.toHaveCSS = toHaveCSS;
exports.toHaveClass = toHaveClass;
exports.toHaveCount = toHaveCount;
exports.toHaveId = toHaveId;
exports.toHaveJSProperty = toHaveJSProperty;
exports.toHaveRole = toHaveRole;
exports.toHaveText = toHaveText;
exports.toHaveTitle = toHaveTitle;
exports.toHaveURL = toHaveURL;
exports.toHaveValue = toHaveValue;
exports.toHaveValues = toHaveValues;
exports.toPass = toPass;
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _util = require("../util");
var _toBeTruthy = require("./toBeTruthy");
var _toEqual = require("./toEqual");
var _toMatchText = require("./toMatchText");
var _utils = require("playwright-core/lib/utils");
var _globals = require("../common/globals");
var _testInfo = require("../worker/testInfo");
var _config = require("../common/config");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function toBeAttached(locator, options) {
const attached = !options || options.attached === undefined || options.attached;
const expected = attached ? 'attached' : 'detached';
const unexpected = attached ? 'detached' : 'attached';
const arg = attached ? '' : '{ attached: false }';
return _toBeTruthy.toBeTruthy.call(this, 'toBeAttached', locator, 'Locator', expected, unexpected, arg, async (isNot, timeout) => {
return await locator._expect(attached ? 'to.be.attached' : 'to.be.detached', {
isNot,
timeout
});
}, options);
}
function toBeChecked(locator, options) {
const checked = !options || options.checked === undefined || options.checked;
const expected = checked ? 'checked' : 'unchecked';
const unexpected = checked ? 'unchecked' : 'checked';
const arg = checked ? '' : '{ checked: false }';
return _toBeTruthy.toBeTruthy.call(this, 'toBeChecked', locator, 'Locator', expected, unexpected, arg, async (isNot, timeout) => {
return await locator._expect(checked ? 'to.be.checked' : 'to.be.unchecked', {
isNot,
timeout
});
}, options);
}
function toBeDisabled(locator, options) {
return _toBeTruthy.toBeTruthy.call(this, 'toBeDisabled', locator, 'Locator', 'disabled', 'enabled', '', async (isNot, timeout) => {
return await locator._expect('to.be.disabled', {
isNot,
timeout
});
}, options);
}
function toBeEditable(locator, options) {
const editable = !options || options.editable === undefined || options.editable;
const expected = editable ? 'editable' : 'readOnly';
const unexpected = editable ? 'readOnly' : 'editable';
const arg = editable ? '' : '{ editable: false }';
return _toBeTruthy.toBeTruthy.call(this, 'toBeEditable', locator, 'Locator', expected, unexpected, arg, async (isNot, timeout) => {
return await locator._expect(editable ? 'to.be.editable' : 'to.be.readonly', {
isNot,
timeout
});
}, options);
}
function toBeEmpty(locator, options) {
return _toBeTruthy.toBeTruthy.call(this, 'toBeEmpty', locator, 'Locator', 'empty', 'notEmpty', '', async (isNot, timeout) => {
return await locator._expect('to.be.empty', {
isNot,
timeout
});
}, options);
}
function toBeEnabled(locator, options) {
const enabled = !options || options.enabled === undefined || options.enabled;
const expected = enabled ? 'enabled' : 'disabled';
const unexpected = enabled ? 'disabled' : 'enabled';
const arg = enabled ? '' : '{ enabled: false }';
return _toBeTruthy.toBeTruthy.call(this, 'toBeEnabled', locator, 'Locator', expected, unexpected, arg, async (isNot, timeout) => {
return await locator._expect(enabled ? 'to.be.enabled' : 'to.be.disabled', {
isNot,
timeout
});
}, options);
}
function toBeFocused(locator, options) {
return _toBeTruthy.toBeTruthy.call(this, 'toBeFocused', locator, 'Locator', 'focused', 'inactive', '', async (isNot, timeout) => {
return await locator._expect('to.be.focused', {
isNot,
timeout
});
}, options);
}
function toBeHidden(locator, options) {
return _toBeTruthy.toBeTruthy.call(this, 'toBeHidden', locator, 'Locator', 'hidden', 'visible', '', async (isNot, timeout) => {
return await locator._expect('to.be.hidden', {
isNot,
timeout
});
}, options);
}
function toBeVisible(locator, options) {
const visible = !options || options.visible === undefined || options.visible;
const expected = visible ? 'visible' : 'hidden';
const unexpected = visible ? 'hidden' : 'visible';
const arg = visible ? '' : '{ visible: false }';
return _toBeTruthy.toBeTruthy.call(this, 'toBeVisible', locator, 'Locator', expected, unexpected, arg, async (isNot, timeout) => {
return await locator._expect(visible ? 'to.be.visible' : 'to.be.hidden', {
isNot,
timeout
});
}, options);
}
function toBeInViewport(locator, options) {
return _toBeTruthy.toBeTruthy.call(this, 'toBeInViewport', locator, 'Locator', 'in viewport', 'outside viewport', '', async (isNot, timeout) => {
return await locator._expect('to.be.in.viewport', {
isNot,
expectedNumber: options === null || options === void 0 ? void 0 : options.ratio,
timeout
});
}, options);
}
function toContainText(locator, expected, options = {}) {
if (Array.isArray(expected)) {
return _toEqual.toEqual.call(this, 'toContainText', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)(expected, {
matchSubstring: true,
normalizeWhiteSpace: true,
ignoreCase: options.ignoreCase
});
return await locator._expect('to.contain.text.array', {
expectedText,
isNot,
useInnerText: options.useInnerText,
timeout
});
}, expected, {
...options,
contains: true
});
} else {
return _toMatchText.toMatchText.call(this, 'toContainText', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)([expected], {
matchSubstring: true,
normalizeWhiteSpace: true,
ignoreCase: options.ignoreCase
});
return await locator._expect('to.have.text', {
expectedText,
isNot,
useInnerText: options.useInnerText,
timeout
});
}, expected, options);
}
}
function toHaveAccessibleDescription(locator, expected, options) {
return _toMatchText.toMatchText.call(this, 'toHaveAccessibleDescription', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)([expected], {
ignoreCase: options === null || options === void 0 ? void 0 : options.ignoreCase,
normalizeWhiteSpace: true
});
return await locator._expect('to.have.accessible.description', {
expectedText,
isNot,
timeout
});
}, expected, options);
}
function toHaveAccessibleName(locator, expected, options) {
return _toMatchText.toMatchText.call(this, 'toHaveAccessibleName', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)([expected], {
ignoreCase: options === null || options === void 0 ? void 0 : options.ignoreCase,
normalizeWhiteSpace: true
});
return await locator._expect('to.have.accessible.name', {
expectedText,
isNot,
timeout
});
}, expected, options);
}
function toHaveAttribute(locator, name, expected, options) {
if (!options) {
// Update params for the case toHaveAttribute(name, options);
if (typeof expected === 'object' && !(0, _utils.isRegExp)(expected)) {
options = expected;
expected = undefined;
}
}
if (expected === undefined) {
return _toBeTruthy.toBeTruthy.call(this, 'toHaveAttribute', locator, 'Locator', 'have attribute', 'not have attribute', '', async (isNot, timeout) => {
return await locator._expect('to.have.attribute', {
expressionArg: name,
isNot,
timeout
});
}, options);
}
return _toMatchText.toMatchText.call(this, 'toHaveAttribute', locator, 'Locator', async (isNot, timeout) => {
var _options;
const expectedText = (0, _utils.serializeExpectedTextValues)([expected], {
ignoreCase: (_options = options) === null || _options === void 0 ? void 0 : _options.ignoreCase
});
return await locator._expect('to.have.attribute.value', {
expressionArg: name,
expectedText,
isNot,
timeout
});
}, expected, options);
}
function toHaveClass(locator, expected, options) {
if (Array.isArray(expected)) {
return _toEqual.toEqual.call(this, 'toHaveClass', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)(expected);
return await locator._expect('to.have.class.array', {
expectedText,
isNot,
timeout
});
}, expected, options);
} else {
return _toMatchText.toMatchText.call(this, 'toHaveClass', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)([expected]);
return await locator._expect('to.have.class', {
expectedText,
isNot,
timeout
});
}, expected, options);
}
}
function toHaveCount(locator, expected, options) {
return _toEqual.toEqual.call(this, 'toHaveCount', locator, 'Locator', async (isNot, timeout) => {
return await locator._expect('to.have.count', {
expectedNumber: expected,
isNot,
timeout
});
}, expected, options);
}
function toHaveCSS(locator, name, expected, options) {
return _toMatchText.toMatchText.call(this, 'toHaveCSS', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)([expected]);
return await locator._expect('to.have.css', {
expressionArg: name,
expectedText,
isNot,
timeout
});
}, expected, options);
}
function toHaveId(locator, expected, options) {
return _toMatchText.toMatchText.call(this, 'toHaveId', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)([expected]);
return await locator._expect('to.have.id', {
expectedText,
isNot,
timeout
});
}, expected, options);
}
function toHaveJSProperty(locator, name, expected, options) {
return _toEqual.toEqual.call(this, 'toHaveJSProperty', locator, 'Locator', async (isNot, timeout) => {
return await locator._expect('to.have.property', {
expressionArg: name,
expectedValue: expected,
isNot,
timeout
});
}, expected, options);
}
function toHaveRole(locator, expected, options) {
if (!(0, _utils.isString)(expected)) throw new Error(`"role" argument in toHaveRole must be a string`);
return _toMatchText.toMatchText.call(this, 'toHaveRole', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)([expected]);
return await locator._expect('to.have.role', {
expectedText,
isNot,
timeout
});
}, expected, options);
}
function toHaveText(locator, expected, options = {}) {
if (Array.isArray(expected)) {
return _toEqual.toEqual.call(this, 'toHaveText', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)(expected, {
normalizeWhiteSpace: true,
ignoreCase: options.ignoreCase
});
return await locator._expect('to.have.text.array', {
expectedText,
isNot,
useInnerText: options === null || options === void 0 ? void 0 : options.useInnerText,
timeout
});
}, expected, options);
} else {
return _toMatchText.toMatchText.call(this, 'toHaveText', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)([expected], {
normalizeWhiteSpace: true,
ignoreCase: options.ignoreCase
});
return await locator._expect('to.have.text', {
expectedText,
isNot,
useInnerText: options === null || options === void 0 ? void 0 : options.useInnerText,
timeout
});
}, expected, options);
}
}
function toHaveValue(locator, expected, options) {
return _toMatchText.toMatchText.call(this, 'toHaveValue', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)([expected]);
return await locator._expect('to.have.value', {
expectedText,
isNot,
timeout
});
}, expected, options);
}
function toHaveValues(locator, expected, options) {
return _toEqual.toEqual.call(this, 'toHaveValues', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)(expected);
return await locator._expect('to.have.values', {
expectedText,
isNot,
timeout
});
}, expected, options);
}
function toHaveTitle(page, expected, options = {}) {
const locator = page.locator(':root');
return _toMatchText.toMatchText.call(this, 'toHaveTitle', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)([expected], {
normalizeWhiteSpace: true
});
return await locator._expect('to.have.title', {
expectedText,
isNot,
timeout
});
}, expected, options);
}
function toHaveURL(page, expected, options) {
const baseURL = page.context()._options.baseURL;
expected = typeof expected === 'string' ? (0, _utils.constructURLBasedOnBaseURL)(baseURL, expected) : expected;
const locator = page.locator(':root');
return _toMatchText.toMatchText.call(this, 'toHaveURL', locator, 'Locator', async (isNot, timeout) => {
const expectedText = (0, _utils.serializeExpectedTextValues)([expected], {
ignoreCase: options === null || options === void 0 ? void 0 : options.ignoreCase
});
return await locator._expect('to.have.url', {
expectedText,
isNot,
timeout
});
}, expected, options);
}
async function toBeOK(response) {
const matcherName = 'toBeOK';
(0, _util.expectTypes)(response, ['APIResponse'], matcherName);
const contentType = response.headers()['content-type'];
const isTextEncoding = contentType && (0, _utils.isTextualMimeType)(contentType);
const [log, text] = this.isNot === response.ok() ? await Promise.all([response._fetchLog(), isTextEncoding ? response.text() : null]) : [];
const message = () => this.utils.matcherHint(matcherName, undefined, '', {
isNot: this.isNot
}) + (0, _util.callLogText)(log) + (text === null ? '' : `\nResponse text:\n${_utilsBundle.colors.dim((text === null || text === void 0 ? void 0 : text.substring(0, 1000)) || '')}`);
const pass = response.ok();
return {
message,
pass
};
}
async function toPass(callback, options = {}) {
var _testInfo$_projectInt, _testInfo$_projectInt2;
const testInfo = (0, _globals.currentTestInfo)();
const timeout = (0, _config.takeFirst)(options.timeout, testInfo === null || testInfo === void 0 || (_testInfo$_projectInt = testInfo._projectInternal.expect) === null || _testInfo$_projectInt === void 0 || (_testInfo$_projectInt = _testInfo$_projectInt.toPass) === null || _testInfo$_projectInt === void 0 ? void 0 : _testInfo$_projectInt.timeout, 0);
const intervals = (0, _config.takeFirst)(options.intervals, testInfo === null || testInfo === void 0 || (_testInfo$_projectInt2 = testInfo._projectInternal.expect) === null || _testInfo$_projectInt2 === void 0 || (_testInfo$_projectInt2 = _testInfo$_projectInt2.toPass) === null || _testInfo$_projectInt2 === void 0 ? void 0 : _testInfo$_projectInt2.intervals, [100, 250, 500, 1000]);
const {
deadline,
timeoutMessage
} = testInfo ? testInfo._deadlineForMatcher(timeout) : _testInfo.TestInfoImpl._defaultDeadlineForMatcher(timeout);
const result = await (0, _utils.pollAgainstDeadline)(async () => {
if (testInfo && (0, _globals.currentTestInfo)() !== testInfo) return {
continuePolling: false,
result: undefined
};
try {
await callback();
return {
continuePolling: !!this.isNot,
result: undefined
};
} catch (e) {
return {
continuePolling: !this.isNot,
result: e
};
}
}, deadline, intervals);
if (result.timedOut) {
const message = result.result ? [result.result.message, '', `Call Log:`, `- ${timeoutMessage}`].join('\n') : timeoutMessage;
return {
message: () => message,
pass: !!this.isNot
};
}
return {
pass: !this.isNot,
message: () => ''
};
}

72
node_modules/playwright/lib/matchers/toBeTruthy.js generated vendored Normal file
View File

@@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toBeTruthy = toBeTruthy;
var _util = require("../util");
var _matcherHint = require("./matcherHint");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
async function toBeTruthy(matcherName, receiver, receiverType, expected, unexpected, arg, query, options = {}) {
var _options$timeout;
(0, _util.expectTypes)(receiver, [receiverType], matcherName);
const matcherOptions = {
isNot: this.isNot,
promise: this.promise
};
const timeout = (_options$timeout = options.timeout) !== null && _options$timeout !== void 0 ? _options$timeout : this.timeout;
const {
matches: pass,
log,
timedOut,
received
} = await query(!!this.isNot, timeout);
if (pass === !this.isNot) {
return {
name: matcherName,
message: () => '',
pass,
expected
};
}
const notFound = received === _matcherHint.kNoElementsFoundError ? received : undefined;
const actual = pass ? expected : unexpected;
let printedReceived;
let printedExpected;
if (pass) {
printedExpected = `Expected: not ${expected}`;
printedReceived = `Received: ${notFound ? _matcherHint.kNoElementsFoundError : expected}`;
} else {
printedExpected = `Expected: ${expected}`;
printedReceived = `Received: ${notFound ? _matcherHint.kNoElementsFoundError : unexpected}`;
}
const message = () => {
const header = (0, _matcherHint.matcherHint)(this, receiver, matcherName, 'locator', arg, matcherOptions, timedOut ? timeout : undefined);
const logText = (0, _util.callLogText)(log);
return `${header}${printedExpected}\n${printedReceived}${logText}`;
};
return {
message,
pass,
actual,
name: matcherName,
expected,
log,
timeout: timedOut ? timeout : undefined
};
}

85
node_modules/playwright/lib/matchers/toEqual.js generated vendored Normal file
View File

@@ -0,0 +1,85 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toEqual = toEqual;
var _util = require("../util");
var _matcherHint = require("./matcherHint");
var _utils = require("playwright-core/lib/utils");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Omit colon and one or more spaces, so can call getLabelPrinter.
const EXPECTED_LABEL = 'Expected';
const RECEIVED_LABEL = 'Received';
async function toEqual(matcherName, receiver, receiverType, query, expected, options = {}) {
var _options$timeout;
(0, _util.expectTypes)(receiver, [receiverType], matcherName);
const matcherOptions = {
comment: options.contains ? '' : 'deep equality',
isNot: this.isNot,
promise: this.promise
};
const timeout = (_options$timeout = options.timeout) !== null && _options$timeout !== void 0 ? _options$timeout : this.timeout;
const {
matches: pass,
received,
log,
timedOut
} = await query(!!this.isNot, timeout);
if (pass === !this.isNot) {
return {
name: matcherName,
message: () => '',
pass,
expected
};
}
let printedReceived;
let printedExpected;
let printedDiff;
if (pass) {
printedExpected = `Expected: not ${this.utils.printExpected(expected)}`;
printedReceived = `Received: ${this.utils.printReceived(received)}`;
} else if (Array.isArray(expected) && Array.isArray(received)) {
const normalizedExpected = expected.map((exp, index) => {
const rec = received[index];
if ((0, _utils.isRegExp)(exp)) return exp.test(rec) ? rec : exp;
return exp;
});
printedDiff = this.utils.printDiffOrStringify(normalizedExpected, received, EXPECTED_LABEL, RECEIVED_LABEL, false);
} else {
printedDiff = this.utils.printDiffOrStringify(expected, received, EXPECTED_LABEL, RECEIVED_LABEL, false);
}
const message = () => {
const header = (0, _matcherHint.matcherHint)(this, receiver, matcherName, 'locator', undefined, matcherOptions, timedOut ? timeout : undefined);
const details = printedDiff || `${printedExpected}\n${printedReceived}`;
return `${header}${details}${(0, _util.callLogText)(log)}`;
};
// Passing the actual and expected objects so that a custom reporter
// could access them, for example in order to display a custom visual diff,
// or create a different error message
return {
actual: received,
expected,
message,
name: matcherName,
pass,
log,
timeout: timedOut ? timeout : undefined
};
}

View File

@@ -0,0 +1,132 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toMatchAriaSnapshot = toMatchAriaSnapshot;
var _matcherHint = require("./matcherHint");
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _expectBundle = require("../common/expectBundle");
var _util = require("../util");
var _expect = require("./expect");
var _globals = require("../common/globals");
var _utils = require("playwright-core/lib/utils");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
async function toMatchAriaSnapshot(receiver, expected, options = {}) {
var _options$timeout;
const matcherName = 'toMatchAriaSnapshot';
const testInfo = (0, _globals.currentTestInfo)();
if (!testInfo) throw new Error(`toMatchAriaSnapshot() must be called during the test`);
if (testInfo._projectInternal.ignoreSnapshots) return {
pass: !this.isNot,
message: () => '',
name: 'toMatchAriaSnapshot',
expected
};
const updateSnapshots = testInfo.config.updateSnapshots;
const matcherOptions = {
isNot: this.isNot,
promise: this.promise
};
if (typeof expected !== 'string') {
throw new Error([(0, _matcherHint.matcherHint)(this, receiver, matcherName, receiver, expected, matcherOptions), `${_utilsBundle.colors.bold('Matcher error')}: ${(0, _expectBundle.EXPECTED_COLOR)('expected')} value must be a string`, this.utils.printWithType('Expected', expected, this.utils.printExpected)].join('\n\n'));
}
const generateMissingBaseline = updateSnapshots === 'missing' && !expected;
const generateNewBaseline = updateSnapshots === 'all' || generateMissingBaseline;
if (generateMissingBaseline) {
if (this.isNot) {
const message = `Matchers using ".not" can't generate new baselines`;
return {
pass: this.isNot,
message: () => message,
name: 'toMatchAriaSnapshot'
};
} else {
// When generating new baseline, run entire pipeline against impossible match.
expected = `- none "Generating new baseline"`;
}
}
const timeout = (_options$timeout = options.timeout) !== null && _options$timeout !== void 0 ? _options$timeout : this.timeout;
expected = unshift(expected);
const {
matches: pass,
received,
log,
timedOut
} = await receiver._expect('to.match.aria', {
expectedValue: expected,
isNot: this.isNot,
timeout
});
const typedReceived = received;
const messagePrefix = (0, _matcherHint.matcherHint)(this, receiver, matcherName, 'locator', undefined, matcherOptions, timedOut ? timeout : undefined);
const notFound = typedReceived === _matcherHint.kNoElementsFoundError;
if (notFound) {
return {
pass: this.isNot,
message: () => messagePrefix + `Expected: ${this.utils.printExpected(expected)}\nReceived: ${(0, _expectBundle.EXPECTED_COLOR)('<element not found>')}` + (0, _util.callLogText)(log),
name: 'toMatchAriaSnapshot',
expected
};
}
const receivedText = typedReceived.raw;
const message = () => {
if (pass) {
if (notFound) return messagePrefix + `Expected: not ${this.utils.printExpected(expected)}\nReceived: ${receivedText}` + (0, _util.callLogText)(log);
const printedReceived = (0, _expect.printReceivedStringContainExpectedSubstring)(receivedText, receivedText.indexOf(expected), expected.length);
return messagePrefix + `Expected: not ${this.utils.printExpected(expected)}\nReceived: ${printedReceived}` + (0, _util.callLogText)(log);
} else {
const labelExpected = `Expected`;
if (notFound) return messagePrefix + `${labelExpected}: ${this.utils.printExpected(expected)}\nReceived: ${receivedText}` + (0, _util.callLogText)(log);
return messagePrefix + this.utils.printDiffOrStringify(expected, receivedText, labelExpected, 'Received', false) + (0, _util.callLogText)(log);
}
};
if (!this.isNot && pass === this.isNot && generateNewBaseline) {
// Only rebaseline failed snapshots.
const suggestedRebaseline = `toMatchAriaSnapshot(\`\n${(0, _utils.escapeTemplateString)(indent(typedReceived.regex, '{indent} '))}\n{indent}\`)`;
return {
pass: this.isNot,
message: () => '',
name: 'toMatchAriaSnapshot',
suggestedRebaseline
};
}
return {
name: matcherName,
expected,
message,
pass,
actual: received,
log,
timeout: timedOut ? timeout : undefined
};
}
function unshift(snapshot) {
const lines = snapshot.split('\n');
let whitespacePrefixLength = 100;
for (const line of lines) {
if (!line.trim()) continue;
const match = line.match(/^(\s*)/);
if (match && match[1].length < whitespacePrefixLength) whitespacePrefixLength = match[1].length;
break;
}
return lines.filter(t => t.trim()).map(line => line.substring(whitespacePrefixLength)).join('\n');
}
function indent(snapshot, indent) {
return snapshot.split('\n').map(line => indent + line).join('\n');
}

394
node_modules/playwright/lib/matchers/toMatchSnapshot.js generated vendored Normal file
View File

@@ -0,0 +1,394 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toHaveScreenshot = toHaveScreenshot;
exports.toHaveScreenshotStepTitle = toHaveScreenshotStepTitle;
exports.toMatchSnapshot = toMatchSnapshot;
var _globals = require("../common/globals");
var _utils = require("playwright-core/lib/utils");
var _util = require("../util");
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _matcherHint = require("./matcherHint");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const snapshotNamesSymbol = Symbol('snapshotNames');
// Keep in sync with above (begin).
const NonConfigProperties = ['clip', 'fullPage', 'mask', 'maskColor', 'omitBackground', 'timeout'];
// Keep in sync with above (end).
class SnapshotHelper {
constructor(testInfo, matcherName, locator, anonymousSnapshotExtension, configOptions, nameOrOptions, optOptions) {
var _mime$getType;
this.testInfo = void 0;
this.attachmentBaseName = void 0;
this.legacyExpectedPath = void 0;
this.previousPath = void 0;
this.expectedPath = void 0;
this.actualPath = void 0;
this.diffPath = void 0;
this.mimeType = void 0;
this.kind = void 0;
this.updateSnapshots = void 0;
this.comparator = void 0;
this.options = void 0;
this.matcherName = void 0;
this.locator = void 0;
let name;
if (Array.isArray(nameOrOptions) || typeof nameOrOptions === 'string') {
name = nameOrOptions;
this.options = {
...optOptions
};
} else {
const {
name: nameFromOptions,
...options
} = nameOrOptions;
this.options = options;
name = nameFromOptions;
}
let snapshotNames = testInfo[snapshotNamesSymbol];
if (!testInfo[snapshotNamesSymbol]) {
snapshotNames = {
anonymousSnapshotIndex: 0,
namedSnapshotIndex: {}
};
testInfo[snapshotNamesSymbol] = snapshotNames;
}
let expectedPathSegments;
let outputBasePath;
if (!name) {
// Consider the use case below. We should save actual to different paths.
// Therefore we auto-increment |anonymousSnapshotIndex|.
//
// expect.toMatchSnapshot('a.png')
// // noop
// expect.toMatchSnapshot('a.png')
const fullTitleWithoutSpec = [...testInfo.titlePath.slice(1), ++snapshotNames.anonymousSnapshotIndex].join(' ');
// Note: expected path must not ever change for backwards compatibility.
expectedPathSegments = [(0, _utils.sanitizeForFilePath)((0, _util.trimLongString)(fullTitleWithoutSpec)) + '.' + anonymousSnapshotExtension];
// Trim the output file paths more aggressively to avoid hitting Windows filesystem limits.
const sanitizedName = (0, _utils.sanitizeForFilePath)((0, _util.trimLongString)(fullTitleWithoutSpec, _util.windowsFilesystemFriendlyLength)) + '.' + anonymousSnapshotExtension;
outputBasePath = testInfo._getOutputPath(sanitizedName);
this.attachmentBaseName = sanitizedName;
} else {
// We intentionally do not sanitize user-provided array of segments, assuming
// it is a file system path. See https://github.com/microsoft/playwright/pull/9156.
// Note: expected path must not ever change for backwards compatibility.
expectedPathSegments = Array.isArray(name) ? name : [(0, _util.sanitizeFilePathBeforeExtension)(name)];
const joinedName = Array.isArray(name) ? name.join(_path.default.sep) : (0, _util.sanitizeFilePathBeforeExtension)((0, _util.trimLongString)(name, _util.windowsFilesystemFriendlyLength));
snapshotNames.namedSnapshotIndex[joinedName] = (snapshotNames.namedSnapshotIndex[joinedName] || 0) + 1;
const index = snapshotNames.namedSnapshotIndex[joinedName];
const sanitizedName = index > 1 ? (0, _util.addSuffixToFilePath)(joinedName, `-${index - 1}`) : joinedName;
outputBasePath = testInfo._getOutputPath(sanitizedName);
this.attachmentBaseName = sanitizedName;
}
this.expectedPath = testInfo.snapshotPath(...expectedPathSegments);
this.legacyExpectedPath = (0, _util.addSuffixToFilePath)(outputBasePath, '-expected');
this.previousPath = (0, _util.addSuffixToFilePath)(outputBasePath, '-previous');
this.actualPath = (0, _util.addSuffixToFilePath)(outputBasePath, '-actual');
this.diffPath = (0, _util.addSuffixToFilePath)(outputBasePath, '-diff');
const filteredConfigOptions = {
...configOptions
};
for (const prop of NonConfigProperties) delete filteredConfigOptions[prop];
this.options = {
...filteredConfigOptions,
...this.options
};
// While comparator is not a part of the public API, it is translated here.
if (this.options._comparator) {
this.options.comparator = this.options._comparator;
delete this.options._comparator;
}
if (this.options.maxDiffPixels !== undefined && this.options.maxDiffPixels < 0) throw new Error('`maxDiffPixels` option value must be non-negative integer');
if (this.options.maxDiffPixelRatio !== undefined && (this.options.maxDiffPixelRatio < 0 || this.options.maxDiffPixelRatio > 1)) throw new Error('`maxDiffPixelRatio` option value must be between 0 and 1');
this.matcherName = matcherName;
this.locator = locator;
this.updateSnapshots = testInfo.config.updateSnapshots;
this.mimeType = (_mime$getType = _utilsBundle.mime.getType(_path.default.basename(this.expectedPath))) !== null && _mime$getType !== void 0 ? _mime$getType : 'application/octet-string';
this.comparator = (0, _utils.getComparator)(this.mimeType);
this.testInfo = testInfo;
this.kind = this.mimeType.startsWith('image/') ? 'Screenshot' : 'Snapshot';
}
createMatcherResult(message, pass, log) {
const unfiltered = {
name: this.matcherName,
expected: this.expectedPath,
actual: this.actualPath,
diff: this.diffPath,
pass,
message: () => message,
log
};
return Object.fromEntries(Object.entries(unfiltered).filter(([_, v]) => v !== undefined));
}
handleMissingNegated() {
const isWriteMissingMode = this.updateSnapshots === 'all' || this.updateSnapshots === 'missing';
const message = `A snapshot doesn't exist at ${this.expectedPath}${isWriteMissingMode ? ', matchers using ".not" won\'t write them automatically.' : '.'}`;
// NOTE: 'isNot' matcher implies inversed value.
return this.createMatcherResult(message, true);
}
handleDifferentNegated() {
// NOTE: 'isNot' matcher implies inversed value.
return this.createMatcherResult('', false);
}
handleMatchingNegated() {
const message = [_utilsBundle.colors.red(`${this.kind} comparison failed:`), '', indent('Expected result should be different from the actual one.', ' ')].join('\n');
// NOTE: 'isNot' matcher implies inversed value.
return this.createMatcherResult(message, true);
}
handleMissing(actual) {
const isWriteMissingMode = this.updateSnapshots === 'all' || this.updateSnapshots === 'missing';
if (isWriteMissingMode) writeFileSync(this.expectedPath, actual);
this.testInfo.attachments.push({
name: (0, _util.addSuffixToFilePath)(this.attachmentBaseName, '-expected'),
contentType: this.mimeType,
path: this.expectedPath
});
writeFileSync(this.actualPath, actual);
this.testInfo.attachments.push({
name: (0, _util.addSuffixToFilePath)(this.attachmentBaseName, '-actual'),
contentType: this.mimeType,
path: this.actualPath
});
const message = `A snapshot doesn't exist at ${this.expectedPath}${isWriteMissingMode ? ', writing actual.' : '.'}`;
if (this.updateSnapshots === 'all') {
/* eslint-disable no-console */
console.log(message);
return this.createMatcherResult(message, true);
}
if (this.updateSnapshots === 'missing') {
this.testInfo._hasNonRetriableError = true;
this.testInfo._failWithError(new Error(message));
return this.createMatcherResult('', true);
}
return this.createMatcherResult(message, false);
}
handleDifferent(actual, expected, previous, diff, header, diffError, log) {
const output = [`${header}${indent(diffError, ' ')}`];
if (expected !== undefined) {
// Copy the expectation inside the `test-results/` folder for backwards compatibility,
// so that one can upload `test-results/` directory and have all the data inside.
writeFileSync(this.legacyExpectedPath, expected);
this.testInfo.attachments.push({
name: (0, _util.addSuffixToFilePath)(this.attachmentBaseName, '-expected'),
contentType: this.mimeType,
path: this.expectedPath
});
output.push(`\nExpected: ${_utilsBundle.colors.yellow(this.expectedPath)}`);
}
if (previous !== undefined) {
writeFileSync(this.previousPath, previous);
this.testInfo.attachments.push({
name: (0, _util.addSuffixToFilePath)(this.attachmentBaseName, '-previous'),
contentType: this.mimeType,
path: this.previousPath
});
output.push(`Previous: ${_utilsBundle.colors.yellow(this.previousPath)}`);
}
if (actual !== undefined) {
writeFileSync(this.actualPath, actual);
this.testInfo.attachments.push({
name: (0, _util.addSuffixToFilePath)(this.attachmentBaseName, '-actual'),
contentType: this.mimeType,
path: this.actualPath
});
output.push(`Received: ${_utilsBundle.colors.yellow(this.actualPath)}`);
}
if (diff !== undefined) {
writeFileSync(this.diffPath, diff);
this.testInfo.attachments.push({
name: (0, _util.addSuffixToFilePath)(this.attachmentBaseName, '-diff'),
contentType: this.mimeType,
path: this.diffPath
});
output.push(` Diff: ${_utilsBundle.colors.yellow(this.diffPath)}`);
}
if (log !== null && log !== void 0 && log.length) output.push((0, _util.callLogText)(log));else output.push('');
return this.createMatcherResult(output.join('\n'), false, log);
}
handleMatching() {
return this.createMatcherResult('', true);
}
}
function toMatchSnapshot(received, nameOrOptions = {}, optOptions = {}) {
var _testInfo$_projectInt;
const testInfo = (0, _globals.currentTestInfo)();
if (!testInfo) throw new Error(`toMatchSnapshot() must be called during the test`);
if (received instanceof Promise) throw new Error('An unresolved Promise was passed to toMatchSnapshot(), make sure to resolve it by adding await to it.');
if (testInfo._projectInternal.ignoreSnapshots) return {
pass: !this.isNot,
message: () => '',
name: 'toMatchSnapshot',
expected: nameOrOptions
};
const configOptions = ((_testInfo$_projectInt = testInfo._projectInternal.expect) === null || _testInfo$_projectInt === void 0 ? void 0 : _testInfo$_projectInt.toMatchSnapshot) || {};
const helper = new SnapshotHelper(testInfo, 'toMatchSnapshot', undefined, determineFileExtension(received), configOptions, nameOrOptions, optOptions);
if (this.isNot) {
if (!_fs.default.existsSync(helper.expectedPath)) return helper.handleMissingNegated();
const isDifferent = !!helper.comparator(received, _fs.default.readFileSync(helper.expectedPath), helper.options);
return isDifferent ? helper.handleDifferentNegated() : helper.handleMatchingNegated();
}
if (!_fs.default.existsSync(helper.expectedPath)) return helper.handleMissing(received);
const expected = _fs.default.readFileSync(helper.expectedPath);
const result = helper.comparator(received, expected, helper.options);
if (!result) return helper.handleMatching();
if (helper.updateSnapshots === 'all') {
writeFileSync(helper.expectedPath, received);
/* eslint-disable no-console */
console.log(helper.expectedPath + ' does not match, writing actual.');
return helper.createMatcherResult(helper.expectedPath + ' running with --update-snapshots, writing actual.', true);
}
const receiver = (0, _utils.isString)(received) ? 'string' : 'Buffer';
const header = (0, _matcherHint.matcherHint)(this, undefined, 'toMatchSnapshot', receiver, undefined, undefined);
return helper.handleDifferent(received, expected, undefined, result.diff, header, result.errorMessage, undefined);
}
function toHaveScreenshotStepTitle(nameOrOptions = {}, optOptions = {}) {
let name;
if (typeof nameOrOptions === 'object' && !Array.isArray(nameOrOptions)) name = nameOrOptions.name;else name = nameOrOptions;
return Array.isArray(name) ? name.join(_path.default.sep) : name || '';
}
async function toHaveScreenshot(pageOrLocator, nameOrOptions = {}, optOptions = {}) {
var _testInfo$_projectInt2, _helper$options$timeo, _helper$options$anima, _helper$options$caret, _helper$options$scale;
const testInfo = (0, _globals.currentTestInfo)();
if (!testInfo) throw new Error(`toHaveScreenshot() must be called during the test`);
if (testInfo._projectInternal.ignoreSnapshots) return {
pass: !this.isNot,
message: () => '',
name: 'toHaveScreenshot',
expected: nameOrOptions
};
(0, _util.expectTypes)(pageOrLocator, ['Page', 'Locator'], 'toHaveScreenshot');
const [page, locator] = pageOrLocator.constructor.name === 'Page' ? [pageOrLocator, undefined] : [pageOrLocator.page(), pageOrLocator];
const configOptions = ((_testInfo$_projectInt2 = testInfo._projectInternal.expect) === null || _testInfo$_projectInt2 === void 0 ? void 0 : _testInfo$_projectInt2.toHaveScreenshot) || {};
const helper = new SnapshotHelper(testInfo, 'toHaveScreenshot', locator, 'png', configOptions, nameOrOptions, optOptions);
if (!helper.expectedPath.toLowerCase().endsWith('.png')) throw new Error(`Screenshot name "${_path.default.basename(helper.expectedPath)}" must have '.png' extension`);
(0, _util.expectTypes)(pageOrLocator, ['Page', 'Locator'], 'toHaveScreenshot');
const style = await loadScreenshotStyles(helper.options.stylePath);
const timeout = (_helper$options$timeo = helper.options.timeout) !== null && _helper$options$timeo !== void 0 ? _helper$options$timeo : this.timeout;
const expectScreenshotOptions = {
locator,
animations: (_helper$options$anima = helper.options.animations) !== null && _helper$options$anima !== void 0 ? _helper$options$anima : 'disabled',
caret: (_helper$options$caret = helper.options.caret) !== null && _helper$options$caret !== void 0 ? _helper$options$caret : 'hide',
clip: helper.options.clip,
fullPage: helper.options.fullPage,
mask: helper.options.mask,
maskColor: helper.options.maskColor,
omitBackground: helper.options.omitBackground,
scale: (_helper$options$scale = helper.options.scale) !== null && _helper$options$scale !== void 0 ? _helper$options$scale : 'css',
style,
isNot: !!this.isNot,
timeout,
comparator: helper.options.comparator,
maxDiffPixels: helper.options.maxDiffPixels,
maxDiffPixelRatio: helper.options.maxDiffPixelRatio,
threshold: helper.options.threshold
};
const hasSnapshot = _fs.default.existsSync(helper.expectedPath);
if (this.isNot) {
if (!hasSnapshot) return helper.handleMissingNegated();
// Having `errorMessage` means we timed out while waiting
// for screenshots not to match, so screenshots
// are actually the same in the end.
expectScreenshotOptions.expected = await _fs.default.promises.readFile(helper.expectedPath);
const isDifferent = !(await page._expectScreenshot(expectScreenshotOptions)).errorMessage;
return isDifferent ? helper.handleDifferentNegated() : helper.handleMatchingNegated();
}
// Fast path: there's no screenshot and we don't intend to update it.
if (helper.updateSnapshots === 'none' && !hasSnapshot) return helper.createMatcherResult(`A snapshot doesn't exist at ${helper.expectedPath}.`, false);
const receiver = locator ? 'locator' : 'page';
if (!hasSnapshot) {
// Regenerate a new screenshot by waiting until two screenshots are the same.
const {
actual,
previous,
diff,
errorMessage,
log,
timedOut
} = await page._expectScreenshot(expectScreenshotOptions);
// We tried re-generating new snapshot but failed.
// This can be due to e.g. spinning animation, so we want to show it as a diff.
if (errorMessage) {
const header = (0, _matcherHint.matcherHint)(this, locator, 'toHaveScreenshot', receiver, undefined, undefined, timedOut ? timeout : undefined);
return helper.handleDifferent(actual, undefined, previous, diff, header, errorMessage, log);
}
// We successfully generated new screenshot.
return helper.handleMissing(actual);
}
// General case:
// - snapshot exists
// - regular matcher (i.e. not a `.not`)
// - perhaps an 'all' flag to update non-matching screenshots
expectScreenshotOptions.expected = await _fs.default.promises.readFile(helper.expectedPath);
const {
actual,
previous,
diff,
errorMessage,
log,
timedOut
} = await page._expectScreenshot(expectScreenshotOptions);
if (!errorMessage) return helper.handleMatching();
if (helper.updateSnapshots === 'all') {
writeFileSync(helper.expectedPath, actual);
writeFileSync(helper.actualPath, actual);
/* eslint-disable no-console */
console.log(helper.expectedPath + ' is re-generated, writing actual.');
return helper.createMatcherResult(helper.expectedPath + ' running with --update-snapshots, writing actual.', true);
}
const header = (0, _matcherHint.matcherHint)(this, undefined, 'toHaveScreenshot', receiver, undefined, undefined, timedOut ? timeout : undefined);
return helper.handleDifferent(actual, expectScreenshotOptions.expected, previous, diff, header, errorMessage, log);
}
function writeFileSync(aPath, content) {
_fs.default.mkdirSync(_path.default.dirname(aPath), {
recursive: true
});
_fs.default.writeFileSync(aPath, content);
}
function indent(lines, tab) {
return lines.replace(/^(?=.+$)/gm, tab);
}
function determineFileExtension(file) {
if (typeof file === 'string') return 'txt';
if (compareMagicBytes(file, [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])) return 'png';
if (compareMagicBytes(file, [0xff, 0xd8, 0xff])) return 'jpg';
return 'dat';
}
function compareMagicBytes(file, magicBytes) {
return Buffer.compare(Buffer.from(magicBytes), file.slice(0, magicBytes.length)) === 0;
}
async function loadScreenshotStyles(stylePath) {
if (!stylePath) return;
const stylePaths = Array.isArray(stylePath) ? stylePath : [stylePath];
const styles = await Promise.all(stylePaths.map(async stylePath => {
const text = await _fs.default.promises.readFile(stylePath, 'utf8');
return text.trim();
}));
return styles.join('\n').trim() || undefined;
}

103
node_modules/playwright/lib/matchers/toMatchText.js generated vendored Normal file
View File

@@ -0,0 +1,103 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toMatchText = toMatchText;
var _util = require("../util");
var _expect = require("./expect");
var _expectBundle = require("../common/expectBundle");
var _matcherHint = require("./matcherHint");
var _utilsBundle = require("playwright-core/lib/utilsBundle");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
async function toMatchText(matcherName, receiver, receiverType, query, expected, options = {}) {
var _options$timeout;
(0, _util.expectTypes)(receiver, [receiverType], matcherName);
const matcherOptions = {
isNot: this.isNot,
promise: this.promise
};
if (!(typeof expected === 'string') && !(expected && typeof expected.test === 'function')) {
// Same format as jest's matcherErrorMessage
throw new Error([(0, _matcherHint.matcherHint)(this, receiver, matcherName, receiver, expected, matcherOptions), `${_utilsBundle.colors.bold('Matcher error')}: ${(0, _expectBundle.EXPECTED_COLOR)('expected')} value must be a string or regular expression`, this.utils.printWithType('Expected', expected, this.utils.printExpected)].join('\n\n'));
}
const timeout = (_options$timeout = options.timeout) !== null && _options$timeout !== void 0 ? _options$timeout : this.timeout;
const {
matches: pass,
received,
log,
timedOut
} = await query(!!this.isNot, timeout);
if (pass === !this.isNot) {
return {
name: matcherName,
message: () => '',
pass,
expected
};
}
const stringSubstring = options.matchSubstring ? 'substring' : 'string';
const receivedString = received || '';
const messagePrefix = (0, _matcherHint.matcherHint)(this, receiver, matcherName, 'locator', undefined, matcherOptions, timedOut ? timeout : undefined);
const notFound = received === _matcherHint.kNoElementsFoundError;
let printedReceived;
let printedExpected;
let printedDiff;
if (pass) {
if (typeof expected === 'string') {
if (notFound) {
printedExpected = `Expected ${stringSubstring}: not ${this.utils.printExpected(expected)}`;
printedReceived = `Received: ${received}`;
} else {
printedExpected = `Expected ${stringSubstring}: not ${this.utils.printExpected(expected)}`;
const formattedReceived = (0, _expect.printReceivedStringContainExpectedSubstring)(receivedString, receivedString.indexOf(expected), expected.length);
printedReceived = `Received string: ${formattedReceived}`;
}
} else {
if (notFound) {
printedExpected = `Expected pattern: not ${this.utils.printExpected(expected)}`;
printedReceived = `Received: ${received}`;
} else {
printedExpected = `Expected pattern: not ${this.utils.printExpected(expected)}`;
const formattedReceived = (0, _expect.printReceivedStringContainExpectedResult)(receivedString, typeof expected.exec === 'function' ? expected.exec(receivedString) : null);
printedReceived = `Received string: ${formattedReceived}`;
}
}
} else {
const labelExpected = `Expected ${typeof expected === 'string' ? stringSubstring : 'pattern'}`;
if (notFound) {
printedExpected = `${labelExpected}: ${this.utils.printExpected(expected)}`;
printedReceived = `Received: ${received}`;
} else {
printedDiff = this.utils.printDiffOrStringify(expected, receivedString, labelExpected, 'Received string', false);
}
}
const message = () => {
const resultDetails = printedDiff ? printedDiff : printedExpected + '\n' + printedReceived;
return messagePrefix + resultDetails + (0, _util.callLogText)(log);
};
return {
name: matcherName,
expected,
message,
pass,
actual: received,
log,
timeout: timedOut ? timeout : undefined
};
}

View File

@@ -0,0 +1,78 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.gitStatusFromCLI = exports.gitCommitInfo = void 0;
var _utils = require("playwright-core/lib/utils");
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const GIT_OPERATIONS_TIMEOUT_MS = 1500;
const gitCommitInfo = options => {
return {
name: 'playwright:git-commit-info',
setup: async (config, configDir) => {
const info = {
...linksFromEnv(),
...(options !== null && options !== void 0 && options.info ? options.info : await gitStatusFromCLI((options === null || options === void 0 ? void 0 : options.directory) || configDir)),
timestamp: Date.now()
};
// Normalize dates
const timestamp = info['revision.timestamp'];
if (timestamp instanceof Date) info['revision.timestamp'] = timestamp.getTime();
config.metadata = config.metadata || {};
Object.assign(config.metadata, info);
}
};
};
exports.gitCommitInfo = gitCommitInfo;
const linksFromEnv = () => {
const out = {};
// Jenkins: https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
if (process.env.BUILD_URL) out['ci.link'] = process.env.BUILD_URL;
// GitLab: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
if (process.env.CI_PROJECT_URL && process.env.CI_COMMIT_SHA) out['revision.link'] = `${process.env.CI_PROJECT_URL}/-/commit/${process.env.CI_COMMIT_SHA}`;
if (process.env.CI_JOB_URL) out['ci.link'] = process.env.CI_JOB_URL;
// GitHub: https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables
if (process.env.GITHUB_SERVER_URL && process.env.GITHUB_REPOSITORY && process.env.GITHUB_SHA) out['revision.link'] = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/commit/${process.env.GITHUB_SHA}`;
if (process.env.GITHUB_SERVER_URL && process.env.GITHUB_REPOSITORY && process.env.GITHUB_RUN_ID) out['ci.link'] = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`;
return out;
};
const gitStatusFromCLI = async gitDir => {
const separator = `:${(0, _utils.createGuid)().slice(0, 4)}:`;
const {
code,
stdout
} = await (0, _utils.spawnAsync)('git', ['show', '-s', `--format=%H${separator}%s${separator}%an${separator}%ae${separator}%ct`, 'HEAD'], {
stdio: 'pipe',
cwd: gitDir,
timeout: GIT_OPERATIONS_TIMEOUT_MS
});
if (code) return;
const showOutput = stdout.trim();
const [id, subject, author, email, rawTimestamp] = showOutput.split(separator);
let timestamp = Number.parseInt(rawTimestamp, 10);
timestamp = Number.isInteger(timestamp) ? timestamp * 1000 : 0;
return {
'revision.id': id,
'revision.author': author,
'revision.email': email,
'revision.subject': subject,
'revision.timestamp': timestamp
};
};
exports.gitStatusFromCLI = gitStatusFromCLI;

19
node_modules/playwright/lib/plugins/index.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "gitCommitInfo", {
enumerable: true,
get: function () {
return _gitCommitInfoPlugin.gitCommitInfo;
}
});
Object.defineProperty(exports, "webServer", {
enumerable: true,
get: function () {
return _webServerPlugin.webServer;
}
});
var _webServerPlugin = require("./webServerPlugin");
var _gitCommitInfoPlugin = require("./gitCommitInfoPlugin");

187
node_modules/playwright/lib/plugins/webServerPlugin.js generated vendored Normal file
View File

@@ -0,0 +1,187 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.webServerPluginsForConfig = exports.webServer = exports.WebServerPlugin = void 0;
var _path = _interopRequireDefault(require("path"));
var _net = _interopRequireDefault(require("net"));
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _utils = require("playwright-core/lib/utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const DEFAULT_ENVIRONMENT_VARIABLES = {
'BROWSER': 'none',
// Disable that create-react-app will open the page in the browser
'FORCE_COLOR': '1',
'DEBUG_COLORS': '1'
};
const debugWebServer = (0, _utilsBundle.debug)('pw:webserver');
class WebServerPlugin {
constructor(options, checkPortOnly) {
this._isAvailableCallback = void 0;
this._killProcess = void 0;
this._processExitedPromise = void 0;
this._options = void 0;
this._checkPortOnly = void 0;
this._reporter = void 0;
this.name = 'playwright:webserver';
this._options = options;
this._checkPortOnly = checkPortOnly;
}
async setup(config, configDir, reporter) {
var _this$_reporter$onStd;
this._reporter = reporter;
this._isAvailableCallback = this._options.url ? getIsAvailableFunction(this._options.url, this._checkPortOnly, !!this._options.ignoreHTTPSErrors, (_this$_reporter$onStd = this._reporter.onStdErr) === null || _this$_reporter$onStd === void 0 ? void 0 : _this$_reporter$onStd.bind(this._reporter)) : undefined;
this._options.cwd = this._options.cwd ? _path.default.resolve(configDir, this._options.cwd) : configDir;
try {
await this._startProcess();
await this._waitForProcess();
} catch (error) {
await this.teardown();
throw error;
}
}
async teardown() {
var _this$_killProcess;
debugWebServer(`Terminating the WebServer`);
await ((_this$_killProcess = this._killProcess) === null || _this$_killProcess === void 0 ? void 0 : _this$_killProcess.call(this));
debugWebServer(`Terminated the WebServer`);
}
async _startProcess() {
var _this$_isAvailableCal;
let processExitedReject = error => {};
this._processExitedPromise = new Promise((_, reject) => processExitedReject = reject);
const isAlreadyAvailable = await ((_this$_isAvailableCal = this._isAvailableCallback) === null || _this$_isAvailableCal === void 0 ? void 0 : _this$_isAvailableCal.call(this));
if (isAlreadyAvailable) {
var _this$_options$url;
debugWebServer(`WebServer is already available`);
if (this._options.reuseExistingServer) return;
const port = new URL(this._options.url).port;
throw new Error(`${(_this$_options$url = this._options.url) !== null && _this$_options$url !== void 0 ? _this$_options$url : `http://localhost${port ? ':' + port : ''}`} is already used, make sure that nothing is running on the port/url or set reuseExistingServer:true in config.webServer.`);
}
debugWebServer(`Starting WebServer process ${this._options.command}...`);
const {
launchedProcess,
kill
} = await (0, _utils.launchProcess)({
command: this._options.command,
env: {
...DEFAULT_ENVIRONMENT_VARIABLES,
...process.env,
...this._options.env
},
cwd: this._options.cwd,
stdio: 'stdin',
shell: true,
// Reject to indicate that we cannot close the web server gracefully
// and should fallback to non-graceful shutdown.
attemptToGracefullyClose: () => Promise.reject(),
log: () => {},
onExit: code => processExitedReject(new Error(code ? `Process from config.webServer was not able to start. Exit code: ${code}` : 'Process from config.webServer exited early.')),
tempDirectories: []
});
this._killProcess = kill;
debugWebServer(`Process started`);
launchedProcess.stderr.on('data', data => {
var _onStdErr, _ref;
if (debugWebServer.enabled || this._options.stderr === 'pipe' || !this._options.stderr) (_onStdErr = (_ref = this._reporter).onStdErr) === null || _onStdErr === void 0 || _onStdErr.call(_ref, prefixOutputLines(data.toString()));
});
launchedProcess.stdout.on('data', data => {
var _onStdOut, _ref2;
if (debugWebServer.enabled || this._options.stdout === 'pipe') (_onStdOut = (_ref2 = this._reporter).onStdOut) === null || _onStdOut === void 0 || _onStdOut.call(_ref2, prefixOutputLines(data.toString()));
});
}
async _waitForProcess() {
if (!this._isAvailableCallback) {
this._processExitedPromise.catch(() => {});
return;
}
debugWebServer(`Waiting for availability...`);
const launchTimeout = this._options.timeout || 60 * 1000;
const cancellationToken = {
canceled: false
};
const {
timedOut
} = await Promise.race([(0, _utils.raceAgainstDeadline)(() => waitFor(this._isAvailableCallback, cancellationToken), (0, _utils.monotonicTime)() + launchTimeout), this._processExitedPromise]);
cancellationToken.canceled = true;
if (timedOut) throw new Error(`Timed out waiting ${launchTimeout}ms from config.webServer.`);
debugWebServer(`WebServer available`);
}
}
exports.WebServerPlugin = WebServerPlugin;
async function isPortUsed(port) {
const innerIsPortUsed = host => new Promise(resolve => {
const conn = _net.default.connect(port, host).on('error', () => {
resolve(false);
}).on('connect', () => {
conn.end();
resolve(true);
});
});
return (await innerIsPortUsed('127.0.0.1')) || (await innerIsPortUsed('::1'));
}
async function waitFor(waitFn, cancellationToken) {
const logScale = [100, 250, 500];
while (!cancellationToken.canceled) {
const connected = await waitFn();
if (connected) return;
const delay = logScale.shift() || 1000;
debugWebServer(`Waiting ${delay}ms`);
await new Promise(x => setTimeout(x, delay));
}
}
function getIsAvailableFunction(url, checkPortOnly, ignoreHTTPSErrors, onStdErr) {
const urlObject = new URL(url);
if (!checkPortOnly) return () => (0, _utils.isURLAvailable)(urlObject, ignoreHTTPSErrors, debugWebServer, onStdErr);
const port = urlObject.port;
return () => isPortUsed(+port);
}
const webServer = options => {
return new WebServerPlugin(options, false);
};
exports.webServer = webServer;
const webServerPluginsForConfig = config => {
const shouldSetBaseUrl = !!config.config.webServer;
const webServerPlugins = [];
for (const webServerConfig of config.webServers) {
if (webServerConfig.port && webServerConfig.url) throw new Error(`Either 'port' or 'url' should be specified in config.webServer.`);
let url;
if (webServerConfig.port || webServerConfig.url) {
url = webServerConfig.url || `http://localhost:${webServerConfig.port}`;
// We only set base url when only the port is given. That's a legacy mode we have regrets about.
if (shouldSetBaseUrl && !webServerConfig.url) process.env.PLAYWRIGHT_TEST_BASE_URL = url;
}
webServerPlugins.push(new WebServerPlugin({
...webServerConfig,
url
}, webServerConfig.port !== undefined));
}
return webServerPlugins;
};
exports.webServerPluginsForConfig = webServerPluginsForConfig;
function prefixOutputLines(output) {
const lastIsNewLine = output[output.length - 1] === '\n';
let lines = output.split('\n');
if (lastIsNewLine) lines.pop();
lines = lines.map(line => _utilsBundle.colors.dim('[WebServer] ') + line);
if (lastIsNewLine) lines.push('');
return lines.join('\n');
}

339
node_modules/playwright/lib/program.js generated vendored Normal file
View File

@@ -0,0 +1,339 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "program", {
enumerable: true,
get: function () {
return _program.program;
}
});
exports.withRunnerAndMutedWrite = withRunnerAndMutedWrite;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _runner = require("./runner/runner");
var _utils = require("playwright-core/lib/utils");
var _util = require("./util");
var _html = require("./reporters/html");
var _merge = require("./reporters/merge");
var _configLoader = require("./common/configLoader");
var _config = require("./common/config");
var _program = require("playwright-core/lib/cli/program");
var _base = require("./reporters/base");
var testServer = _interopRequireWildcard(require("./runner/testServer"));
var _watchMode = require("./runner/watchMode");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the 'License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable no-console */
function addTestCommand(program) {
const command = program.command('test [test-filter...]');
command.description('run tests with Playwright Test');
const options = testOptions.sort((a, b) => a[0].replace(/-/g, '').localeCompare(b[0].replace(/-/g, '')));
options.forEach(([name, description]) => command.option(name, description));
command.action(async (args, opts) => {
try {
await runTests(args, opts);
} catch (e) {
console.error(e);
(0, _utils.gracefullyProcessExitDoNotHang)(1);
}
});
command.addHelpText('afterAll', `
Arguments [test-filter...]:
Pass arguments to filter test files. Each argument is treated as a regular expression. Matching is performed against the absolute file paths.
Examples:
$ npx playwright test my.spec.ts
$ npx playwright test some.spec.ts:42
$ npx playwright test --headed
$ npx playwright test --project=webkit`);
}
function addListFilesCommand(program) {
const command = program.command('list-files [file-filter...]', {
hidden: true
});
command.description('List files with Playwright Test tests');
command.option('-c, --config <file>', `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
command.option('--project <project-name...>', `Only run tests from the specified list of projects, supports '*' wildcard (default: list all projects)`);
command.action(async (args, opts) => listTestFiles(opts));
}
function addClearCacheCommand(program) {
const command = program.command('clear-cache');
command.description('clears build and test caches');
command.option('-c, --config <file>', `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
command.action(async opts => {
const config = await (0, _configLoader.loadConfigFromFileRestartIfNeeded)(opts.config);
if (!config) return;
const runner = new _runner.Runner(config);
const {
status
} = await runner.clearCache();
const exitCode = status === 'interrupted' ? 130 : status === 'passed' ? 0 : 1;
(0, _utils.gracefullyProcessExitDoNotHang)(exitCode);
});
}
function addFindRelatedTestFilesCommand(program) {
const command = program.command('find-related-test-files [source-files...]', {
hidden: true
});
command.description('Returns the list of related tests to the given files');
command.option('-c, --config <file>', `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
command.action(async (files, options) => {
const resolvedFiles = files.map(file => _path.default.resolve(process.cwd(), file));
await withRunnerAndMutedWrite(options.config, runner => runner.findRelatedTestFiles(resolvedFiles));
});
}
function addDevServerCommand(program) {
const command = program.command('dev-server', {
hidden: true
});
command.description('start dev server');
command.option('-c, --config <file>', `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
command.action(async options => {
const config = await (0, _configLoader.loadConfigFromFileRestartIfNeeded)(options.config);
if (!config) return;
const runner = new _runner.Runner(config);
const {
status
} = await runner.runDevServer();
const exitCode = status === 'interrupted' ? 130 : status === 'passed' ? 0 : 1;
(0, _utils.gracefullyProcessExitDoNotHang)(exitCode);
});
}
function addTestServerCommand(program) {
const command = program.command('test-server', {
hidden: true
});
command.description('start test server');
command.option('-c, --config <file>', `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
command.option('--host <host>', 'Host to start the server on', 'localhost');
command.option('--port <port>', 'Port to start the server on', '0');
command.action(opts => runTestServer(opts));
}
function addShowReportCommand(program) {
const command = program.command('show-report [report]');
command.description('show HTML report');
command.action((report, options) => (0, _html.showHTMLReport)(report, options.host, +options.port));
command.option('--host <host>', 'Host to serve report on', 'localhost');
command.option('--port <port>', 'Port to serve report on', '9323');
command.addHelpText('afterAll', `
Arguments [report]:
When specified, opens given report, otherwise opens last generated report.
Examples:
$ npx playwright show-report
$ npx playwright show-report playwright-report`);
}
function addMergeReportsCommand(program) {
const command = program.command('merge-reports [dir]');
command.description('merge multiple blob reports (for sharded tests) into a single report');
command.action(async (dir, options) => {
try {
await mergeReports(dir, options);
} catch (e) {
console.error(e);
(0, _utils.gracefullyProcessExitDoNotHang)(1);
}
});
command.option('-c, --config <file>', `Configuration file. Can be used to specify additional configuration for the output report.`);
command.option('--reporter <reporter>', `Reporter to use, comma-separated, can be ${_config.builtInReporters.map(name => `"${name}"`).join(', ')} (default: "${_config.defaultReporter}")`);
command.addHelpText('afterAll', `
Arguments [dir]:
Directory containing blob reports.
Examples:
$ npx playwright merge-reports playwright-report`);
}
async function runTests(args, opts) {
await (0, _utils.startProfiling)();
const cliOverrides = overridesFromOptions(opts);
if (opts.ui || opts.uiHost || opts.uiPort) {
if (opts.onlyChanged) throw new Error(`--only-changed is not supported in UI mode. If you'd like that to change, see https://github.com/microsoft/playwright/issues/15075 for more details.`);
const status = await testServer.runUIMode(opts.config, cliOverrides, {
host: opts.uiHost,
port: opts.uiPort ? +opts.uiPort : undefined,
args,
grep: opts.grep,
grepInvert: opts.grepInvert,
project: opts.project || undefined,
reporter: Array.isArray(opts.reporter) ? opts.reporter : opts.reporter ? [opts.reporter] : undefined
});
await (0, _utils.stopProfiling)('runner');
if (status === 'restarted') return;
const exitCode = status === 'interrupted' ? 130 : status === 'passed' ? 0 : 1;
(0, _utils.gracefullyProcessExitDoNotHang)(exitCode);
return;
}
if (process.env.PWTEST_WATCH) {
if (opts.onlyChanged) throw new Error(`--only-changed is not supported in watch mode. If you'd like that to change, file an issue and let us know about your usecase for it.`);
const status = await (0, _watchMode.runWatchModeLoop)((0, _configLoader.resolveConfigLocation)(opts.config), {
projects: opts.project,
files: args,
grep: opts.grep
});
await (0, _utils.stopProfiling)('runner');
if (status === 'restarted') return;
const exitCode = status === 'interrupted' ? 130 : status === 'passed' ? 0 : 1;
(0, _utils.gracefullyProcessExitDoNotHang)(exitCode);
return;
}
const config = await (0, _configLoader.loadConfigFromFileRestartIfNeeded)(opts.config, cliOverrides, opts.deps === false);
if (!config) return;
config.cliArgs = args;
config.cliGrep = opts.grep;
config.cliOnlyChanged = opts.onlyChanged === true ? 'HEAD' : opts.onlyChanged;
config.cliGrepInvert = opts.grepInvert;
config.cliListOnly = !!opts.list;
config.cliProjectFilter = opts.project || undefined;
config.cliPassWithNoTests = !!opts.passWithNoTests;
config.cliFailOnFlakyTests = !!opts.failOnFlakyTests;
config.cliLastFailed = !!opts.lastFailed;
const runner = new _runner.Runner(config);
const status = await runner.runAllTests();
await (0, _utils.stopProfiling)('runner');
const exitCode = status === 'interrupted' ? 130 : status === 'passed' ? 0 : 1;
(0, _utils.gracefullyProcessExitDoNotHang)(exitCode);
}
async function runTestServer(opts) {
const host = opts.host || 'localhost';
const port = opts.port ? +opts.port : 0;
const status = await testServer.runTestServer(opts.config, {}, {
host,
port
});
if (status === 'restarted') return;
const exitCode = status === 'interrupted' ? 130 : status === 'passed' ? 0 : 1;
(0, _utils.gracefullyProcessExitDoNotHang)(exitCode);
}
async function withRunnerAndMutedWrite(configFile, callback) {
// Redefine process.stdout.write in case config decides to pollute stdio.
const stdoutWrite = process.stdout.write.bind(process.stdout);
process.stdout.write = (a, b, c) => process.stderr.write(a, b, c);
try {
const config = await (0, _configLoader.loadConfigFromFileRestartIfNeeded)(configFile);
if (!config) return;
const runner = new _runner.Runner(config);
const result = await callback(runner);
stdoutWrite(JSON.stringify(result, undefined, 2), () => {
(0, _utils.gracefullyProcessExitDoNotHang)(0);
});
} catch (e) {
const error = (0, _util.serializeError)(e);
error.location = (0, _base.prepareErrorStack)(e.stack).location;
stdoutWrite(JSON.stringify({
error
}, undefined, 2), () => {
(0, _utils.gracefullyProcessExitDoNotHang)(0);
});
}
}
async function listTestFiles(opts) {
await withRunnerAndMutedWrite(opts.config, async runner => {
return await runner.listTestFiles();
});
}
async function mergeReports(reportDir, opts) {
const configFile = opts.config;
const config = configFile ? await (0, _configLoader.loadConfigFromFileRestartIfNeeded)(configFile) : await (0, _configLoader.loadEmptyConfigForMergeReports)();
if (!config) return;
const dir = _path.default.resolve(process.cwd(), reportDir || '');
const dirStat = await _fs.default.promises.stat(dir).catch(e => null);
if (!dirStat) throw new Error('Directory does not exist: ' + dir);
if (!dirStat.isDirectory()) throw new Error(`"${dir}" is not a directory`);
let reporterDescriptions = resolveReporterOption(opts.reporter);
if (!reporterDescriptions && configFile) reporterDescriptions = config.config.reporter;
if (!reporterDescriptions) reporterDescriptions = [[_config.defaultReporter]];
const rootDirOverride = configFile ? config.config.rootDir : undefined;
await (0, _merge.createMergedReport)(config, dir, reporterDescriptions, rootDirOverride);
(0, _utils.gracefullyProcessExitDoNotHang)(0);
}
function overridesFromOptions(options) {
const shardPair = options.shard ? options.shard.split('/').map(t => parseInt(t, 10)) : undefined;
const overrides = {
forbidOnly: options.forbidOnly ? true : undefined,
fullyParallel: options.fullyParallel ? true : undefined,
globalTimeout: options.globalTimeout ? parseInt(options.globalTimeout, 10) : undefined,
maxFailures: options.x ? 1 : options.maxFailures ? parseInt(options.maxFailures, 10) : undefined,
outputDir: options.output ? _path.default.resolve(process.cwd(), options.output) : undefined,
quiet: options.quiet ? options.quiet : undefined,
repeatEach: options.repeatEach ? parseInt(options.repeatEach, 10) : undefined,
retries: options.retries ? parseInt(options.retries, 10) : undefined,
reporter: resolveReporterOption(options.reporter),
shard: shardPair ? {
current: shardPair[0],
total: shardPair[1]
} : undefined,
timeout: options.timeout ? parseInt(options.timeout, 10) : undefined,
tsconfig: options.tsconfig ? _path.default.resolve(process.cwd(), options.tsconfig) : undefined,
ignoreSnapshots: options.ignoreSnapshots ? !!options.ignoreSnapshots : undefined,
updateSnapshots: options.updateSnapshots ? 'all' : undefined,
workers: options.workers
};
if (options.browser) {
const browserOpt = options.browser.toLowerCase();
if (!['all', 'chromium', 'firefox', 'webkit'].includes(browserOpt)) throw new Error(`Unsupported browser "${options.browser}", must be one of "all", "chromium", "firefox" or "webkit"`);
const browserNames = browserOpt === 'all' ? ['chromium', 'firefox', 'webkit'] : [browserOpt];
overrides.projects = browserNames.map(browserName => {
return {
name: browserName,
use: {
browserName
}
};
});
}
if (options.headed || options.debug) overrides.use = {
headless: false
};
if (!options.ui && options.debug) {
overrides.debug = true;
process.env.PWDEBUG = '1';
}
if (!options.ui && options.trace) {
if (!kTraceModes.includes(options.trace)) throw new Error(`Unsupported trace mode "${options.trace}", must be one of ${kTraceModes.map(mode => `"${mode}"`).join(', ')}`);
overrides.use = overrides.use || {};
overrides.use.trace = options.trace;
}
return overrides;
}
function resolveReporterOption(reporter) {
if (!reporter || !reporter.length) return undefined;
return reporter.split(',').map(r => [resolveReporter(r)]);
}
function resolveReporter(id) {
if (_config.builtInReporters.includes(id)) return id;
const localPath = _path.default.resolve(process.cwd(), id);
if (_fs.default.existsSync(localPath)) return localPath;
return require.resolve(id, {
paths: [process.cwd()]
});
}
const kTraceModes = ['on', 'off', 'on-first-retry', 'on-all-retries', 'retain-on-failure', 'retain-on-first-failure'];
const testOptions = [['--browser <browser>', `Browser to use for tests, one of "all", "chromium", "firefox" or "webkit" (default: "chromium")`], ['-c, --config <file>', `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`], ['--debug', `Run tests with Playwright Inspector. Shortcut for "PWDEBUG=1" environment variable and "--timeout=0 --max-failures=1 --headed --workers=1" options`], ['--fail-on-flaky-tests', `Fail if any test is flagged as flaky (default: false)`], ['--forbid-only', `Fail if test.only is called (default: false)`], ['--fully-parallel', `Run all tests in parallel (default: false)`], ['--global-timeout <timeout>', `Maximum time this test suite can run in milliseconds (default: unlimited)`], ['-g, --grep <grep>', `Only run tests matching this regular expression (default: ".*")`], ['-gv, --grep-invert <grep>', `Only run tests that do not match this regular expression`], ['--headed', `Run tests in headed browsers (default: headless)`], ['--ignore-snapshots', `Ignore screenshot and snapshot expectations`], ['--last-failed', `Only re-run the failures`], ['--list', `Collect all the tests and report them, but do not run`], ['--max-failures <N>', `Stop after the first N failures`], ['--no-deps', 'Do not run project dependencies'], ['--output <dir>', `Folder for output artifacts (default: "test-results")`], ['--only-changed [ref]', `Only run test files that have been changed between 'HEAD' and 'ref'. Defaults to running all uncommitted changes. Only supports Git.`], ['--pass-with-no-tests', `Makes test run succeed even if no tests were found`], ['--project <project-name...>', `Only run tests from the specified list of projects, supports '*' wildcard (default: run all projects)`], ['--quiet', `Suppress stdio`], ['--repeat-each <N>', `Run each test N times (default: 1)`], ['--reporter <reporter>', `Reporter to use, comma-separated, can be ${_config.builtInReporters.map(name => `"${name}"`).join(', ')} (default: "${_config.defaultReporter}")`], ['--retries <retries>', `Maximum retry count for flaky tests, zero for no retries (default: no retries)`], ['--shard <shard>', `Shard tests and execute only the selected shard, specify in the form "current/all", 1-based, for example "3/5"`], ['--timeout <timeout>', `Specify test timeout threshold in milliseconds, zero for unlimited (default: ${_config.defaultTimeout})`], ['--trace <mode>', `Force tracing mode, can be ${kTraceModes.map(mode => `"${mode}"`).join(', ')}`], ['--tsconfig <path>', `Path to a single tsconfig applicable to all imported files (default: look up tsconfig for each imported file separately)`], ['--ui', `Run tests in interactive UI mode`], ['--ui-host <host>', 'Host to serve UI on; specifying this option opens UI in a browser tab'], ['--ui-port <port>', 'Port to serve UI on, 0 for any free port; specifying this option opens UI in a browser tab'], ['-u, --update-snapshots', `Update snapshots with actual results (default: only create missing snapshots)`], ['-j, --workers <workers>', `Number of concurrent workers or percentage of logical CPU cores, use 1 to run in a single worker (default: 50%)`], ['-x', `Stop after the first failure`]];
addTestCommand(_program.program);
addShowReportCommand(_program.program);
addListFilesCommand(_program.program);
addMergeReportsCommand(_program.program);
addClearCacheCommand(_program.program);
addFindRelatedTestFilesCommand(_program.program);
addDevServerCommand(_program.program);
addTestServerCommand(_program.program);

549
node_modules/playwright/lib/reporters/base.js generated vendored Normal file
View File

@@ -0,0 +1,549 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.colors = exports.BaseReporter = void 0;
exports.fitToWidth = fitToWidth;
exports.formatError = formatError;
exports.formatFailure = formatFailure;
exports.formatResultFailure = formatResultFailure;
exports.formatRetry = formatRetry;
exports.formatTestHeader = formatTestHeader;
exports.formatTestTitle = formatTestTitle;
exports.kOutputSymbol = exports.isTTY = void 0;
exports.prepareErrorStack = prepareErrorStack;
exports.relativeFilePath = relativeFilePath;
exports.resolveOutputFile = resolveOutputFile;
exports.separator = separator;
exports.stepSuffix = stepSuffix;
exports.stripAnsiEscapes = stripAnsiEscapes;
exports.ttyWidth = void 0;
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _path = _interopRequireDefault(require("path"));
var _utils = require("playwright-core/lib/utils");
var _utilsBundle2 = require("../utilsBundle");
var _util = require("../util");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const kOutputSymbol = exports.kOutputSymbol = Symbol('output');
const {
isTTY,
ttyWidth,
colors
} = (() => {
let isTTY = !!process.stdout.isTTY;
let ttyWidth = process.stdout.columns || 0;
if (process.env.PLAYWRIGHT_FORCE_TTY === 'false' || process.env.PLAYWRIGHT_FORCE_TTY === '0') {
isTTY = false;
ttyWidth = 0;
} else if (process.env.PLAYWRIGHT_FORCE_TTY === 'true' || process.env.PLAYWRIGHT_FORCE_TTY === '1') {
isTTY = true;
ttyWidth = process.stdout.columns || 100;
} else if (process.env.PLAYWRIGHT_FORCE_TTY) {
isTTY = true;
ttyWidth = +process.env.PLAYWRIGHT_FORCE_TTY;
if (isNaN(ttyWidth)) ttyWidth = 100;
}
let useColors = isTTY;
if (process.env.DEBUG_COLORS === '0' || process.env.DEBUG_COLORS === 'false' || process.env.FORCE_COLOR === '0' || process.env.FORCE_COLOR === 'false') useColors = false;else if (process.env.DEBUG_COLORS || process.env.FORCE_COLOR) useColors = true;
const colors = useColors ? _utilsBundle.colors : {
bold: t => t,
cyan: t => t,
dim: t => t,
gray: t => t,
green: t => t,
red: t => t,
yellow: t => t,
enabled: false
};
return {
isTTY,
ttyWidth,
colors
};
})();
exports.colors = colors;
exports.ttyWidth = ttyWidth;
exports.isTTY = isTTY;
class BaseReporter {
constructor(options = {}) {
this.config = void 0;
this.suite = void 0;
this.totalTestCount = 0;
this.result = void 0;
this.fileDurations = new Map();
this._omitFailures = void 0;
this._fatalErrors = [];
this._failureCount = 0;
this._omitFailures = options.omitFailures || false;
}
version() {
return 'v2';
}
onConfigure(config) {
this.config = config;
}
onBegin(suite) {
this.suite = suite;
this.totalTestCount = suite.allTests().length;
}
onStdOut(chunk, test, result) {
this._appendOutput({
chunk,
type: 'stdout'
}, result);
}
onStdErr(chunk, test, result) {
this._appendOutput({
chunk,
type: 'stderr'
}, result);
}
_appendOutput(output, result) {
if (!result) return;
result[kOutputSymbol] = result[kOutputSymbol] || [];
result[kOutputSymbol].push(output);
}
onTestEnd(test, result) {
if (result.status !== 'skipped' && result.status !== test.expectedStatus) ++this._failureCount;
const projectName = test.titlePath()[1];
const relativePath = relativeTestPath(this.config, test);
const fileAndProject = (projectName ? `[${projectName}] ` : '') + relativePath;
const entry = this.fileDurations.get(fileAndProject) || {
duration: 0,
workers: new Set()
};
entry.duration += result.duration;
entry.workers.add(result.workerIndex);
this.fileDurations.set(fileAndProject, entry);
}
onError(error) {
this._fatalErrors.push(error);
}
async onEnd(result) {
this.result = result;
}
fitToScreen(line, prefix) {
if (!ttyWidth) {
// Guard against the case where we cannot determine available width.
return line;
}
return fitToWidth(line, ttyWidth, prefix);
}
generateStartingMessage() {
var _this$config$metadata;
const jobs = (_this$config$metadata = this.config.metadata.actualWorkers) !== null && _this$config$metadata !== void 0 ? _this$config$metadata : this.config.workers;
const shardDetails = this.config.shard ? `, shard ${this.config.shard.current} of ${this.config.shard.total}` : '';
if (!this.totalTestCount) return '';
return '\n' + colors.dim('Running ') + this.totalTestCount + colors.dim(` test${this.totalTestCount !== 1 ? 's' : ''} using `) + jobs + colors.dim(` worker${jobs !== 1 ? 's' : ''}${shardDetails}`);
}
getSlowTests() {
if (!this.config.reportSlowTests) return [];
// Only pick durations that were served by single worker.
const fileDurations = [...this.fileDurations.entries()].filter(([key, value]) => value.workers.size === 1).map(([key, value]) => [key, value.duration]);
fileDurations.sort((a, b) => b[1] - a[1]);
const count = Math.min(fileDurations.length, this.config.reportSlowTests.max || Number.POSITIVE_INFINITY);
const threshold = this.config.reportSlowTests.threshold;
return fileDurations.filter(([, duration]) => duration > threshold).slice(0, count);
}
generateSummaryMessage({
didNotRun,
skipped,
expected,
interrupted,
unexpected,
flaky,
fatalErrors
}) {
const tokens = [];
if (unexpected.length) {
tokens.push(colors.red(` ${unexpected.length} failed`));
for (const test of unexpected) tokens.push(colors.red(formatTestHeader(this.config, test, {
indent: ' '
})));
}
if (interrupted.length) {
tokens.push(colors.yellow(` ${interrupted.length} interrupted`));
for (const test of interrupted) tokens.push(colors.yellow(formatTestHeader(this.config, test, {
indent: ' '
})));
}
if (flaky.length) {
tokens.push(colors.yellow(` ${flaky.length} flaky`));
for (const test of flaky) tokens.push(colors.yellow(formatTestHeader(this.config, test, {
indent: ' '
})));
}
if (skipped) tokens.push(colors.yellow(` ${skipped} skipped`));
if (didNotRun) tokens.push(colors.yellow(` ${didNotRun} did not run`));
if (expected) tokens.push(colors.green(` ${expected} passed`) + colors.dim(` (${(0, _utilsBundle.ms)(this.result.duration)})`));
if (fatalErrors.length && expected + unexpected.length + interrupted.length + flaky.length > 0) tokens.push(colors.red(` ${fatalErrors.length === 1 ? '1 error was not a part of any test' : fatalErrors.length + ' errors were not a part of any test'}, see above for details`));
return tokens.join('\n');
}
generateSummary() {
let didNotRun = 0;
let skipped = 0;
let expected = 0;
const interrupted = [];
const interruptedToPrint = [];
const unexpected = [];
const flaky = [];
this.suite.allTests().forEach(test => {
switch (test.outcome()) {
case 'skipped':
{
if (test.results.some(result => result.status === 'interrupted')) {
if (test.results.some(result => !!result.error)) interruptedToPrint.push(test);
interrupted.push(test);
} else if (!test.results.length || test.expectedStatus !== 'skipped') {
++didNotRun;
} else {
++skipped;
}
break;
}
case 'expected':
++expected;
break;
case 'unexpected':
unexpected.push(test);
break;
case 'flaky':
flaky.push(test);
break;
}
});
const failuresToPrint = [...unexpected, ...flaky, ...interruptedToPrint];
return {
didNotRun,
skipped,
expected,
interrupted,
unexpected,
flaky,
failuresToPrint,
fatalErrors: this._fatalErrors
};
}
epilogue(full) {
const summary = this.generateSummary();
const summaryMessage = this.generateSummaryMessage(summary);
if (full && summary.failuresToPrint.length && !this._omitFailures) this._printFailures(summary.failuresToPrint);
this._printSlowTests();
this._printSummary(summaryMessage);
}
_printFailures(failures) {
console.log('');
failures.forEach((test, index) => {
console.log(formatFailure(this.config, test, index + 1));
});
}
_printSlowTests() {
const slowTests = this.getSlowTests();
slowTests.forEach(([file, duration]) => {
console.log(colors.yellow(' Slow test file: ') + file + colors.yellow(` (${(0, _utilsBundle.ms)(duration)})`));
});
if (slowTests.length) console.log(colors.yellow(' Consider splitting slow test files to speed up parallel execution'));
}
_printSummary(summary) {
if (summary.trim()) console.log(summary);
}
willRetry(test) {
return test.outcome() === 'unexpected' && test.results.length <= test.retries;
}
}
exports.BaseReporter = BaseReporter;
function formatFailure(config, test, index) {
const lines = [];
const header = formatTestHeader(config, test, {
indent: ' ',
index,
mode: 'error'
});
lines.push(colors.red(header));
for (const result of test.results) {
const resultLines = [];
const errors = formatResultFailure(test, result, ' ', colors.enabled);
if (!errors.length) continue;
const retryLines = [];
if (result.retry) {
retryLines.push('');
retryLines.push(colors.gray(separator(` Retry #${result.retry}`)));
}
resultLines.push(...retryLines);
resultLines.push(...errors.map(error => '\n' + error.message));
for (let i = 0; i < result.attachments.length; ++i) {
const attachment = result.attachments[i];
const hasPrintableContent = attachment.contentType.startsWith('text/');
if (!attachment.path && !hasPrintableContent) continue;
resultLines.push('');
resultLines.push(colors.cyan(separator(` attachment #${i + 1}: ${attachment.name} (${attachment.contentType})`)));
if (attachment.path) {
const relativePath = _path.default.relative(process.cwd(), attachment.path);
resultLines.push(colors.cyan(` ${relativePath}`));
// Make this extensible
if (attachment.name === 'trace') {
const packageManagerCommand = (0, _utils.getPackageManagerExecCommand)();
resultLines.push(colors.cyan(` Usage:`));
resultLines.push('');
resultLines.push(colors.cyan(` ${packageManagerCommand} playwright show-trace ${quotePathIfNeeded(relativePath)}`));
resultLines.push('');
}
} else {
if (attachment.contentType.startsWith('text/') && attachment.body) {
let text = attachment.body.toString();
if (text.length > 300) text = text.slice(0, 300) + '...';
for (const line of text.split('\n')) resultLines.push(colors.cyan(` ${line}`));
}
}
resultLines.push(colors.cyan(separator(' ')));
}
lines.push(...resultLines);
}
lines.push('');
return lines.join('\n');
}
function formatRetry(result) {
const retryLines = [];
if (result.retry) {
retryLines.push('');
retryLines.push(colors.gray(separator(` Retry #${result.retry}`)));
}
return retryLines;
}
function quotePathIfNeeded(path) {
if (/\s/.test(path)) return `"${path}"`;
return path;
}
function formatResultFailure(test, result, initialIndent, highlightCode) {
const errorDetails = [];
if (result.status === 'passed' && test.expectedStatus === 'failed') {
errorDetails.push({
message: indent(colors.red(`Expected to fail, but passed.`), initialIndent)
});
}
if (result.status === 'interrupted') {
errorDetails.push({
message: indent(colors.red(`Test was interrupted.`), initialIndent)
});
}
for (const error of result.errors) {
const formattedError = formatError(error, highlightCode);
errorDetails.push({
message: indent(formattedError.message, initialIndent),
location: formattedError.location
});
}
return errorDetails;
}
function relativeFilePath(config, file) {
return _path.default.relative(config.rootDir, file) || _path.default.basename(file);
}
function relativeTestPath(config, test) {
return relativeFilePath(config, test.location.file);
}
function stepSuffix(step) {
const stepTitles = step ? step.titlePath() : [];
return stepTitles.map(t => t.split('\n')[0]).map(t => ' ' + t).join('');
}
function formatTestTitle(config, test, step, omitLocation = false) {
var _step$location$line, _step$location, _step$location$column, _step$location2;
// root, project, file, ...describes, test
const [, projectName,, ...titles] = test.titlePath();
let location;
if (omitLocation) location = `${relativeTestPath(config, test)}`;else location = `${relativeTestPath(config, test)}:${(_step$location$line = step === null || step === void 0 || (_step$location = step.location) === null || _step$location === void 0 ? void 0 : _step$location.line) !== null && _step$location$line !== void 0 ? _step$location$line : test.location.line}:${(_step$location$column = step === null || step === void 0 || (_step$location2 = step.location) === null || _step$location2 === void 0 ? void 0 : _step$location2.column) !== null && _step$location$column !== void 0 ? _step$location$column : test.location.column}`;
const projectTitle = projectName ? `[${projectName}] ` : '';
const testTitle = `${projectTitle}${location} ${titles.join(' ')}`;
const extraTags = test.tags.filter(t => !testTitle.includes(t));
return `${testTitle}${stepSuffix(step)}${extraTags.length ? ' ' + extraTags.join(' ') : ''}`;
}
function formatTestHeader(config, test, options = {}) {
const title = formatTestTitle(config, test);
const header = `${options.indent || ''}${options.index ? options.index + ') ' : ''}${title}`;
let fullHeader = header;
// Render the path to the deepest failing test.step.
if (options.mode === 'error') {
const stepPaths = new Set();
for (const result of test.results.filter(r => !!r.errors.length)) {
const stepPath = [];
const visit = steps => {
const errors = steps.filter(s => s.error);
if (errors.length > 1) return;
if (errors.length === 1 && errors[0].category === 'test.step') {
stepPath.push(errors[0].title);
visit(errors[0].steps);
}
};
visit(result.steps);
stepPaths.add(['', ...stepPath].join(' '));
}
fullHeader = header + (stepPaths.size === 1 ? stepPaths.values().next().value : '');
}
return separator(fullHeader);
}
function formatError(error, highlightCode) {
const message = error.message || error.value || '';
const stack = error.stack;
if (!stack && !error.location) return {
message
};
const tokens = [];
// Now that we filter out internals from our stack traces, we can safely render
// the helper / original exception locations.
const parsedStack = stack ? prepareErrorStack(stack) : undefined;
tokens.push((parsedStack === null || parsedStack === void 0 ? void 0 : parsedStack.message) || message);
if (error.snippet) {
let snippet = error.snippet;
if (!highlightCode) snippet = stripAnsiEscapes(snippet);
tokens.push('');
tokens.push(snippet);
}
if (parsedStack && parsedStack.stackLines.length) tokens.push(colors.dim(parsedStack.stackLines.join('\n')));
let location = error.location;
if (parsedStack && !location) location = parsedStack.location;
if (error.cause) tokens.push(colors.dim('[cause]: ') + formatError(error.cause, highlightCode).message);
return {
location,
message: tokens.join('\n')
};
}
function separator(text = '') {
if (text) text += ' ';
const columns = Math.min(100, ttyWidth || 100);
return text + colors.dim('─'.repeat(Math.max(0, columns - text.length)));
}
function indent(lines, tab) {
return lines.replace(/^(?=.+$)/gm, tab);
}
function prepareErrorStack(stack) {
const lines = stack.split('\n');
let firstStackLine = lines.findIndex(line => line.startsWith(' at '));
if (firstStackLine === -1) firstStackLine = lines.length;
const message = lines.slice(0, firstStackLine).join('\n');
const stackLines = lines.slice(firstStackLine);
let location;
for (const line of stackLines) {
const frame = (0, _utilsBundle.parseStackTraceLine)(line);
if (!frame || !frame.file) continue;
if (belongsToNodeModules(frame.file)) continue;
location = {
file: frame.file,
column: frame.column || 0,
line: frame.line || 0
};
break;
}
return {
message,
stackLines,
location
};
}
const ansiRegex = new RegExp('([\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~])))', 'g');
function stripAnsiEscapes(str) {
return str.replace(ansiRegex, '');
}
function characterWidth(c) {
return _utilsBundle2.getEastAsianWidth.eastAsianWidth(c.codePointAt(0));
}
function stringWidth(v) {
let width = 0;
for (const {
segment
} of new Intl.Segmenter(undefined, {
granularity: 'grapheme'
}).segment(v)) width += characterWidth(segment);
return width;
}
function suffixOfWidth(v, width) {
const segments = [...new Intl.Segmenter(undefined, {
granularity: 'grapheme'
}).segment(v)];
let suffixBegin = v.length;
for (const {
segment,
index
} of segments.reverse()) {
const segmentWidth = stringWidth(segment);
if (segmentWidth > width) break;
width -= segmentWidth;
suffixBegin = index;
}
return v.substring(suffixBegin);
}
// Leaves enough space for the "prefix" to also fit.
function fitToWidth(line, width, prefix) {
const prefixLength = prefix ? stripAnsiEscapes(prefix).length : 0;
width -= prefixLength;
if (stringWidth(line) <= width) return line;
// Even items are plain text, odd items are control sequences.
const parts = line.split(ansiRegex);
const taken = [];
for (let i = parts.length - 1; i >= 0; i--) {
if (i % 2) {
// Include all control sequences to preserve formatting.
taken.push(parts[i]);
} else {
let part = suffixOfWidth(parts[i], width);
const wasTruncated = part.length < parts[i].length;
if (wasTruncated && parts[i].length > 0) {
// Add ellipsis if we are truncating.
part = '\u2026' + suffixOfWidth(parts[i], width - 1);
}
taken.push(part);
width -= stringWidth(part);
}
}
return taken.reverse().join('');
}
function belongsToNodeModules(file) {
return file.includes(`${_path.default.sep}node_modules${_path.default.sep}`);
}
function resolveFromEnv(name) {
const value = process.env[name];
if (value) return _path.default.resolve(process.cwd(), value);
return undefined;
}
// In addition to `outputFile` the function returns `outputDir` which should
// be cleaned up if present by some reporters contract.
function resolveOutputFile(reporterName, options) {
var _ref, _process$env, _options$default;
const name = reporterName.toUpperCase();
let outputFile = resolveFromEnv(`PLAYWRIGHT_${name}_OUTPUT_FILE`);
if (!outputFile && options.outputFile) outputFile = _path.default.resolve(options.configDir, options.outputFile);
if (outputFile) return {
outputFile
};
let outputDir = resolveFromEnv(`PLAYWRIGHT_${name}_OUTPUT_DIR`);
if (!outputDir && options.outputDir) outputDir = _path.default.resolve(options.configDir, options.outputDir);
if (!outputDir && options.default) outputDir = (0, _util.resolveReporterOutputPath)(options.default.outputDir, options.configDir, undefined);
if (!outputDir) outputDir = options.configDir;
const reportName = (_ref = (_process$env = process.env[`PLAYWRIGHT_${name}_OUTPUT_NAME`]) !== null && _process$env !== void 0 ? _process$env : options.fileName) !== null && _ref !== void 0 ? _ref : (_options$default = options.default) === null || _options$default === void 0 ? void 0 : _options$default.fileName;
if (!reportName) return undefined;
outputFile = _path.default.resolve(outputDir, reportName);
return {
outputFile,
outputDir
};
}

133
node_modules/playwright/lib/reporters/blob.js generated vendored Normal file
View File

@@ -0,0 +1,133 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.currentBlobReportVersion = exports.BlobReporter = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _utils = require("playwright-core/lib/utils");
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _stream = require("stream");
var _teleEmitter = require("./teleEmitter");
var _zipBundle = require("playwright-core/lib/zipBundle");
var _base = require("./base");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const currentBlobReportVersion = exports.currentBlobReportVersion = 2;
class BlobReporter extends _teleEmitter.TeleReporterEmitter {
constructor(options) {
super(message => this._messages.push(message));
this._messages = [];
this._attachments = [];
this._options = void 0;
this._salt = void 0;
this._config = void 0;
this._options = options;
if (this._options.fileName && !this._options.fileName.endsWith('.zip')) throw new Error(`Blob report file name must end with .zip extension: ${this._options.fileName}`);
this._salt = (0, _utils.createGuid)();
}
onConfigure(config) {
var _config$shard;
const metadata = {
version: currentBlobReportVersion,
userAgent: (0, _utils.getUserAgent)(),
name: process.env.PWTEST_BOT_NAME,
shard: (_config$shard = config.shard) !== null && _config$shard !== void 0 ? _config$shard : undefined,
pathSeparator: _path.default.sep
};
this._messages.push({
method: 'onBlobReportMetadata',
params: metadata
});
this._config = config;
super.onConfigure(config);
}
async onEnd(result) {
await super.onEnd(result);
const zipFileName = await this._prepareOutputFile();
const zipFile = new _zipBundle.yazl.ZipFile();
const zipFinishPromise = new _utils.ManualPromise();
const finishPromise = zipFinishPromise.catch(e => {
throw new Error(`Failed to write report ${zipFileName}: ` + e.message);
});
zipFile.on('error', error => zipFinishPromise.reject(error));
zipFile.outputStream.pipe(_fs.default.createWriteStream(zipFileName)).on('close', () => {
zipFinishPromise.resolve(undefined);
}).on('error', error => zipFinishPromise.reject(error));
for (const {
originalPath,
zipEntryPath
} of this._attachments) {
var _fs$statSync;
if (!((_fs$statSync = _fs.default.statSync(originalPath, {
throwIfNoEntry: false
})) !== null && _fs$statSync !== void 0 && _fs$statSync.isFile())) continue;
zipFile.addFile(originalPath, zipEntryPath);
}
const lines = this._messages.map(m => JSON.stringify(m) + '\n');
const content = _stream.Readable.from(lines);
zipFile.addReadStream(content, 'report.jsonl');
zipFile.end();
await finishPromise;
}
async _prepareOutputFile() {
const {
outputFile,
outputDir
} = (0, _base.resolveOutputFile)('BLOB', {
...this._options,
default: {
fileName: this._defaultReportName(this._config),
outputDir: 'blob-report'
}
});
if (!process.env.PWTEST_BLOB_DO_NOT_REMOVE) await (0, _utils.removeFolders)([outputDir]);
await _fs.default.promises.mkdir(_path.default.dirname(outputFile), {
recursive: true
});
return outputFile;
}
_defaultReportName(config) {
let reportName = 'report';
if (this._options._commandHash) reportName += '-' + (0, _utils.sanitizeForFilePath)(this._options._commandHash);
if (config.shard) {
const paddedNumber = `${config.shard.current}`.padStart(`${config.shard.total}`.length, '0');
reportName = `${reportName}-${paddedNumber}`;
}
return `${reportName}.zip`;
}
_serializeAttachments(attachments) {
return super._serializeAttachments(attachments).map(attachment => {
if (!attachment.path) return attachment;
// Add run guid to avoid clashes between shards.
const sha1 = (0, _utils.calculateSha1)(attachment.path + this._salt);
const extension = _utilsBundle.mime.getExtension(attachment.contentType) || 'dat';
const newPath = `resources/${sha1}.${extension}`;
this._attachments.push({
originalPath: attachment.path,
zipEntryPath: newPath
});
return {
...attachment,
path: newPath
};
});
}
}
exports.BlobReporter = BlobReporter;

79
node_modules/playwright/lib/reporters/dot.js generated vendored Normal file
View File

@@ -0,0 +1,79 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _base = require("./base");
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class DotReporter extends _base.BaseReporter {
constructor(...args) {
super(...args);
this._counter = 0;
}
onBegin(suite) {
super.onBegin(suite);
console.log(this.generateStartingMessage());
}
onStdOut(chunk, test, result) {
super.onStdOut(chunk, test, result);
if (!this.config.quiet) process.stdout.write(chunk);
}
onStdErr(chunk, test, result) {
super.onStdErr(chunk, test, result);
if (!this.config.quiet) process.stderr.write(chunk);
}
onTestEnd(test, result) {
super.onTestEnd(test, result);
if (this._counter === 80) {
process.stdout.write('\n');
this._counter = 0;
}
++this._counter;
if (result.status === 'skipped') {
process.stdout.write(_base.colors.yellow('°'));
return;
}
if (this.willRetry(test)) {
process.stdout.write(_base.colors.gray('×'));
return;
}
switch (test.outcome()) {
case 'expected':
process.stdout.write(_base.colors.green('·'));
break;
case 'unexpected':
process.stdout.write(_base.colors.red(result.status === 'timedOut' ? 'T' : 'F'));
break;
case 'flaky':
process.stdout.write(_base.colors.yellow('±'));
break;
}
}
onError(error) {
super.onError(error);
console.log('\n' + (0, _base.formatError)(error, _base.colors.enabled).message);
this._counter = 0;
}
async onEnd(result) {
await super.onEnd(result);
process.stdout.write('\n');
this.epilogue(true);
}
}
var _default = exports.default = DotReporter;

31
node_modules/playwright/lib/reporters/empty.js generated vendored Normal file
View File

@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class EmptyReporter {
version() {
return 'v2';
}
printsToStdio() {
return false;
}
}
var _default = exports.default = EmptyReporter;

115
node_modules/playwright/lib/reporters/github.js generated vendored Normal file
View File

@@ -0,0 +1,115 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.GitHubReporter = void 0;
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _path = _interopRequireDefault(require("path"));
var _base = require("./base");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class GitHubLogger {
_log(message, type = 'notice', options = {}) {
message = message.replace(/\n/g, '%0A');
const configs = Object.entries(options).map(([key, option]) => `${key}=${option}`).join(',');
console.log((0, _base.stripAnsiEscapes)(`::${type} ${configs}::${message}`));
}
debug(message, options) {
this._log(message, 'debug', options);
}
error(message, options) {
this._log(message, 'error', options);
}
notice(message, options) {
this._log(message, 'notice', options);
}
warning(message, options) {
this._log(message, 'warning', options);
}
}
class GitHubReporter extends _base.BaseReporter {
constructor(...args) {
super(...args);
this.githubLogger = new GitHubLogger();
}
printsToStdio() {
return false;
}
async onEnd(result) {
await super.onEnd(result);
this._printAnnotations();
}
onError(error) {
const errorMessage = (0, _base.formatError)(error, false).message;
this.githubLogger.error(errorMessage);
}
_printAnnotations() {
const summary = this.generateSummary();
const summaryMessage = this.generateSummaryMessage(summary);
if (summary.failuresToPrint.length) this._printFailureAnnotations(summary.failuresToPrint);
this._printSlowTestAnnotations();
this._printSummaryAnnotation(summaryMessage);
}
_printSlowTestAnnotations() {
this.getSlowTests().forEach(([file, duration]) => {
const filePath = workspaceRelativePath(_path.default.join(process.cwd(), file));
this.githubLogger.warning(`${filePath} took ${(0, _utilsBundle.ms)(duration)}`, {
title: 'Slow Test',
file: filePath
});
});
}
_printSummaryAnnotation(summary) {
this.githubLogger.notice(summary, {
title: '🎭 Playwright Run Summary'
});
}
_printFailureAnnotations(failures) {
failures.forEach((test, index) => {
const title = (0, _base.formatTestTitle)(this.config, test);
const header = (0, _base.formatTestHeader)(this.config, test, {
indent: ' ',
index: index + 1,
mode: 'error'
});
for (const result of test.results) {
const errors = (0, _base.formatResultFailure)(test, result, ' ', _base.colors.enabled);
for (const error of errors) {
var _error$location;
const options = {
file: workspaceRelativePath(((_error$location = error.location) === null || _error$location === void 0 ? void 0 : _error$location.file) || test.location.file),
title
};
if (error.location) {
options.line = error.location.line;
options.col = error.location.column;
}
const message = [header, ...(0, _base.formatRetry)(result), error.message].join('\n');
this.githubLogger.error(message, options);
}
}
});
}
}
exports.GitHubReporter = GitHubReporter;
function workspaceRelativePath(filePath) {
var _process$env$GITHUB_W;
return _path.default.relative((_process$env$GITHUB_W = process.env['GITHUB_WORKSPACE']) !== null && _process$env$GITHUB_W !== void 0 ? _process$env$GITHUB_W : '', filePath);
}
var _default = exports.default = GitHubReporter;

645
node_modules/playwright/lib/reporters/html.js generated vendored Normal file
View File

@@ -0,0 +1,645 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.showHTMLReport = showHTMLReport;
exports.startHtmlReportServer = startHtmlReportServer;
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _utils = require("playwright-core/lib/utils");
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _stream = require("stream");
var _babelBundle = require("../transform/babelBundle");
var _base = require("./base");
var _util = require("../util");
var _zipBundle = require("playwright-core/lib/zipBundle");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const htmlReportOptions = ['always', 'never', 'on-failure'];
const isHtmlReportOption = type => {
return htmlReportOptions.includes(type);
};
class HtmlReporter {
constructor(options) {
this.config = void 0;
this.suite = void 0;
this._options = void 0;
this._outputFolder = void 0;
this._attachmentsBaseURL = void 0;
this._open = void 0;
this._port = void 0;
this._host = void 0;
this._buildResult = void 0;
this._topLevelErrors = [];
this._options = options;
}
version() {
return 'v2';
}
printsToStdio() {
return false;
}
onConfigure(config) {
this.config = config;
}
onBegin(suite) {
const {
outputFolder,
open,
attachmentsBaseURL,
host,
port
} = this._resolveOptions();
this._outputFolder = outputFolder;
this._open = open;
this._host = host;
this._port = port;
this._attachmentsBaseURL = attachmentsBaseURL;
const reportedWarnings = new Set();
for (const project of this.config.projects) {
if (this._isSubdirectory(outputFolder, project.outputDir) || this._isSubdirectory(project.outputDir, outputFolder)) {
const key = outputFolder + '|' + project.outputDir;
if (reportedWarnings.has(key)) continue;
reportedWarnings.add(key);
console.log(_base.colors.red(`Configuration Error: HTML reporter output folder clashes with the tests output folder:`));
console.log(`
html reporter folder: ${_base.colors.bold(outputFolder)}
test results folder: ${_base.colors.bold(project.outputDir)}`);
console.log('');
console.log(`HTML reporter will clear its output directory prior to being generated, which will lead to the artifact loss.
`);
}
}
this.suite = suite;
}
_resolveOptions() {
var _reportFolderFromEnv;
const outputFolder = (_reportFolderFromEnv = reportFolderFromEnv()) !== null && _reportFolderFromEnv !== void 0 ? _reportFolderFromEnv : (0, _util.resolveReporterOutputPath)('playwright-report', this._options.configDir, this._options.outputFolder);
return {
outputFolder,
open: getHtmlReportOptionProcessEnv() || this._options.open || 'on-failure',
attachmentsBaseURL: process.env.PLAYWRIGHT_HTML_ATTACHMENTS_BASE_URL || this._options.attachmentsBaseURL || 'data/',
host: process.env.PLAYWRIGHT_HTML_HOST || this._options.host,
port: process.env.PLAYWRIGHT_HTML_PORT ? +process.env.PLAYWRIGHT_HTML_PORT : this._options.port
};
}
_isSubdirectory(parentDir, dir) {
const relativePath = _path.default.relative(parentDir, dir);
return !!relativePath && !relativePath.startsWith('..') && !_path.default.isAbsolute(relativePath);
}
onError(error) {
this._topLevelErrors.push(error);
}
async onEnd(result) {
const projectSuites = this.suite.suites;
await (0, _utils.removeFolders)([this._outputFolder]);
const builder = new HtmlBuilder(this.config, this._outputFolder, this._attachmentsBaseURL);
this._buildResult = await builder.build(this.config.metadata, projectSuites, result, this._topLevelErrors);
}
async onExit() {
if (process.env.CI || !this._buildResult) return;
const {
ok,
singleTestId
} = this._buildResult;
const shouldOpen = !this._options._isTestServer && (this._open === 'always' || !ok && this._open === 'on-failure');
if (shouldOpen) {
await showHTMLReport(this._outputFolder, this._host, this._port, singleTestId);
} else if (this._options._mode === 'test' && !this._options._isTestServer) {
const packageManagerCommand = (0, _utils.getPackageManagerExecCommand)();
const relativeReportPath = this._outputFolder === standaloneDefaultFolder() ? '' : ' ' + _path.default.relative(process.cwd(), this._outputFolder);
const hostArg = this._host ? ` --host ${this._host}` : '';
const portArg = this._port ? ` --port ${this._port}` : '';
console.log('');
console.log('To open last HTML report run:');
console.log(_base.colors.cyan(`
${packageManagerCommand} playwright show-report${relativeReportPath}${hostArg}${portArg}
`));
}
}
}
function reportFolderFromEnv() {
// Note: PLAYWRIGHT_HTML_REPORT is for backwards compatibility.
const envValue = process.env.PLAYWRIGHT_HTML_OUTPUT_DIR || process.env.PLAYWRIGHT_HTML_REPORT;
return envValue ? _path.default.resolve(envValue) : undefined;
}
function getHtmlReportOptionProcessEnv() {
// Note: PW_TEST_HTML_REPORT_OPEN is for backwards compatibility.
const htmlOpenEnv = process.env.PLAYWRIGHT_HTML_OPEN || process.env.PW_TEST_HTML_REPORT_OPEN;
if (!htmlOpenEnv) return undefined;
if (!isHtmlReportOption(htmlOpenEnv)) {
console.log(_base.colors.red(`Configuration Error: HTML reporter Invalid value for PLAYWRIGHT_HTML_OPEN: ${htmlOpenEnv}. Valid values are: ${htmlReportOptions.join(', ')}`));
return undefined;
}
return htmlOpenEnv;
}
function standaloneDefaultFolder() {
var _reportFolderFromEnv2;
return (_reportFolderFromEnv2 = reportFolderFromEnv()) !== null && _reportFolderFromEnv2 !== void 0 ? _reportFolderFromEnv2 : (0, _util.resolveReporterOutputPath)('playwright-report', process.cwd(), undefined);
}
async function showHTMLReport(reportFolder, host = 'localhost', port, testId) {
const folder = reportFolder !== null && reportFolder !== void 0 ? reportFolder : standaloneDefaultFolder();
try {
(0, _utils.assert)(_fs.default.statSync(folder).isDirectory());
} catch (e) {
console.log(_base.colors.red(`No report found at "${folder}"`));
(0, _utils.gracefullyProcessExitDoNotHang)(1);
return;
}
const server = startHtmlReportServer(folder);
await server.start({
port,
host,
preferredPort: port ? undefined : 9323
});
let url = server.urlPrefix('human-readable');
console.log('');
console.log(_base.colors.cyan(` Serving HTML report at ${url}. Press Ctrl+C to quit.`));
if (testId) url += `#?testId=${testId}`;
url = url.replace('0.0.0.0', 'localhost');
await (0, _utilsBundle.open)(url, {
wait: true
}).catch(() => {});
await new Promise(() => {});
}
function startHtmlReportServer(folder) {
const server = new _utils.HttpServer();
server.routePrefix('/', (request, response) => {
let relativePath = new URL('http://localhost' + request.url).pathname;
if (relativePath.startsWith('/trace/file')) {
const url = new URL('http://localhost' + request.url);
try {
return server.serveFile(request, response, url.searchParams.get('path'));
} catch (e) {
return false;
}
}
if (relativePath.endsWith('/stall.js')) return true;
if (relativePath === '/') relativePath = '/index.html';
const absolutePath = _path.default.join(folder, ...relativePath.split('/'));
return server.serveFile(request, response, absolutePath);
});
return server;
}
class HtmlBuilder {
constructor(config, outputDir, attachmentsBaseURL) {
this._config = void 0;
this._reportFolder = void 0;
this._stepsInFile = new _utils.MultiMap();
this._dataZipFile = void 0;
this._hasTraces = false;
this._attachmentsBaseURL = void 0;
this._config = config;
this._reportFolder = outputDir;
_fs.default.mkdirSync(this._reportFolder, {
recursive: true
});
this._dataZipFile = new _zipBundle.yazl.ZipFile();
this._attachmentsBaseURL = attachmentsBaseURL;
}
async build(metadata, projectSuites, result, topLevelErrors) {
const data = new Map();
for (const projectSuite of projectSuites) {
const testDir = projectSuite.project().testDir;
for (const fileSuite of projectSuite.suites) {
const fileName = this._relativeLocation(fileSuite.location).file;
// Preserve file ids computed off the testDir.
const relativeFile = _path.default.relative(testDir, fileSuite.location.file);
const fileId = (0, _utils.calculateSha1)((0, _utils.toPosixPath)(relativeFile)).slice(0, 20);
let fileEntry = data.get(fileId);
if (!fileEntry) {
fileEntry = {
testFile: {
fileId,
fileName,
tests: []
},
testFileSummary: {
fileId,
fileName,
tests: [],
stats: emptyStats()
}
};
data.set(fileId, fileEntry);
}
const {
testFile,
testFileSummary
} = fileEntry;
const testEntries = [];
this._processSuite(fileSuite, projectSuite.project().name, [], testEntries);
for (const test of testEntries) {
testFile.tests.push(test.testCase);
testFileSummary.tests.push(test.testCaseSummary);
}
}
}
createSnippets(this._stepsInFile);
let ok = true;
for (const [fileId, {
testFile,
testFileSummary
}] of data) {
const stats = testFileSummary.stats;
for (const test of testFileSummary.tests) {
if (test.outcome === 'expected') ++stats.expected;
if (test.outcome === 'skipped') ++stats.skipped;
if (test.outcome === 'unexpected') ++stats.unexpected;
if (test.outcome === 'flaky') ++stats.flaky;
++stats.total;
}
stats.ok = stats.unexpected + stats.flaky === 0;
if (!stats.ok) ok = false;
const testCaseSummaryComparator = (t1, t2) => {
const w1 = (t1.outcome === 'unexpected' ? 1000 : 0) + (t1.outcome === 'flaky' ? 1 : 0);
const w2 = (t2.outcome === 'unexpected' ? 1000 : 0) + (t2.outcome === 'flaky' ? 1 : 0);
return w2 - w1;
};
testFileSummary.tests.sort(testCaseSummaryComparator);
this._addDataFile(fileId + '.json', testFile);
}
const htmlReport = {
metadata,
startTime: result.startTime.getTime(),
duration: result.duration,
files: [...data.values()].map(e => e.testFileSummary),
projectNames: projectSuites.map(r => r.project().name),
stats: {
...[...data.values()].reduce((a, e) => addStats(a, e.testFileSummary.stats), emptyStats())
},
errors: topLevelErrors.map(error => (0, _base.formatError)(error, true).message)
};
htmlReport.files.sort((f1, f2) => {
const w1 = f1.stats.unexpected * 1000 + f1.stats.flaky;
const w2 = f2.stats.unexpected * 1000 + f2.stats.flaky;
return w2 - w1;
});
this._addDataFile('report.json', htmlReport);
let singleTestId;
if (htmlReport.stats.total === 1) {
const testFile = data.values().next().value.testFile;
singleTestId = testFile.tests[0].testId;
}
if (process.env.PW_HMR === '1') {
const redirectFile = _path.default.join(this._reportFolder, 'index.html');
await this._writeReportData(redirectFile);
async function redirect() {
const hmrURL = new URL('http://localhost:44224'); // dev server, port is harcoded in build.js
const popup = window.open(hmrURL);
window.addEventListener('message', evt => {
if (evt.source === popup && evt.data === 'ready') {
popup.postMessage(window.playwrightReportBase64, hmrURL.origin);
window.close();
}
}, {
once: true
});
}
_fs.default.appendFileSync(redirectFile, `<script>(${redirect.toString()})()</script>`);
return {
ok,
singleTestId
};
}
// Copy app.
const appFolder = _path.default.join(require.resolve('playwright-core'), '..', 'lib', 'vite', 'htmlReport');
await (0, _utils.copyFileAndMakeWritable)(_path.default.join(appFolder, 'index.html'), _path.default.join(this._reportFolder, 'index.html'));
// Copy trace viewer.
if (this._hasTraces) {
const traceViewerFolder = _path.default.join(require.resolve('playwright-core'), '..', 'lib', 'vite', 'traceViewer');
const traceViewerTargetFolder = _path.default.join(this._reportFolder, 'trace');
const traceViewerAssetsTargetFolder = _path.default.join(traceViewerTargetFolder, 'assets');
_fs.default.mkdirSync(traceViewerAssetsTargetFolder, {
recursive: true
});
for (const file of _fs.default.readdirSync(traceViewerFolder)) {
if (file.endsWith('.map') || file.includes('watch') || file.includes('assets')) continue;
await (0, _utils.copyFileAndMakeWritable)(_path.default.join(traceViewerFolder, file), _path.default.join(traceViewerTargetFolder, file));
}
for (const file of _fs.default.readdirSync(_path.default.join(traceViewerFolder, 'assets'))) {
if (file.endsWith('.map') || file.includes('xtermModule')) continue;
await (0, _utils.copyFileAndMakeWritable)(_path.default.join(traceViewerFolder, 'assets', file), _path.default.join(traceViewerAssetsTargetFolder, file));
}
}
await this._writeReportData(_path.default.join(this._reportFolder, 'index.html'));
return {
ok,
singleTestId
};
}
async _writeReportData(filePath) {
_fs.default.appendFileSync(filePath, '<script>\nwindow.playwrightReportBase64 = "data:application/zip;base64,');
await new Promise(f => {
this._dataZipFile.end(undefined, () => {
this._dataZipFile.outputStream.pipe(new Base64Encoder()).pipe(_fs.default.createWriteStream(filePath, {
flags: 'a'
})).on('close', f);
});
});
_fs.default.appendFileSync(filePath, '";</script>');
}
_addDataFile(fileName, data) {
this._dataZipFile.addBuffer(Buffer.from(JSON.stringify(data)), fileName);
}
_processSuite(suite, projectName, path, outTests) {
const newPath = [...path, suite.title];
suite.entries().forEach(e => {
if (e.type === 'test') outTests.push(this._createTestEntry(e, projectName, newPath));else this._processSuite(e, projectName, newPath, outTests);
});
}
_createTestEntry(test, projectName, path) {
const duration = test.results.reduce((a, r) => a + r.duration, 0);
const location = this._relativeLocation(test.location);
path = path.slice(1).filter(path => path.length > 0);
const results = test.results.map(r => this._createTestResult(test, r));
return {
testCase: {
testId: test.id,
title: test.title,
projectName,
location,
duration,
// Annotations can be pushed directly, with a wrong type.
annotations: test.annotations.map(a => ({
type: a.type,
description: a.description ? String(a.description) : a.description
})),
tags: test.tags,
outcome: test.outcome(),
path,
results,
ok: test.outcome() === 'expected' || test.outcome() === 'flaky'
},
testCaseSummary: {
testId: test.id,
title: test.title,
projectName,
location,
duration,
// Annotations can be pushed directly, with a wrong type.
annotations: test.annotations.map(a => ({
type: a.type,
description: a.description ? String(a.description) : a.description
})),
tags: test.tags,
outcome: test.outcome(),
path,
ok: test.outcome() === 'expected' || test.outcome() === 'flaky',
results: results.map(result => {
return {
attachments: result.attachments.map(a => ({
name: a.name,
contentType: a.contentType,
path: a.path
}))
};
})
}
};
}
_serializeAttachments(attachments) {
let lastAttachment;
return attachments.map(a => {
if (a.name === 'trace') this._hasTraces = true;
if ((a.name === 'stdout' || a.name === 'stderr') && a.contentType === 'text/plain') {
if (lastAttachment && lastAttachment.name === a.name && lastAttachment.contentType === a.contentType) {
lastAttachment.body += (0, _base.stripAnsiEscapes)(a.body);
return null;
}
a.body = (0, _base.stripAnsiEscapes)(a.body);
lastAttachment = a;
return a;
}
if (a.path) {
let fileName = a.path;
try {
const buffer = _fs.default.readFileSync(a.path);
const sha1 = (0, _utils.calculateSha1)(buffer) + _path.default.extname(a.path);
fileName = this._attachmentsBaseURL + sha1;
_fs.default.mkdirSync(_path.default.join(this._reportFolder, 'data'), {
recursive: true
});
_fs.default.writeFileSync(_path.default.join(this._reportFolder, 'data', sha1), buffer);
} catch (e) {}
return {
name: a.name,
contentType: a.contentType,
path: fileName,
body: a.body
};
}
if (a.body instanceof Buffer) {
if (isTextContentType(a.contentType)) {
var _a$contentType$match;
// Content type is like this: "text/html; charset=UTF-8"
const charset = (_a$contentType$match = a.contentType.match(/charset=(.*)/)) === null || _a$contentType$match === void 0 ? void 0 : _a$contentType$match[1];
try {
const body = a.body.toString(charset || 'utf-8');
return {
name: a.name,
contentType: a.contentType,
body
};
} catch (e) {
// Invalid encoding, fall through and save to file.
}
}
_fs.default.mkdirSync(_path.default.join(this._reportFolder, 'data'), {
recursive: true
});
const extension = (0, _utils.sanitizeForFilePath)(_path.default.extname(a.name).replace(/^\./, '')) || _utilsBundle.mime.getExtension(a.contentType) || 'dat';
const sha1 = (0, _utils.calculateSha1)(a.body) + '.' + extension;
_fs.default.writeFileSync(_path.default.join(this._reportFolder, 'data', sha1), a.body);
return {
name: a.name,
contentType: a.contentType,
path: this._attachmentsBaseURL + sha1
};
}
// string
return {
name: a.name,
contentType: a.contentType,
body: a.body
};
}).filter(Boolean);
}
_createTestResult(test, result) {
return {
duration: result.duration,
startTime: result.startTime.toISOString(),
retry: result.retry,
steps: dedupeSteps(result.steps).map(s => this._createTestStep(s)),
errors: (0, _base.formatResultFailure)(test, result, '', true).map(error => error.message),
status: result.status,
attachments: this._serializeAttachments([...result.attachments, ...result.stdout.map(m => stdioAttachment(m, 'stdout')), ...result.stderr.map(m => stdioAttachment(m, 'stderr'))])
};
}
_createTestStep(dedupedStep) {
var _step$error;
const {
step,
duration,
count
} = dedupedStep;
const result = {
title: step.title,
startTime: step.startTime.toISOString(),
duration,
steps: dedupeSteps(step.steps).map(s => this._createTestStep(s)),
location: this._relativeLocation(step.location),
error: (_step$error = step.error) === null || _step$error === void 0 ? void 0 : _step$error.message,
count
};
if (step.location) this._stepsInFile.set(step.location.file, result);
return result;
}
_relativeLocation(location) {
if (!location) return undefined;
const file = (0, _utils.toPosixPath)(_path.default.relative(this._config.rootDir, location.file));
return {
file,
line: location.line,
column: location.column
};
}
}
const emptyStats = () => {
return {
total: 0,
expected: 0,
unexpected: 0,
flaky: 0,
skipped: 0,
ok: true
};
};
const addStats = (stats, delta) => {
stats.total += delta.total;
stats.skipped += delta.skipped;
stats.expected += delta.expected;
stats.unexpected += delta.unexpected;
stats.flaky += delta.flaky;
stats.ok = stats.ok && delta.ok;
return stats;
};
class Base64Encoder extends _stream.Transform {
constructor(...args) {
super(...args);
this._remainder = void 0;
}
_transform(chunk, encoding, callback) {
if (this._remainder) {
chunk = Buffer.concat([this._remainder, chunk]);
this._remainder = undefined;
}
const remaining = chunk.length % 3;
if (remaining) {
this._remainder = chunk.slice(chunk.length - remaining);
chunk = chunk.slice(0, chunk.length - remaining);
}
chunk = chunk.toString('base64');
this.push(Buffer.from(chunk));
callback();
}
_flush(callback) {
if (this._remainder) this.push(Buffer.from(this._remainder.toString('base64')));
callback();
}
}
function isTextContentType(contentType) {
return contentType.startsWith('text/') || contentType.startsWith('application/json');
}
function stdioAttachment(chunk, type) {
if (typeof chunk === 'string') {
return {
name: type,
contentType: 'text/plain',
body: chunk
};
}
return {
name: type,
contentType: 'application/octet-stream',
body: chunk
};
}
function dedupeSteps(steps) {
const result = [];
let lastResult = undefined;
for (const step of steps) {
var _step$location, _lastResult, _step$location2, _lastStep$location, _step$location3, _lastStep$location2, _step$location4, _lastStep$location3;
const canDedupe = !step.error && step.duration >= 0 && ((_step$location = step.location) === null || _step$location === void 0 ? void 0 : _step$location.file) && !step.steps.length;
const lastStep = (_lastResult = lastResult) === null || _lastResult === void 0 ? void 0 : _lastResult.step;
if (canDedupe && lastResult && lastStep && step.category === lastStep.category && step.title === lastStep.title && ((_step$location2 = step.location) === null || _step$location2 === void 0 ? void 0 : _step$location2.file) === ((_lastStep$location = lastStep.location) === null || _lastStep$location === void 0 ? void 0 : _lastStep$location.file) && ((_step$location3 = step.location) === null || _step$location3 === void 0 ? void 0 : _step$location3.line) === ((_lastStep$location2 = lastStep.location) === null || _lastStep$location2 === void 0 ? void 0 : _lastStep$location2.line) && ((_step$location4 = step.location) === null || _step$location4 === void 0 ? void 0 : _step$location4.column) === ((_lastStep$location3 = lastStep.location) === null || _lastStep$location3 === void 0 ? void 0 : _lastStep$location3.column)) {
++lastResult.count;
lastResult.duration += step.duration;
continue;
}
lastResult = {
step,
count: 1,
duration: step.duration
};
result.push(lastResult);
if (!canDedupe) lastResult = undefined;
}
return result;
}
function createSnippets(stepsInFile) {
for (const file of stepsInFile.keys()) {
let source;
try {
source = _fs.default.readFileSync(file, 'utf-8') + '\n//';
} catch (e) {
continue;
}
const lines = source.split('\n').length;
const highlighted = (0, _babelBundle.codeFrameColumns)(source, {
start: {
line: lines,
column: 1
}
}, {
highlightCode: true,
linesAbove: lines,
linesBelow: 0
});
const highlightedLines = highlighted.split('\n');
const lineWithArrow = highlightedLines[highlightedLines.length - 1];
for (const step of stepsInFile.get(file)) {
// Don't bother with snippets that have less than 3 lines.
if (step.location.line < 2 || step.location.line >= lines) continue;
// Cut out snippet.
const snippetLines = highlightedLines.slice(step.location.line - 2, step.location.line + 1);
// Relocate arrow.
const index = lineWithArrow.indexOf('^');
const shiftedArrow = lineWithArrow.slice(0, index) + ' '.repeat(step.location.column - 1) + lineWithArrow.slice(index);
// Insert arrow line.
snippetLines.splice(2, 0, shiftedArrow);
step.snippet = snippetLines.join('\n');
}
}
}
var _default = exports.default = HtmlReporter;

View File

@@ -0,0 +1,134 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.InternalReporter = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _babelBundle = require("../transform/babelBundle");
var _test = require("../common/test");
var _base = require("./base");
var _utils = require("playwright-core/lib/utils");
var _multiplexer = require("./multiplexer");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class InternalReporter {
constructor(reporters) {
this._reporter = void 0;
this._didBegin = false;
this._config = void 0;
this._startTime = void 0;
this._monotonicStartTime = void 0;
this._reporter = new _multiplexer.Multiplexer(reporters);
}
version() {
return 'v2';
}
onConfigure(config) {
var _this$_reporter$onCon, _this$_reporter;
this._config = config;
this._startTime = new Date();
this._monotonicStartTime = (0, _utils.monotonicTime)();
(_this$_reporter$onCon = (_this$_reporter = this._reporter).onConfigure) === null || _this$_reporter$onCon === void 0 || _this$_reporter$onCon.call(_this$_reporter, config);
}
onBegin(suite) {
var _this$_reporter$onBeg, _this$_reporter2;
this._didBegin = true;
(_this$_reporter$onBeg = (_this$_reporter2 = this._reporter).onBegin) === null || _this$_reporter$onBeg === void 0 || _this$_reporter$onBeg.call(_this$_reporter2, suite);
}
onTestBegin(test, result) {
var _this$_reporter$onTes, _this$_reporter3;
(_this$_reporter$onTes = (_this$_reporter3 = this._reporter).onTestBegin) === null || _this$_reporter$onTes === void 0 || _this$_reporter$onTes.call(_this$_reporter3, test, result);
}
onStdOut(chunk, test, result) {
var _this$_reporter$onStd, _this$_reporter4;
(_this$_reporter$onStd = (_this$_reporter4 = this._reporter).onStdOut) === null || _this$_reporter$onStd === void 0 || _this$_reporter$onStd.call(_this$_reporter4, chunk, test, result);
}
onStdErr(chunk, test, result) {
var _this$_reporter$onStd2, _this$_reporter5;
(_this$_reporter$onStd2 = (_this$_reporter5 = this._reporter).onStdErr) === null || _this$_reporter$onStd2 === void 0 || _this$_reporter$onStd2.call(_this$_reporter5, chunk, test, result);
}
onTestEnd(test, result) {
var _this$_reporter$onTes2, _this$_reporter6;
this._addSnippetToTestErrors(test, result);
(_this$_reporter$onTes2 = (_this$_reporter6 = this._reporter).onTestEnd) === null || _this$_reporter$onTes2 === void 0 || _this$_reporter$onTes2.call(_this$_reporter6, test, result);
}
async onEnd(result) {
var _this$_reporter$onEnd, _this$_reporter7;
if (!this._didBegin) {
// onBegin was not reported, emit it.
this.onBegin(new _test.Suite('', 'root'));
}
return await ((_this$_reporter$onEnd = (_this$_reporter7 = this._reporter).onEnd) === null || _this$_reporter$onEnd === void 0 ? void 0 : _this$_reporter$onEnd.call(_this$_reporter7, {
...result,
startTime: this._startTime,
duration: (0, _utils.monotonicTime)() - this._monotonicStartTime
}));
}
async onExit() {
var _this$_reporter$onExi, _this$_reporter8;
await ((_this$_reporter$onExi = (_this$_reporter8 = this._reporter).onExit) === null || _this$_reporter$onExi === void 0 ? void 0 : _this$_reporter$onExi.call(_this$_reporter8));
}
onError(error) {
var _this$_reporter$onErr, _this$_reporter9;
addLocationAndSnippetToError(this._config, error);
(_this$_reporter$onErr = (_this$_reporter9 = this._reporter).onError) === null || _this$_reporter$onErr === void 0 || _this$_reporter$onErr.call(_this$_reporter9, error);
}
onStepBegin(test, result, step) {
var _this$_reporter$onSte, _this$_reporter10;
(_this$_reporter$onSte = (_this$_reporter10 = this._reporter).onStepBegin) === null || _this$_reporter$onSte === void 0 || _this$_reporter$onSte.call(_this$_reporter10, test, result, step);
}
onStepEnd(test, result, step) {
var _this$_reporter$onSte2, _this$_reporter11;
this._addSnippetToStepError(test, step);
(_this$_reporter$onSte2 = (_this$_reporter11 = this._reporter).onStepEnd) === null || _this$_reporter$onSte2 === void 0 || _this$_reporter$onSte2.call(_this$_reporter11, test, result, step);
}
printsToStdio() {
return this._reporter.printsToStdio ? this._reporter.printsToStdio() : true;
}
_addSnippetToTestErrors(test, result) {
for (const error of result.errors) addLocationAndSnippetToError(this._config, error, test.location.file);
}
_addSnippetToStepError(test, step) {
if (step.error) addLocationAndSnippetToError(this._config, step.error, test.location.file);
}
}
exports.InternalReporter = InternalReporter;
function addLocationAndSnippetToError(config, error, file) {
if (error.stack && !error.location) error.location = (0, _base.prepareErrorStack)(error.stack).location;
const location = error.location;
if (!location) return;
try {
const tokens = [];
const source = _fs.default.readFileSync(location.file, 'utf8');
const codeFrame = (0, _babelBundle.codeFrameColumns)(source, {
start: location
}, {
highlightCode: true
});
// Convert /var/folders to /private/var/folders on Mac.
if (!file || _fs.default.realpathSync(file) !== location.file) {
tokens.push(_base.colors.gray(` at `) + `${(0, _base.relativeFilePath)(config, location.file)}:${location.line}`);
tokens.push('');
}
tokens.push(codeFrame);
error.snippet = tokens.join('\n');
} catch (e) {
// Failed to read the source file - that's ok.
}
}

244
node_modules/playwright/lib/reporters/json.js generated vendored Normal file
View File

@@ -0,0 +1,244 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.serializePatterns = serializePatterns;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _base = require("./base");
var _utils = require("playwright-core/lib/utils");
var _config = require("../common/config");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class JSONReporter {
constructor(options) {
var _resolveOutputFile;
this.config = void 0;
this.suite = void 0;
this._errors = [];
this._resolvedOutputFile = void 0;
this._resolvedOutputFile = (_resolveOutputFile = (0, _base.resolveOutputFile)('JSON', options)) === null || _resolveOutputFile === void 0 ? void 0 : _resolveOutputFile.outputFile;
}
version() {
return 'v2';
}
printsToStdio() {
return !this._resolvedOutputFile;
}
onConfigure(config) {
this.config = config;
}
onBegin(suite) {
this.suite = suite;
}
onError(error) {
this._errors.push(error);
}
async onEnd(result) {
await outputReport(this._serializeReport(result), this._resolvedOutputFile);
}
_serializeReport(result) {
const report = {
config: {
...removePrivateFields(this.config),
rootDir: (0, _utils.toPosixPath)(this.config.rootDir),
projects: this.config.projects.map(project => {
return {
outputDir: (0, _utils.toPosixPath)(project.outputDir),
repeatEach: project.repeatEach,
retries: project.retries,
metadata: project.metadata,
id: (0, _config.getProjectId)(project),
name: project.name,
testDir: (0, _utils.toPosixPath)(project.testDir),
testIgnore: serializePatterns(project.testIgnore),
testMatch: serializePatterns(project.testMatch),
timeout: project.timeout
};
})
},
suites: this._mergeSuites(this.suite.suites),
errors: this._errors,
stats: {
startTime: result.startTime.toISOString(),
duration: result.duration,
expected: 0,
skipped: 0,
unexpected: 0,
flaky: 0
}
};
for (const test of this.suite.allTests()) ++report.stats[test.outcome()];
return report;
}
_mergeSuites(suites) {
const fileSuites = new _utils.MultiMap();
for (const projectSuite of suites) {
const projectId = (0, _config.getProjectId)(projectSuite.project());
const projectName = projectSuite.project().name;
for (const fileSuite of projectSuite.suites) {
const file = fileSuite.location.file;
const serialized = this._serializeSuite(projectId, projectName, fileSuite);
if (serialized) fileSuites.set(file, serialized);
}
}
const results = [];
for (const [, suites] of fileSuites) {
const result = {
title: suites[0].title,
file: suites[0].file,
column: 0,
line: 0,
specs: []
};
for (const suite of suites) this._mergeTestsFromSuite(result, suite);
results.push(result);
}
return results;
}
_relativeLocation(location) {
if (!location) return {
file: '',
line: 0,
column: 0
};
return {
file: (0, _utils.toPosixPath)(_path.default.relative(this.config.rootDir, location.file)),
line: location.line,
column: location.column
};
}
_locationMatches(s1, s2) {
return s1.file === s2.file && s1.line === s2.line && s1.column === s2.column;
}
_mergeTestsFromSuite(to, from) {
for (const fromSuite of from.suites || []) {
const toSuite = (to.suites || []).find(s => s.title === fromSuite.title && this._locationMatches(s, fromSuite));
if (toSuite) {
this._mergeTestsFromSuite(toSuite, fromSuite);
} else {
if (!to.suites) to.suites = [];
to.suites.push(fromSuite);
}
}
for (const spec of from.specs || []) {
const toSpec = to.specs.find(s => s.title === spec.title && s.file === (0, _utils.toPosixPath)(_path.default.relative(this.config.rootDir, spec.file)) && s.line === spec.line && s.column === spec.column);
if (toSpec) toSpec.tests.push(...spec.tests);else to.specs.push(spec);
}
}
_serializeSuite(projectId, projectName, suite) {
if (!suite.allTests().length) return null;
const suites = suite.suites.map(suite => this._serializeSuite(projectId, projectName, suite)).filter(s => s);
return {
title: suite.title,
...this._relativeLocation(suite.location),
specs: suite.tests.map(test => this._serializeTestSpec(projectId, projectName, test)),
suites: suites.length ? suites : undefined
};
}
_serializeTestSpec(projectId, projectName, test) {
return {
title: test.title,
ok: test.ok(),
tags: test.tags.map(tag => tag.substring(1)),
// Strip '@'.
tests: [this._serializeTest(projectId, projectName, test)],
id: test.id,
...this._relativeLocation(test.location)
};
}
_serializeTest(projectId, projectName, test) {
return {
timeout: test.timeout,
annotations: test.annotations,
expectedStatus: test.expectedStatus,
projectId,
projectName,
results: test.results.map(r => this._serializeTestResult(r, test)),
status: test.outcome()
};
}
_serializeTestResult(result, test) {
var _result$error;
const steps = result.steps.filter(s => s.category === 'test.step');
const jsonResult = {
workerIndex: result.workerIndex,
status: result.status,
duration: result.duration,
error: result.error,
errors: result.errors.map(e => this._serializeError(e)),
stdout: result.stdout.map(s => stdioEntry(s)),
stderr: result.stderr.map(s => stdioEntry(s)),
retry: result.retry,
steps: steps.length ? steps.map(s => this._serializeTestStep(s)) : undefined,
startTime: result.startTime.toISOString(),
attachments: result.attachments.map(a => {
var _a$body;
return {
name: a.name,
contentType: a.contentType,
path: a.path,
body: (_a$body = a.body) === null || _a$body === void 0 ? void 0 : _a$body.toString('base64')
};
})
};
if ((_result$error = result.error) !== null && _result$error !== void 0 && _result$error.stack) jsonResult.errorLocation = (0, _base.prepareErrorStack)(result.error.stack).location;
return jsonResult;
}
_serializeError(error) {
return (0, _base.formatError)(error, true);
}
_serializeTestStep(step) {
const steps = step.steps.filter(s => s.category === 'test.step');
return {
title: step.title,
duration: step.duration,
error: step.error,
steps: steps.length ? steps.map(s => this._serializeTestStep(s)) : undefined
};
}
}
async function outputReport(report, resolvedOutputFile) {
const reportString = JSON.stringify(report, undefined, 2);
if (resolvedOutputFile) {
await _fs.default.promises.mkdir(_path.default.dirname(resolvedOutputFile), {
recursive: true
});
await _fs.default.promises.writeFile(resolvedOutputFile, reportString);
} else {
console.log(reportString);
}
}
function stdioEntry(s) {
if (typeof s === 'string') return {
text: s
};
return {
buffer: s.toString('base64')
};
}
function removePrivateFields(config) {
return Object.fromEntries(Object.entries(config).filter(([name, value]) => !name.startsWith('_')));
}
function serializePatterns(patterns) {
if (!Array.isArray(patterns)) patterns = [patterns];
return patterns.map(s => s.toString());
}
var _default = exports.default = JSONReporter;

234
node_modules/playwright/lib/reporters/junit.js generated vendored Normal file
View File

@@ -0,0 +1,234 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _base = require("./base");
var _utils = require("playwright-core/lib/utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class JUnitReporter {
constructor(options) {
var _resolveOutputFile;
this.config = void 0;
this.configDir = void 0;
this.suite = void 0;
this.timestamp = void 0;
this.totalTests = 0;
this.totalFailures = 0;
this.totalSkipped = 0;
this.resolvedOutputFile = void 0;
this.stripANSIControlSequences = false;
this.includeProjectInTestName = false;
this.stripANSIControlSequences = (0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_JUNIT_STRIP_ANSI', !!options.stripANSIControlSequences);
this.includeProjectInTestName = (0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_JUNIT_INCLUDE_PROJECT_IN_TEST_NAME', !!options.includeProjectInTestName);
this.configDir = options.configDir;
this.resolvedOutputFile = (_resolveOutputFile = (0, _base.resolveOutputFile)('JUNIT', options)) === null || _resolveOutputFile === void 0 ? void 0 : _resolveOutputFile.outputFile;
}
version() {
return 'v2';
}
printsToStdio() {
return !this.resolvedOutputFile;
}
onConfigure(config) {
this.config = config;
}
onBegin(suite) {
this.suite = suite;
this.timestamp = new Date();
}
async onEnd(result) {
const children = [];
for (const projectSuite of this.suite.suites) {
for (const fileSuite of projectSuite.suites) children.push(await this._buildTestSuite(projectSuite.title, fileSuite));
}
const tokens = [];
const self = this;
const root = {
name: 'testsuites',
attributes: {
id: process.env[`PLAYWRIGHT_JUNIT_SUITE_ID`] || '',
name: process.env[`PLAYWRIGHT_JUNIT_SUITE_NAME`] || '',
tests: self.totalTests,
failures: self.totalFailures,
skipped: self.totalSkipped,
errors: 0,
time: result.duration / 1000
},
children
};
serializeXML(root, tokens, this.stripANSIControlSequences);
const reportString = tokens.join('\n');
if (this.resolvedOutputFile) {
await _fs.default.promises.mkdir(_path.default.dirname(this.resolvedOutputFile), {
recursive: true
});
await _fs.default.promises.writeFile(this.resolvedOutputFile, reportString);
} else {
console.log(reportString);
}
}
async _buildTestSuite(projectName, suite) {
let tests = 0;
let skipped = 0;
let failures = 0;
let duration = 0;
const children = [];
const testCaseNamePrefix = projectName && this.includeProjectInTestName ? `[${projectName}] ` : '';
for (const test of suite.allTests()) {
++tests;
if (test.outcome() === 'skipped') ++skipped;
if (!test.ok()) ++failures;
for (const result of test.results) duration += result.duration;
await this._addTestCase(suite.title, testCaseNamePrefix, test, children);
}
this.totalTests += tests;
this.totalSkipped += skipped;
this.totalFailures += failures;
const entry = {
name: 'testsuite',
attributes: {
name: suite.title,
timestamp: this.timestamp.toISOString(),
hostname: projectName,
tests,
failures,
skipped,
time: duration / 1000,
errors: 0
},
children
};
return entry;
}
async _addTestCase(suiteName, namePrefix, test, entries) {
var _properties$children2;
const entry = {
name: 'testcase',
attributes: {
// Skip root, project, file
name: namePrefix + test.titlePath().slice(3).join(' '),
// filename
classname: suiteName,
time: test.results.reduce((acc, value) => acc + value.duration, 0) / 1000
},
children: []
};
entries.push(entry);
// Xray Test Management supports testcase level properties, where additional metadata may be provided
// some annotations are encoded as value attributes, other as cdata content; this implementation supports
// Xray JUnit extensions but it also agnostic, so other tools can also take advantage of this format
const properties = {
name: 'properties',
children: []
};
for (const annotation of test.annotations) {
var _properties$children;
const property = {
name: 'property',
attributes: {
name: annotation.type,
value: annotation !== null && annotation !== void 0 && annotation.description ? annotation.description : ''
}
};
(_properties$children = properties.children) === null || _properties$children === void 0 || _properties$children.push(property);
}
if ((_properties$children2 = properties.children) !== null && _properties$children2 !== void 0 && _properties$children2.length) entry.children.push(properties);
if (test.outcome() === 'skipped') {
entry.children.push({
name: 'skipped'
});
return;
}
if (!test.ok()) {
entry.children.push({
name: 'failure',
attributes: {
message: `${_path.default.basename(test.location.file)}:${test.location.line}:${test.location.column} ${test.title}`,
type: 'FAILURE'
},
text: (0, _base.stripAnsiEscapes)((0, _base.formatFailure)(this.config, test))
});
}
const systemOut = [];
const systemErr = [];
for (const result of test.results) {
systemOut.push(...result.stdout.map(item => item.toString()));
systemErr.push(...result.stderr.map(item => item.toString()));
for (const attachment of result.attachments) {
if (!attachment.path) continue;
let attachmentPath = _path.default.relative(this.configDir, attachment.path);
try {
if (this.resolvedOutputFile) attachmentPath = _path.default.relative(_path.default.dirname(this.resolvedOutputFile), attachment.path);
} catch {
systemOut.push(`\nWarning: Unable to make attachment path ${attachment.path} relative to report output file ${this.resolvedOutputFile}`);
}
try {
await _fs.default.promises.access(attachment.path);
systemOut.push(`\n[[ATTACHMENT|${attachmentPath}]]\n`);
} catch {
systemErr.push(`\nWarning: attachment ${attachmentPath} is missing`);
}
}
}
// Note: it is important to only produce a single system-out/system-err entry
// so that parsers in the wild understand it.
if (systemOut.length) entry.children.push({
name: 'system-out',
text: systemOut.join('')
});
if (systemErr.length) entry.children.push({
name: 'system-err',
text: systemErr.join('')
});
}
}
function serializeXML(entry, tokens, stripANSIControlSequences) {
const attrs = [];
for (const [name, value] of Object.entries(entry.attributes || {})) attrs.push(`${name}="${escape(String(value), stripANSIControlSequences, false)}"`);
tokens.push(`<${entry.name}${attrs.length ? ' ' : ''}${attrs.join(' ')}>`);
for (const child of entry.children || []) serializeXML(child, tokens, stripANSIControlSequences);
if (entry.text) tokens.push(escape(entry.text, stripANSIControlSequences, true));
tokens.push(`</${entry.name}>`);
}
// See https://en.wikipedia.org/wiki/Valid_characters_in_XML
const discouragedXMLCharacters = /[\u0000-\u0008\u000b-\u000c\u000e-\u001f\u007f-\u0084\u0086-\u009f]/g;
function escape(text, stripANSIControlSequences, isCharacterData) {
if (stripANSIControlSequences) text = (0, _base.stripAnsiEscapes)(text);
if (isCharacterData) {
text = '<![CDATA[' + text.replace(/]]>/g, ']]&gt;') + ']]>';
} else {
const escapeRe = /[&"'<>]/g;
text = text.replace(escapeRe, c => ({
'&': '&amp;',
'"': '&quot;',
"'": '&apos;',
'<': '&lt;',
'>': '&gt;'
})[c]);
}
text = text.replace(discouragedXMLCharacters, '');
return text;
}
var _default = exports.default = JUnitReporter;

100
node_modules/playwright/lib/reporters/line.js generated vendored Normal file
View File

@@ -0,0 +1,100 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _base = require("./base");
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class LineReporter extends _base.BaseReporter {
constructor(...args) {
super(...args);
this._current = 0;
this._failures = 0;
this._lastTest = void 0;
this._didBegin = false;
}
onBegin(suite) {
super.onBegin(suite);
const startingMessage = this.generateStartingMessage();
if (startingMessage) {
console.log(startingMessage);
console.log();
}
this._didBegin = true;
}
onStdOut(chunk, test, result) {
super.onStdOut(chunk, test, result);
this._dumpToStdio(test, chunk, process.stdout);
}
onStdErr(chunk, test, result) {
super.onStdErr(chunk, test, result);
this._dumpToStdio(test, chunk, process.stderr);
}
_dumpToStdio(test, chunk, stream) {
if (this.config.quiet) return;
if (!process.env.PW_TEST_DEBUG_REPORTERS) stream.write(`\u001B[1A\u001B[2K`);
if (test && this._lastTest !== test) {
// Write new header for the output.
const title = _base.colors.dim((0, _base.formatTestTitle)(this.config, test));
stream.write(this.fitToScreen(title) + `\n`);
this._lastTest = test;
}
stream.write(chunk);
if (chunk[chunk.length - 1] !== '\n') console.log();
console.log();
}
onTestBegin(test, result) {
++this._current;
this._updateLine(test, result, undefined);
}
onStepBegin(test, result, step) {
if (step.category === 'test.step') this._updateLine(test, result, step);
}
onStepEnd(test, result, step) {
if (step.category === 'test.step') this._updateLine(test, result, step.parent);
}
onTestEnd(test, result) {
super.onTestEnd(test, result);
if (!this.willRetry(test) && (test.outcome() === 'flaky' || test.outcome() === 'unexpected' || result.status === 'interrupted')) {
if (!process.env.PW_TEST_DEBUG_REPORTERS) process.stdout.write(`\u001B[1A\u001B[2K`);
console.log((0, _base.formatFailure)(this.config, test, ++this._failures));
console.log();
}
}
_updateLine(test, result, step) {
const retriesPrefix = this.totalTestCount < this._current ? ` (retries)` : ``;
const prefix = `[${this._current}/${this.totalTestCount}]${retriesPrefix} `;
const currentRetrySuffix = result.retry ? _base.colors.yellow(` (retry #${result.retry})`) : '';
const title = (0, _base.formatTestTitle)(this.config, test, step) + currentRetrySuffix;
if (process.env.PW_TEST_DEBUG_REPORTERS) process.stdout.write(`${prefix + title}\n`);else process.stdout.write(`\u001B[1A\u001B[2K${prefix + this.fitToScreen(title, prefix)}\n`);
}
onError(error) {
super.onError(error);
const message = (0, _base.formatError)(error, _base.colors.enabled).message + '\n';
if (!process.env.PW_TEST_DEBUG_REPORTERS && this._didBegin) process.stdout.write(`\u001B[1A\u001B[2K`);
process.stdout.write(message);
console.log();
}
async onEnd(result) {
if (!process.env.PW_TEST_DEBUG_REPORTERS && this._didBegin) process.stdout.write(`\u001B[1A\u001B[2K`);
await super.onEnd(result);
this.epilogue(false);
}
}
var _default = exports.default = LineReporter;

216
node_modules/playwright/lib/reporters/list.js generated vendored Normal file
View File

@@ -0,0 +1,216 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _base = require("./base");
var _utils = require("playwright-core/lib/utils");
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Allow it in the Visual Studio Code Terminal and the new Windows Terminal
const DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === 'win32' && process.env.TERM_PROGRAM !== 'vscode' && !process.env.WT_SESSION;
const POSITIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? 'ok' : '✓';
const NEGATIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? 'x' : '✘';
class ListReporter extends _base.BaseReporter {
constructor(options = {}) {
super();
this._lastRow = 0;
this._lastColumn = 0;
this._testRows = new Map();
this._stepRows = new Map();
this._resultIndex = new Map();
this._stepIndex = new Map();
this._needNewLine = false;
this._printSteps = void 0;
this._printSteps = (0, _utils.getAsBooleanFromENV)('PLAYWRIGHT_LIST_PRINT_STEPS', options.printSteps);
}
onBegin(suite) {
super.onBegin(suite);
const startingMessage = this.generateStartingMessage();
if (startingMessage) {
console.log(startingMessage);
console.log();
}
}
onTestBegin(test, result) {
const index = String(this._resultIndex.size + 1);
this._resultIndex.set(result, index);
if (!_base.isTTY) return;
this._maybeWriteNewLine();
this._testRows.set(test, this._lastRow);
const prefix = this._testPrefix(index, '');
const line = _base.colors.dim((0, _base.formatTestTitle)(this.config, test)) + this._retrySuffix(result);
this._appendLine(line, prefix);
}
onStdOut(chunk, test, result) {
super.onStdOut(chunk, test, result);
this._dumpToStdio(test, chunk, process.stdout);
}
onStdErr(chunk, test, result) {
super.onStdErr(chunk, test, result);
this._dumpToStdio(test, chunk, process.stderr);
}
getStepIndex(testIndex, result, step) {
if (this._stepIndex.has(step)) return this._stepIndex.get(step);
const ordinal = (result[lastStepOrdinalSymbol] || 0) + 1;
result[lastStepOrdinalSymbol] = ordinal;
const stepIndex = `${testIndex}.${ordinal}`;
this._stepIndex.set(step, stepIndex);
return stepIndex;
}
onStepBegin(test, result, step) {
if (step.category !== 'test.step') return;
const testIndex = this._resultIndex.get(result) || '';
if (!_base.isTTY) return;
if (this._printSteps) {
this._maybeWriteNewLine();
this._stepRows.set(step, this._lastRow);
const prefix = this._testPrefix(this.getStepIndex(testIndex, result, step), '');
const line = test.title + _base.colors.dim((0, _base.stepSuffix)(step));
this._appendLine(line, prefix);
} else {
this._updateLine(this._testRows.get(test), _base.colors.dim((0, _base.formatTestTitle)(this.config, test, step)) + this._retrySuffix(result), this._testPrefix(testIndex, ''));
}
}
onStepEnd(test, result, step) {
if (step.category !== 'test.step') return;
const testIndex = this._resultIndex.get(result) || '';
if (!this._printSteps) {
if (_base.isTTY) this._updateLine(this._testRows.get(test), _base.colors.dim((0, _base.formatTestTitle)(this.config, test, step.parent)) + this._retrySuffix(result), this._testPrefix(testIndex, ''));
return;
}
const index = this.getStepIndex(testIndex, result, step);
const title = _base.isTTY ? test.title + _base.colors.dim((0, _base.stepSuffix)(step)) : (0, _base.formatTestTitle)(this.config, test, step);
const prefix = this._testPrefix(index, '');
let text = '';
if (step.error) text = _base.colors.red(title);else text = title;
text += _base.colors.dim(` (${(0, _utilsBundle.ms)(step.duration)})`);
this._updateOrAppendLine(this._stepRows.get(step), text, prefix);
}
_maybeWriteNewLine() {
if (this._needNewLine) {
this._needNewLine = false;
process.stdout.write('\n');
}
}
_updateLineCountAndNewLineFlagForOutput(text) {
this._needNewLine = text[text.length - 1] !== '\n';
if (!_base.ttyWidth) return;
for (const ch of text) {
if (ch === '\n') {
this._lastColumn = 0;
++this._lastRow;
continue;
}
++this._lastColumn;
if (this._lastColumn > _base.ttyWidth) {
this._lastColumn = 0;
++this._lastRow;
}
}
}
_dumpToStdio(test, chunk, stream) {
if (this.config.quiet) return;
const text = chunk.toString('utf-8');
this._updateLineCountAndNewLineFlagForOutput(text);
stream.write(chunk);
}
onTestEnd(test, result) {
super.onTestEnd(test, result);
const title = (0, _base.formatTestTitle)(this.config, test);
let prefix = '';
let text = '';
// In TTY mode test index is incremented in onTestStart
// and in non-TTY mode it is incremented onTestEnd.
let index = this._resultIndex.get(result);
if (!index) {
index = String(this._resultIndex.size + 1);
this._resultIndex.set(result, index);
}
if (result.status === 'skipped') {
prefix = this._testPrefix(index, _base.colors.green('-'));
// Do not show duration for skipped.
text = _base.colors.cyan(title) + this._retrySuffix(result);
} else {
const statusMark = result.status === 'passed' ? POSITIVE_STATUS_MARK : NEGATIVE_STATUS_MARK;
if (result.status === test.expectedStatus) {
prefix = this._testPrefix(index, _base.colors.green(statusMark));
text = title;
} else {
prefix = this._testPrefix(index, _base.colors.red(statusMark));
text = _base.colors.red(title);
}
text += this._retrySuffix(result) + _base.colors.dim(` (${(0, _utilsBundle.ms)(result.duration)})`);
}
this._updateOrAppendLine(this._testRows.get(test), text, prefix);
}
_updateOrAppendLine(row, text, prefix) {
if (_base.isTTY) {
this._updateLine(row, text, prefix);
} else {
this._maybeWriteNewLine();
this._appendLine(text, prefix);
}
}
_appendLine(text, prefix) {
const line = prefix + this.fitToScreen(text, prefix);
if (process.env.PW_TEST_DEBUG_REPORTERS) {
process.stdout.write('#' + this._lastRow + ' : ' + line + '\n');
} else {
process.stdout.write(line);
process.stdout.write('\n');
}
++this._lastRow;
}
_updateLine(row, text, prefix) {
const line = prefix + this.fitToScreen(text, prefix);
if (process.env.PW_TEST_DEBUG_REPORTERS) process.stdout.write('#' + row + ' : ' + line + '\n');else this._updateLineForTTY(row, line);
}
_updateLineForTTY(row, line) {
// Go up if needed
if (row !== this._lastRow) process.stdout.write(`\u001B[${this._lastRow - row}A`);
// Erase line, go to the start
process.stdout.write('\u001B[2K\u001B[0G');
process.stdout.write(line);
// Go down if needed.
if (row !== this._lastRow) process.stdout.write(`\u001B[${this._lastRow - row}E`);
}
_testPrefix(index, statusMark) {
const statusMarkLength = (0, _base.stripAnsiEscapes)(statusMark).length;
return ' ' + statusMark + ' '.repeat(3 - statusMarkLength) + _base.colors.dim(index + ' ');
}
_retrySuffix(result) {
return result.retry ? _base.colors.yellow(` (retry #${result.retry})`) : '';
}
onError(error) {
super.onError(error);
this._maybeWriteNewLine();
const message = (0, _base.formatError)(error, _base.colors.enabled).message + '\n';
this._updateLineCountAndNewLineFlagForOutput(message);
process.stdout.write(message);
}
async onEnd(result) {
await super.onEnd(result);
process.stdout.write('\n');
this.epilogue(true);
}
}
const lastStepOrdinalSymbol = Symbol('lastStepOrdinal');
var _default = exports.default = ListReporter;

76
node_modules/playwright/lib/reporters/markdown.js generated vendored Normal file
View File

@@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _util = require("../util");
var _base = require("./base");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class MarkdownReporter extends _base.BaseReporter {
constructor(options) {
super();
this._options = void 0;
this._options = options;
}
printsToStdio() {
return false;
}
async onEnd(result) {
await super.onEnd(result);
const summary = this.generateSummary();
const lines = [];
if (summary.fatalErrors.length) lines.push(`**${summary.fatalErrors.length} fatal errors, not part of any test**`);
if (summary.unexpected.length) {
lines.push(`**${summary.unexpected.length} failed**`);
this._printTestList(':x:', summary.unexpected, lines);
}
if (summary.flaky.length) {
lines.push(`<details>`);
lines.push(`<summary><b>${summary.flaky.length} flaky</b></summary>`);
this._printTestList(':warning:', summary.flaky, lines, ' <br/>');
lines.push(`</details>`);
lines.push(``);
}
if (summary.interrupted.length) {
lines.push(`<details>`);
lines.push(`<summary><b>${summary.interrupted.length} interrupted</b></summary>`);
this._printTestList(':warning:', summary.interrupted, lines, ' <br/>');
lines.push(`</details>`);
lines.push(``);
}
const skipped = summary.skipped ? `, ${summary.skipped} skipped` : '';
const didNotRun = summary.didNotRun ? `, ${summary.didNotRun} did not run` : '';
lines.push(`**${summary.expected} passed${skipped}${didNotRun}**`);
lines.push(`:heavy_check_mark::heavy_check_mark::heavy_check_mark:`);
lines.push(``);
const reportFile = (0, _util.resolveReporterOutputPath)('report.md', this._options.configDir, this._options.outputFile);
await _fs.default.promises.mkdir(_path.default.dirname(reportFile), {
recursive: true
});
await _fs.default.promises.writeFile(reportFile, lines.join('\n'));
}
_printTestList(prefix, tests, lines, suffix) {
for (const test of tests) lines.push(`${prefix} ${(0, _base.formatTestTitle)(this.config, test)}${suffix || ''}`);
lines.push(``);
}
}
var _default = exports.default = MarkdownReporter;

488
node_modules/playwright/lib/reporters/merge.js generated vendored Normal file
View File

@@ -0,0 +1,488 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createMergedReport = createMergedReport;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _teleReceiver = require("../isomorphic/teleReceiver");
var _stringInternPool = require("../isomorphic/stringInternPool");
var _reporters = require("../runner/reporters");
var _multiplexer = require("./multiplexer");
var _utils = require("playwright-core/lib/utils");
var _blob = require("./blob");
var _util = require("../util");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
async function createMergedReport(config, dir, reporterDescriptions, rootDirOverride) {
var _eventData$pathSepara;
const reporters = await (0, _reporters.createReporters)(config, 'merge', false, reporterDescriptions);
const multiplexer = new _multiplexer.Multiplexer(reporters);
const stringPool = new _stringInternPool.StringInternPool();
let printStatus = () => {};
if (!multiplexer.printsToStdio()) {
printStatus = printStatusToStdout;
printStatus(`merging reports from ${dir}`);
}
const shardFiles = await sortedShardFiles(dir);
if (shardFiles.length === 0) throw new Error(`No report files found in ${dir}`);
const eventData = await mergeEvents(dir, shardFiles, stringPool, printStatus, rootDirOverride);
// If explicit config is provided, use platform path separator, otherwise use the one from the report (if any).
const pathSeparator = rootDirOverride ? _path.default.sep : (_eventData$pathSepara = eventData.pathSeparatorFromMetadata) !== null && _eventData$pathSepara !== void 0 ? _eventData$pathSepara : _path.default.sep;
const receiver = new _teleReceiver.TeleReporterReceiver(multiplexer, {
mergeProjects: false,
mergeTestCases: false,
resolvePath: (rootDir, relativePath) => stringPool.internString(rootDir + pathSeparator + relativePath),
configOverrides: config.config
});
printStatus(`processing test events`);
const dispatchEvents = async events => {
for (const event of events) {
if (event.method === 'onEnd') printStatus(`building final report`);
await receiver.dispatch(event);
if (event.method === 'onEnd') printStatus(`finished building report`);
}
};
await dispatchEvents(eventData.prologue);
for (const {
reportFile,
eventPatchers,
metadata
} of eventData.reports) {
const reportJsonl = await _fs.default.promises.readFile(reportFile);
const events = parseTestEvents(reportJsonl);
new _stringInternPool.JsonStringInternalizer(stringPool).traverse(events);
eventPatchers.patchers.push(new AttachmentPathPatcher(dir));
if (metadata.name) eventPatchers.patchers.push(new GlobalErrorPatcher(metadata.name));
eventPatchers.patchEvents(events);
await dispatchEvents(events);
}
await dispatchEvents(eventData.epilogue);
}
const commonEventNames = ['onBlobReportMetadata', 'onConfigure', 'onProject', 'onBegin', 'onEnd'];
const commonEvents = new Set(commonEventNames);
const commonEventRegex = new RegExp(`${commonEventNames.join('|')}`);
function parseCommonEvents(reportJsonl) {
return splitBufferLines(reportJsonl).map(line => line.toString('utf8')).filter(line => commonEventRegex.test(line)) // quick filter
.map(line => JSON.parse(line)).filter(event => commonEvents.has(event.method));
}
function parseTestEvents(reportJsonl) {
return splitBufferLines(reportJsonl).map(line => line.toString('utf8')).filter(line => line.length).map(line => JSON.parse(line)).filter(event => !commonEvents.has(event.method));
}
function splitBufferLines(buffer) {
const lines = [];
let start = 0;
while (start < buffer.length) {
// 0x0A is the byte for '\n'
const end = buffer.indexOf(0x0A, start);
if (end === -1) {
lines.push(buffer.slice(start));
break;
}
lines.push(buffer.slice(start, end));
start = end + 1;
}
return lines;
}
async function extractAndParseReports(dir, shardFiles, internalizer, printStatus) {
const shardEvents = [];
await _fs.default.promises.mkdir(_path.default.join(dir, 'resources'), {
recursive: true
});
const reportNames = new UniqueFileNameGenerator();
for (const file of shardFiles) {
const absolutePath = _path.default.join(dir, file);
printStatus(`extracting: ${(0, _util.relativeFilePath)(absolutePath)}`);
const zipFile = new _utils.ZipFile(absolutePath);
const entryNames = await zipFile.entries();
for (const entryName of entryNames.sort()) {
let fileName = _path.default.join(dir, entryName);
const content = await zipFile.read(entryName);
if (entryName.endsWith('.jsonl')) {
fileName = reportNames.makeUnique(fileName);
let parsedEvents = parseCommonEvents(content);
// Passing reviver to JSON.parse doesn't work, as the original strings
// keep being used. To work around that we traverse the parsed events
// as a post-processing step.
internalizer.traverse(parsedEvents);
const metadata = findMetadata(parsedEvents, file);
parsedEvents = modernizer.modernize(metadata.version, parsedEvents);
shardEvents.push({
file,
localPath: fileName,
metadata,
parsedEvents
});
}
await _fs.default.promises.writeFile(fileName, content);
}
zipFile.close();
}
return shardEvents;
}
function findMetadata(events, file) {
var _events$;
if (((_events$ = events[0]) === null || _events$ === void 0 ? void 0 : _events$.method) !== 'onBlobReportMetadata') throw new Error(`No metadata event found in ${file}`);
const metadata = events[0].params;
if (metadata.version > _blob.currentBlobReportVersion) throw new Error(`Blob report ${file} was created with a newer version of Playwright.`);
return metadata;
}
async function mergeEvents(dir, shardReportFiles, stringPool, printStatus, rootDirOverride) {
var _blobs$;
const internalizer = new _stringInternPool.JsonStringInternalizer(stringPool);
const configureEvents = [];
const projectEvents = [];
const endEvents = [];
const blobs = await extractAndParseReports(dir, shardReportFiles, internalizer, printStatus);
// Sort by (report name; shard; file name), so that salt generation below is deterministic when:
// - report names are unique;
// - report names are missing;
// - report names are clashing between shards.
blobs.sort((a, b) => {
var _a$metadata$name, _b$metadata$name, _a$metadata$shard$cur, _a$metadata$shard, _b$metadata$shard$cur, _b$metadata$shard;
const nameA = (_a$metadata$name = a.metadata.name) !== null && _a$metadata$name !== void 0 ? _a$metadata$name : '';
const nameB = (_b$metadata$name = b.metadata.name) !== null && _b$metadata$name !== void 0 ? _b$metadata$name : '';
if (nameA !== nameB) return nameA.localeCompare(nameB);
const shardA = (_a$metadata$shard$cur = (_a$metadata$shard = a.metadata.shard) === null || _a$metadata$shard === void 0 ? void 0 : _a$metadata$shard.current) !== null && _a$metadata$shard$cur !== void 0 ? _a$metadata$shard$cur : 0;
const shardB = (_b$metadata$shard$cur = (_b$metadata$shard = b.metadata.shard) === null || _b$metadata$shard === void 0 ? void 0 : _b$metadata$shard.current) !== null && _b$metadata$shard$cur !== void 0 ? _b$metadata$shard$cur : 0;
if (shardA !== shardB) return shardA - shardB;
return a.file.localeCompare(b.file);
});
printStatus(`merging events`);
const reports = [];
const globalTestIdSet = new Set();
for (let i = 0; i < blobs.length; ++i) {
// Generate unique salt for each blob.
const {
parsedEvents,
metadata,
localPath
} = blobs[i];
const eventPatchers = new JsonEventPatchers();
eventPatchers.patchers.push(new IdsPatcher(stringPool, metadata.name, String(i), globalTestIdSet));
// Only patch path separators if we are merging reports with explicit config.
if (rootDirOverride) eventPatchers.patchers.push(new PathSeparatorPatcher(metadata.pathSeparator));
eventPatchers.patchEvents(parsedEvents);
for (const event of parsedEvents) {
if (event.method === 'onConfigure') configureEvents.push(event);else if (event.method === 'onProject') projectEvents.push(event);else if (event.method === 'onEnd') endEvents.push(event);
}
// Save information about the reports to stream their test events later.
reports.push({
eventPatchers,
reportFile: localPath,
metadata
});
}
return {
prologue: [mergeConfigureEvents(configureEvents, rootDirOverride), ...projectEvents, {
method: 'onBegin',
params: undefined
}],
reports,
epilogue: [mergeEndEvents(endEvents), {
method: 'onExit',
params: undefined
}],
pathSeparatorFromMetadata: (_blobs$ = blobs[0]) === null || _blobs$ === void 0 ? void 0 : _blobs$.metadata.pathSeparator
};
}
function mergeConfigureEvents(configureEvents, rootDirOverride) {
if (!configureEvents.length) throw new Error('No configure events found');
let config = {
configFile: undefined,
globalTimeout: 0,
maxFailures: 0,
metadata: {},
rootDir: '',
version: '',
workers: 0
};
for (const event of configureEvents) config = mergeConfigs(config, event.params.config);
if (rootDirOverride) {
config.rootDir = rootDirOverride;
} else {
const rootDirs = new Set(configureEvents.map(e => e.params.config.rootDir));
if (rootDirs.size > 1) {
throw new Error([`Blob reports being merged were recorded with different test directories, and`, `merging cannot proceed. This may happen if you are merging reports from`, `machines with different environments, like different operating systems or`, `if the tests ran with different playwright configs.`, ``, `You can force merge by specifying a merge config file with "-c" option. If`, `you'd like all test paths to be correct, make sure 'testDir' in the merge config`, `file points to the actual tests location.`, ``, `Found directories:`, ...rootDirs].join('\n'));
}
}
return {
method: 'onConfigure',
params: {
config
}
};
}
function mergeConfigs(to, from) {
return {
...to,
...from,
metadata: {
...to.metadata,
...from.metadata,
actualWorkers: (to.metadata.actualWorkers || 0) + (from.metadata.actualWorkers || 0)
},
workers: to.workers + from.workers
};
}
function mergeEndEvents(endEvents) {
let startTime = endEvents.length ? 10000000000000 : Date.now();
let status = 'passed';
let duration = 0;
for (const event of endEvents) {
const shardResult = event.params.result;
if (shardResult.status === 'failed') status = 'failed';else if (shardResult.status === 'timedout' && status !== 'failed') status = 'timedout';else if (shardResult.status === 'interrupted' && status !== 'failed' && status !== 'timedout') status = 'interrupted';
startTime = Math.min(startTime, shardResult.startTime);
duration = Math.max(duration, shardResult.duration);
}
const result = {
status,
startTime,
duration
};
return {
method: 'onEnd',
params: {
result
}
};
}
async function sortedShardFiles(dir) {
const files = await _fs.default.promises.readdir(dir);
return files.filter(file => file.endsWith('.zip')).sort();
}
function printStatusToStdout(message) {
process.stdout.write(`${message}\n`);
}
class UniqueFileNameGenerator {
constructor() {
this._usedNames = new Set();
}
makeUnique(name) {
if (!this._usedNames.has(name)) {
this._usedNames.add(name);
return name;
}
const extension = _path.default.extname(name);
name = name.substring(0, name.length - extension.length);
let index = 0;
while (true) {
const candidate = `${name}-${++index}${extension}`;
if (!this._usedNames.has(candidate)) {
this._usedNames.add(candidate);
return candidate;
}
}
}
}
class IdsPatcher {
constructor(stringPool, botName, salt, globalTestIdSet) {
this._stringPool = void 0;
this._botName = void 0;
this._salt = void 0;
this._testIdsMap = void 0;
this._globalTestIdSet = void 0;
this._stringPool = stringPool;
this._botName = botName;
this._salt = salt;
this._testIdsMap = new Map();
this._globalTestIdSet = globalTestIdSet;
}
patchEvent(event) {
const {
method,
params
} = event;
switch (method) {
case 'onProject':
this._onProject(params.project);
return;
case 'onTestBegin':
case 'onStepBegin':
case 'onStepEnd':
case 'onStdIO':
params.testId = this._mapTestId(params.testId);
return;
case 'onTestEnd':
params.test.testId = this._mapTestId(params.test.testId);
return;
}
}
_onProject(project) {
var _project$metadata;
(_project$metadata = project.metadata) !== null && _project$metadata !== void 0 ? _project$metadata : project.metadata = {};
project.suites.forEach(suite => this._updateTestIds(suite));
}
_updateTestIds(suite) {
suite.entries.forEach(entry => {
if ('testId' in entry) this._updateTestId(entry);else this._updateTestIds(entry);
});
}
_updateTestId(test) {
test.testId = this._mapTestId(test.testId);
if (this._botName) {
test.tags = test.tags || [];
test.tags.unshift('@' + this._botName);
}
}
_mapTestId(testId) {
const t1 = this._stringPool.internString(testId);
if (this._testIdsMap.has(t1))
// already mapped
return this._testIdsMap.get(t1);
if (this._globalTestIdSet.has(t1)) {
// test id is used in another blob, so we need to salt it.
const t2 = this._stringPool.internString(testId + this._salt);
this._globalTestIdSet.add(t2);
this._testIdsMap.set(t1, t2);
return t2;
}
this._globalTestIdSet.add(t1);
this._testIdsMap.set(t1, t1);
return t1;
}
}
class AttachmentPathPatcher {
constructor(_resourceDir) {
this._resourceDir = _resourceDir;
}
patchEvent(event) {
if (event.method !== 'onTestEnd') return;
for (const attachment of event.params.result.attachments) {
if (!attachment.path) continue;
attachment.path = _path.default.join(this._resourceDir, attachment.path);
}
}
}
class PathSeparatorPatcher {
constructor(from) {
this._from = void 0;
this._to = void 0;
this._from = from !== null && from !== void 0 ? from : _path.default.sep === '/' ? '\\' : '/';
this._to = _path.default.sep;
}
patchEvent(jsonEvent) {
if (this._from === this._to) return;
if (jsonEvent.method === 'onProject') {
this._updateProject(jsonEvent.params.project);
return;
}
if (jsonEvent.method === 'onTestEnd') {
const testResult = jsonEvent.params.result;
testResult.errors.forEach(error => this._updateErrorLocations(error));
testResult.attachments.forEach(attachment => {
if (attachment.path) attachment.path = this._updatePath(attachment.path);
});
return;
}
if (jsonEvent.method === 'onStepBegin') {
const step = jsonEvent.params.step;
this._updateLocation(step.location);
return;
}
if (jsonEvent.method === 'onStepEnd') {
const step = jsonEvent.params.step;
this._updateErrorLocations(step.error);
return;
}
}
_updateProject(project) {
project.outputDir = this._updatePath(project.outputDir);
project.testDir = this._updatePath(project.testDir);
project.snapshotDir = this._updatePath(project.snapshotDir);
project.suites.forEach(suite => this._updateSuite(suite, true));
}
_updateSuite(suite, isFileSuite = false) {
this._updateLocation(suite.location);
if (isFileSuite) suite.title = this._updatePath(suite.title);
for (const entry of suite.entries) {
if ('testId' in entry) this._updateLocation(entry.location);else this._updateSuite(entry);
}
}
_updateErrorLocations(error) {
while (error) {
this._updateLocation(error.location);
error = error.cause;
}
}
_updateLocation(location) {
if (location) location.file = this._updatePath(location.file);
}
_updatePath(text) {
return text.split(this._from).join(this._to);
}
}
class GlobalErrorPatcher {
constructor(botName) {
this._prefix = void 0;
this._prefix = `(${botName}) `;
}
patchEvent(event) {
if (event.method !== 'onError') return;
const error = event.params.error;
if (error.message !== undefined) error.message = this._prefix + error.message;
if (error.stack !== undefined) error.stack = this._prefix + error.stack;
}
}
class JsonEventPatchers {
constructor() {
this.patchers = [];
}
patchEvents(events) {
for (const event of events) {
for (const patcher of this.patchers) patcher.patchEvent(event);
}
}
}
class BlobModernizer {
modernize(fromVersion, events) {
const result = [];
for (const event of events) result.push(...this._modernize(fromVersion, event));
return result;
}
_modernize(fromVersion, event) {
let events = [event];
for (let version = fromVersion; version < _blob.currentBlobReportVersion; ++version) events = this[`_modernize_${version}_to_${version + 1}`].call(this, events);
return events;
}
_modernize_1_to_2(events) {
return events.map(event => {
if (event.method === 'onProject') {
const modernizeSuite = suite => {
const newSuites = suite.suites.map(modernizeSuite);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const {
suites,
tests,
...remainder
} = suite;
return {
entries: [...newSuites, ...tests],
...remainder
};
};
const project = event.params.project;
project.suites = project.suites.map(modernizeSuite);
}
return event;
});
}
}
const modernizer = new BlobModernizer();

123
node_modules/playwright/lib/reporters/multiplexer.js generated vendored Normal file
View File

@@ -0,0 +1,123 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Multiplexer = void 0;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Multiplexer {
constructor(reporters) {
this._reporters = void 0;
this._reporters = reporters;
}
version() {
return 'v2';
}
onConfigure(config) {
for (const reporter of this._reporters) wrap(() => {
var _reporter$onConfigure;
return (_reporter$onConfigure = reporter.onConfigure) === null || _reporter$onConfigure === void 0 ? void 0 : _reporter$onConfigure.call(reporter, config);
});
}
onBegin(suite) {
for (const reporter of this._reporters) wrap(() => {
var _reporter$onBegin;
return (_reporter$onBegin = reporter.onBegin) === null || _reporter$onBegin === void 0 ? void 0 : _reporter$onBegin.call(reporter, suite);
});
}
onTestBegin(test, result) {
for (const reporter of this._reporters) wrap(() => {
var _reporter$onTestBegin;
return (_reporter$onTestBegin = reporter.onTestBegin) === null || _reporter$onTestBegin === void 0 ? void 0 : _reporter$onTestBegin.call(reporter, test, result);
});
}
onStdOut(chunk, test, result) {
for (const reporter of this._reporters) wrap(() => {
var _reporter$onStdOut;
return (_reporter$onStdOut = reporter.onStdOut) === null || _reporter$onStdOut === void 0 ? void 0 : _reporter$onStdOut.call(reporter, chunk, test, result);
});
}
onStdErr(chunk, test, result) {
for (const reporter of this._reporters) wrap(() => {
var _reporter$onStdErr;
return (_reporter$onStdErr = reporter.onStdErr) === null || _reporter$onStdErr === void 0 ? void 0 : _reporter$onStdErr.call(reporter, chunk, test, result);
});
}
onTestEnd(test, result) {
for (const reporter of this._reporters) wrap(() => {
var _reporter$onTestEnd;
return (_reporter$onTestEnd = reporter.onTestEnd) === null || _reporter$onTestEnd === void 0 ? void 0 : _reporter$onTestEnd.call(reporter, test, result);
});
}
async onEnd(result) {
for (const reporter of this._reporters) {
const outResult = await wrapAsync(() => {
var _reporter$onEnd;
return (_reporter$onEnd = reporter.onEnd) === null || _reporter$onEnd === void 0 ? void 0 : _reporter$onEnd.call(reporter, result);
});
if (outResult !== null && outResult !== void 0 && outResult.status) result.status = outResult.status;
}
return result;
}
async onExit() {
for (const reporter of this._reporters) await wrapAsync(() => {
var _reporter$onExit;
return (_reporter$onExit = reporter.onExit) === null || _reporter$onExit === void 0 ? void 0 : _reporter$onExit.call(reporter);
});
}
onError(error) {
for (const reporter of this._reporters) wrap(() => {
var _reporter$onError;
return (_reporter$onError = reporter.onError) === null || _reporter$onError === void 0 ? void 0 : _reporter$onError.call(reporter, error);
});
}
onStepBegin(test, result, step) {
for (const reporter of this._reporters) wrap(() => {
var _reporter$onStepBegin;
return (_reporter$onStepBegin = reporter.onStepBegin) === null || _reporter$onStepBegin === void 0 ? void 0 : _reporter$onStepBegin.call(reporter, test, result, step);
});
}
onStepEnd(test, result, step) {
for (const reporter of this._reporters) wrap(() => {
var _reporter$onStepEnd;
return (_reporter$onStepEnd = reporter.onStepEnd) === null || _reporter$onStepEnd === void 0 ? void 0 : _reporter$onStepEnd.call(reporter, test, result, step);
});
}
printsToStdio() {
return this._reporters.some(r => {
let prints = false;
wrap(() => prints = r.printsToStdio ? r.printsToStdio() : true);
return prints;
});
}
}
exports.Multiplexer = Multiplexer;
async function wrapAsync(callback) {
try {
return await callback();
} catch (e) {
console.error('Error in reporter', e);
}
}
function wrap(callback) {
try {
callback();
} catch (e) {
console.error('Error in reporter', e);
}
}

118
node_modules/playwright/lib/reporters/reporterV2.js generated vendored Normal file
View File

@@ -0,0 +1,118 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.wrapReporterAsV2 = wrapReporterAsV2;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function wrapReporterAsV2(reporter) {
try {
if ('version' in reporter && reporter.version() === 'v2') return reporter;
} catch (e) {}
return new ReporterV2Wrapper(reporter);
}
class ReporterV2Wrapper {
constructor(reporter) {
this._reporter = void 0;
this._deferred = [];
this._config = void 0;
this._reporter = reporter;
}
version() {
return 'v2';
}
onConfigure(config) {
this._config = config;
}
onBegin(suite) {
var _this$_reporter$onBeg, _this$_reporter;
(_this$_reporter$onBeg = (_this$_reporter = this._reporter).onBegin) === null || _this$_reporter$onBeg === void 0 || _this$_reporter$onBeg.call(_this$_reporter, this._config, suite);
const deferred = this._deferred;
this._deferred = null;
for (const item of deferred) {
if (item.error) this.onError(item.error);
if (item.stdout) this.onStdOut(item.stdout.chunk, item.stdout.test, item.stdout.result);
if (item.stderr) this.onStdErr(item.stderr.chunk, item.stderr.test, item.stderr.result);
}
}
onTestBegin(test, result) {
var _this$_reporter$onTes, _this$_reporter2;
(_this$_reporter$onTes = (_this$_reporter2 = this._reporter).onTestBegin) === null || _this$_reporter$onTes === void 0 || _this$_reporter$onTes.call(_this$_reporter2, test, result);
}
onStdOut(chunk, test, result) {
var _this$_reporter$onStd, _this$_reporter3;
if (this._deferred) {
this._deferred.push({
stdout: {
chunk,
test,
result
}
});
return;
}
(_this$_reporter$onStd = (_this$_reporter3 = this._reporter).onStdOut) === null || _this$_reporter$onStd === void 0 || _this$_reporter$onStd.call(_this$_reporter3, chunk, test, result);
}
onStdErr(chunk, test, result) {
var _this$_reporter$onStd2, _this$_reporter4;
if (this._deferred) {
this._deferred.push({
stderr: {
chunk,
test,
result
}
});
return;
}
(_this$_reporter$onStd2 = (_this$_reporter4 = this._reporter).onStdErr) === null || _this$_reporter$onStd2 === void 0 || _this$_reporter$onStd2.call(_this$_reporter4, chunk, test, result);
}
onTestEnd(test, result) {
var _this$_reporter$onTes2, _this$_reporter5;
(_this$_reporter$onTes2 = (_this$_reporter5 = this._reporter).onTestEnd) === null || _this$_reporter$onTes2 === void 0 || _this$_reporter$onTes2.call(_this$_reporter5, test, result);
}
async onEnd(result) {
var _this$_reporter$onEnd, _this$_reporter6;
return await ((_this$_reporter$onEnd = (_this$_reporter6 = this._reporter).onEnd) === null || _this$_reporter$onEnd === void 0 ? void 0 : _this$_reporter$onEnd.call(_this$_reporter6, result));
}
async onExit() {
var _this$_reporter$onExi, _this$_reporter7;
await ((_this$_reporter$onExi = (_this$_reporter7 = this._reporter).onExit) === null || _this$_reporter$onExi === void 0 ? void 0 : _this$_reporter$onExi.call(_this$_reporter7));
}
onError(error) {
var _this$_reporter$onErr, _this$_reporter8;
if (this._deferred) {
this._deferred.push({
error
});
return;
}
(_this$_reporter$onErr = (_this$_reporter8 = this._reporter).onError) === null || _this$_reporter$onErr === void 0 || _this$_reporter$onErr.call(_this$_reporter8, error);
}
onStepBegin(test, result, step) {
var _this$_reporter$onSte, _this$_reporter9;
(_this$_reporter$onSte = (_this$_reporter9 = this._reporter).onStepBegin) === null || _this$_reporter$onSte === void 0 || _this$_reporter$onSte.call(_this$_reporter9, test, result, step);
}
onStepEnd(test, result, step) {
var _this$_reporter$onSte2, _this$_reporter10;
(_this$_reporter$onSte2 = (_this$_reporter10 = this._reporter).onStepEnd) === null || _this$_reporter$onSte2 === void 0 || _this$_reporter$onSte2.call(_this$_reporter10, test, result, step);
}
printsToStdio() {
return this._reporter.printsToStdio ? this._reporter.printsToStdio() : true;
}
}

267
node_modules/playwright/lib/reporters/teleEmitter.js generated vendored Normal file
View File

@@ -0,0 +1,267 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TeleReporterEmitter = void 0;
var _path = _interopRequireDefault(require("path"));
var _utils = require("playwright-core/lib/utils");
var _teleReceiver = require("../isomorphic/teleReceiver");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class TeleReporterEmitter {
constructor(messageSink, options = {}) {
this._messageSink = void 0;
this._rootDir = void 0;
this._emitterOptions = void 0;
// In case there is blob reporter and UI mode, make sure one does override
// the id assigned by the other.
this._idSymbol = Symbol('id');
this._messageSink = messageSink;
this._emitterOptions = options;
}
version() {
return 'v2';
}
onConfigure(config) {
this._rootDir = config.rootDir;
this._messageSink({
method: 'onConfigure',
params: {
config: this._serializeConfig(config)
}
});
}
onBegin(suite) {
const projects = suite.suites.map(projectSuite => this._serializeProject(projectSuite));
for (const project of projects) this._messageSink({
method: 'onProject',
params: {
project
}
});
this._messageSink({
method: 'onBegin',
params: undefined
});
}
onTestBegin(test, result) {
result[this._idSymbol] = (0, _utils.createGuid)();
this._messageSink({
method: 'onTestBegin',
params: {
testId: test.id,
result: this._serializeResultStart(result)
}
});
}
onTestEnd(test, result) {
const testEnd = {
testId: test.id,
expectedStatus: test.expectedStatus,
annotations: test.annotations,
timeout: test.timeout
};
this._messageSink({
method: 'onTestEnd',
params: {
test: testEnd,
result: this._serializeResultEnd(result)
}
});
}
onStepBegin(test, result, step) {
step[this._idSymbol] = (0, _utils.createGuid)();
this._messageSink({
method: 'onStepBegin',
params: {
testId: test.id,
resultId: result[this._idSymbol],
step: this._serializeStepStart(step)
}
});
}
onStepEnd(test, result, step) {
this._messageSink({
method: 'onStepEnd',
params: {
testId: test.id,
resultId: result[this._idSymbol],
step: this._serializeStepEnd(step)
}
});
}
onError(error) {
this._messageSink({
method: 'onError',
params: {
error
}
});
}
onStdOut(chunk, test, result) {
this._onStdIO('stdout', chunk, test, result);
}
onStdErr(chunk, test, result) {
this._onStdIO('stderr', chunk, test, result);
}
_onStdIO(type, chunk, test, result) {
if (this._emitterOptions.omitOutput) return;
const isBase64 = typeof chunk !== 'string';
const data = isBase64 ? chunk.toString('base64') : chunk;
this._messageSink({
method: 'onStdIO',
params: {
testId: test === null || test === void 0 ? void 0 : test.id,
resultId: result ? result[this._idSymbol] : undefined,
type,
data,
isBase64
}
});
}
async onEnd(result) {
const resultPayload = {
status: result.status,
startTime: result.startTime.getTime(),
duration: result.duration
};
this._messageSink({
method: 'onEnd',
params: {
result: resultPayload
}
});
}
printsToStdio() {
return false;
}
_serializeConfig(config) {
return {
configFile: this._relativePath(config.configFile),
globalTimeout: config.globalTimeout,
maxFailures: config.maxFailures,
metadata: config.metadata,
rootDir: config.rootDir,
version: config.version,
workers: config.workers
};
}
_serializeProject(suite) {
const project = suite.project();
const report = {
metadata: project.metadata,
name: project.name,
outputDir: this._relativePath(project.outputDir),
repeatEach: project.repeatEach,
retries: project.retries,
testDir: this._relativePath(project.testDir),
testIgnore: (0, _teleReceiver.serializeRegexPatterns)(project.testIgnore),
testMatch: (0, _teleReceiver.serializeRegexPatterns)(project.testMatch),
timeout: project.timeout,
suites: suite.suites.map(fileSuite => {
return this._serializeSuite(fileSuite);
}),
grep: (0, _teleReceiver.serializeRegexPatterns)(project.grep),
grepInvert: (0, _teleReceiver.serializeRegexPatterns)(project.grepInvert || []),
dependencies: project.dependencies,
snapshotDir: this._relativePath(project.snapshotDir),
teardown: project.teardown
};
return report;
}
_serializeSuite(suite) {
const result = {
title: suite.title,
location: this._relativeLocation(suite.location),
entries: suite.entries().map(e => {
if (e.type === 'test') return this._serializeTest(e);
return this._serializeSuite(e);
})
};
return result;
}
_serializeTest(test) {
return {
testId: test.id,
title: test.title,
location: this._relativeLocation(test.location),
retries: test.retries,
tags: test.tags,
repeatEachIndex: test.repeatEachIndex,
annotations: test.annotations
};
}
_serializeResultStart(result) {
return {
id: result[this._idSymbol],
retry: result.retry,
workerIndex: result.workerIndex,
parallelIndex: result.parallelIndex,
startTime: +result.startTime
};
}
_serializeResultEnd(result) {
return {
id: result[this._idSymbol],
duration: result.duration,
status: result.status,
errors: result.errors,
attachments: this._serializeAttachments(result.attachments)
};
}
_serializeAttachments(attachments) {
return attachments.map(a => {
return {
...a,
// There is no Buffer in the browser, so there is no point in sending the data there.
base64: a.body && !this._emitterOptions.omitBuffers ? a.body.toString('base64') : undefined
};
});
}
_serializeStepStart(step) {
var _step$parent;
return {
id: step[this._idSymbol],
parentStepId: (_step$parent = step.parent) === null || _step$parent === void 0 ? void 0 : _step$parent[this._idSymbol],
title: step.title,
category: step.category,
startTime: +step.startTime,
location: this._relativeLocation(step.location)
};
}
_serializeStepEnd(step) {
return {
id: step[this._idSymbol],
duration: step.duration,
error: step.error
};
}
_relativeLocation(location) {
if (!location) return location;
return {
...location,
file: this._relativePath(location.file)
};
}
_relativePath(absolutePath) {
if (!absolutePath) return absolutePath;
return _path.default.relative(this._rootDir, absolutePath);
}
}
exports.TeleReporterEmitter = TeleReporterEmitter;

View File

@@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});

550
node_modules/playwright/lib/runner/dispatcher.js generated vendored Normal file
View File

@@ -0,0 +1,550 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Dispatcher = void 0;
var _ipc = require("../common/ipc");
var _utils = require("playwright-core/lib/utils");
var _workerHost = require("./workerHost");
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _rebase = require("./rebase");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Dispatcher {
constructor(config, reporter, failureTracker) {
this._workerSlots = [];
this._queue = [];
this._queuedOrRunningHashCount = new Map();
this._finished = new _utils.ManualPromise();
this._isStopped = true;
this._config = void 0;
this._reporter = void 0;
this._failureTracker = void 0;
this._extraEnvByProjectId = new Map();
this._producedEnvByProjectId = new Map();
this._config = config;
this._reporter = reporter;
this._failureTracker = failureTracker;
}
async _scheduleJob() {
// 1. Find a job to run.
if (this._isStopped || !this._queue.length) return;
const job = this._queue[0];
// 2. Find a worker with the same hash, or just some free worker.
let index = this._workerSlots.findIndex(w => !w.busy && w.worker && w.worker.hash() === job.workerHash && !w.worker.didSendStop());
if (index === -1) index = this._workerSlots.findIndex(w => !w.busy);
// No workers available, bail out.
if (index === -1) return;
// 3. Claim both the job and the worker, run the job and release the worker.
this._queue.shift();
this._workerSlots[index].busy = true;
await this._startJobInWorker(index, job);
this._workerSlots[index].busy = false;
// 4. Check the "finished" condition.
this._checkFinished();
// 5. We got a free worker - perhaps we can immediately start another job?
void this._scheduleJob();
}
async _startJobInWorker(index, job) {
const stopCallback = () => this.stop().catch(() => {});
const jobDispatcher = new JobDispatcher(job, this._reporter, this._failureTracker, stopCallback);
if (jobDispatcher.skipWholeJob()) return;
let worker = this._workerSlots[index].worker;
// 1. Restart the worker if it has the wrong hash or is being stopped already.
if (worker && (worker.hash() !== job.workerHash || worker.didSendStop())) {
await worker.stop();
worker = undefined;
if (this._isStopped)
// Check stopped signal after async hop.
return;
}
this._workerSlots[index].jobDispatcher = jobDispatcher;
// 2. Start the worker if it is down.
let startError;
if (!worker) {
worker = this._createWorker(job, index, (0, _ipc.serializeConfig)(this._config, true));
this._workerSlots[index].worker = worker;
worker.on('exit', () => this._workerSlots[index].worker = undefined);
startError = await worker.start();
if (this._isStopped)
// Check stopped signal after async hop.
return;
}
// 3. Run the job.
if (startError) jobDispatcher.onExit(startError);else jobDispatcher.runInWorker(worker);
const result = await jobDispatcher.jobResult;
this._workerSlots[index].jobDispatcher = undefined;
this._updateCounterForWorkerHash(job.workerHash, -1);
// 4. When worker encounters error, we stop it and create a new one.
// We also do not keep the worker alive if it cannot serve any more jobs.
if (result.didFail) void worker.stop(true /* didFail */);else if (this._isWorkerRedundant(worker)) void worker.stop();
// 5. Possibly schedule a new job with leftover tests and/or retries.
if (!this._isStopped && result.newJob) {
this._queue.unshift(result.newJob);
this._updateCounterForWorkerHash(job.workerHash, +1);
}
}
_checkFinished() {
if (this._finished.isDone()) return;
// Check that we have no more work to do.
if (this._queue.length && !this._isStopped) return;
// Make sure all workers have finished the current job.
if (this._workerSlots.some(w => w.busy)) return;
this._finished.resolve();
}
_isWorkerRedundant(worker) {
let workersWithSameHash = 0;
for (const slot of this._workerSlots) {
if (slot.worker && !slot.worker.didSendStop() && slot.worker.hash() === worker.hash()) workersWithSameHash++;
}
return workersWithSameHash > this._queuedOrRunningHashCount.get(worker.hash());
}
_updateCounterForWorkerHash(hash, delta) {
this._queuedOrRunningHashCount.set(hash, delta + (this._queuedOrRunningHashCount.get(hash) || 0));
}
async run(testGroups, extraEnvByProjectId) {
this._extraEnvByProjectId = extraEnvByProjectId;
this._queue = testGroups;
for (const group of testGroups) this._updateCounterForWorkerHash(group.workerHash, +1);
this._isStopped = false;
this._workerSlots = [];
// 0. Stop right away if we have reached max failures.
if (this._failureTracker.hasReachedMaxFailures()) void this.stop();
// 1. Allocate workers.
for (let i = 0; i < this._config.config.workers; i++) this._workerSlots.push({
busy: false
});
// 2. Schedule enough jobs.
for (let i = 0; i < this._workerSlots.length; i++) void this._scheduleJob();
this._checkFinished();
// 3. More jobs are scheduled when the worker becomes free.
// 4. Wait for all jobs to finish.
await this._finished;
}
_createWorker(testGroup, parallelIndex, loaderData) {
const projectConfig = this._config.projects.find(p => p.id === testGroup.projectId);
const outputDir = projectConfig.project.outputDir;
const worker = new _workerHost.WorkerHost(testGroup, parallelIndex, loaderData, this._extraEnvByProjectId.get(testGroup.projectId) || {}, outputDir);
const handleOutput = params => {
var _this$_workerSlots$pa;
const chunk = chunkFromParams(params);
if (worker.didFail()) {
// Note: we keep reading stdio from workers that are currently stopping after failure,
// to debug teardown issues. However, we avoid spoiling the test result from
// the next retry.
return {
chunk
};
}
const currentlyRunning = (_this$_workerSlots$pa = this._workerSlots[parallelIndex].jobDispatcher) === null || _this$_workerSlots$pa === void 0 ? void 0 : _this$_workerSlots$pa.currentlyRunning();
if (!currentlyRunning) return {
chunk
};
return {
chunk,
test: currentlyRunning.test,
result: currentlyRunning.result
};
};
worker.on('stdOut', params => {
var _this$_reporter$onStd, _this$_reporter;
const {
chunk,
test,
result
} = handleOutput(params);
result === null || result === void 0 || result.stdout.push(chunk);
(_this$_reporter$onStd = (_this$_reporter = this._reporter).onStdOut) === null || _this$_reporter$onStd === void 0 || _this$_reporter$onStd.call(_this$_reporter, chunk, test, result);
});
worker.on('stdErr', params => {
var _this$_reporter$onStd2, _this$_reporter2;
const {
chunk,
test,
result
} = handleOutput(params);
result === null || result === void 0 || result.stderr.push(chunk);
(_this$_reporter$onStd2 = (_this$_reporter2 = this._reporter).onStdErr) === null || _this$_reporter$onStd2 === void 0 || _this$_reporter$onStd2.call(_this$_reporter2, chunk, test, result);
});
worker.on('teardownErrors', params => {
this._failureTracker.onWorkerError();
for (const error of params.fatalErrors) {
var _this$_reporter$onErr, _this$_reporter3;
(_this$_reporter$onErr = (_this$_reporter3 = this._reporter).onError) === null || _this$_reporter$onErr === void 0 || _this$_reporter$onErr.call(_this$_reporter3, error);
}
});
worker.on('exit', () => {
const producedEnv = this._producedEnvByProjectId.get(testGroup.projectId) || {};
this._producedEnvByProjectId.set(testGroup.projectId, {
...producedEnv,
...worker.producedEnv()
});
});
return worker;
}
producedEnvByProjectId() {
return this._producedEnvByProjectId;
}
async stop() {
if (this._isStopped) return;
this._isStopped = true;
await Promise.all(this._workerSlots.map(({
worker
}) => worker === null || worker === void 0 ? void 0 : worker.stop()));
this._checkFinished();
}
}
exports.Dispatcher = Dispatcher;
class JobDispatcher {
constructor(_job, _reporter, _failureTracker, _stopCallback) {
this.jobResult = new _utils.ManualPromise();
this._listeners = [];
this._failedTests = new Set();
this._failedWithNonRetriableError = new Set();
this._remainingByTestId = new Map();
this._dataByTestId = new Map();
this._parallelIndex = 0;
this._workerIndex = 0;
this._currentlyRunning = void 0;
this._job = _job;
this._reporter = _reporter;
this._failureTracker = _failureTracker;
this._stopCallback = _stopCallback;
this._remainingByTestId = new Map(this._job.tests.map(e => [e.id, e]));
}
_onTestBegin(params) {
var _this$_reporter$onTes, _this$_reporter4;
const test = this._remainingByTestId.get(params.testId);
if (!test) {
// TODO: this should never be the case, report an internal error?
return;
}
const result = test._appendTestResult();
this._dataByTestId.set(test.id, {
test,
result,
steps: new Map()
});
result.parallelIndex = this._parallelIndex;
result.workerIndex = this._workerIndex;
result.startTime = new Date(params.startWallTime);
(_this$_reporter$onTes = (_this$_reporter4 = this._reporter).onTestBegin) === null || _this$_reporter$onTes === void 0 || _this$_reporter$onTes.call(_this$_reporter4, test, result);
this._currentlyRunning = {
test,
result
};
}
_onTestEnd(params) {
if (this._failureTracker.hasReachedMaxFailures()) {
// Do not show more than one error to avoid confusion, but report
// as interrupted to indicate that we did actually start the test.
params.status = 'interrupted';
params.errors = [];
}
const data = this._dataByTestId.get(params.testId);
if (!data) {
// TODO: this should never be the case, report an internal error?
return;
}
this._dataByTestId.delete(params.testId);
this._remainingByTestId.delete(params.testId);
const {
result,
test
} = data;
result.duration = params.duration;
result.errors = params.errors;
result.error = result.errors[0];
result.status = params.status;
test.expectedStatus = params.expectedStatus;
test.annotations = params.annotations;
test.timeout = params.timeout;
const isFailure = result.status !== 'skipped' && result.status !== test.expectedStatus;
if (isFailure) this._failedTests.add(test);
if (params.hasNonRetriableError) this._addNonretriableTestAndSerialModeParents(test);
this._reportTestEnd(test, result);
this._currentlyRunning = undefined;
}
_addNonretriableTestAndSerialModeParents(test) {
this._failedWithNonRetriableError.add(test);
for (let parent = test.parent; parent; parent = parent.parent) {
if (parent._parallelMode === 'serial') this._failedWithNonRetriableError.add(parent);
}
}
_onStepBegin(params) {
var _this$_reporter$onSte, _this$_reporter5;
const data = this._dataByTestId.get(params.testId);
if (!data) {
// The test has finished, but steps are still coming. Just ignore them.
return;
}
const {
result,
steps,
test
} = data;
const parentStep = params.parentStepId ? steps.get(params.parentStepId) : undefined;
const step = {
title: params.title,
titlePath: () => {
const parentPath = (parentStep === null || parentStep === void 0 ? void 0 : parentStep.titlePath()) || [];
return [...parentPath, params.title];
},
parent: parentStep,
category: params.category,
startTime: new Date(params.wallTime),
duration: -1,
steps: [],
location: params.location
};
steps.set(params.stepId, step);
(parentStep || result).steps.push(step);
(_this$_reporter$onSte = (_this$_reporter5 = this._reporter).onStepBegin) === null || _this$_reporter$onSte === void 0 || _this$_reporter$onSte.call(_this$_reporter5, test, result, step);
}
_onStepEnd(params) {
var _this$_reporter$onSte2, _this$_reporter7;
const data = this._dataByTestId.get(params.testId);
if (!data) {
// The test has finished, but steps are still coming. Just ignore them.
return;
}
const {
result,
steps,
test
} = data;
const step = steps.get(params.stepId);
if (!step) {
var _this$_reporter$onStd3, _this$_reporter6;
(_this$_reporter$onStd3 = (_this$_reporter6 = this._reporter).onStdErr) === null || _this$_reporter$onStd3 === void 0 || _this$_reporter$onStd3.call(_this$_reporter6, 'Internal error: step end without step begin: ' + params.stepId, test, result);
return;
}
step.duration = params.wallTime - step.startTime.getTime();
if (params.error) step.error = params.error;
if (params.suggestedRebaseline) (0, _rebase.addSuggestedRebaseline)(step.location, params.suggestedRebaseline);
steps.delete(params.stepId);
(_this$_reporter$onSte2 = (_this$_reporter7 = this._reporter).onStepEnd) === null || _this$_reporter$onSte2 === void 0 || _this$_reporter$onSte2.call(_this$_reporter7, test, result, step);
}
_onAttach(params) {
const data = this._dataByTestId.get(params.testId);
if (!data) {
// The test has finished, but attachments are still coming. Just ignore them.
return;
}
const attachment = {
name: params.name,
path: params.path,
contentType: params.contentType,
body: params.body !== undefined ? Buffer.from(params.body, 'base64') : undefined
};
data.result.attachments.push(attachment);
}
_failTestWithErrors(test, errors) {
const runData = this._dataByTestId.get(test.id);
// There might be a single test that has started but has not finished yet.
let result;
if (runData) {
result = runData.result;
} else {
var _this$_reporter$onTes2, _this$_reporter8;
result = test._appendTestResult();
(_this$_reporter$onTes2 = (_this$_reporter8 = this._reporter).onTestBegin) === null || _this$_reporter$onTes2 === void 0 || _this$_reporter$onTes2.call(_this$_reporter8, test, result);
}
result.errors = [...errors];
result.error = result.errors[0];
result.status = errors.length ? 'failed' : 'skipped';
this._reportTestEnd(test, result);
this._failedTests.add(test);
}
_massSkipTestsFromRemaining(testIds, errors) {
for (const test of this._remainingByTestId.values()) {
if (!testIds.has(test.id)) continue;
if (!this._failureTracker.hasReachedMaxFailures()) {
this._failTestWithErrors(test, errors);
errors = []; // Only report errors for the first test.
}
this._remainingByTestId.delete(test.id);
}
if (errors.length) {
// We had fatal errors after all tests have passed - most likely in some teardown.
// Let's just fail the test run.
this._failureTracker.onWorkerError();
for (const error of errors) {
var _this$_reporter$onErr2, _this$_reporter9;
(_this$_reporter$onErr2 = (_this$_reporter9 = this._reporter).onError) === null || _this$_reporter$onErr2 === void 0 || _this$_reporter$onErr2.call(_this$_reporter9, error);
}
}
}
_onDone(params) {
// We won't file remaining if:
// - there are no remaining
// - we are here not because something failed
// - no unrecoverable worker error
if (!this._remainingByTestId.size && !this._failedTests.size && !params.fatalErrors.length && !params.skipTestsDueToSetupFailure.length && !params.fatalUnknownTestIds && !params.unexpectedExitError) {
this._finished({
didFail: false
});
return;
}
for (const testId of params.fatalUnknownTestIds || []) {
const test = this._remainingByTestId.get(testId);
if (test) {
this._remainingByTestId.delete(testId);
this._failTestWithErrors(test, [{
message: `Test not found in the worker process. Make sure test title does not change.`
}]);
}
}
if (params.fatalErrors.length) {
// In case of fatal errors, report first remaining test as failing with these errors,
// and all others as skipped.
this._massSkipTestsFromRemaining(new Set(this._remainingByTestId.keys()), params.fatalErrors);
}
// Handle tests that should be skipped because of the setup failure.
this._massSkipTestsFromRemaining(new Set(params.skipTestsDueToSetupFailure), []);
if (params.unexpectedExitError) {
// When worker exits during a test, we blame the test itself.
//
// The most common situation when worker exits while not running a test is:
// worker failed to require the test file (at the start) because of an exception in one of imports.
// In this case, "skip" all remaining tests, to avoid running into the same exception over and over.
if (this._currentlyRunning) this._massSkipTestsFromRemaining(new Set([this._currentlyRunning.test.id]), [params.unexpectedExitError]);else this._massSkipTestsFromRemaining(new Set(this._remainingByTestId.keys()), [params.unexpectedExitError]);
}
const retryCandidates = new Set();
const serialSuitesWithFailures = new Set();
for (const failedTest of this._failedTests) {
if (this._failedWithNonRetriableError.has(failedTest)) continue;
retryCandidates.add(failedTest);
let outermostSerialSuite;
for (let parent = failedTest.parent; parent; parent = parent.parent) {
if (parent._parallelMode === 'serial') outermostSerialSuite = parent;
}
if (outermostSerialSuite && !this._failedWithNonRetriableError.has(outermostSerialSuite)) serialSuitesWithFailures.add(outermostSerialSuite);
}
// If we have failed tests that belong to a serial suite,
// we should skip all future tests from the same serial suite.
const testsBelongingToSomeSerialSuiteWithFailures = [...this._remainingByTestId.values()].filter(test => {
let parent = test.parent;
while (parent && !serialSuitesWithFailures.has(parent)) parent = parent.parent;
return !!parent;
});
this._massSkipTestsFromRemaining(new Set(testsBelongingToSomeSerialSuiteWithFailures.map(test => test.id)), []);
for (const serialSuite of serialSuitesWithFailures) {
// Add all tests from failed serial suites for possible retry.
// These will only be retried together, because they have the same
// "retries" setting and the same number of previous runs.
serialSuite.allTests().forEach(test => retryCandidates.add(test));
}
const remaining = [...this._remainingByTestId.values()];
for (const test of retryCandidates) {
if (test.results.length < test.retries + 1) remaining.push(test);
}
// This job is over, we will schedule another one.
const newJob = remaining.length ? {
...this._job,
tests: remaining
} : undefined;
this._finished({
didFail: true,
newJob
});
}
onExit(data) {
const unexpectedExitError = data.unexpectedly ? {
message: `Error: worker process exited unexpectedly (code=${data.code}, signal=${data.signal})`
} : undefined;
this._onDone({
skipTestsDueToSetupFailure: [],
fatalErrors: [],
unexpectedExitError
});
}
_finished(result) {
_utils.eventsHelper.removeEventListeners(this._listeners);
this.jobResult.resolve(result);
}
runInWorker(worker) {
this._parallelIndex = worker.parallelIndex;
this._workerIndex = worker.workerIndex;
const runPayload = {
file: this._job.requireFile,
entries: this._job.tests.map(test => {
return {
testId: test.id,
retry: test.results.length
};
})
};
worker.runTestGroup(runPayload);
this._listeners = [_utils.eventsHelper.addEventListener(worker, 'testBegin', this._onTestBegin.bind(this)), _utils.eventsHelper.addEventListener(worker, 'testEnd', this._onTestEnd.bind(this)), _utils.eventsHelper.addEventListener(worker, 'stepBegin', this._onStepBegin.bind(this)), _utils.eventsHelper.addEventListener(worker, 'stepEnd', this._onStepEnd.bind(this)), _utils.eventsHelper.addEventListener(worker, 'attach', this._onAttach.bind(this)), _utils.eventsHelper.addEventListener(worker, 'done', this._onDone.bind(this)), _utils.eventsHelper.addEventListener(worker, 'exit', this.onExit.bind(this))];
}
skipWholeJob() {
// If all the tests in a group are skipped, we report them immediately
// without sending anything to a worker. This avoids creating unnecessary worker processes.
//
// However, if there is at least one non-skipped test in a group, we'll send
// the whole group to the worker process and report tests in the natural order,
// with skipped tests mixed in-between non-skipped. This makes
// for a better reporter experience.
const allTestsSkipped = this._job.tests.every(test => test.expectedStatus === 'skipped');
if (allTestsSkipped && !this._failureTracker.hasReachedMaxFailures()) {
for (const test of this._job.tests) {
var _this$_reporter$onTes3, _this$_reporter10;
const result = test._appendTestResult();
(_this$_reporter$onTes3 = (_this$_reporter10 = this._reporter).onTestBegin) === null || _this$_reporter$onTes3 === void 0 || _this$_reporter$onTes3.call(_this$_reporter10, test, result);
result.status = 'skipped';
this._reportTestEnd(test, result);
}
return true;
}
return false;
}
currentlyRunning() {
return this._currentlyRunning;
}
_reportTestEnd(test, result) {
var _this$_reporter$onTes4, _this$_reporter11;
(_this$_reporter$onTes4 = (_this$_reporter11 = this._reporter).onTestEnd) === null || _this$_reporter$onTes4 === void 0 || _this$_reporter$onTes4.call(_this$_reporter11, test, result);
const hadMaxFailures = this._failureTracker.hasReachedMaxFailures();
this._failureTracker.onTestEnd(test, result);
if (this._failureTracker.hasReachedMaxFailures()) {
var _this$_reporter$onErr3, _this$_reporter12;
this._stopCallback();
if (!hadMaxFailures) (_this$_reporter$onErr3 = (_this$_reporter12 = this._reporter).onError) === null || _this$_reporter$onErr3 === void 0 || _this$_reporter$onErr3.call(_this$_reporter12, {
message: _utilsBundle.colors.red(`Testing stopped early after ${this._failureTracker.maxFailures()} maximum allowed failures.`)
});
}
}
}
function chunkFromParams(params) {
if (typeof params.text === 'string') return params.text;
return Buffer.from(params.buffer, 'base64');
}

61
node_modules/playwright/lib/runner/failureTracker.js generated vendored Normal file
View File

@@ -0,0 +1,61 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FailureTracker = void 0;
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class FailureTracker {
constructor(_config) {
this._failureCount = 0;
this._hasWorkerErrors = false;
this._rootSuite = void 0;
this._config = _config;
}
onRootSuite(rootSuite) {
this._rootSuite = rootSuite;
}
onTestEnd(test, result) {
// Test is considered failing after the last retry.
if (test.outcome() === 'unexpected' && test.results.length > test.retries) ++this._failureCount;
}
onWorkerError() {
this._hasWorkerErrors = true;
}
hasReachedMaxFailures() {
return this.maxFailures() > 0 && this._failureCount >= this.maxFailures();
}
hasWorkerErrors() {
return this._hasWorkerErrors;
}
result() {
return this._hasWorkerErrors || this.hasReachedMaxFailures() || this.hasFailedTests() || this._config.cliFailOnFlakyTests && this.hasFlakyTests() ? 'failed' : 'passed';
}
hasFailedTests() {
var _this$_rootSuite;
return (_this$_rootSuite = this._rootSuite) === null || _this$_rootSuite === void 0 ? void 0 : _this$_rootSuite.allTests().some(test => !test.ok());
}
hasFlakyTests() {
var _this$_rootSuite2;
return (_this$_rootSuite2 = this._rootSuite) === null || _this$_rootSuite2 === void 0 ? void 0 : _this$_rootSuite2.allTests().some(test => test.outcome() === 'flaky');
}
maxFailures() {
return this._config.config.maxFailures;
}
}
exports.FailureTracker = FailureTracker;

66
node_modules/playwright/lib/runner/lastRun.js generated vendored Normal file
View File

@@ -0,0 +1,66 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LastRunReporter = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _projectUtils = require("./projectUtils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class LastRunReporter {
constructor(config) {
this._config = void 0;
this._lastRunFile = void 0;
this._suite = void 0;
this._config = config;
const [project] = (0, _projectUtils.filterProjects)(config.projects, config.cliProjectFilter);
if (project) this._lastRunFile = _path.default.join(project.project.outputDir, '.last-run.json');
}
async filterLastFailed() {
if (!this._lastRunFile) return;
try {
const lastRunInfo = JSON.parse(await _fs.default.promises.readFile(this._lastRunFile, 'utf8'));
this._config.testIdMatcher = id => lastRunInfo.failedTests.includes(id);
} catch {}
}
version() {
return 'v2';
}
printsToStdio() {
return false;
}
onBegin(suite) {
this._suite = suite;
}
async onEnd(result) {
var _this$_suite;
if (!this._lastRunFile || this._config.cliListOnly) return;
await _fs.default.promises.mkdir(_path.default.dirname(this._lastRunFile), {
recursive: true
});
const failedTests = (_this$_suite = this._suite) === null || _this$_suite === void 0 ? void 0 : _this$_suite.allTests().filter(t => !t.ok()).map(t => t.id);
const lastRunReport = JSON.stringify({
status: result.status,
failedTests
}, undefined, 2);
await _fs.default.promises.writeFile(this._lastRunFile, lastRunReport);
}
}
exports.LastRunReporter = LastRunReporter;

312
node_modules/playwright/lib/runner/loadUtils.js generated vendored Normal file
View File

@@ -0,0 +1,312 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.collectProjectsAndTestFiles = collectProjectsAndTestFiles;
exports.createRootSuite = createRootSuite;
exports.loadFileSuites = loadFileSuites;
exports.loadGlobalHook = loadGlobalHook;
exports.loadReporter = loadReporter;
var _path = _interopRequireDefault(require("path"));
var _loaderHost = require("./loaderHost");
var _test = require("../common/test");
var _util = require("../util");
var _projectUtils = require("./projectUtils");
var _transform = require("../transform/transform");
var _suiteUtils = require("../common/suiteUtils");
var _testGroups = require("./testGroups");
var _compilationCache = require("../transform/compilationCache");
var _utilsBundle = require("../utilsBundle");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
async function collectProjectsAndTestFiles(testRun, doNotRunTestsOutsideProjectFilter) {
const config = testRun.config;
const fsCache = new Map();
const sourceMapCache = new Map();
const cliFileMatcher = config.cliArgs.length ? (0, _util.createFileMatcherFromArguments)(config.cliArgs) : null;
// First collect all files for the projects in the command line, don't apply any file filters.
const allFilesForProject = new Map();
const filteredProjects = (0, _projectUtils.filterProjects)(config.projects, config.cliProjectFilter);
for (const project of filteredProjects) {
const files = await (0, _projectUtils.collectFilesForProject)(project, fsCache);
allFilesForProject.set(project, files);
}
// Filter files based on the file filters, eliminate the empty projects.
const filesToRunByProject = new Map();
for (const [project, files] of allFilesForProject) {
const matchedFiles = files.filter(file => {
const hasMatchingSources = sourceMapSources(file, sourceMapCache).some(source => {
if (cliFileMatcher && !cliFileMatcher(source)) return false;
return true;
});
return hasMatchingSources;
});
const filteredFiles = matchedFiles.filter(Boolean);
filesToRunByProject.set(project, filteredFiles);
}
// (Re-)add all files for dependent projects, disregard filters.
const projectClosure = (0, _projectUtils.buildProjectsClosure)([...filesToRunByProject.keys()]);
for (const [project, type] of projectClosure) {
if (type === 'dependency') {
const treatProjectAsEmpty = doNotRunTestsOutsideProjectFilter && !filteredProjects.includes(project);
const files = treatProjectAsEmpty ? [] : allFilesForProject.get(project) || (await (0, _projectUtils.collectFilesForProject)(project, fsCache));
filesToRunByProject.set(project, files);
}
}
testRun.projectFiles = filesToRunByProject;
testRun.projectSuites = new Map();
}
async function loadFileSuites(testRun, mode, errors) {
// Determine all files to load.
const config = testRun.config;
const allTestFiles = new Set();
for (const files of testRun.projectFiles.values()) files.forEach(file => allTestFiles.add(file));
// Load test files.
const fileSuiteByFile = new Map();
const loaderHost = mode === 'out-of-process' ? new _loaderHost.OutOfProcessLoaderHost(config) : new _loaderHost.InProcessLoaderHost(config);
if (await loaderHost.start(errors)) {
for (const file of allTestFiles) {
const fileSuite = await loaderHost.loadTestFile(file, errors);
fileSuiteByFile.set(file, fileSuite);
errors.push(...createDuplicateTitlesErrors(config, fileSuite));
}
await loaderHost.stop();
}
// Check that no test file imports another test file.
// Loader must be stopped first, since it populates the dependency tree.
for (const file of allTestFiles) {
for (const dependency of (0, _compilationCache.dependenciesForTestFile)(file)) {
if (allTestFiles.has(dependency)) {
const importer = _path.default.relative(config.config.rootDir, file);
const importee = _path.default.relative(config.config.rootDir, dependency);
errors.push({
message: `Error: test file "${importer}" should not import test file "${importee}"`,
location: {
file,
line: 1,
column: 1
}
});
}
}
}
// Collect file suites for each project.
for (const [project, files] of testRun.projectFiles) {
const suites = files.map(file => fileSuiteByFile.get(file)).filter(Boolean);
testRun.projectSuites.set(project, suites);
}
}
async function createRootSuite(testRun, errors, shouldFilterOnly, additionalFileMatcher) {
const config = testRun.config;
// Create root suite, where each child will be a project suite with cloned file suites inside it.
const rootSuite = new _test.Suite('', 'root');
const projectSuites = new Map();
const filteredProjectSuites = new Map();
// Filter all the projects using grep, testId, file names.
{
// Interpret cli parameters.
const cliFileFilters = (0, _util.createFileFiltersFromArguments)(config.cliArgs);
const grepMatcher = config.cliGrep ? (0, _util.createTitleMatcher)((0, _util.forceRegExp)(config.cliGrep)) : () => true;
const grepInvertMatcher = config.cliGrepInvert ? (0, _util.createTitleMatcher)((0, _util.forceRegExp)(config.cliGrepInvert)) : () => false;
const cliTitleMatcher = title => !grepInvertMatcher(title) && grepMatcher(title);
// Filter file suites for all projects.
for (const [project, fileSuites] of testRun.projectSuites) {
const projectSuite = createProjectSuite(project, fileSuites);
projectSuites.set(project, projectSuite);
const filteredProjectSuite = filterProjectSuite(projectSuite, {
cliFileFilters,
cliTitleMatcher,
testIdMatcher: config.testIdMatcher,
additionalFileMatcher
});
filteredProjectSuites.set(project, filteredProjectSuite);
}
}
if (shouldFilterOnly) {
// Create a fake root to execute the exclusive semantics across the projects.
const filteredRoot = new _test.Suite('', 'root');
for (const filteredProjectSuite of filteredProjectSuites.values()) filteredRoot._addSuite(filteredProjectSuite);
(0, _suiteUtils.filterOnly)(filteredRoot);
for (const [project, filteredProjectSuite] of filteredProjectSuites) {
if (!filteredRoot.suites.includes(filteredProjectSuite)) filteredProjectSuites.delete(project);
}
}
// Add post-filtered top-level projects to the root suite for sharding and 'only' processing.
const projectClosure = (0, _projectUtils.buildProjectsClosure)([...filteredProjectSuites.keys()], project => filteredProjectSuites.get(project)._hasTests());
for (const [project, type] of projectClosure) {
if (type === 'top-level') {
var _project$fullConfig$c;
project.project.repeatEach = (_project$fullConfig$c = project.fullConfig.configCLIOverrides.repeatEach) !== null && _project$fullConfig$c !== void 0 ? _project$fullConfig$c : project.project.repeatEach;
rootSuite._addSuite(buildProjectSuite(project, filteredProjectSuites.get(project)));
}
}
// Complain about only.
if (config.config.forbidOnly) {
const onlyTestsAndSuites = rootSuite._getOnlyItems();
if (onlyTestsAndSuites.length > 0) {
const configFilePath = config.config.configFile ? _path.default.relative(config.config.rootDir, config.config.configFile) : undefined;
errors.push(...createForbidOnlyErrors(onlyTestsAndSuites, config.configCLIOverrides.forbidOnly, configFilePath));
}
}
// Shard only the top-level projects.
if (config.config.shard) {
// Create test groups for top-level projects.
const testGroups = [];
for (const projectSuite of rootSuite.suites) {
// Split beforeAll-grouped tests into "config.shard.total" groups when needed.
// Later on, we'll re-split them between workers by using "config.workers" instead.
testGroups.push(...(0, _testGroups.createTestGroups)(projectSuite, config.config.shard.total));
}
// Shard test groups.
const testGroupsInThisShard = (0, _testGroups.filterForShard)(config.config.shard, testGroups);
const testsInThisShard = new Set();
for (const group of testGroupsInThisShard) {
for (const test of group.tests) testsInThisShard.add(test);
}
// Update project suites, removing empty ones.
(0, _suiteUtils.filterTestsRemoveEmptySuites)(rootSuite, test => testsInThisShard.has(test));
}
// Now prepend dependency projects without filtration.
{
// Filtering 'only' and sharding might have reduced the number of top-level projects.
// Build the project closure to only include dependencies that are still needed.
const projectClosure = new Map((0, _projectUtils.buildProjectsClosure)(rootSuite.suites.map(suite => suite._fullProject)));
// Clone file suites for dependency projects.
for (const [project, level] of projectClosure.entries()) {
if (level === 'dependency') rootSuite._prependSuite(buildProjectSuite(project, projectSuites.get(project)));
}
}
return rootSuite;
}
function createProjectSuite(project, fileSuites) {
const projectSuite = new _test.Suite(project.project.name, 'project');
for (const fileSuite of fileSuites) projectSuite._addSuite((0, _suiteUtils.bindFileSuiteToProject)(project, fileSuite));
const grepMatcher = (0, _util.createTitleMatcher)(project.project.grep);
const grepInvertMatcher = project.project.grepInvert ? (0, _util.createTitleMatcher)(project.project.grepInvert) : null;
(0, _suiteUtils.filterTestsRemoveEmptySuites)(projectSuite, test => {
const grepTitle = test._grepTitle();
if (grepInvertMatcher !== null && grepInvertMatcher !== void 0 && grepInvertMatcher(grepTitle)) return false;
return grepMatcher(grepTitle);
});
return projectSuite;
}
function filterProjectSuite(projectSuite, options) {
// Fast path.
if (!options.cliFileFilters.length && !options.cliTitleMatcher && !options.testIdMatcher && !options.additionalFileMatcher) return projectSuite;
const result = projectSuite._deepClone();
if (options.cliFileFilters.length) (0, _suiteUtils.filterByFocusedLine)(result, options.cliFileFilters);
if (options.testIdMatcher) (0, _suiteUtils.filterByTestIds)(result, options.testIdMatcher);
(0, _suiteUtils.filterTestsRemoveEmptySuites)(result, test => {
if (options.cliTitleMatcher && !options.cliTitleMatcher(test._grepTitle())) return false;
if (options.additionalFileMatcher && !options.additionalFileMatcher(test.location.file)) return false;
return true;
});
return result;
}
function buildProjectSuite(project, projectSuite) {
const result = new _test.Suite(project.project.name, 'project');
result._fullProject = project;
if (project.fullyParallel) result._parallelMode = 'parallel';
for (const fileSuite of projectSuite.suites) {
// Fast path for the repeatEach = 0.
result._addSuite(fileSuite);
for (let repeatEachIndex = 1; repeatEachIndex < project.project.repeatEach; repeatEachIndex++) {
const clone = fileSuite._deepClone();
(0, _suiteUtils.applyRepeatEachIndex)(project, clone, repeatEachIndex);
result._addSuite(clone);
}
}
return result;
}
function createForbidOnlyErrors(onlyTestsAndSuites, forbidOnlyCLIFlag, configFilePath) {
const errors = [];
for (const testOrSuite of onlyTestsAndSuites) {
// Skip root and file.
const title = testOrSuite.titlePath().slice(2).join(' ');
const configFilePathName = configFilePath ? `'${configFilePath}'` : 'the Playwright configuration file';
const forbidOnlySource = forbidOnlyCLIFlag ? `'--forbid-only' CLI flag` : `'forbidOnly' option in ${configFilePathName}`;
const error = {
message: `Error: item focused with '.only' is not allowed due to the ${forbidOnlySource}: "${title}"`,
location: testOrSuite.location
};
errors.push(error);
}
return errors;
}
function createDuplicateTitlesErrors(config, fileSuite) {
const errors = [];
const testsByFullTitle = new Map();
for (const test of fileSuite.allTests()) {
const fullTitle = test.titlePath().slice(1).join(' ');
const existingTest = testsByFullTitle.get(fullTitle);
if (existingTest) {
const error = {
message: `Error: duplicate test title "${fullTitle}", first declared in ${buildItemLocation(config.config.rootDir, existingTest)}`,
location: test.location
};
errors.push(error);
}
testsByFullTitle.set(fullTitle, test);
}
return errors;
}
function buildItemLocation(rootDir, testOrSuite) {
if (!testOrSuite.location) return '';
return `${_path.default.relative(rootDir, testOrSuite.location.file)}:${testOrSuite.location.line}`;
}
async function requireOrImportDefaultFunction(file, expectConstructor) {
let func = await (0, _transform.requireOrImport)(file);
if (func && typeof func === 'object' && 'default' in func) func = func['default'];
if (typeof func !== 'function') throw (0, _util.errorWithFile)(file, `file must export a single ${expectConstructor ? 'class' : 'function'}.`);
return func;
}
function loadGlobalHook(config, file) {
return requireOrImportDefaultFunction(_path.default.resolve(config.config.rootDir, file), false);
}
function loadReporter(config, file) {
return requireOrImportDefaultFunction(config ? _path.default.resolve(config.config.rootDir, file) : file, true);
}
function sourceMapSources(file, cache) {
let sources = [file];
if (!file.endsWith('.js')) return sources;
if (cache.has(file)) return cache.get(file);
try {
const sourceMap = _utilsBundle.sourceMapSupport.retrieveSourceMap(file);
const sourceMapData = typeof (sourceMap === null || sourceMap === void 0 ? void 0 : sourceMap.map) === 'string' ? JSON.parse(sourceMap.map) : sourceMap === null || sourceMap === void 0 ? void 0 : sourceMap.map;
if (sourceMapData !== null && sourceMapData !== void 0 && sourceMapData.sources) sources = sourceMapData.sources.map(source => _path.default.resolve(_path.default.dirname(file), source));
} finally {
cache.set(file, sources);
return sources;
}
}

85
node_modules/playwright/lib/runner/loaderHost.js generated vendored Normal file
View File

@@ -0,0 +1,85 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.OutOfProcessLoaderHost = exports.InProcessLoaderHost = void 0;
var _ipc = require("../common/ipc");
var _processHost = require("./processHost");
var _test = require("../common/test");
var _testLoader = require("../common/testLoader");
var _poolBuilder = require("../common/poolBuilder");
var _compilationCache = require("../transform/compilationCache");
var _esmLoaderHost = require("../common/esmLoaderHost");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class InProcessLoaderHost {
constructor(config) {
this._config = void 0;
this._poolBuilder = void 0;
this._config = config;
this._poolBuilder = _poolBuilder.PoolBuilder.createForLoader();
}
async start(errors) {
return true;
}
async loadTestFile(file, testErrors) {
const result = await (0, _testLoader.loadTestFile)(file, this._config.config.rootDir, testErrors);
this._poolBuilder.buildPools(result, testErrors);
return result;
}
async stop() {
await (0, _esmLoaderHost.incorporateCompilationCache)();
}
}
exports.InProcessLoaderHost = InProcessLoaderHost;
class OutOfProcessLoaderHost {
constructor(config) {
this._config = void 0;
this._processHost = void 0;
this._config = config;
this._processHost = new _processHost.ProcessHost(require.resolve('../loader/loaderMain.js'), 'loader', {});
}
async start(errors) {
const startError = await this._processHost.startRunner((0, _ipc.serializeConfig)(this._config, false));
if (startError) {
errors.push({
message: `Test loader process failed to start with code "${startError.code}" and signal "${startError.signal}"`
});
return false;
}
return true;
}
async loadTestFile(file, testErrors) {
const result = await this._processHost.sendMessage({
method: 'loadTestFile',
params: {
file
}
});
testErrors.push(...result.testErrors);
return _test.Suite._deepParse(result.fileSuite);
}
async stop() {
const result = await this._processHost.sendMessage({
method: 'getCompilationCacheFromLoader'
});
(0, _compilationCache.addToCompilationCache)(result);
await this._processHost.stop();
}
}
exports.OutOfProcessLoaderHost = OutOfProcessLoaderHost;

175
node_modules/playwright/lib/runner/processHost.js generated vendored Normal file
View File

@@ -0,0 +1,175 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ProcessHost = void 0;
var _child_process = _interopRequireDefault(require("child_process"));
var _events = require("events");
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _esmUtils = require("../transform/esmUtils");
var _utils = require("playwright-core/lib/utils");
var _esmLoaderHost = require("../common/esmLoaderHost");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ProcessHost extends _events.EventEmitter {
constructor(runnerScript, processName, env) {
super();
this.process = void 0;
this._didSendStop = false;
this._processDidExit = false;
this._didExitAndRanOnExit = false;
this._runnerScript = void 0;
this._lastMessageId = 0;
this._callbacks = new Map();
this._processName = void 0;
this._producedEnv = {};
this._extraEnv = void 0;
this._runnerScript = runnerScript;
this._processName = processName;
this._extraEnv = env;
}
async startRunner(runnerParams, options = {}) {
var _this$process$stdout, _this$process$stderr;
(0, _utils.assert)(!this.process, 'Internal error: starting the same process twice');
this.process = _child_process.default.fork(require.resolve('../common/process'), {
detached: false,
env: {
...process.env,
...this._extraEnv,
...(_esmLoaderHost.esmLoaderRegistered ? {
PW_TS_ESM_LOADER_ON: '1'
} : {})
},
stdio: ['ignore', options.onStdOut ? 'pipe' : 'inherit', options.onStdErr && !process.env.PW_RUNNER_DEBUG ? 'pipe' : 'inherit', 'ipc'],
...(process.env.PW_TS_ESM_LEGACY_LOADER_ON ? {
execArgv: (0, _esmUtils.execArgvWithExperimentalLoaderOptions)()
} : {})
});
this.process.on('exit', async (code, signal) => {
this._processDidExit = true;
await this.onExit();
this._didExitAndRanOnExit = true;
this.emit('exit', {
unexpectedly: !this._didSendStop,
code,
signal
});
});
this.process.on('error', e => {}); // do not yell at a send to dead process.
this.process.on('message', message => {
if (_utilsBundle.debug.enabled('pw:test:protocol')) (0, _utilsBundle.debug)('pw:test:protocol')('◀ RECV ' + JSON.stringify(message));
if (message.method === '__env_produced__') {
const producedEnv = message.params;
this._producedEnv = Object.fromEntries(producedEnv.map(e => {
var _e$;
return [e[0], (_e$ = e[1]) !== null && _e$ !== void 0 ? _e$ : undefined];
}));
} else if (message.method === '__dispatch__') {
const {
id,
error,
method,
params,
result
} = message.params;
if (id && this._callbacks.has(id)) {
const {
resolve,
reject
} = this._callbacks.get(id);
this._callbacks.delete(id);
if (error) {
const errorObject = new Error(error.message);
errorObject.stack = error.stack;
reject(errorObject);
} else {
resolve(result);
}
} else {
this.emit(method, params);
}
} else {
this.emit(message.method, message.params);
}
});
if (options.onStdOut) (_this$process$stdout = this.process.stdout) === null || _this$process$stdout === void 0 || _this$process$stdout.on('data', options.onStdOut);
if (options.onStdErr) (_this$process$stderr = this.process.stderr) === null || _this$process$stderr === void 0 || _this$process$stderr.on('data', options.onStdErr);
const error = await new Promise(resolve => {
this.process.once('exit', (code, signal) => resolve({
unexpectedly: true,
code,
signal
}));
this.once('ready', () => resolve(undefined));
});
if (error) return error;
const processParams = {
processName: this._processName
};
this.send({
method: '__init__',
params: {
processParams,
runnerScript: this._runnerScript,
runnerParams
}
});
}
sendMessage(message) {
const id = ++this._lastMessageId;
this.send({
method: '__dispatch__',
params: {
id,
...message
}
});
return new Promise((resolve, reject) => {
this._callbacks.set(id, {
resolve,
reject
});
});
}
sendMessageNoReply(message) {
this.sendMessage(message).catch(() => {});
}
async onExit() {}
async stop() {
if (!this._processDidExit && !this._didSendStop) {
this.send({
method: '__stop__'
});
this._didSendStop = true;
}
if (!this._didExitAndRanOnExit) await new Promise(f => this.once('exit', f));
}
didSendStop() {
return this._didSendStop;
}
producedEnv() {
return this._producedEnv;
}
send(message) {
var _this$process;
if (_utilsBundle.debug.enabled('pw:test:protocol')) (0, _utilsBundle.debug)('pw:test:protocol')('SEND ► ' + JSON.stringify(message));
(_this$process = this.process) === null || _this$process === void 0 || _this$process.send(message);
}
}
exports.ProcessHost = ProcessHost;

203
node_modules/playwright/lib/runner/projectUtils.js generated vendored Normal file
View File

@@ -0,0 +1,203 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.buildDependentProjects = buildDependentProjects;
exports.buildProjectsClosure = buildProjectsClosure;
exports.buildTeardownToSetupsMap = buildTeardownToSetupsMap;
exports.collectFilesForProject = collectFilesForProject;
exports.filterProjects = filterProjects;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _utils = require("playwright-core/lib/utils");
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _util = require("util");
var _util2 = require("../util");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const readFileAsync = (0, _util.promisify)(_fs.default.readFile);
const readDirAsync = (0, _util.promisify)(_fs.default.readdir);
function wildcardPatternToRegExp(pattern) {
return new RegExp('^' + pattern.split('*').map(_utils.escapeRegExp).join('.*') + '$', 'ig');
}
function filterProjects(projects, projectNames) {
if (!projectNames) return [...projects];
const projectNamesToFind = new Set();
const unmatchedProjectNames = new Map();
const patterns = new Set();
for (const name of projectNames) {
const lowerCaseName = name.toLocaleLowerCase();
if (lowerCaseName.includes('*')) {
patterns.add(wildcardPatternToRegExp(lowerCaseName));
} else {
projectNamesToFind.add(lowerCaseName);
unmatchedProjectNames.set(lowerCaseName, name);
}
}
const result = projects.filter(project => {
const lowerCaseName = project.project.name.toLocaleLowerCase();
if (projectNamesToFind.has(lowerCaseName)) {
unmatchedProjectNames.delete(lowerCaseName);
return true;
}
for (const regex of patterns) {
regex.lastIndex = 0;
if (regex.test(lowerCaseName)) return true;
}
return false;
});
if (unmatchedProjectNames.size) {
const unknownProjectNames = Array.from(unmatchedProjectNames.values()).map(n => `"${n}"`).join(', ');
throw new Error(`Project(s) ${unknownProjectNames} not found. Available projects: ${projects.map(p => `"${p.project.name}"`).join(', ')}`);
}
if (!result.length) {
const allProjects = projects.map(p => `"${p.project.name}"`).join(', ');
throw new Error(`No projects matched. Available projects: ${allProjects}`);
}
return result;
}
function buildTeardownToSetupsMap(projects) {
const result = new Map();
for (const project of projects) {
if (project.teardown) {
const setups = result.get(project.teardown) || [];
setups.push(project);
result.set(project.teardown, setups);
}
}
return result;
}
function buildProjectsClosure(projects, hasTests) {
const result = new Map();
const visit = (depth, project) => {
if (depth > 100) {
const error = new Error('Circular dependency detected between projects.');
error.stack = '';
throw error;
}
if (depth === 0 && hasTests && !hasTests(project)) return;
if (result.get(project) !== 'dependency') result.set(project, depth ? 'dependency' : 'top-level');
for (const dep of project.deps) visit(depth + 1, dep);
if (project.teardown) visit(depth + 1, project.teardown);
};
for (const p of projects) visit(0, p);
return result;
}
function buildDependentProjects(forProjects, projects) {
const reverseDeps = new Map(projects.map(p => [p, []]));
for (const project of projects) {
for (const dep of project.deps) reverseDeps.get(dep).push(project);
}
const result = new Set();
const visit = (depth, project) => {
if (depth > 100) {
const error = new Error('Circular dependency detected between projects.');
error.stack = '';
throw error;
}
result.add(project);
for (const reverseDep of reverseDeps.get(project)) visit(depth + 1, reverseDep);
if (project.teardown) visit(depth + 1, project.teardown);
};
for (const forProject of forProjects) visit(0, forProject);
return result;
}
async function collectFilesForProject(project, fsCache = new Map()) {
const extensions = new Set(['.js', '.ts', '.mjs', '.mts', '.cjs', '.cts', '.jsx', '.tsx', '.mjsx', '.mtsx', '.cjsx', '.ctsx']);
const testFileExtension = file => extensions.has(_path.default.extname(file));
const allFiles = await cachedCollectFiles(project.project.testDir, project.respectGitIgnore, fsCache);
const testMatch = (0, _util2.createFileMatcher)(project.project.testMatch);
const testIgnore = (0, _util2.createFileMatcher)(project.project.testIgnore);
const testFiles = allFiles.filter(file => {
if (!testFileExtension(file)) return false;
const isTest = !testIgnore(file) && testMatch(file);
if (!isTest) return false;
return true;
});
return testFiles;
}
async function cachedCollectFiles(testDir, respectGitIgnore, fsCache) {
const key = testDir + ':' + respectGitIgnore;
let result = fsCache.get(key);
if (!result) {
result = await collectFiles(testDir, respectGitIgnore);
fsCache.set(key, result);
}
return result;
}
async function collectFiles(testDir, respectGitIgnore) {
if (!_fs.default.existsSync(testDir)) return [];
if (!_fs.default.statSync(testDir).isDirectory()) return [];
const checkIgnores = (entryPath, rules, isDirectory, parentStatus) => {
let status = parentStatus;
for (const rule of rules) {
const ruleIncludes = rule.negate;
if (status === 'included' === ruleIncludes) continue;
const relative = _path.default.relative(rule.dir, entryPath);
if (rule.match('/' + relative) || rule.match(relative)) {
// Matches "/dir/file" or "dir/file"
status = ruleIncludes ? 'included' : 'ignored';
} else if (isDirectory && (rule.match('/' + relative + '/') || rule.match(relative + '/'))) {
// Matches "/dir/subdir/" or "dir/subdir/" for directories.
status = ruleIncludes ? 'included' : 'ignored';
} else if (isDirectory && ruleIncludes && (rule.match('/' + relative, true) || rule.match(relative, true))) {
// Matches "/dir/donotskip/" when "/dir" is excluded, but "!/dir/donotskip/file" is included.
status = 'ignored-but-recurse';
}
}
return status;
};
const files = [];
const visit = async (dir, rules, status) => {
const entries = await readDirAsync(dir, {
withFileTypes: true
});
entries.sort((a, b) => a.name.localeCompare(b.name));
if (respectGitIgnore) {
const gitignore = entries.find(e => e.isFile() && e.name === '.gitignore');
if (gitignore) {
const content = await readFileAsync(_path.default.join(dir, gitignore.name), 'utf8');
const newRules = content.split(/\r?\n/).map(s => {
s = s.trim();
if (!s) return;
// Use flipNegate, because we handle negation ourselves.
const rule = new _utilsBundle.minimatch.Minimatch(s, {
matchBase: true,
dot: true,
flipNegate: true
});
if (rule.comment) return;
rule.dir = dir;
return rule;
}).filter(rule => !!rule);
rules = [...rules, ...newRules];
}
}
for (const entry of entries) {
if (entry.name === '.' || entry.name === '..') continue;
if (entry.isFile() && entry.name === '.gitignore') continue;
if (entry.isDirectory() && entry.name === 'node_modules') continue;
const entryPath = _path.default.join(dir, entry.name);
const entryStatus = checkIgnores(entryPath, rules, entry.isDirectory(), status);
if (entry.isDirectory() && entryStatus !== 'ignored') await visit(entryPath, rules, entryStatus);else if (entry.isFile() && entryStatus === 'included') files.push(entryPath);
}
};
await visit(testDir, [], 'included');
return files;
}

100
node_modules/playwright/lib/runner/rebase.js generated vendored Normal file
View File

@@ -0,0 +1,100 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.addSuggestedRebaseline = addSuggestedRebaseline;
exports.applySuggestedRebaselines = applySuggestedRebaselines;
var _path = _interopRequireDefault(require("path"));
var _fs = _interopRequireDefault(require("fs"));
var _babelBundle = require("../transform/babelBundle");
var _utils = require("playwright-core/lib/utils");
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _projectUtils = require("./projectUtils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const t = _babelBundle.types;
const suggestedRebaselines = new _utils.MultiMap();
function addSuggestedRebaseline(location, suggestedRebaseline) {
suggestedRebaselines.set(location.file, {
location,
code: suggestedRebaseline
});
}
async function applySuggestedRebaselines(config, reporter) {
if (config.config.updateSnapshots !== 'all' && config.config.updateSnapshots !== 'missing') return;
if (!suggestedRebaselines.size) return;
const [project] = (0, _projectUtils.filterProjects)(config.projects, config.cliProjectFilter);
if (!project) return;
const patches = [];
const files = [];
for (const fileName of [...suggestedRebaselines.keys()].sort()) {
const source = await _fs.default.promises.readFile(fileName, 'utf8');
const lines = source.split('\n');
const replacements = suggestedRebaselines.get(fileName);
const fileNode = (0, _babelBundle.babelParse)(source, fileName, true);
const ranges = [];
(0, _babelBundle.traverse)(fileNode, {
CallExpression: path => {
const node = path.node;
if (node.arguments.length !== 1) return;
if (!t.isMemberExpression(node.callee)) return;
const argument = node.arguments[0];
if (!t.isStringLiteral(argument) && !t.isTemplateLiteral(argument)) return;
const matcher = node.callee.property;
for (const replacement of replacements) {
// In Babel, rows are 1-based, columns are 0-based.
if (matcher.loc.start.line !== replacement.location.line) continue;
if (matcher.loc.start.column + 1 !== replacement.location.column) continue;
const indent = lines[matcher.loc.start.line - 1].match(/^\s*/)[0];
const newText = replacement.code.replace(/\{indent\}/g, indent);
ranges.push({
start: matcher.start,
end: node.end,
oldText: source.substring(matcher.start, node.end),
newText
});
// We can have multiple, hopefully equal, replacements for the same location,
// for example when a single test runs multiple times because of projects or retries.
// Do not apply multiple replacements for the same assertion.
break;
}
}
});
ranges.sort((a, b) => b.start - a.start);
let result = source;
for (const range of ranges) result = result.substring(0, range.start) + range.newText + result.substring(range.end);
const relativeName = _path.default.relative(process.cwd(), fileName);
files.push(relativeName);
patches.push(createPatch(relativeName, source, result));
}
const patchFile = _path.default.join(project.project.outputDir, 'rebaselines.patch');
await _fs.default.promises.mkdir(_path.default.dirname(patchFile), {
recursive: true
});
await _fs.default.promises.writeFile(patchFile, patches.join('\n'));
const fileList = files.map(file => ' ' + _utilsBundle.colors.dim(file)).join('\n');
reporter.onStdErr(`\nNew baselines created for:\n\n${fileList}\n\n ` + _utilsBundle.colors.cyan('git apply ' + _path.default.relative(process.cwd(), patchFile)) + '\n');
}
function createPatch(fileName, before, after) {
const file = fileName.replace(/\\/g, '/');
const text = _utilsBundle.diff.createPatch(file, before, after, undefined, undefined, {
context: 3
});
return ['diff --git a/' + file + ' b/' + file, '--- a/' + file, '+++ b/' + file, ...text.split('\n').slice(4)].join('\n');
}

152
node_modules/playwright/lib/runner/reporters.js generated vendored Normal file
View File

@@ -0,0 +1,152 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createErrorCollectingReporter = createErrorCollectingReporter;
exports.createReporterForTestServer = createReporterForTestServer;
exports.createReporters = createReporters;
var _path = _interopRequireDefault(require("path"));
var _base = require("../reporters/base");
var _dot = _interopRequireDefault(require("../reporters/dot"));
var _empty = _interopRequireDefault(require("../reporters/empty"));
var _github = _interopRequireDefault(require("../reporters/github"));
var _html = _interopRequireDefault(require("../reporters/html"));
var _json = _interopRequireDefault(require("../reporters/json"));
var _junit = _interopRequireDefault(require("../reporters/junit"));
var _line = _interopRequireDefault(require("../reporters/line"));
var _list = _interopRequireDefault(require("../reporters/list"));
var _loadUtils = require("./loadUtils");
var _blob = require("../reporters/blob");
var _reporterV = require("../reporters/reporterV2");
var _utils = require("playwright-core/lib/utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
async function createReporters(config, mode, isTestServer, descriptions) {
var _descriptions;
const defaultReporters = {
blob: _blob.BlobReporter,
dot: mode === 'list' ? ListModeReporter : _dot.default,
line: mode === 'list' ? ListModeReporter : _line.default,
list: mode === 'list' ? ListModeReporter : _list.default,
github: _github.default,
json: _json.default,
junit: _junit.default,
null: _empty.default,
html: _html.default
};
const reporters = [];
(_descriptions = descriptions) !== null && _descriptions !== void 0 ? _descriptions : descriptions = config.config.reporter;
if (config.configCLIOverrides.additionalReporters) descriptions = [...descriptions, ...config.configCLIOverrides.additionalReporters];
const runOptions = reporterOptions(config, mode, isTestServer);
for (const r of descriptions) {
const [name, arg] = r;
const options = {
...runOptions,
...arg
};
if (name in defaultReporters) {
reporters.push(new defaultReporters[name](options));
} else {
const reporterConstructor = await (0, _loadUtils.loadReporter)(config, name);
reporters.push((0, _reporterV.wrapReporterAsV2)(new reporterConstructor(options)));
}
}
if (process.env.PW_TEST_REPORTER) {
const reporterConstructor = await (0, _loadUtils.loadReporter)(config, process.env.PW_TEST_REPORTER);
reporters.push((0, _reporterV.wrapReporterAsV2)(new reporterConstructor(runOptions)));
}
const someReporterPrintsToStdio = reporters.some(r => r.printsToStdio ? r.printsToStdio() : true);
if (reporters.length && !someReporterPrintsToStdio) {
// Add a line/dot/list-mode reporter for convenience.
// Important to put it first, just in case some other reporter stalls onEnd.
if (mode === 'list') reporters.unshift(new ListModeReporter());else if (mode !== 'merge') reporters.unshift(!process.env.CI ? new _line.default({
omitFailures: true
}) : new _dot.default());
}
return reporters;
}
async function createReporterForTestServer(file, messageSink) {
const reporterConstructor = await (0, _loadUtils.loadReporter)(null, file);
return (0, _reporterV.wrapReporterAsV2)(new reporterConstructor({
_send: messageSink
}));
}
function createErrorCollectingReporter(writeToConsole) {
const errors = [];
return {
version: () => 'v2',
onError(error) {
errors.push(error);
if (writeToConsole) process.stdout.write((0, _base.formatError)(error, _base.colors.enabled).message + '\n');
},
errors: () => errors
};
}
function reporterOptions(config, mode, isTestServer) {
return {
configDir: config.configDir,
_mode: mode,
_isTestServer: isTestServer,
_commandHash: computeCommandHash(config)
};
}
function computeCommandHash(config) {
const parts = [];
// Include project names for readability.
if (config.cliProjectFilter) parts.push(...config.cliProjectFilter);
const command = {};
if (config.cliArgs.length) command.cliArgs = config.cliArgs;
if (config.cliGrep) command.cliGrep = config.cliGrep;
if (config.cliGrepInvert) command.cliGrepInvert = config.cliGrepInvert;
if (config.cliOnlyChanged) command.cliOnlyChanged = config.cliOnlyChanged;
if (Object.keys(command).length) parts.push((0, _utils.calculateSha1)(JSON.stringify(command)).substring(0, 7));
return parts.join('-');
}
class ListModeReporter {
constructor() {
this.config = void 0;
}
version() {
return 'v2';
}
onConfigure(config) {
this.config = config;
}
onBegin(suite) {
// eslint-disable-next-line no-console
console.log(`Listing tests:`);
const tests = suite.allTests();
const files = new Set();
for (const test of tests) {
// root, project, file, ...describes, test
const [, projectName,, ...titles] = test.titlePath();
const location = `${_path.default.relative(this.config.rootDir, test.location.file)}:${test.location.line}:${test.location.column}`;
const projectTitle = projectName ? `[${projectName}] ` : '';
// eslint-disable-next-line no-console
console.log(` ${projectTitle}${location} ${titles.join(' ')}`);
files.add(test.location.file);
}
// eslint-disable-next-line no-console
console.log(`Total: ${tests.length} ${tests.length === 1 ? 'test' : 'tests'} in ${files.size} ${files.size === 1 ? 'file' : 'files'}`);
}
onError(error) {
// eslint-disable-next-line no-console
console.error('\n' + (0, _base.formatError)(error, false).message);
}
}

118
node_modules/playwright/lib/runner/runner.js generated vendored Normal file
View File

@@ -0,0 +1,118 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Runner = void 0;
var _webServerPlugin = require("../plugins/webServerPlugin");
var _projectUtils = require("./projectUtils");
var _reporters = require("./reporters");
var _tasks = require("./tasks");
var _compilationCache = require("../transform/compilationCache");
var _internalReporter = require("../reporters/internalReporter");
var _lastRun = require("./lastRun");
/**
* Copyright 2019 Google Inc. All rights reserved.
* Modifications copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Runner {
constructor(config) {
this._config = void 0;
this._config = config;
}
async listTestFiles(projectNames) {
const projects = (0, _projectUtils.filterProjects)(this._config.projects, projectNames);
const report = {
projects: []
};
for (const project of projects) {
report.projects.push({
name: project.project.name,
testDir: project.project.testDir,
use: {
testIdAttribute: project.project.use.testIdAttribute
},
files: await (0, _projectUtils.collectFilesForProject)(project)
});
}
return report;
}
async runAllTests() {
const config = this._config;
const listOnly = config.cliListOnly;
// Legacy webServer support.
(0, _webServerPlugin.webServerPluginsForConfig)(config).forEach(p => config.plugins.push({
factory: p
}));
const reporters = await (0, _reporters.createReporters)(config, listOnly ? 'list' : 'test', false);
const lastRun = new _lastRun.LastRunReporter(config);
if (config.cliLastFailed) await lastRun.filterLastFailed();
const reporter = new _internalReporter.InternalReporter([...reporters, lastRun]);
const tasks = listOnly ? [(0, _tasks.createLoadTask)('in-process', {
failOnLoadErrors: true,
filterOnly: false
}), (0, _tasks.createReportBeginTask)()] : [(0, _tasks.createApplyRebaselinesTask)(), ...(0, _tasks.createGlobalSetupTasks)(config), (0, _tasks.createLoadTask)('in-process', {
filterOnly: true,
failOnLoadErrors: true
}), ...(0, _tasks.createRunTestsTasks)(config)];
const status = await (0, _tasks.runTasks)(new _tasks.TestRun(config, reporter), tasks, config.config.globalTimeout);
// Calling process.exit() might truncate large stdout/stderr output.
// See https://github.com/nodejs/node/issues/6456.
// See https://github.com/nodejs/node/issues/12921
await new Promise(resolve => process.stdout.write('', () => resolve()));
await new Promise(resolve => process.stderr.write('', () => resolve()));
return status;
}
async findRelatedTestFiles(files) {
const errorReporter = (0, _reporters.createErrorCollectingReporter)();
const reporter = new _internalReporter.InternalReporter([errorReporter]);
const status = await (0, _tasks.runTasks)(new _tasks.TestRun(this._config, reporter), [...(0, _tasks.createPluginSetupTasks)(this._config), (0, _tasks.createLoadTask)('in-process', {
failOnLoadErrors: true,
filterOnly: false,
populateDependencies: true
})]);
if (status !== 'passed') return {
errors: errorReporter.errors(),
testFiles: []
};
return {
testFiles: (0, _compilationCache.affectedTestFiles)(files)
};
}
async runDevServer() {
const reporter = new _internalReporter.InternalReporter([(0, _reporters.createErrorCollectingReporter)(true)]);
const status = await (0, _tasks.runTasks)(new _tasks.TestRun(this._config, reporter), [...(0, _tasks.createPluginSetupTasks)(this._config), (0, _tasks.createLoadTask)('in-process', {
failOnLoadErrors: true,
filterOnly: false
}), (0, _tasks.createStartDevServerTask)(), {
title: 'wait until interrupted',
setup: async () => new Promise(() => {})
}]);
return {
status
};
}
async clearCache() {
const reporter = new _internalReporter.InternalReporter([(0, _reporters.createErrorCollectingReporter)(true)]);
const status = await (0, _tasks.runTasks)(new _tasks.TestRun(this._config, reporter), [...(0, _tasks.createPluginSetupTasks)(this._config), (0, _tasks.createClearCacheTask)(this._config)]);
return {
status
};
}
}
exports.Runner = Runner;

100
node_modules/playwright/lib/runner/sigIntWatcher.js generated vendored Normal file
View File

@@ -0,0 +1,100 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SigIntWatcher = void 0;
var _class2;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class SigIntWatcher {
constructor() {
this._hadSignal = false;
this._sigintPromise = void 0;
this._sigintHandler = void 0;
let sigintCallback;
this._sigintPromise = new Promise(f => sigintCallback = f);
this._sigintHandler = () => {
FixedNodeSIGINTHandler.off(this._sigintHandler);
this._hadSignal = true;
sigintCallback();
};
FixedNodeSIGINTHandler.on(this._sigintHandler);
}
promise() {
return this._sigintPromise;
}
hadSignal() {
return this._hadSignal;
}
disarm() {
FixedNodeSIGINTHandler.off(this._sigintHandler);
}
}
// NPM/NPX will send us duplicate SIGINT signals, so we need to ignore them.
exports.SigIntWatcher = SigIntWatcher;
class FixedNodeSIGINTHandler {
static _install() {
if (!this._handlerInstalled) {
this._handlerInstalled = true;
process.on('SIGINT', this._dispatch);
}
}
static _uninstall() {
if (this._handlerInstalled) {
this._handlerInstalled = false;
process.off('SIGINT', this._dispatch);
}
}
static on(handler) {
this._handlers.push(handler);
if (this._handlers.length === 1) this._install();
}
static off(handler) {
this._handlers = this._handlers.filter(h => h !== handler);
if (!this._ignoreNextSIGINTs && !this._handlers.length) this._uninstall();
}
}
_class2 = FixedNodeSIGINTHandler;
FixedNodeSIGINTHandler._handlers = [];
FixedNodeSIGINTHandler._ignoreNextSIGINTs = false;
FixedNodeSIGINTHandler._handlerInstalled = false;
FixedNodeSIGINTHandler._dispatch = () => {
if (_class2._ignoreNextSIGINTs) return;
_class2._ignoreNextSIGINTs = true;
setTimeout(() => {
_class2._ignoreNextSIGINTs = false;
// We remove the handler so that second Ctrl+C immediately kills the process
// via the default sigint handler. This is handy in the case where our shutdown
// takes a lot of time or is buggy.
//
// When running through NPM we might get multiple SIGINT signals
// for a single Ctrl+C - this is an NPM bug present since NPM v6+.
// https://github.com/npm/cli/issues/1591
// https://github.com/npm/cli/issues/2124
// https://github.com/npm/cli/issues/5021
//
// Therefore, removing the handler too soon will just kill the process
// with default handler without printing the results.
// We work around this by giving NPM 1000ms to send us duplicate signals.
// The side effect is that slow shutdown or bug in our process will force
// the user to hit Ctrl+C again after at least a second.
if (!_class2._handlers.length) _class2._uninstall();
}, 1000);
for (const handler of _class2._handlers) handler();
};

136
node_modules/playwright/lib/runner/taskRunner.js generated vendored Normal file
View File

@@ -0,0 +1,136 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TaskRunner = void 0;
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _utils = require("playwright-core/lib/utils");
var _sigIntWatcher = require("./sigIntWatcher");
var _util = require("../util");
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class TaskRunner {
constructor(reporter, globalTimeoutForError) {
this._tasks = [];
this._reporter = void 0;
this._hasErrors = false;
this._interrupted = false;
this._isTearDown = false;
this._globalTimeoutForError = void 0;
this._reporter = reporter;
this._globalTimeoutForError = globalTimeoutForError;
}
addTask(task) {
this._tasks.push(task);
}
async run(context, deadline, cancelPromise) {
const {
status,
cleanup
} = await this.runDeferCleanup(context, deadline, cancelPromise);
const teardownStatus = await cleanup();
return status === 'passed' ? teardownStatus : status;
}
async runDeferCleanup(context, deadline, cancelPromise = new _utils.ManualPromise()) {
const sigintWatcher = new _sigIntWatcher.SigIntWatcher();
const timeoutWatcher = new TimeoutWatcher(deadline);
const teardownRunner = new TaskRunner(this._reporter, this._globalTimeoutForError);
teardownRunner._isTearDown = true;
let currentTaskName;
const taskLoop = async () => {
for (const task of this._tasks) {
currentTaskName = task.title;
if (this._interrupted) break;
(0, _utilsBundle.debug)('pw:test:task')(`"${task.title}" started`);
const errors = [];
const softErrors = [];
try {
var _task$setup;
teardownRunner._tasks.unshift({
title: `teardown for ${task.title}`,
setup: task.teardown
});
await ((_task$setup = task.setup) === null || _task$setup === void 0 ? void 0 : _task$setup.call(task, context, errors, softErrors));
} catch (e) {
(0, _utilsBundle.debug)('pw:test:task')(`error in "${task.title}": `, e);
errors.push((0, _util.serializeError)(e));
} finally {
for (const error of [...softErrors, ...errors]) {
var _this$_reporter$onErr, _this$_reporter;
(_this$_reporter$onErr = (_this$_reporter = this._reporter).onError) === null || _this$_reporter$onErr === void 0 || _this$_reporter$onErr.call(_this$_reporter, error);
}
if (errors.length) {
if (!this._isTearDown) this._interrupted = true;
this._hasErrors = true;
}
}
(0, _utilsBundle.debug)('pw:test:task')(`"${task.title}" finished`);
}
};
await Promise.race([taskLoop(), cancelPromise, sigintWatcher.promise(), timeoutWatcher.promise]);
sigintWatcher.disarm();
timeoutWatcher.disarm();
// Prevent subsequent tasks from running.
this._interrupted = true;
let status = 'passed';
if (sigintWatcher.hadSignal() || cancelPromise !== null && cancelPromise !== void 0 && cancelPromise.isDone()) {
status = 'interrupted';
} else if (timeoutWatcher.timedOut()) {
var _this$_reporter$onErr2, _this$_reporter2;
(_this$_reporter$onErr2 = (_this$_reporter2 = this._reporter).onError) === null || _this$_reporter$onErr2 === void 0 || _this$_reporter$onErr2.call(_this$_reporter2, {
message: _utilsBundle.colors.red(`Timed out waiting ${this._globalTimeoutForError / 1000}s for the ${currentTaskName} to run`)
});
status = 'timedout';
} else if (this._hasErrors) {
status = 'failed';
}
cancelPromise === null || cancelPromise === void 0 || cancelPromise.resolve();
// Note that upon hitting deadline, we "run cleanup", but it exits immediately
// because of the same deadline. Essentially, we're not performing any cleanup.
const cleanup = () => teardownRunner.runDeferCleanup(context, deadline).then(r => r.status);
return {
status,
cleanup
};
}
}
exports.TaskRunner = TaskRunner;
class TimeoutWatcher {
constructor(deadline) {
this._timedOut = false;
this.promise = new _utils.ManualPromise();
this._timer = void 0;
if (!deadline) return;
if (deadline - (0, _utils.monotonicTime)() <= 0) {
this._timedOut = true;
this.promise.resolve();
return;
}
this._timer = setTimeout(() => {
this._timedOut = true;
this.promise.resolve();
}, deadline - (0, _utils.monotonicTime)());
}
timedOut() {
return this._timedOut;
}
disarm() {
clearTimeout(this._timer);
}
}

430
node_modules/playwright/lib/runner/tasks.js generated vendored Normal file
View File

@@ -0,0 +1,430 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TestRun = void 0;
exports.createApplyRebaselinesTask = createApplyRebaselinesTask;
exports.createClearCacheTask = createClearCacheTask;
exports.createGlobalSetupTasks = createGlobalSetupTasks;
exports.createListFilesTask = createListFilesTask;
exports.createLoadTask = createLoadTask;
exports.createPluginSetupTasks = createPluginSetupTasks;
exports.createReportBeginTask = createReportBeginTask;
exports.createRunTestsTasks = createRunTestsTasks;
exports.createStartDevServerTask = createStartDevServerTask;
exports.runTasks = runTasks;
exports.runTasksDeferCleanup = runTasksDeferCleanup;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _util = require("util");
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _utils = require("playwright-core/lib/utils");
var _dispatcher = require("./dispatcher");
var _testGroups = require("../runner/testGroups");
var _taskRunner = require("./taskRunner");
var _loadUtils = require("./loadUtils");
var _util2 = require("../util");
var _test = require("../common/test");
var _projectUtils = require("./projectUtils");
var _failureTracker = require("./failureTracker");
var _vcs = require("./vcs");
var _compilationCache = require("../transform/compilationCache");
var _rebase = require("./rebase");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const readDirAsync = (0, _util.promisify)(_fs.default.readdir);
class TestRun {
constructor(config, reporter) {
this.config = void 0;
this.reporter = void 0;
this.failureTracker = void 0;
this.rootSuite = undefined;
this.phases = [];
this.projectFiles = new Map();
this.projectSuites = new Map();
this.config = config;
this.reporter = reporter;
this.failureTracker = new _failureTracker.FailureTracker(config);
}
}
exports.TestRun = TestRun;
async function runTasks(testRun, tasks, globalTimeout, cancelPromise) {
const deadline = globalTimeout ? (0, _utils.monotonicTime)() + globalTimeout : 0;
const taskRunner = new _taskRunner.TaskRunner(testRun.reporter, globalTimeout || 0);
for (const task of tasks) taskRunner.addTask(task);
testRun.reporter.onConfigure(testRun.config.config);
const status = await taskRunner.run(testRun, deadline, cancelPromise);
return await finishTaskRun(testRun, status);
}
async function runTasksDeferCleanup(testRun, tasks) {
const taskRunner = new _taskRunner.TaskRunner(testRun.reporter, 0);
for (const task of tasks) taskRunner.addTask(task);
testRun.reporter.onConfigure(testRun.config.config);
const {
status,
cleanup
} = await taskRunner.runDeferCleanup(testRun, 0);
return {
status: await finishTaskRun(testRun, status),
cleanup
};
}
async function finishTaskRun(testRun, status) {
if (status === 'passed') status = testRun.failureTracker.result();
const modifiedResult = await testRun.reporter.onEnd({
status
});
if (modifiedResult && modifiedResult.status) status = modifiedResult.status;
await testRun.reporter.onExit();
return status;
}
function createGlobalSetupTasks(config) {
const tasks = [];
if (!config.configCLIOverrides.preserveOutputDir && !process.env.PW_TEST_NO_REMOVE_OUTPUT_DIRS) tasks.push(createRemoveOutputDirsTask());
tasks.push(...createPluginSetupTasks(config), ...config.globalTeardowns.map(file => createGlobalTeardownTask(file, config)).reverse(), ...config.globalSetups.map(file => createGlobalSetupTask(file, config)));
return tasks;
}
function createRunTestsTasks(config) {
return [createPhasesTask(), createReportBeginTask(), ...config.plugins.map(plugin => createPluginBeginTask(plugin)), createRunTestsTask()];
}
function createClearCacheTask(config) {
return {
title: 'clear cache',
setup: async () => {
await (0, _util2.removeDirAndLogToConsole)(_compilationCache.cacheDir);
for (const plugin of config.plugins) {
var _plugin$instance, _plugin$instance$clea;
await ((_plugin$instance = plugin.instance) === null || _plugin$instance === void 0 || (_plugin$instance$clea = _plugin$instance.clearCache) === null || _plugin$instance$clea === void 0 ? void 0 : _plugin$instance$clea.call(_plugin$instance));
}
}
};
}
function createReportBeginTask() {
return {
title: 'report begin',
setup: async testRun => {
var _testRun$reporter$onB, _testRun$reporter;
(_testRun$reporter$onB = (_testRun$reporter = testRun.reporter).onBegin) === null || _testRun$reporter$onB === void 0 || _testRun$reporter$onB.call(_testRun$reporter, testRun.rootSuite);
},
teardown: async ({}) => {}
};
}
function createPluginSetupTasks(config) {
return config.plugins.map(plugin => ({
title: 'plugin setup',
setup: async ({
reporter
}) => {
var _plugin$instance2, _plugin$instance2$set;
if (typeof plugin.factory === 'function') plugin.instance = await plugin.factory();else plugin.instance = plugin.factory;
await ((_plugin$instance2 = plugin.instance) === null || _plugin$instance2 === void 0 || (_plugin$instance2$set = _plugin$instance2.setup) === null || _plugin$instance2$set === void 0 ? void 0 : _plugin$instance2$set.call(_plugin$instance2, config.config, config.configDir, reporter));
},
teardown: async () => {
var _plugin$instance3, _plugin$instance3$tea;
await ((_plugin$instance3 = plugin.instance) === null || _plugin$instance3 === void 0 || (_plugin$instance3$tea = _plugin$instance3.teardown) === null || _plugin$instance3$tea === void 0 ? void 0 : _plugin$instance3$tea.call(_plugin$instance3));
}
}));
}
function createPluginBeginTask(plugin) {
return {
title: 'plugin begin',
setup: async testRun => {
var _plugin$instance4, _plugin$instance4$beg;
await ((_plugin$instance4 = plugin.instance) === null || _plugin$instance4 === void 0 || (_plugin$instance4$beg = _plugin$instance4.begin) === null || _plugin$instance4$beg === void 0 ? void 0 : _plugin$instance4$beg.call(_plugin$instance4, testRun.rootSuite));
},
teardown: async () => {
var _plugin$instance5, _plugin$instance5$end;
await ((_plugin$instance5 = plugin.instance) === null || _plugin$instance5 === void 0 || (_plugin$instance5$end = _plugin$instance5.end) === null || _plugin$instance5$end === void 0 ? void 0 : _plugin$instance5$end.call(_plugin$instance5));
}
};
}
function createGlobalSetupTask(file, config) {
let title = 'global setup';
if (config.globalSetups.length > 1) title += ` (${file})`;
let globalSetupResult;
return {
title,
setup: async ({
config
}) => {
const setupHook = await (0, _loadUtils.loadGlobalHook)(config, file);
globalSetupResult = await setupHook(config.config);
},
teardown: async () => {
if (typeof globalSetupResult === 'function') await globalSetupResult();
}
};
}
function createGlobalTeardownTask(file, config) {
let title = 'global teardown';
if (config.globalTeardowns.length > 1) title += ` (${file})`;
return {
title,
teardown: async ({
config
}) => {
const teardownHook = await (0, _loadUtils.loadGlobalHook)(config, file);
await teardownHook(config.config);
}
};
}
function createRemoveOutputDirsTask() {
return {
title: 'clear output',
setup: async ({
config
}) => {
const outputDirs = new Set();
const projects = (0, _projectUtils.filterProjects)(config.projects, config.cliProjectFilter);
projects.forEach(p => outputDirs.add(p.project.outputDir));
await Promise.all(Array.from(outputDirs).map(outputDir => (0, _utils.removeFolders)([outputDir]).then(async ([error]) => {
if (!error) return;
if (error.code === 'EBUSY') {
// We failed to remove folder, might be due to the whole folder being mounted inside a container:
// https://github.com/microsoft/playwright/issues/12106
// Do a best-effort to remove all files inside of it instead.
const entries = await readDirAsync(outputDir).catch(e => []);
await Promise.all(entries.map(entry => (0, _utils.removeFolders)([_path.default.join(outputDir, entry)])));
} else {
throw error;
}
})));
}
};
}
function createListFilesTask() {
return {
title: 'load tests',
setup: async (testRun, errors) => {
testRun.rootSuite = await (0, _loadUtils.createRootSuite)(testRun, errors, false);
testRun.failureTracker.onRootSuite(testRun.rootSuite);
await (0, _loadUtils.collectProjectsAndTestFiles)(testRun, false);
for (const [project, files] of testRun.projectFiles) {
const projectSuite = new _test.Suite(project.project.name, 'project');
projectSuite._fullProject = project;
testRun.rootSuite._addSuite(projectSuite);
const suites = files.map(file => {
const title = _path.default.relative(testRun.config.config.rootDir, file);
const suite = new _test.Suite(title, 'file');
suite.location = {
file,
line: 0,
column: 0
};
projectSuite._addSuite(suite);
return suite;
});
testRun.projectSuites.set(project, suites);
}
}
};
}
function createLoadTask(mode, options) {
return {
title: 'load tests',
setup: async (testRun, errors, softErrors) => {
await (0, _loadUtils.collectProjectsAndTestFiles)(testRun, !!options.doNotRunDepsOutsideProjectFilter);
await (0, _loadUtils.loadFileSuites)(testRun, mode, options.failOnLoadErrors ? errors : softErrors);
if (testRun.config.cliOnlyChanged || options.populateDependencies) {
for (const plugin of testRun.config.plugins) {
var _plugin$instance6, _plugin$instance6$pop;
await ((_plugin$instance6 = plugin.instance) === null || _plugin$instance6 === void 0 || (_plugin$instance6$pop = _plugin$instance6.populateDependencies) === null || _plugin$instance6$pop === void 0 ? void 0 : _plugin$instance6$pop.call(_plugin$instance6));
}
}
let cliOnlyChangedMatcher = undefined;
if (testRun.config.cliOnlyChanged) {
const changedFiles = await (0, _vcs.detectChangedTestFiles)(testRun.config.cliOnlyChanged, testRun.config.configDir);
cliOnlyChangedMatcher = file => changedFiles.has(file);
}
testRun.rootSuite = await (0, _loadUtils.createRootSuite)(testRun, options.failOnLoadErrors ? errors : softErrors, !!options.filterOnly, cliOnlyChangedMatcher);
testRun.failureTracker.onRootSuite(testRun.rootSuite);
// Fail when no tests.
if (options.failOnLoadErrors && !testRun.rootSuite.allTests().length && !testRun.config.cliPassWithNoTests && !testRun.config.config.shard && !testRun.config.cliOnlyChanged) {
if (testRun.config.cliArgs.length) {
throw new Error([`No tests found.`, `Make sure that arguments are regular expressions matching test files.`, `You may need to escape symbols like "$" or "*" and quote the arguments.`].join('\n'));
}
throw new Error(`No tests found`);
}
}
};
}
function createApplyRebaselinesTask() {
return {
title: 'apply rebaselines',
teardown: async ({
config,
reporter
}) => {
await (0, _rebase.applySuggestedRebaselines)(config, reporter);
}
};
}
function createPhasesTask() {
return {
title: 'create phases',
setup: async testRun => {
let maxConcurrentTestGroups = 0;
const processed = new Set();
const projectToSuite = new Map(testRun.rootSuite.suites.map(suite => [suite._fullProject, suite]));
const allProjects = [...projectToSuite.keys()];
const teardownToSetups = (0, _projectUtils.buildTeardownToSetupsMap)(allProjects);
const teardownToSetupsDependents = new Map();
for (const [teardown, setups] of teardownToSetups) {
const closure = (0, _projectUtils.buildDependentProjects)(setups, allProjects);
closure.delete(teardown);
teardownToSetupsDependents.set(teardown, [...closure]);
}
for (let i = 0; i < projectToSuite.size; i++) {
// Find all projects that have all their dependencies processed by previous phases.
const phaseProjects = [];
for (const project of projectToSuite.keys()) {
if (processed.has(project)) continue;
const projectsThatShouldFinishFirst = [...project.deps, ...(teardownToSetupsDependents.get(project) || [])];
if (projectsThatShouldFinishFirst.find(p => !processed.has(p))) continue;
phaseProjects.push(project);
}
// Create a new phase.
for (const project of phaseProjects) processed.add(project);
if (phaseProjects.length) {
let testGroupsInPhase = 0;
const phase = {
dispatcher: new _dispatcher.Dispatcher(testRun.config, testRun.reporter, testRun.failureTracker),
projects: []
};
testRun.phases.push(phase);
for (const project of phaseProjects) {
const projectSuite = projectToSuite.get(project);
const testGroups = (0, _testGroups.createTestGroups)(projectSuite, testRun.config.config.workers);
phase.projects.push({
project,
projectSuite,
testGroups
});
testGroupsInPhase += testGroups.length;
}
(0, _utilsBundle.debug)('pw:test:task')(`created phase #${testRun.phases.length} with ${phase.projects.map(p => p.project.project.name).sort()} projects, ${testGroupsInPhase} testGroups`);
maxConcurrentTestGroups = Math.max(maxConcurrentTestGroups, testGroupsInPhase);
}
}
testRun.config.config.metadata.actualWorkers = Math.min(testRun.config.config.workers, maxConcurrentTestGroups);
}
};
}
function createRunTestsTask() {
return {
title: 'test suite',
setup: async ({
phases,
failureTracker
}) => {
const successfulProjects = new Set();
const extraEnvByProjectId = new Map();
const teardownToSetups = (0, _projectUtils.buildTeardownToSetupsMap)(phases.map(phase => phase.projects.map(p => p.project)).flat());
for (const {
dispatcher,
projects
} of phases) {
// Each phase contains dispatcher and a set of test groups.
// We don't want to run the test groups belonging to the projects
// that depend on the projects that failed previously.
const phaseTestGroups = [];
for (const {
project,
testGroups
} of projects) {
// Inherit extra environment variables from dependencies.
let extraEnv = {};
for (const dep of project.deps) extraEnv = {
...extraEnv,
...extraEnvByProjectId.get(dep.id)
};
for (const setup of teardownToSetups.get(project) || []) extraEnv = {
...extraEnv,
...extraEnvByProjectId.get(setup.id)
};
extraEnvByProjectId.set(project.id, extraEnv);
const hasFailedDeps = project.deps.some(p => !successfulProjects.has(p));
if (!hasFailedDeps) phaseTestGroups.push(...testGroups);
}
if (phaseTestGroups.length) {
await dispatcher.run(phaseTestGroups, extraEnvByProjectId);
await dispatcher.stop();
for (const [projectId, envProduced] of dispatcher.producedEnvByProjectId()) {
const extraEnv = extraEnvByProjectId.get(projectId) || {};
extraEnvByProjectId.set(projectId, {
...extraEnv,
...envProduced
});
}
}
// If the worker broke, fail everything, we have no way of knowing which
// projects failed.
if (!failureTracker.hasWorkerErrors()) {
for (const {
project,
projectSuite
} of projects) {
const hasFailedDeps = project.deps.some(p => !successfulProjects.has(p));
if (!hasFailedDeps && !projectSuite.allTests().some(test => !test.ok())) successfulProjects.add(project);
}
}
}
},
teardown: async ({
phases
}) => {
for (const {
dispatcher
} of phases.reverse()) await dispatcher.stop();
}
};
}
function createStartDevServerTask() {
return {
title: 'start dev server',
setup: async ({
config
}, errors, softErrors) => {
if (config.plugins.some(plugin => !!plugin.devServerCleanup)) {
errors.push({
message: `DevServer is already running`
});
return;
}
for (const plugin of config.plugins) {
var _plugin$instance7, _plugin$instance7$sta;
plugin.devServerCleanup = await ((_plugin$instance7 = plugin.instance) === null || _plugin$instance7 === void 0 || (_plugin$instance7$sta = _plugin$instance7.startDevServer) === null || _plugin$instance7$sta === void 0 ? void 0 : _plugin$instance7$sta.call(_plugin$instance7));
}
if (!config.plugins.some(plugin => !!plugin.devServerCleanup)) errors.push({
message: `DevServer is not available in the package you are using. Did you mean to use component testing?`
});
},
teardown: async ({
config
}) => {
for (const plugin of config.plugins) {
var _plugin$devServerClea;
await ((_plugin$devServerClea = plugin.devServerCleanup) === null || _plugin$devServerClea === void 0 ? void 0 : _plugin$devServerClea.call(plugin));
plugin.devServerCleanup = undefined;
}
}
};
}

136
node_modules/playwright/lib/runner/testGroups.js generated vendored Normal file
View File

@@ -0,0 +1,136 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createTestGroups = createTestGroups;
exports.filterForShard = filterForShard;
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function createTestGroups(projectSuite, expectedParallelism) {
// This function groups tests that can be run together.
// Tests cannot be run together when:
// - They belong to different projects - requires different workers.
// - They have a different repeatEachIndex - requires different workers.
// - They have a different set of worker fixtures in the pool - requires different workers.
// - They have a different requireFile - reuses the worker, but runs each requireFile separately.
// - They belong to a parallel suite.
// Using the map "workerHash -> requireFile -> group" makes us preserve the natural order
// of worker hashes and require files for the simple cases.
const groups = new Map();
const createGroup = test => {
return {
workerHash: test._workerHash,
requireFile: test._requireFile,
repeatEachIndex: test.repeatEachIndex,
projectId: test._projectId,
tests: []
};
};
for (const test of projectSuite.allTests()) {
let withWorkerHash = groups.get(test._workerHash);
if (!withWorkerHash) {
withWorkerHash = new Map();
groups.set(test._workerHash, withWorkerHash);
}
let withRequireFile = withWorkerHash.get(test._requireFile);
if (!withRequireFile) {
withRequireFile = {
general: createGroup(test),
parallel: new Map(),
parallelWithHooks: createGroup(test)
};
withWorkerHash.set(test._requireFile, withRequireFile);
}
// Note that a parallel suite cannot be inside a serial suite. This is enforced in TestType.
let insideParallel = false;
let outerMostSequentialSuite;
let hasAllHooks = false;
for (let parent = test.parent; parent; parent = parent.parent) {
if (parent._parallelMode === 'serial' || parent._parallelMode === 'default') outerMostSequentialSuite = parent;
insideParallel = insideParallel || parent._parallelMode === 'parallel';
hasAllHooks = hasAllHooks || parent._hooks.some(hook => hook.type === 'beforeAll' || hook.type === 'afterAll');
}
if (insideParallel) {
if (hasAllHooks && !outerMostSequentialSuite) {
withRequireFile.parallelWithHooks.tests.push(test);
} else {
const key = outerMostSequentialSuite || test;
let group = withRequireFile.parallel.get(key);
if (!group) {
group = createGroup(test);
withRequireFile.parallel.set(key, group);
}
group.tests.push(test);
}
} else {
withRequireFile.general.tests.push(test);
}
}
const result = [];
for (const withWorkerHash of groups.values()) {
for (const withRequireFile of withWorkerHash.values()) {
// Tests without parallel mode should run serially as a single group.
if (withRequireFile.general.tests.length) result.push(withRequireFile.general);
// Parallel test groups without beforeAll/afterAll can be run independently.
result.push(...withRequireFile.parallel.values());
// Tests with beforeAll/afterAll should try to share workers as much as possible.
const parallelWithHooksGroupSize = Math.ceil(withRequireFile.parallelWithHooks.tests.length / expectedParallelism);
let lastGroup;
for (const test of withRequireFile.parallelWithHooks.tests) {
if (!lastGroup || lastGroup.tests.length >= parallelWithHooksGroupSize) {
lastGroup = createGroup(test);
result.push(lastGroup);
}
lastGroup.tests.push(test);
}
}
}
return result;
}
function filterForShard(shard, testGroups) {
// Note that sharding works based on test groups.
// This means parallel files will be sharded by single tests,
// while non-parallel files will be sharded by the whole file.
//
// Shards are still balanced by the number of tests, not files,
// even in the case of non-paralleled files.
let shardableTotal = 0;
for (const group of testGroups) shardableTotal += group.tests.length;
// Each shard gets some tests.
const shardSize = Math.floor(shardableTotal / shard.total);
// First few shards get one more test each.
const extraOne = shardableTotal - shardSize * shard.total;
const currentShard = shard.current - 1; // Make it zero-based for calculations.
const from = shardSize * currentShard + Math.min(extraOne, currentShard);
const to = from + shardSize + (currentShard < extraOne ? 1 : 0);
let current = 0;
const result = new Set();
for (const group of testGroups) {
// Any test group goes to the shard that contains the first test of this group.
// So, this shard gets any group that starts at [from; to)
if (current >= from && current < to) result.add(group);
current += group.tests.length;
}
return result;
}

569
node_modules/playwright/lib/runner/testServer.js generated vendored Normal file
View File

@@ -0,0 +1,569 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TestServerDispatcher = void 0;
exports.resolveCtDirs = resolveCtDirs;
exports.runTestServer = runTestServer;
exports.runUIMode = runUIMode;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _server = require("playwright-core/lib/server");
var _utils = require("playwright-core/lib/utils");
var _compilationCache = require("../transform/compilationCache");
var _reporters = require("./reporters");
var _tasks = require("./tasks");
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _list = _interopRequireDefault(require("../reporters/list"));
var _sigIntWatcher = require("./sigIntWatcher");
var _fsWatcher = require("../fsWatcher");
var _configLoader = require("../common/configLoader");
var _webServerPlugin = require("../plugins/webServerPlugin");
var _util = require("../util");
var _teleReceiver = require("../isomorphic/teleReceiver");
var _internalReporter = require("../reporters/internalReporter");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const originalStdoutWrite = process.stdout.write;
const originalStderrWrite = process.stderr.write;
class TestServer {
constructor(configLocation, configCLIOverrides) {
this._configLocation = void 0;
this._configCLIOverrides = void 0;
this._dispatcher = void 0;
this._configLocation = configLocation;
this._configCLIOverrides = configCLIOverrides;
}
async start(options) {
this._dispatcher = new TestServerDispatcher(this._configLocation, this._configCLIOverrides);
return await (0, _server.startTraceViewerServer)({
...options,
transport: this._dispatcher.transport
});
}
async stop() {
var _this$_dispatcher, _this$_dispatcher2;
await ((_this$_dispatcher = this._dispatcher) === null || _this$_dispatcher === void 0 ? void 0 : _this$_dispatcher._setInterceptStdio(false));
await ((_this$_dispatcher2 = this._dispatcher) === null || _this$_dispatcher2 === void 0 ? void 0 : _this$_dispatcher2.runGlobalTeardown());
}
}
class TestServerDispatcher {
constructor(configLocation, configCLIOverrides) {
this._configLocation = void 0;
this._configCLIOverrides = void 0;
this._watcher = void 0;
this._watchedProjectDirs = new Set();
this._ignoredProjectOutputs = new Set();
this._watchedTestDependencies = new Set();
this._testRun = void 0;
this.transport = void 0;
this._queue = Promise.resolve();
this._globalSetup = void 0;
this._devServer = void 0;
this._dispatchEvent = void 0;
this._plugins = void 0;
this._serializer = require.resolve('./uiModeReporter');
this._watchTestDirs = false;
this._closeOnDisconnect = false;
this._populateDependenciesOnList = false;
this._configLocation = configLocation;
this._configCLIOverrides = configCLIOverrides;
this.transport = {
onconnect: () => {},
dispatch: (method, params) => this[method](params),
onclose: () => {
if (this._closeOnDisconnect) (0, _utils.gracefullyProcessExitDoNotHang)(0);
}
};
this._watcher = new _fsWatcher.Watcher(events => {
const collector = new Set();
events.forEach(f => (0, _compilationCache.collectAffectedTestFiles)(f.file, collector));
this._dispatchEvent('testFilesChanged', {
testFiles: [...collector]
});
});
this._dispatchEvent = (method, params) => {
var _this$transport$sendE, _this$transport;
return (_this$transport$sendE = (_this$transport = this.transport).sendEvent) === null || _this$transport$sendE === void 0 ? void 0 : _this$transport$sendE.call(_this$transport, method, params);
};
}
async _wireReporter(messageSink) {
return await (0, _reporters.createReporterForTestServer)(this._serializer, messageSink);
}
async _collectingInternalReporter(...extraReporters) {
const report = [];
const collectingReporter = await (0, _reporters.createReporterForTestServer)(this._serializer, e => report.push(e));
return {
reporter: new _internalReporter.InternalReporter([collectingReporter, ...extraReporters]),
report
};
}
async initialize(params) {
// Note: this method can be called multiple times, for example from a new connection after UI mode reload.
this._serializer = params.serializer || require.resolve('./uiModeReporter');
this._closeOnDisconnect = !!params.closeOnDisconnect;
await this._setInterceptStdio(!!params.interceptStdio);
this._watchTestDirs = !!params.watchTestDirs;
this._populateDependenciesOnList = !!params.populateDependenciesOnList;
}
async ping() {}
async open(params) {
if ((0, _utils.isUnderTest)()) return;
// eslint-disable-next-line no-console
(0, _utilsBundle.open)('vscode://file/' + params.location.file + ':' + params.location.line).catch(e => console.error(e));
}
async resizeTerminal(params) {
process.stdout.columns = params.cols;
process.stdout.rows = params.rows;
process.stderr.columns = params.cols;
process.stderr.columns = params.rows;
}
async checkBrowsers() {
return {
hasBrowsers: hasSomeBrowsers()
};
}
async installBrowsers() {
await installBrowsers();
}
async runGlobalSetup(params) {
await this.runGlobalTeardown();
const {
reporter,
report
} = await this._collectingInternalReporter(new _list.default());
const config = await this._loadConfigOrReportError(reporter, this._configCLIOverrides);
if (!config) return {
status: 'failed',
report
};
const {
status,
cleanup
} = await (0, _tasks.runTasksDeferCleanup)(new _tasks.TestRun(config, reporter), [...(0, _tasks.createGlobalSetupTasks)(config)]);
if (status !== 'passed') await cleanup();else this._globalSetup = {
cleanup,
report
};
return {
report,
status
};
}
async runGlobalTeardown() {
const globalSetup = this._globalSetup;
const status = await (globalSetup === null || globalSetup === void 0 ? void 0 : globalSetup.cleanup());
this._globalSetup = undefined;
return {
status,
report: (globalSetup === null || globalSetup === void 0 ? void 0 : globalSetup.report) || []
};
}
async startDevServer(params) {
await this.stopDevServer({});
const {
reporter,
report
} = await this._collectingInternalReporter();
const config = await this._loadConfigOrReportError(reporter);
if (!config) return {
report,
status: 'failed'
};
const {
status,
cleanup
} = await (0, _tasks.runTasksDeferCleanup)(new _tasks.TestRun(config, reporter), [(0, _tasks.createLoadTask)('out-of-process', {
failOnLoadErrors: true,
filterOnly: false
}), (0, _tasks.createStartDevServerTask)()]);
if (status !== 'passed') await cleanup();else this._devServer = {
cleanup,
report
};
return {
report,
status
};
}
async stopDevServer(params) {
const devServer = this._devServer;
const status = await (devServer === null || devServer === void 0 ? void 0 : devServer.cleanup());
this._devServer = undefined;
return {
status,
report: (devServer === null || devServer === void 0 ? void 0 : devServer.report) || []
};
}
async clearCache(params) {
const reporter = new _internalReporter.InternalReporter([]);
const config = await this._loadConfigOrReportError(reporter);
if (!config) return;
await (0, _tasks.runTasks)(new _tasks.TestRun(config, reporter), [(0, _tasks.createClearCacheTask)(config)]);
}
async listFiles(params) {
var _params$projects;
const {
reporter,
report
} = await this._collectingInternalReporter();
const config = await this._loadConfigOrReportError(reporter);
if (!config) return {
status: 'failed',
report
};
config.cliProjectFilter = (_params$projects = params.projects) !== null && _params$projects !== void 0 && _params$projects.length ? params.projects : undefined;
const status = await (0, _tasks.runTasks)(new _tasks.TestRun(config, reporter), [(0, _tasks.createListFilesTask)(), (0, _tasks.createReportBeginTask)()]);
return {
report,
status
};
}
async listTests(params) {
let result;
this._queue = this._queue.then(async () => {
const {
config,
report,
status
} = await this._innerListTests(params);
if (config) await this._updateWatchedDirs(config);
result = {
report,
status
};
}).catch(printInternalError);
await this._queue;
return result;
}
async _innerListTests(params) {
var _params$projects2;
const overrides = {
...this._configCLIOverrides,
repeatEach: 1,
retries: 0
};
const {
reporter,
report
} = await this._collectingInternalReporter();
const config = await this._loadConfigOrReportError(reporter, overrides);
if (!config) return {
report,
reporter,
status: 'failed'
};
config.cliArgs = params.locations || [];
config.cliGrep = params.grep;
config.cliGrepInvert = params.grepInvert;
config.cliProjectFilter = (_params$projects2 = params.projects) !== null && _params$projects2 !== void 0 && _params$projects2.length ? params.projects : undefined;
config.cliListOnly = true;
const status = await (0, _tasks.runTasks)(new _tasks.TestRun(config, reporter), [(0, _tasks.createLoadTask)('out-of-process', {
failOnLoadErrors: false,
filterOnly: false,
populateDependencies: this._populateDependenciesOnList
}), (0, _tasks.createReportBeginTask)()]);
return {
config,
report,
reporter,
status
};
}
async _updateWatchedDirs(config) {
this._watchedProjectDirs = new Set();
this._ignoredProjectOutputs = new Set();
for (const p of config.projects) {
this._watchedProjectDirs.add(p.project.testDir);
this._ignoredProjectOutputs.add(p.project.outputDir);
}
const result = await resolveCtDirs(config);
if (result) {
this._watchedProjectDirs.add(result.templateDir);
this._ignoredProjectOutputs.add(result.outDir);
}
if (this._watchTestDirs) await this._updateWatcher(false);
}
async _updateWatcher(reportPending) {
await this._watcher.update([...this._watchedProjectDirs, ...this._watchedTestDependencies], [...this._ignoredProjectOutputs], reportPending);
}
async runTests(params) {
let result = {
status: 'passed'
};
this._queue = this._queue.then(async () => {
result = await this._innerRunTests(params).catch(e => {
printInternalError(e);
return {
status: 'failed'
};
});
});
await this._queue;
return result;
}
async _innerRunTests(params) {
var _params$projects3;
await this.stopTests();
const overrides = {
...this._configCLIOverrides,
repeatEach: 1,
retries: 0,
preserveOutputDir: true,
reporter: params.reporters ? params.reporters.map(r => [r]) : undefined,
use: {
...this._configCLIOverrides.use,
...(params.trace === 'on' ? {
trace: {
mode: 'on',
sources: false,
_live: true
}
} : {}),
...(params.trace === 'off' ? {
trace: 'off'
} : {}),
...(params.video === 'on' || params.video === 'off' ? {
video: params.video
} : {}),
...(params.headed !== undefined ? {
headless: !params.headed
} : {}),
_optionContextReuseMode: params.reuseContext ? 'when-possible' : undefined,
_optionConnectOptions: params.connectWsEndpoint ? {
wsEndpoint: params.connectWsEndpoint
} : undefined
},
...(params.updateSnapshots ? {
updateSnapshots: params.updateSnapshots
} : {}),
...(params.workers ? {
workers: params.workers
} : {})
};
if (params.trace === 'on') process.env.PW_LIVE_TRACE_STACKS = '1';else process.env.PW_LIVE_TRACE_STACKS = undefined;
const wireReporter = await this._wireReporter(e => this._dispatchEvent('report', e));
const config = await this._loadConfigOrReportError(new _internalReporter.InternalReporter([wireReporter]), overrides);
if (!config) return {
status: 'failed'
};
const testIdSet = params.testIds ? new Set(params.testIds) : null;
config.cliListOnly = false;
config.cliPassWithNoTests = true;
config.cliArgs = params.locations || [];
config.cliGrep = params.grep;
config.cliGrepInvert = params.grepInvert;
config.cliProjectFilter = (_params$projects3 = params.projects) !== null && _params$projects3 !== void 0 && _params$projects3.length ? params.projects : undefined;
config.testIdMatcher = testIdSet ? id => testIdSet.has(id) : undefined;
const configReporters = await (0, _reporters.createReporters)(config, 'test', true);
const reporter = new _internalReporter.InternalReporter([...configReporters, wireReporter]);
const stop = new _utils.ManualPromise();
const tasks = [(0, _tasks.createApplyRebaselinesTask)(), (0, _tasks.createLoadTask)('out-of-process', {
filterOnly: true,
failOnLoadErrors: false,
doNotRunDepsOutsideProjectFilter: true
}), ...(0, _tasks.createRunTestsTasks)(config)];
const run = (0, _tasks.runTasks)(new _tasks.TestRun(config, reporter), tasks, 0, stop).then(async status => {
this._testRun = undefined;
return status;
});
this._testRun = {
run,
stop
};
return {
status: await run
};
}
async watch(params) {
this._watchedTestDependencies = new Set();
for (const fileName of params.fileNames) {
this._watchedTestDependencies.add(fileName);
(0, _compilationCache.dependenciesForTestFile)(fileName).forEach(file => this._watchedTestDependencies.add(file));
}
await this._updateWatcher(true);
}
async findRelatedTestFiles(params) {
const errorReporter = (0, _reporters.createErrorCollectingReporter)();
const reporter = new _internalReporter.InternalReporter([errorReporter]);
const config = await this._loadConfigOrReportError(reporter);
if (!config) return {
errors: errorReporter.errors(),
testFiles: []
};
const status = await (0, _tasks.runTasks)(new _tasks.TestRun(config, reporter), [(0, _tasks.createLoadTask)('out-of-process', {
failOnLoadErrors: true,
filterOnly: false,
populateDependencies: true
})]);
if (status !== 'passed') return {
errors: errorReporter.errors(),
testFiles: []
};
return {
testFiles: (0, _compilationCache.affectedTestFiles)(params.files)
};
}
async stopTests() {
var _this$_testRun, _this$_testRun2;
(_this$_testRun = this._testRun) === null || _this$_testRun === void 0 || (_this$_testRun = _this$_testRun.stop) === null || _this$_testRun === void 0 || _this$_testRun.resolve();
await ((_this$_testRun2 = this._testRun) === null || _this$_testRun2 === void 0 ? void 0 : _this$_testRun2.run);
}
async _setInterceptStdio(intercept) {
if (process.env.PWTEST_DEBUG) return;
if (intercept) {
process.stdout.write = chunk => {
this._dispatchEvent('stdio', chunkToPayload('stdout', chunk));
return true;
};
process.stderr.write = chunk => {
this._dispatchEvent('stdio', chunkToPayload('stderr', chunk));
return true;
};
} else {
process.stdout.write = originalStdoutWrite;
process.stderr.write = originalStderrWrite;
}
}
async closeGracefully() {
(0, _utils.gracefullyProcessExitDoNotHang)(0);
}
async _loadConfig(overrides) {
try {
const config = await (0, _configLoader.loadConfig)(this._configLocation, overrides);
// Preserve plugin instances between setup and build.
if (!this._plugins) {
(0, _webServerPlugin.webServerPluginsForConfig)(config).forEach(p => config.plugins.push({
factory: p
}));
this._plugins = config.plugins || [];
} else {
config.plugins.splice(0, config.plugins.length, ...this._plugins);
}
return {
config
};
} catch (e) {
return {
config: null,
error: (0, _util.serializeError)(e)
};
}
}
async _loadConfigOrReportError(reporter, overrides) {
const {
config,
error
} = await this._loadConfig(overrides);
if (config) return config;
// Produce dummy config when it has an error.
reporter.onConfigure(_teleReceiver.baseFullConfig);
reporter.onError(error);
await reporter.onEnd({
status: 'failed'
});
await reporter.onExit();
return null;
}
}
exports.TestServerDispatcher = TestServerDispatcher;
async function runUIMode(configFile, configCLIOverrides, options) {
const configLocation = (0, _configLoader.resolveConfigLocation)(configFile);
return await innerRunTestServer(configLocation, configCLIOverrides, options, async (server, cancelPromise) => {
await (0, _server.installRootRedirect)(server, [], {
...options,
webApp: 'uiMode.html'
});
if (options.host !== undefined || options.port !== undefined) {
await (0, _server.openTraceInBrowser)(server.urlPrefix('human-readable'));
} else {
const page = await (0, _server.openTraceViewerApp)(server.urlPrefix('precise'), 'chromium', {
headless: (0, _utils.isUnderTest)() && process.env.PWTEST_HEADED_FOR_TEST !== '1',
persistentContextOptions: {
handleSIGINT: false
}
});
page.on('close', () => cancelPromise.resolve());
}
});
}
async function runTestServer(configFile, configCLIOverrides, options) {
const configLocation = (0, _configLoader.resolveConfigLocation)(configFile);
return await innerRunTestServer(configLocation, configCLIOverrides, options, async server => {
// eslint-disable-next-line no-console
console.log('Listening on ' + server.urlPrefix('precise').replace('http:', 'ws:') + '/' + server.wsGuid());
});
}
async function innerRunTestServer(configLocation, configCLIOverrides, options, openUI) {
if ((0, _configLoader.restartWithExperimentalTsEsm)(undefined, true)) return 'restarted';
const testServer = new TestServer(configLocation, configCLIOverrides);
const cancelPromise = new _utils.ManualPromise();
const sigintWatcher = new _sigIntWatcher.SigIntWatcher();
process.stdin.on('close', () => (0, _utils.gracefullyProcessExitDoNotHang)(0));
void sigintWatcher.promise().then(() => cancelPromise.resolve());
try {
const server = await testServer.start(options);
await openUI(server, cancelPromise, configLocation);
await cancelPromise;
} finally {
await testServer.stop();
sigintWatcher.disarm();
}
return sigintWatcher.hadSignal() ? 'interrupted' : 'passed';
}
function chunkToPayload(type, chunk) {
if (chunk instanceof Buffer) return {
type,
buffer: chunk.toString('base64')
};
return {
type,
text: chunk
};
}
function hasSomeBrowsers() {
for (const browserName of ['chromium', 'webkit', 'firefox']) {
try {
_server.registry.findExecutable(browserName).executablePathOrDie('javascript');
return true;
} catch {}
}
return false;
}
async function installBrowsers() {
const executables = _server.registry.defaultExecutables();
await _server.registry.install(executables, false);
}
function printInternalError(e) {
// eslint-disable-next-line no-console
console.error('Internal error:', e);
}
// TODO: remove CT dependency.
async function resolveCtDirs(config) {
const use = config.config.projects[0].use;
const relativeTemplateDir = use.ctTemplateDir || 'playwright';
const templateDir = await _fs.default.promises.realpath(_path.default.normalize(_path.default.join(config.configDir, relativeTemplateDir))).catch(() => undefined);
if (!templateDir) return null;
const outDir = use.ctCacheDir ? _path.default.resolve(config.configDir, use.ctCacheDir) : _path.default.resolve(templateDir, '.cache');
return {
outDir,
templateDir
};
}

31
node_modules/playwright/lib/runner/uiModeReporter.js generated vendored Normal file
View File

@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _teleEmitter = require("../reporters/teleEmitter");
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class UIModeReporter extends _teleEmitter.TeleReporterEmitter {
constructor(options) {
super(options._send, {
omitBuffers: true
});
}
}
var _default = exports.default = UIModeReporter;

55
node_modules/playwright/lib/runner/vcs.js generated vendored Normal file
View File

@@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.detectChangedTestFiles = detectChangedTestFiles;
var _child_process = _interopRequireDefault(require("child_process"));
var _compilationCache = require("../transform/compilationCache");
var _path = _interopRequireDefault(require("path"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
async function detectChangedTestFiles(baseCommit, configDir) {
function gitFileList(command) {
try {
return _child_process.default.execSync(`git ${command}`, {
encoding: 'utf-8',
stdio: 'pipe',
cwd: configDir
}).split('\n').filter(Boolean);
} catch (_error) {
const error = _error;
const unknownRevision = error.output.some(line => line === null || line === void 0 ? void 0 : line.includes('unknown revision'));
if (unknownRevision) {
const isShallowClone = _child_process.default.execSync('git rev-parse --is-shallow-repository', {
encoding: 'utf-8',
stdio: 'pipe',
cwd: configDir
}).trim() === 'true';
if (isShallowClone) {
throw new Error([`The repository is a shallow clone and does not have '${baseCommit}' available locally.`, `Note that GitHub Actions checkout is shallow by default: https://github.com/actions/checkout`].join('\n'));
}
}
throw new Error([`Cannot detect changed files for --only-changed mode:`, `git ${command}`, '', ...error.output].join('\n'));
}
}
const untrackedFiles = gitFileList(`ls-files --others --exclude-standard`).map(file => _path.default.join(configDir, file));
const [gitRoot] = gitFileList('rev-parse --show-toplevel');
const trackedFilesWithChanges = gitFileList(`diff ${baseCommit} --name-only`).map(file => _path.default.join(gitRoot, file));
return new Set((0, _compilationCache.affectedTestFiles)([...untrackedFiles, ...trackedFilesWithChanges]));
}

423
node_modules/playwright/lib/runner/watchMode.js generated vendored Normal file
View File

@@ -0,0 +1,423 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.runWatchModeLoop = runWatchModeLoop;
var _readline = _interopRequireDefault(require("readline"));
var _path = _interopRequireDefault(require("path"));
var _utils = require("playwright-core/lib/utils");
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _utilsBundle2 = require("../utilsBundle");
var _base = require("../reporters/base");
var _playwrightServer = require("playwright-core/lib/remote/playwrightServer");
var _testServer = require("./testServer");
var _stream = require("stream");
var _testServerConnection = require("../isomorphic/testServerConnection");
var _teleSuiteUpdater = require("../isomorphic/teleSuiteUpdater");
var _configLoader = require("../common/configLoader");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class InMemoryTransport extends _stream.EventEmitter {
constructor(send) {
super();
this._send = void 0;
this._send = send;
}
close() {
this.emit('close');
}
onclose(listener) {
this.on('close', listener);
}
onerror(listener) {
// no-op to fulfil the interface, the user of InMemoryTransport doesn't emit any errors.
}
onmessage(listener) {
this.on('message', listener);
}
onopen(listener) {
this.on('open', listener);
}
send(data) {
this._send(data);
}
}
async function runWatchModeLoop(configLocation, initialOptions) {
if ((0, _configLoader.restartWithExperimentalTsEsm)(undefined, true)) return 'restarted';
const options = {
...initialOptions
};
let bufferMode = false;
const testServerDispatcher = new _testServer.TestServerDispatcher(configLocation, {});
const transport = new InMemoryTransport(async data => {
const {
id,
method,
params
} = JSON.parse(data);
try {
const result = await testServerDispatcher.transport.dispatch(method, params);
transport.emit('message', JSON.stringify({
id,
result
}));
} catch (e) {
transport.emit('message', JSON.stringify({
id,
error: String(e)
}));
}
});
testServerDispatcher.transport.sendEvent = (method, params) => {
transport.emit('message', JSON.stringify({
method,
params
}));
};
const testServerConnection = new _testServerConnection.TestServerConnection(transport);
transport.emit('open');
const teleSuiteUpdater = new _teleSuiteUpdater.TeleSuiteUpdater({
pathSeparator: _path.default.sep,
onUpdate() {}
});
const dirtyTestFiles = new Set();
const dirtyTestIds = new Set();
let onDirtyTests = new _utils.ManualPromise();
let queue = Promise.resolve();
const changedFiles = new Set();
testServerConnection.onTestFilesChanged(({
testFiles
}) => {
testFiles.forEach(file => changedFiles.add(file));
queue = queue.then(async () => {
if (changedFiles.size === 0) return;
const {
report
} = await testServerConnection.listTests({
locations: options.files,
projects: options.projects,
grep: options.grep
});
teleSuiteUpdater.processListReport(report);
for (const test of teleSuiteUpdater.rootSuite.allTests()) {
if (changedFiles.has(test.location.file)) {
dirtyTestFiles.add(test.location.file);
dirtyTestIds.add(test.id);
}
}
changedFiles.clear();
if (dirtyTestIds.size > 0) {
onDirtyTests.resolve('changed');
onDirtyTests = new _utils.ManualPromise();
}
});
});
testServerConnection.onReport(report => teleSuiteUpdater.processTestReportEvent(report));
await testServerConnection.initialize({
interceptStdio: false,
watchTestDirs: true,
populateDependenciesOnList: true
});
await testServerConnection.runGlobalSetup({});
const {
report
} = await testServerConnection.listTests({});
teleSuiteUpdater.processListReport(report);
const projectNames = teleSuiteUpdater.rootSuite.suites.map(s => s.title);
let lastRun = {
type: 'regular'
};
let result = 'passed';
while (true) {
if (bufferMode) printBufferPrompt(dirtyTestFiles, teleSuiteUpdater.config.rootDir);else printPrompt();
const waitForCommand = readCommand();
const command = await Promise.race([onDirtyTests, waitForCommand.result]);
if (command === 'changed') waitForCommand.cancel();
if (bufferMode && command === 'changed') continue;
const shouldRunChangedFiles = bufferMode ? command === 'run' : command === 'changed';
if (shouldRunChangedFiles) {
if (dirtyTestIds.size === 0) continue;
const testIds = [...dirtyTestIds];
dirtyTestIds.clear();
dirtyTestFiles.clear();
await runTests(options, testServerConnection, {
testIds,
title: 'files changed'
});
lastRun = {
type: 'changed',
dirtyTestIds: testIds
};
continue;
}
if (command === 'run') {
// All means reset filters.
await runTests(options, testServerConnection);
lastRun = {
type: 'regular'
};
continue;
}
if (command === 'project') {
const {
selectedProjects
} = await _utilsBundle2.enquirer.prompt({
type: 'multiselect',
name: 'selectedProjects',
message: 'Select projects',
choices: projectNames
}).catch(() => ({
selectedProjects: null
}));
if (!selectedProjects) continue;
options.projects = selectedProjects.length ? selectedProjects : undefined;
await runTests(options, testServerConnection);
lastRun = {
type: 'regular'
};
continue;
}
if (command === 'file') {
const {
filePattern
} = await _utilsBundle2.enquirer.prompt({
type: 'text',
name: 'filePattern',
message: 'Input filename pattern (regex)'
}).catch(() => ({
filePattern: null
}));
if (filePattern === null) continue;
if (filePattern.trim()) options.files = filePattern.split(' ');else options.files = undefined;
await runTests(options, testServerConnection);
lastRun = {
type: 'regular'
};
continue;
}
if (command === 'grep') {
const {
testPattern
} = await _utilsBundle2.enquirer.prompt({
type: 'text',
name: 'testPattern',
message: 'Input test name pattern (regex)'
}).catch(() => ({
testPattern: null
}));
if (testPattern === null) continue;
if (testPattern.trim()) options.grep = testPattern;else options.grep = undefined;
await runTests(options, testServerConnection);
lastRun = {
type: 'regular'
};
continue;
}
if (command === 'failed') {
const failedTestIds = teleSuiteUpdater.rootSuite.allTests().filter(t => !t.ok()).map(t => t.id);
await runTests({}, testServerConnection, {
title: 'running failed tests',
testIds: failedTestIds
});
lastRun = {
type: 'failed',
failedTestIds
};
continue;
}
if (command === 'repeat') {
if (lastRun.type === 'regular') {
await runTests(options, testServerConnection, {
title: 're-running tests'
});
continue;
} else if (lastRun.type === 'changed') {
await runTests(options, testServerConnection, {
title: 're-running tests',
testIds: lastRun.dirtyTestIds
});
} else if (lastRun.type === 'failed') {
await runTests({}, testServerConnection, {
title: 're-running tests',
testIds: lastRun.failedTestIds
});
}
continue;
}
if (command === 'toggle-show-browser') {
await toggleShowBrowser();
continue;
}
if (command === 'toggle-buffer-mode') {
bufferMode = !bufferMode;
continue;
}
if (command === 'exit') break;
if (command === 'interrupted') {
result = 'interrupted';
break;
}
}
const teardown = await testServerConnection.runGlobalTeardown({});
return result === 'passed' ? teardown.status : result;
}
function readKeyPress(handler) {
const promise = new _utils.ManualPromise();
const rl = _readline.default.createInterface({
input: process.stdin,
escapeCodeTimeout: 50
});
_readline.default.emitKeypressEvents(process.stdin, rl);
if (process.stdin.isTTY) process.stdin.setRawMode(true);
const listener = _utils.eventsHelper.addEventListener(process.stdin, 'keypress', (text, key) => {
const result = handler(text, key);
if (result) promise.resolve(result);
});
const cancel = () => {
_utils.eventsHelper.removeEventListeners([listener]);
rl.close();
if (process.stdin.isTTY) process.stdin.setRawMode(false);
};
void promise.finally(cancel);
return {
result: promise,
cancel
};
}
const isInterrupt = (text, key) => text === '\x03' || text === '\x1B' || key && key.name === 'escape' || key && key.ctrl && key.name === 'c';
async function runTests(watchOptions, testServerConnection, options) {
printConfiguration(watchOptions, options === null || options === void 0 ? void 0 : options.title);
const waitForDone = readKeyPress((text, key) => {
if (isInterrupt(text, key)) {
testServerConnection.stopTestsNoReply({});
return 'done';
}
});
await testServerConnection.runTests({
grep: watchOptions.grep,
testIds: options === null || options === void 0 ? void 0 : options.testIds,
locations: watchOptions === null || watchOptions === void 0 ? void 0 : watchOptions.files,
projects: watchOptions.projects,
connectWsEndpoint,
reuseContext: connectWsEndpoint ? true : undefined,
workers: connectWsEndpoint ? 1 : undefined,
headed: connectWsEndpoint ? true : undefined
}).finally(() => waitForDone.cancel());
}
function readCommand() {
return readKeyPress((text, key) => {
if (isInterrupt(text, key)) return 'interrupted';
if (process.platform !== 'win32' && key && key.ctrl && key.name === 'z') {
process.kill(process.ppid, 'SIGTSTP');
process.kill(process.pid, 'SIGTSTP');
}
const name = key === null || key === void 0 ? void 0 : key.name;
if (name === 'q') return 'exit';
if (name === 'h') {
process.stdout.write(`${(0, _base.separator)()}
Run tests
${_utilsBundle.colors.bold('enter')} ${_utilsBundle.colors.dim('run tests')}
${_utilsBundle.colors.bold('f')} ${_utilsBundle.colors.dim('run failed tests')}
${_utilsBundle.colors.bold('r')} ${_utilsBundle.colors.dim('repeat last run')}
${_utilsBundle.colors.bold('q')} ${_utilsBundle.colors.dim('quit')}
Change settings
${_utilsBundle.colors.bold('c')} ${_utilsBundle.colors.dim('set project')}
${_utilsBundle.colors.bold('p')} ${_utilsBundle.colors.dim('set file filter')}
${_utilsBundle.colors.bold('t')} ${_utilsBundle.colors.dim('set title filter')}
${_utilsBundle.colors.bold('s')} ${_utilsBundle.colors.dim('toggle show & reuse the browser')}
${_utilsBundle.colors.bold('b')} ${_utilsBundle.colors.dim('toggle buffer mode')}
`);
return;
}
switch (name) {
case 'return':
return 'run';
case 'r':
return 'repeat';
case 'c':
return 'project';
case 'p':
return 'file';
case 't':
return 'grep';
case 'f':
return 'failed';
case 's':
return 'toggle-show-browser';
case 'b':
return 'toggle-buffer-mode';
}
});
}
let showBrowserServer;
let connectWsEndpoint = undefined;
let seq = 1;
function printConfiguration(options, title) {
const packageManagerCommand = (0, _utils.getPackageManagerExecCommand)();
const tokens = [];
tokens.push(`${packageManagerCommand} playwright test`);
if (options.projects) tokens.push(...options.projects.map(p => _utilsBundle.colors.blue(`--project ${p}`)));
if (options.grep) tokens.push(_utilsBundle.colors.red(`--grep ${options.grep}`));
if (options.files) tokens.push(...options.files.map(a => _utilsBundle.colors.bold(a)));
if (title) tokens.push(_utilsBundle.colors.dim(`(${title})`));
tokens.push(_utilsBundle.colors.dim(`#${seq++}`));
const lines = [];
const sep = (0, _base.separator)();
lines.push('\x1Bc' + sep);
lines.push(`${tokens.join(' ')}`);
lines.push(`${_utilsBundle.colors.dim('Show & reuse browser:')} ${_utilsBundle.colors.bold(showBrowserServer ? 'on' : 'off')}`);
process.stdout.write(lines.join('\n'));
}
function printBufferPrompt(dirtyTestFiles, rootDir) {
const sep = (0, _base.separator)();
process.stdout.write('\x1Bc');
process.stdout.write(`${sep}\n`);
if (dirtyTestFiles.size === 0) {
process.stdout.write(`${_utilsBundle.colors.dim('Waiting for file changes. Press')} ${_utilsBundle.colors.bold('q')} ${_utilsBundle.colors.dim('to quit or')} ${_utilsBundle.colors.bold('h')} ${_utilsBundle.colors.dim('for more options.')}\n\n`);
return;
}
process.stdout.write(`${_utilsBundle.colors.dim(`${dirtyTestFiles.size} test ${dirtyTestFiles.size === 1 ? 'file' : 'files'} changed:`)}\n\n`);
for (const file of dirtyTestFiles) process.stdout.write(` · ${_path.default.relative(rootDir, file)}\n`);
process.stdout.write(`\n${_utilsBundle.colors.dim(`Press`)} ${_utilsBundle.colors.bold('enter')} ${_utilsBundle.colors.dim('to run')}, ${_utilsBundle.colors.bold('q')} ${_utilsBundle.colors.dim('to quit or')} ${_utilsBundle.colors.bold('h')} ${_utilsBundle.colors.dim('for more options.')}\n\n`);
}
function printPrompt() {
const sep = (0, _base.separator)();
process.stdout.write(`
${sep}
${_utilsBundle.colors.dim('Waiting for file changes. Press')} ${_utilsBundle.colors.bold('enter')} ${_utilsBundle.colors.dim('to run tests')}, ${_utilsBundle.colors.bold('q')} ${_utilsBundle.colors.dim('to quit or')} ${_utilsBundle.colors.bold('h')} ${_utilsBundle.colors.dim('for more options.')}
`);
}
async function toggleShowBrowser() {
if (!showBrowserServer) {
showBrowserServer = new _playwrightServer.PlaywrightServer({
mode: 'extension',
path: '/' + (0, _utils.createGuid)(),
maxConnections: 1
});
connectWsEndpoint = await showBrowserServer.listen();
process.stdout.write(`${_utilsBundle.colors.dim('Show & reuse browser:')} ${_utilsBundle.colors.bold('on')}\n`);
} else {
var _showBrowserServer;
await ((_showBrowserServer = showBrowserServer) === null || _showBrowserServer === void 0 ? void 0 : _showBrowserServer.close());
showBrowserServer = undefined;
connectWsEndpoint = undefined;
process.stdout.write(`${_utilsBundle.colors.dim('Show & reuse browser:')} ${_utilsBundle.colors.bold('off')}\n`);
}
}

85
node_modules/playwright/lib/runner/workerHost.js generated vendored Normal file
View File

@@ -0,0 +1,85 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WorkerHost = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _ipc = require("../common/ipc");
var _processHost = require("./processHost");
var _folders = require("../isomorphic/folders");
var _utils = require("playwright-core/lib/utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
let lastWorkerIndex = 0;
class WorkerHost extends _processHost.ProcessHost {
constructor(testGroup, parallelIndex, config, extraEnv, outputDir) {
const workerIndex = lastWorkerIndex++;
super(require.resolve('../worker/workerMain.js'), `worker-${workerIndex}`, {
...extraEnv,
FORCE_COLOR: '1',
DEBUG_COLORS: process.env.DEBUG_COLORS === undefined ? '1' : process.env.DEBUG_COLORS
});
this.parallelIndex = void 0;
this.workerIndex = void 0;
this._hash = void 0;
this._params = void 0;
this._didFail = false;
this.workerIndex = workerIndex;
this.parallelIndex = parallelIndex;
this._hash = testGroup.workerHash;
this._params = {
workerIndex: this.workerIndex,
parallelIndex,
repeatEachIndex: testGroup.repeatEachIndex,
projectId: testGroup.projectId,
config,
artifactsDir: _path.default.join(outputDir, (0, _folders.artifactsFolderName)(workerIndex))
};
}
async start() {
await _fs.default.promises.mkdir(this._params.artifactsDir, {
recursive: true
});
return await this.startRunner(this._params, {
onStdOut: chunk => this.emit('stdOut', (0, _ipc.stdioChunkToParams)(chunk)),
onStdErr: chunk => this.emit('stdErr', (0, _ipc.stdioChunkToParams)(chunk))
});
}
async onExit() {
await (0, _utils.removeFolders)([this._params.artifactsDir]);
}
async stop(didFail) {
if (didFail) this._didFail = true;
await super.stop();
}
runTestGroup(runPayload) {
this.sendMessageNoReply({
method: 'runTestGroup',
params: runPayload
});
}
hash() {
return this._hash;
}
didFail() {
return this._didFail;
}
}
exports.WorkerHost = WorkerHost;

View File

@@ -0,0 +1,111 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.loadTsConfig = loadTsConfig;
var path = _interopRequireWildcard(require("path"));
var fs = _interopRequireWildcard(require("fs"));
var _utilsBundle = require("../utilsBundle");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
* The MIT License (MIT)
*
* Copyright (c) 2016 Jonas Kello
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* eslint-disable */
/**
* Typing for the parts of tsconfig that we care about
*/
function loadTsConfig(configPath) {
try {
const references = [];
const config = innerLoadTsConfig(configPath, references);
return [config, ...references];
} catch (e) {
throw new Error(`Failed to load tsconfig file at ${configPath}:\n${e.message}`);
}
}
function resolveConfigFile(baseConfigFile, referencedConfigFile) {
if (!referencedConfigFile.endsWith('.json')) referencedConfigFile += '.json';
const currentDir = path.dirname(baseConfigFile);
let resolvedConfigFile = path.resolve(currentDir, referencedConfigFile);
// TODO: I don't see how this makes sense, delete in the next minor release.
if (referencedConfigFile.includes('/') && referencedConfigFile.includes('.') && !fs.existsSync(resolvedConfigFile)) resolvedConfigFile = path.join(currentDir, 'node_modules', referencedConfigFile);
return resolvedConfigFile;
}
function innerLoadTsConfig(configFilePath, references, visited = new Map()) {
var _parsedConfig$compile, _parsedConfig$compile2, _parsedConfig$compile3;
if (visited.has(configFilePath)) return visited.get(configFilePath);
let result = {
tsConfigPath: configFilePath
};
// Retain result instance below, so that caching works.
visited.set(configFilePath, result);
if (!fs.existsSync(configFilePath)) return result;
const configString = fs.readFileSync(configFilePath, 'utf-8');
const cleanedJson = StripBom(configString);
const parsedConfig = _utilsBundle.json5.parse(cleanedJson);
const extendsArray = Array.isArray(parsedConfig.extends) ? parsedConfig.extends : parsedConfig.extends ? [parsedConfig.extends] : [];
for (const extendedConfig of extendsArray) {
const extendedConfigPath = resolveConfigFile(configFilePath, extendedConfig);
const base = innerLoadTsConfig(extendedConfigPath, references, visited);
// Retain result instance, so that caching works.
Object.assign(result, base, {
tsConfigPath: configFilePath
});
}
if (((_parsedConfig$compile = parsedConfig.compilerOptions) === null || _parsedConfig$compile === void 0 ? void 0 : _parsedConfig$compile.allowJs) !== undefined) result.allowJs = parsedConfig.compilerOptions.allowJs;
if (((_parsedConfig$compile2 = parsedConfig.compilerOptions) === null || _parsedConfig$compile2 === void 0 ? void 0 : _parsedConfig$compile2.paths) !== undefined) {
// We must store pathsBasePath from the config that defines "paths" and later resolve
// based on this absolute path, when no "baseUrl" is specified. See tsc for reference:
// https://github.com/microsoft/TypeScript/blob/353ccb7688351ae33ccf6e0acb913aa30621eaf4/src/compiler/commandLineParser.ts#L3129
// https://github.com/microsoft/TypeScript/blob/353ccb7688351ae33ccf6e0acb913aa30621eaf4/src/compiler/moduleSpecifiers.ts#L510
result.paths = {
mapping: parsedConfig.compilerOptions.paths,
pathsBasePath: path.dirname(configFilePath)
};
}
if (((_parsedConfig$compile3 = parsedConfig.compilerOptions) === null || _parsedConfig$compile3 === void 0 ? void 0 : _parsedConfig$compile3.baseUrl) !== undefined) {
// Follow tsc and resolve all relative file paths in the config right away.
// This way it is safe to inherit paths between the configs.
result.absoluteBaseUrl = path.resolve(path.dirname(configFilePath), parsedConfig.compilerOptions.baseUrl);
}
for (const ref of parsedConfig.references || []) references.push(innerLoadTsConfig(resolveConfigFile(configFilePath, ref.path), references, visited));
if (path.basename(configFilePath) === 'jsconfig.json' && result.allowJs === undefined) result.allowJs = true;
return result;
}
function StripBom(string) {
if (typeof string !== 'string') {
throw new TypeError(`Expected a string, got ${typeof string}`);
}
// Catches EFBBBF (UTF-8 BOM) because the buffer-to-string
// conversion translates it to FEFF (UTF-16 BOM).
if (string.charCodeAt(0) === 0xFEFF) {
return string.slice(1);
}
return string;
}

28
node_modules/playwright/lib/transform/babelBundle.js generated vendored Normal file
View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.types = exports.traverse = exports.declare = exports.codeFrameColumns = exports.babelTransform = exports.babelParse = void 0;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const codeFrameColumns = exports.codeFrameColumns = require('./babelBundleImpl').codeFrameColumns;
const declare = exports.declare = require('./babelBundleImpl').declare;
const types = exports.types = require('./babelBundleImpl').types;
const traverse = exports.traverse = require('./babelBundleImpl').traverse;
const babelTransform = exports.babelTransform = require('./babelBundleImpl').babelTransform;
const babelParse = exports.babelParse = require('./babelBundleImpl').babelParse;

2032
node_modules/playwright/lib/transform/babelBundleImpl.js generated vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,254 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.addToCompilationCache = addToCompilationCache;
exports.affectedTestFiles = affectedTestFiles;
exports.belongsToNodeModules = belongsToNodeModules;
exports.cacheDir = void 0;
exports.collectAffectedTestFiles = collectAffectedTestFiles;
exports.currentFileDepsCollector = currentFileDepsCollector;
exports.dependenciesForTestFile = dependenciesForTestFile;
exports.fileDependenciesForTest = fileDependenciesForTest;
exports.getFromCompilationCache = getFromCompilationCache;
exports.getUserData = getUserData;
exports.installSourceMapSupport = installSourceMapSupport;
exports.internalDependenciesForTestFile = internalDependenciesForTestFile;
exports.serializeCompilationCache = serializeCompilationCache;
exports.setExternalDependencies = setExternalDependencies;
exports.startCollectingFileDeps = startCollectingFileDeps;
exports.stopCollectingFileDeps = stopCollectingFileDeps;
var _fs = _interopRequireDefault(require("fs"));
var _os = _interopRequireDefault(require("os"));
var _path = _interopRequireDefault(require("path"));
var _utilsBundle = require("../utilsBundle");
var _globals = require("../common/globals");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Assumptions for the compilation cache:
// - Files in the temp directory we work with can disappear at any moment, either some of them or all together.
// - Multiple workers can be trying to read from the compilation cache at the same time.
// - There is a single invocation of the test runner at a time.
//
// Therefore, we implement the following logic:
// - Never assume that file is present, always try to read it to determine whether it's actually present.
// - Never write to the cache from worker processes to avoid "multiple writers" races.
// - Since we perform all static imports in the runner beforehand, most of the time
// workers should be able to read from the cache.
// - For workers-only dynamic imports or some cache problems, we will re-transpile files in
// each worker anew.
const cacheDir = exports.cacheDir = process.env.PWTEST_CACHE_DIR || ((_process$geteuid, _process) => {
if (process.platform === 'win32') return _path.default.join(_os.default.tmpdir(), `playwright-transform-cache`);
// Use `geteuid()` instead of more natural `os.userInfo().username`
// since `os.userInfo()` is not always available.
// Note: `process.geteuid()` is not available on windows.
// See https://github.com/microsoft/playwright/issues/22721
return _path.default.join(_os.default.tmpdir(), `playwright-transform-cache-` + ((_process$geteuid = (_process = process).geteuid) === null || _process$geteuid === void 0 ? void 0 : _process$geteuid.call(_process)));
})();
const sourceMaps = new Map();
const memoryCache = new Map();
// Dependencies resolved by the loader.
const fileDependencies = new Map();
// Dependencies resolved by the external bundler.
const externalDependencies = new Map();
function installSourceMapSupport() {
Error.stackTraceLimit = 200;
_utilsBundle.sourceMapSupport.install({
environment: 'node',
handleUncaughtExceptions: false,
retrieveSourceMap(source) {
if (!sourceMaps.has(source)) return null;
const sourceMapPath = sourceMaps.get(source);
try {
return {
map: JSON.parse(_fs.default.readFileSync(sourceMapPath, 'utf-8')),
url: source
};
} catch {
return null;
}
}
});
}
function _innerAddToCompilationCacheAndSerialize(filename, entry) {
sourceMaps.set(entry.moduleUrl || filename, entry.sourceMapPath);
memoryCache.set(filename, entry);
return {
sourceMaps: [[entry.moduleUrl || filename, entry.sourceMapPath]],
memoryCache: [[filename, entry]],
fileDependencies: [],
externalDependencies: []
};
}
function getFromCompilationCache(filename, hash, moduleUrl) {
// First check the memory cache by filename, this cache will always work in the worker,
// because we just compiled this file in the loader.
const cache = memoryCache.get(filename);
if (cache !== null && cache !== void 0 && cache.codePath) {
try {
return {
cachedCode: _fs.default.readFileSync(cache.codePath, 'utf-8')
};
} catch {
// Not able to read the file - fall through.
}
}
// Then do the disk cache, this cache works between the Playwright Test runs.
const cachePath = calculateCachePath(filename, hash);
const codePath = cachePath + '.js';
const sourceMapPath = cachePath + '.map';
const dataPath = cachePath + '.data';
try {
const cachedCode = _fs.default.readFileSync(codePath, 'utf8');
const serializedCache = _innerAddToCompilationCacheAndSerialize(filename, {
codePath,
sourceMapPath,
dataPath,
moduleUrl
});
return {
cachedCode,
serializedCache
};
} catch {}
return {
addToCache: (code, map, data) => {
if ((0, _globals.isWorkerProcess)()) return {};
_fs.default.mkdirSync(_path.default.dirname(cachePath), {
recursive: true
});
if (map) _fs.default.writeFileSync(sourceMapPath, JSON.stringify(map), 'utf8');
if (data.size) _fs.default.writeFileSync(dataPath, JSON.stringify(Object.fromEntries(data.entries()), undefined, 2), 'utf8');
_fs.default.writeFileSync(codePath, code, 'utf8');
const serializedCache = _innerAddToCompilationCacheAndSerialize(filename, {
codePath,
sourceMapPath,
dataPath,
moduleUrl
});
return {
serializedCache
};
}
};
}
function serializeCompilationCache() {
return {
sourceMaps: [...sourceMaps.entries()],
memoryCache: [...memoryCache.entries()],
fileDependencies: [...fileDependencies.entries()].map(([filename, deps]) => [filename, [...deps]]),
externalDependencies: [...externalDependencies.entries()].map(([filename, deps]) => [filename, [...deps]])
};
}
function addToCompilationCache(payload) {
for (const entry of payload.sourceMaps) sourceMaps.set(entry[0], entry[1]);
for (const entry of payload.memoryCache) memoryCache.set(entry[0], entry[1]);
for (const entry of payload.fileDependencies) {
const existing = fileDependencies.get(entry[0]) || [];
fileDependencies.set(entry[0], new Set([...entry[1], ...existing]));
}
for (const entry of payload.externalDependencies) {
const existing = externalDependencies.get(entry[0]) || [];
externalDependencies.set(entry[0], new Set([...entry[1], ...existing]));
}
}
function calculateCachePath(filePath, hash) {
const fileName = _path.default.basename(filePath, _path.default.extname(filePath)).replace(/\W/g, '') + '_' + hash;
return _path.default.join(cacheDir, hash[0] + hash[1], fileName);
}
// Since ESM and CJS collect dependencies differently,
// we go via the global state to collect them.
let depsCollector;
function startCollectingFileDeps() {
depsCollector = new Set();
}
function stopCollectingFileDeps(filename) {
if (!depsCollector) return;
depsCollector.delete(filename);
for (const dep of depsCollector) {
if (belongsToNodeModules(dep)) depsCollector.delete(dep);
}
fileDependencies.set(filename, depsCollector);
depsCollector = undefined;
}
function currentFileDepsCollector() {
return depsCollector;
}
function setExternalDependencies(filename, deps) {
const depsSet = new Set(deps.filter(dep => !belongsToNodeModules(dep) && dep !== filename));
externalDependencies.set(filename, depsSet);
}
function fileDependenciesForTest() {
return fileDependencies;
}
function collectAffectedTestFiles(changedFile, testFileCollector) {
const isTestFile = file => fileDependencies.has(file);
if (isTestFile(changedFile)) testFileCollector.add(changedFile);
for (const [testFile, deps] of fileDependencies) {
if (deps.has(changedFile)) testFileCollector.add(testFile);
}
for (const [importingFile, depsOfImportingFile] of externalDependencies) {
if (depsOfImportingFile.has(changedFile)) {
if (isTestFile(importingFile)) testFileCollector.add(importingFile);
for (const [testFile, depsOfTestFile] of fileDependencies) {
if (depsOfTestFile.has(importingFile)) testFileCollector.add(testFile);
}
}
}
}
function affectedTestFiles(changes) {
const result = new Set();
for (const change of changes) collectAffectedTestFiles(change, result);
return [...result];
}
function internalDependenciesForTestFile(filename) {
return fileDependencies.get(filename);
}
function dependenciesForTestFile(filename) {
const result = new Set();
for (const testDependency of fileDependencies.get(filename) || []) {
result.add(testDependency);
for (const externalDependency of externalDependencies.get(testDependency) || []) result.add(externalDependency);
}
for (const dep of externalDependencies.get(filename) || []) result.add(dep);
return result;
}
// This is only used in the dev mode, specifically excluding
// files from packages/playwright*. In production mode, node_modules covers
// that.
const kPlaywrightInternalPrefix = _path.default.resolve(__dirname, '../../../playwright');
function belongsToNodeModules(file) {
if (file.includes(`${_path.default.sep}node_modules${_path.default.sep}`)) return true;
if (file.startsWith(kPlaywrightInternalPrefix) && (file.endsWith('.js') || file.endsWith('.mjs'))) return true;
return false;
}
async function getUserData(pluginName) {
const result = new Map();
for (const [fileName, cache] of memoryCache) {
if (!cache.dataPath) continue;
if (!_fs.default.existsSync(cache.dataPath)) continue;
const data = JSON.parse(await _fs.default.promises.readFile(cache.dataPath, 'utf8'));
if (data[pluginName]) result.set(fileName, data[pluginName]);
}
return result;
}

117
node_modules/playwright/lib/transform/esmLoader.js generated vendored Normal file
View File

@@ -0,0 +1,117 @@
"use strict";
var _fs = _interopRequireDefault(require("fs"));
var _url = _interopRequireDefault(require("url"));
var _compilationCache = require("./compilationCache");
var _transform = require("./transform");
var _portTransport = require("./portTransport");
var _util = require("../util");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Node < 18.6: defaultResolve takes 3 arguments.
// Node >= 18.6: nextResolve from the chain takes 2 arguments.
async function resolve(specifier, context, defaultResolve) {
var _currentFileDepsColle;
if (context.parentURL && context.parentURL.startsWith('file://')) {
const filename = _url.default.fileURLToPath(context.parentURL);
const resolved = (0, _transform.resolveHook)(filename, specifier);
if (resolved !== undefined) specifier = _url.default.pathToFileURL(resolved).toString();
}
const result = await defaultResolve(specifier, context, defaultResolve);
// Note: we collect dependencies here that will be sent to the main thread
// (and optionally runner process) after the loading finishes.
if (result !== null && result !== void 0 && result.url && result.url.startsWith('file://')) (_currentFileDepsColle = (0, _compilationCache.currentFileDepsCollector)()) === null || _currentFileDepsColle === void 0 || _currentFileDepsColle.add(_url.default.fileURLToPath(result.url));
return result;
}
// Node < 18.6: defaultLoad takes 3 arguments.
// Node >= 18.6: nextLoad from the chain takes 2 arguments.
async function load(moduleUrl, context, defaultLoad) {
var _transport;
// Bail out for wasm, json, etc.
// non-js files have context.format === undefined
if (context.format !== 'commonjs' && context.format !== 'module' && context.format !== undefined) return defaultLoad(moduleUrl, context, defaultLoad);
// Bail for built-in modules.
if (!moduleUrl.startsWith('file://')) return defaultLoad(moduleUrl, context, defaultLoad);
const filename = _url.default.fileURLToPath(moduleUrl);
// Bail for node_modules.
if (!(0, _transform.shouldTransform)(filename)) return defaultLoad(moduleUrl, context, defaultLoad);
const code = _fs.default.readFileSync(filename, 'utf-8');
const transformed = (0, _transform.transformHook)(code, filename, moduleUrl);
// Flush the source maps to the main thread, so that errors during import() are source-mapped.
if (transformed.serializedCache) await ((_transport = transport) === null || _transport === void 0 ? void 0 : _transport.send('pushToCompilationCache', {
cache: transformed.serializedCache
}));
// Output format is required, so we determine it manually when unknown.
// shortCircuit is required by Node >= 18.6 to designate no more loaders should be called.
return {
format: context.format || ((0, _util.fileIsModule)(filename) ? 'module' : 'commonjs'),
source: transformed.code,
shortCircuit: true
};
}
let transport;
// Node.js < 20
function globalPreload(context) {
transport = createTransport(context.port);
return `
globalThis.__esmLoaderPortPreV20 = port;
`;
}
// Node.js >= 20
function initialize(data) {
transport = createTransport(data === null || data === void 0 ? void 0 : data.port);
}
function createTransport(port) {
return new _portTransport.PortTransport(port, async (method, params) => {
if (method === 'setSingleTSConfig') {
(0, _transform.setSingleTSConfig)(params.tsconfig);
return;
}
if (method === 'setTransformConfig') {
(0, _transform.setTransformConfig)(params.config);
return;
}
if (method === 'addToCompilationCache') {
(0, _compilationCache.addToCompilationCache)(params.cache);
return;
}
if (method === 'getCompilationCache') return {
cache: (0, _compilationCache.serializeCompilationCache)()
};
if (method === 'startCollectingFileDeps') {
(0, _compilationCache.startCollectingFileDeps)();
return;
}
if (method === 'stopCollectingFileDeps') {
(0, _compilationCache.stopCollectingFileDeps)(params.file);
return;
}
});
}
module.exports = {
resolve,
load,
globalPreload,
initialize
};

32
node_modules/playwright/lib/transform/esmUtils.js generated vendored Normal file
View File

@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.execArgvWithExperimentalLoaderOptions = execArgvWithExperimentalLoaderOptions;
exports.execArgvWithoutExperimentalLoaderOptions = execArgvWithoutExperimentalLoaderOptions;
var _url = _interopRequireDefault(require("url"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const kExperimentalLoaderOptions = ['--no-warnings', `--experimental-loader=${_url.default.pathToFileURL(require.resolve('playwright/lib/transform/esmLoader')).toString()}`];
function execArgvWithExperimentalLoaderOptions() {
return [...process.execArgv, ...kExperimentalLoaderOptions];
}
function execArgvWithoutExperimentalLoaderOptions() {
return process.execArgv.filter(arg => !kExperimentalLoaderOptions.includes(arg));
}

81
node_modules/playwright/lib/transform/portTransport.js generated vendored Normal file
View File

@@ -0,0 +1,81 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PortTransport = void 0;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PortTransport {
constructor(port, handler) {
this._lastId = 0;
this._port = void 0;
this._callbacks = new Map();
this._port = port;
port.addEventListener('message', async event => {
const message = event.data;
const {
id,
ackId,
method,
params,
result
} = message;
if (id) {
const result = await handler(method, params);
this._port.postMessage({
ackId: id,
result
});
return;
}
if (ackId) {
const callback = this._callbacks.get(ackId);
this._callbacks.delete(ackId);
this._resetRef();
callback === null || callback === void 0 || callback(result);
return;
}
});
// Make sure to unref **after** adding a 'message' event listener.
// https://nodejs.org/api/worker_threads.html#portref
this._resetRef();
}
async send(method, params) {
return await new Promise(f => {
const id = ++this._lastId;
this._callbacks.set(id, f);
this._resetRef();
this._port.postMessage({
id,
method,
params
});
});
}
_resetRef() {
if (this._callbacks.size) {
// When we are waiting for a response, ref the port to prevent this process from exiting.
this._port.ref();
} else {
// When we are not waiting for a response, unref the port to prevent this process
// from hanging forever.
this._port.unref();
}
}
}
exports.PortTransport = PortTransport;

293
node_modules/playwright/lib/transform/transform.js generated vendored Normal file
View File

@@ -0,0 +1,293 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.requireOrImport = requireOrImport;
exports.resolveHook = resolveHook;
exports.setSingleTSConfig = setSingleTSConfig;
exports.setTransformConfig = setTransformConfig;
exports.setTransformData = setTransformData;
exports.shouldTransform = shouldTransform;
exports.singleTSConfig = singleTSConfig;
exports.transformConfig = transformConfig;
exports.transformHook = transformHook;
exports.wrapFunctionWithLocation = wrapFunctionWithLocation;
var _crypto = _interopRequireDefault(require("crypto"));
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _url = _interopRequireDefault(require("url"));
var _utilsBundle = require("../utilsBundle");
var _tsconfigLoader = require("../third_party/tsconfig-loader");
var _module = _interopRequireDefault(require("module"));
var _util = require("../util");
var _compilationCache = require("./compilationCache");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const version = require('../../package.json').version;
const cachedTSConfigs = new Map();
let _transformConfig = {
babelPlugins: [],
external: []
};
let _externalMatcher = () => false;
function setTransformConfig(config) {
_transformConfig = config;
_externalMatcher = (0, _util.createFileMatcher)(_transformConfig.external);
}
function transformConfig() {
return _transformConfig;
}
let _singleTSConfigPath;
let _singleTSConfig;
function setSingleTSConfig(value) {
_singleTSConfigPath = value;
}
function singleTSConfig() {
return _singleTSConfigPath;
}
function validateTsConfig(tsconfig) {
var _tsconfig$absoluteBas, _tsconfig$paths, _tsconfig$paths2;
// When no explicit baseUrl is set, resolve paths relative to the tsconfig file.
// See https://www.typescriptlang.org/tsconfig#paths
const pathsBase = (_tsconfig$absoluteBas = tsconfig.absoluteBaseUrl) !== null && _tsconfig$absoluteBas !== void 0 ? _tsconfig$absoluteBas : (_tsconfig$paths = tsconfig.paths) === null || _tsconfig$paths === void 0 ? void 0 : _tsconfig$paths.pathsBasePath;
// Only add the catch-all mapping when baseUrl is specified
const pathsFallback = tsconfig.absoluteBaseUrl ? [{
key: '*',
values: ['*']
}] : [];
return {
allowJs: !!tsconfig.allowJs,
pathsBase,
paths: Object.entries(((_tsconfig$paths2 = tsconfig.paths) === null || _tsconfig$paths2 === void 0 ? void 0 : _tsconfig$paths2.mapping) || {}).map(([key, values]) => ({
key,
values
})).concat(pathsFallback)
};
}
function loadAndValidateTsconfigsForFile(file) {
if (_singleTSConfigPath && !_singleTSConfig) _singleTSConfig = (0, _tsconfigLoader.loadTsConfig)(_singleTSConfigPath).map(validateTsConfig);
if (_singleTSConfig) return _singleTSConfig;
return loadAndValidateTsconfigsForFolder(_path.default.dirname(file));
}
function loadAndValidateTsconfigsForFolder(folder) {
const foldersWithConfig = [];
let currentFolder = _path.default.resolve(folder);
let result;
while (true) {
const cached = cachedTSConfigs.get(currentFolder);
if (cached) {
result = cached;
break;
}
foldersWithConfig.push(currentFolder);
for (const name of ['tsconfig.json', 'jsconfig.json']) {
const configPath = _path.default.join(currentFolder, name);
if (_fs.default.existsSync(configPath)) {
const loaded = (0, _tsconfigLoader.loadTsConfig)(configPath);
result = loaded.map(validateTsConfig);
break;
}
}
if (result) break;
const parentFolder = _path.default.resolve(currentFolder, '../');
if (currentFolder === parentFolder) break;
currentFolder = parentFolder;
}
result = result || [];
for (const folder of foldersWithConfig) cachedTSConfigs.set(folder, result);
return result;
}
const pathSeparator = process.platform === 'win32' ? ';' : ':';
const builtins = new Set(_module.default.builtinModules);
function resolveHook(filename, specifier) {
if (specifier.startsWith('node:') || builtins.has(specifier)) return;
if (!shouldTransform(filename)) return;
if (isRelativeSpecifier(specifier)) return (0, _util.resolveImportSpecifierAfterMapping)(_path.default.resolve(_path.default.dirname(filename), specifier), false);
/**
* TypeScript discourages path-mapping into node_modules:
* https://www.typescriptlang.org/docs/handbook/modules/reference.html#paths-should-not-point-to-monorepo-packages-or-node_modules-packages
* However, if path-mapping doesn't yield a result, TypeScript falls back to the default resolution through node_modules.
*/
const isTypeScript = filename.endsWith('.ts') || filename.endsWith('.tsx');
const tsconfigs = loadAndValidateTsconfigsForFile(filename);
for (const tsconfig of tsconfigs) {
if (!isTypeScript && !tsconfig.allowJs) continue;
let longestPrefixLength = -1;
let pathMatchedByLongestPrefix;
for (const {
key,
values
} of tsconfig.paths) {
let matchedPartOfSpecifier = specifier;
const [keyPrefix, keySuffix] = key.split('*');
if (key.includes('*')) {
// * If pattern contains '*' then to match pattern "<prefix>*<suffix>" module name must start with the <prefix> and end with <suffix>.
// * <MatchedStar> denotes part of the module name between <prefix> and <suffix>.
// * If module name can be matches with multiple patterns then pattern with the longest prefix will be picked.
// https://github.com/microsoft/TypeScript/blob/f82d0cb3299c04093e3835bc7e29f5b40475f586/src/compiler/moduleNameResolver.ts#L1049
if (keyPrefix) {
if (!specifier.startsWith(keyPrefix)) continue;
matchedPartOfSpecifier = matchedPartOfSpecifier.substring(keyPrefix.length, matchedPartOfSpecifier.length);
}
if (keySuffix) {
if (!specifier.endsWith(keySuffix)) continue;
matchedPartOfSpecifier = matchedPartOfSpecifier.substring(0, matchedPartOfSpecifier.length - keySuffix.length);
}
} else {
if (specifier !== key) continue;
matchedPartOfSpecifier = specifier;
}
if (keyPrefix.length <= longestPrefixLength) continue;
for (const value of values) {
let candidate = value;
if (value.includes('*')) candidate = candidate.replace('*', matchedPartOfSpecifier);
candidate = _path.default.resolve(tsconfig.pathsBase, candidate);
const existing = (0, _util.resolveImportSpecifierAfterMapping)(candidate, true);
if (existing) {
longestPrefixLength = keyPrefix.length;
pathMatchedByLongestPrefix = existing;
}
}
}
if (pathMatchedByLongestPrefix) return pathMatchedByLongestPrefix;
}
if (_path.default.isAbsolute(specifier)) {
// Handle absolute file paths like `import '/path/to/file'`
// Do not handle module imports like `import 'fs'`
return (0, _util.resolveImportSpecifierAfterMapping)(specifier, false);
}
}
function shouldTransform(filename) {
if (_externalMatcher(filename)) return false;
return !(0, _compilationCache.belongsToNodeModules)(filename);
}
let transformData;
function setTransformData(pluginName, value) {
transformData.set(pluginName, value);
}
function transformHook(originalCode, filename, moduleUrl) {
const hasPreprocessor = process.env.PW_TEST_SOURCE_TRANSFORM && process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE && process.env.PW_TEST_SOURCE_TRANSFORM_SCOPE.split(pathSeparator).some(f => filename.startsWith(f));
const pluginsPrologue = _transformConfig.babelPlugins;
const pluginsEpilogue = hasPreprocessor ? [[process.env.PW_TEST_SOURCE_TRANSFORM]] : [];
const hash = calculateHash(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue);
const {
cachedCode,
addToCache,
serializedCache
} = (0, _compilationCache.getFromCompilationCache)(filename, hash, moduleUrl);
if (cachedCode !== undefined) return {
code: cachedCode,
serializedCache
};
// We don't use any browserslist data, but babel checks it anyway.
// Silence the annoying warning.
process.env.BROWSERSLIST_IGNORE_OLD_DATA = 'true';
const {
babelTransform
} = require('./babelBundle');
transformData = new Map();
const {
code,
map
} = babelTransform(originalCode, filename, !!moduleUrl, pluginsPrologue, pluginsEpilogue);
if (!code) return {
code: '',
serializedCache
};
const added = addToCache(code, map, transformData);
return {
code,
serializedCache: added.serializedCache
};
}
function calculateHash(content, filePath, isModule, pluginsPrologue, pluginsEpilogue) {
const hash = _crypto.default.createHash('sha1').update(isModule ? 'esm' : 'no_esm').update(content).update(filePath).update(version).update(pluginsPrologue.map(p => p[0]).join(',')).update(pluginsEpilogue.map(p => p[0]).join(',')).digest('hex');
return hash;
}
async function requireOrImport(file) {
installTransformIfNeeded();
const isModule = (0, _util.fileIsModule)(file);
const esmImport = () => eval(`import(${JSON.stringify(_url.default.pathToFileURL(file))})`);
if (isModule) return await esmImport();
const result = require(file);
const depsCollector = (0, _compilationCache.currentFileDepsCollector)();
if (depsCollector) {
const module = require.cache[file];
if (module) collectCJSDependencies(module, depsCollector);
}
return result;
}
let transformInstalled = false;
function installTransformIfNeeded() {
if (transformInstalled) return;
transformInstalled = true;
(0, _compilationCache.installSourceMapSupport)();
const originalResolveFilename = _module.default._resolveFilename;
function resolveFilename(specifier, parent, ...rest) {
if (parent) {
const resolved = resolveHook(parent.filename, specifier);
if (resolved !== undefined) specifier = resolved;
}
return originalResolveFilename.call(this, specifier, parent, ...rest);
}
_module.default._resolveFilename = resolveFilename;
_utilsBundle.pirates.addHook((code, filename) => {
if (!shouldTransform(filename)) return code;
return transformHook(code, filename).code;
}, {
exts: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.mts', '.cjs', '.cts']
});
}
const collectCJSDependencies = (module, dependencies) => {
module.children.forEach(child => {
if (!(0, _compilationCache.belongsToNodeModules)(child.filename) && !dependencies.has(child.filename)) {
dependencies.add(child.filename);
collectCJSDependencies(child, dependencies);
}
});
};
function wrapFunctionWithLocation(func) {
return (...args) => {
const oldPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (error, stackFrames) => {
const frame = _utilsBundle.sourceMapSupport.wrapCallSite(stackFrames[1]);
const fileName = frame.getFileName();
// Node error stacks for modules use file:// urls instead of paths.
const file = fileName && fileName.startsWith('file://') ? _url.default.fileURLToPath(fileName) : fileName;
return {
file,
line: frame.getLineNumber(),
column: frame.getColumnNumber()
};
};
const oldStackTraceLimit = Error.stackTraceLimit;
Error.stackTraceLimit = 2;
const obj = {};
Error.captureStackTrace(obj);
const location = obj.stack;
Error.stackTraceLimit = oldStackTraceLimit;
Error.prepareStackTrace = oldPrepareStackTrace;
return func(location, ...args);
};
}
function isRelativeSpecifier(specifier) {
return specifier === '.' || specifier === '..' || specifier.startsWith('./') || specifier.startsWith('../');
}

371
node_modules/playwright/lib/util.js generated vendored Normal file
View File

@@ -0,0 +1,371 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.addSuffixToFilePath = addSuffixToFilePath;
exports.callLogText = void 0;
exports.createFileFiltersFromArguments = createFileFiltersFromArguments;
exports.createFileMatcher = createFileMatcher;
exports.createFileMatcherFromArguments = createFileMatcherFromArguments;
exports.createTitleMatcher = createTitleMatcher;
exports.debugTest = void 0;
exports.errorWithFile = errorWithFile;
exports.expectTypes = expectTypes;
exports.fileIsModule = fileIsModule;
exports.filterStackFile = filterStackFile;
exports.filterStackTrace = filterStackTrace;
exports.filteredStackTrace = filteredStackTrace;
exports.forceRegExp = forceRegExp;
exports.formatLocation = formatLocation;
exports.getContainedPath = getContainedPath;
exports.getPackageJsonPath = getPackageJsonPath;
exports.mergeObjects = mergeObjects;
exports.normalizeAndSaveAttachment = normalizeAndSaveAttachment;
exports.relativeFilePath = relativeFilePath;
exports.removeDirAndLogToConsole = removeDirAndLogToConsole;
exports.resolveImportSpecifierAfterMapping = resolveImportSpecifierAfterMapping;
exports.resolveReporterOutputPath = resolveReporterOutputPath;
exports.sanitizeFilePathBeforeExtension = sanitizeFilePathBeforeExtension;
exports.serializeError = serializeError;
exports.trimLongString = trimLongString;
exports.windowsFilesystemFriendlyLength = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _util = _interopRequireDefault(require("util"));
var _path = _interopRequireDefault(require("path"));
var _url = _interopRequireDefault(require("url"));
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _utils = require("playwright-core/lib/utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const PLAYWRIGHT_TEST_PATH = _path.default.join(__dirname, '..');
const PLAYWRIGHT_CORE_PATH = _path.default.dirname(require.resolve('playwright-core/package.json'));
function filterStackTrace(e) {
var _e$stack;
const name = e.name ? e.name + ': ' : '';
const cause = e.cause instanceof Error ? filterStackTrace(e.cause) : undefined;
if (process.env.PWDEBUGIMPL) return {
message: name + e.message,
stack: e.stack || '',
cause
};
const stackLines = (0, _utils.stringifyStackFrames)(filteredStackTrace(((_e$stack = e.stack) === null || _e$stack === void 0 ? void 0 : _e$stack.split('\n')) || []));
return {
message: name + e.message,
stack: `${name}${e.message}${stackLines.map(line => '\n' + line).join('')}`,
cause
};
}
function filterStackFile(file) {
if (!process.env.PWDEBUGIMPL && file.startsWith(PLAYWRIGHT_TEST_PATH)) return false;
if (!process.env.PWDEBUGIMPL && file.startsWith(PLAYWRIGHT_CORE_PATH)) return false;
return true;
}
function filteredStackTrace(rawStack) {
const frames = [];
for (const line of rawStack) {
const frame = (0, _utilsBundle.parseStackTraceLine)(line);
if (!frame || !frame.file) continue;
if (!filterStackFile(frame.file)) continue;
frames.push(frame);
}
return frames;
}
function serializeError(error) {
if (error instanceof Error) return filterStackTrace(error);
return {
value: _util.default.inspect(error)
};
}
function createFileFiltersFromArguments(args) {
return args.map(arg => {
const match = /^(.*?):(\d+):?(\d+)?$/.exec(arg);
return {
re: forceRegExp(match ? match[1] : arg),
line: match ? parseInt(match[2], 10) : null,
column: match !== null && match !== void 0 && match[3] ? parseInt(match[3], 10) : null
};
});
}
function createFileMatcherFromArguments(args) {
const filters = createFileFiltersFromArguments(args);
return createFileMatcher(filters.map(filter => filter.re || filter.exact || ''));
}
function createFileMatcher(patterns) {
const reList = [];
const filePatterns = [];
for (const pattern of Array.isArray(patterns) ? patterns : [patterns]) {
if ((0, _utils.isRegExp)(pattern)) {
reList.push(pattern);
} else {
if (!pattern.startsWith('**/')) filePatterns.push('**/' + pattern);else filePatterns.push(pattern);
}
}
return filePath => {
for (const re of reList) {
re.lastIndex = 0;
if (re.test(filePath)) return true;
}
// Windows might still receive unix style paths from Cygwin or Git Bash.
// Check against the file url as well.
if (_path.default.sep === '\\') {
const fileURL = _url.default.pathToFileURL(filePath).href;
for (const re of reList) {
re.lastIndex = 0;
if (re.test(fileURL)) return true;
}
}
for (const pattern of filePatterns) {
if ((0, _utilsBundle.minimatch)(filePath, pattern, {
nocase: true,
dot: true
})) return true;
}
return false;
};
}
function createTitleMatcher(patterns) {
const reList = Array.isArray(patterns) ? patterns : [patterns];
return value => {
for (const re of reList) {
re.lastIndex = 0;
if (re.test(value)) return true;
}
return false;
};
}
function mergeObjects(a, b, c) {
const result = {
...a
};
for (const x of [b, c].filter(Boolean)) {
for (const [name, value] of Object.entries(x)) {
if (!Object.is(value, undefined)) result[name] = value;
}
}
return result;
}
function forceRegExp(pattern) {
const match = pattern.match(/^\/(.*)\/([gi]*)$/);
if (match) return new RegExp(match[1], match[2]);
return new RegExp(pattern, 'gi');
}
function relativeFilePath(file) {
if (!_path.default.isAbsolute(file)) return file;
return _path.default.relative(process.cwd(), file);
}
function formatLocation(location) {
return relativeFilePath(location.file) + ':' + location.line + ':' + location.column;
}
function errorWithFile(file, message) {
return new Error(`${relativeFilePath(file)}: ${message}`);
}
function expectTypes(receiver, types, matcherName) {
if (typeof receiver !== 'object' || !types.includes(receiver.constructor.name)) {
const commaSeparated = types.slice();
const lastType = commaSeparated.pop();
const typesString = commaSeparated.length ? commaSeparated.join(', ') + ' or ' + lastType : lastType;
throw new Error(`${matcherName} can be only used with ${typesString} object${types.length > 1 ? 's' : ''}`);
}
}
const windowsFilesystemFriendlyLength = exports.windowsFilesystemFriendlyLength = 60;
function trimLongString(s, length = 100) {
if (s.length <= length) return s;
const hash = (0, _utils.calculateSha1)(s);
const middle = `-${hash.substring(0, 5)}-`;
const start = Math.floor((length - middle.length) / 2);
const end = length - middle.length - start;
return s.substring(0, start) + middle + s.slice(-end);
}
function addSuffixToFilePath(filePath, suffix) {
const ext = _path.default.extname(filePath);
const base = filePath.substring(0, filePath.length - ext.length);
return base + suffix + ext;
}
function sanitizeFilePathBeforeExtension(filePath) {
const ext = _path.default.extname(filePath);
const base = filePath.substring(0, filePath.length - ext.length);
return (0, _utils.sanitizeForFilePath)(base) + ext;
}
/**
* Returns absolute path contained within parent directory.
*/
function getContainedPath(parentPath, subPath = '') {
const resolvedPath = _path.default.resolve(parentPath, subPath);
if (resolvedPath === parentPath || resolvedPath.startsWith(parentPath + _path.default.sep)) return resolvedPath;
return null;
}
const debugTest = exports.debugTest = (0, _utilsBundle.debug)('pw:test');
const callLogText = exports.callLogText = _utils.formatCallLog;
const folderToPackageJsonPath = new Map();
function getPackageJsonPath(folderPath) {
const cached = folderToPackageJsonPath.get(folderPath);
if (cached !== undefined) return cached;
const packageJsonPath = _path.default.join(folderPath, 'package.json');
if (_fs.default.existsSync(packageJsonPath)) {
folderToPackageJsonPath.set(folderPath, packageJsonPath);
return packageJsonPath;
}
const parentFolder = _path.default.dirname(folderPath);
if (folderPath === parentFolder) {
folderToPackageJsonPath.set(folderPath, '');
return '';
}
const result = getPackageJsonPath(parentFolder);
folderToPackageJsonPath.set(folderPath, result);
return result;
}
function resolveReporterOutputPath(defaultValue, configDir, configValue) {
if (configValue) return _path.default.resolve(configDir, configValue);
let basePath = getPackageJsonPath(configDir);
basePath = basePath ? _path.default.dirname(basePath) : process.cwd();
return _path.default.resolve(basePath, defaultValue);
}
async function normalizeAndSaveAttachment(outputPath, name, options = {}) {
if (options.path === undefined && options.body === undefined) return {
name,
contentType: 'text/plain'
};
if ((options.path !== undefined ? 1 : 0) + (options.body !== undefined ? 1 : 0) !== 1) throw new Error(`Exactly one of "path" and "body" must be specified`);
if (options.path !== undefined) {
var _options$contentType;
const hash = (0, _utils.calculateSha1)(options.path);
if (!(0, _utils.isString)(name)) throw new Error('"name" should be string.');
const sanitizedNamePrefix = (0, _utils.sanitizeForFilePath)(name) + '-';
const dest = _path.default.join(outputPath, 'attachments', sanitizedNamePrefix + hash + _path.default.extname(options.path));
await _fs.default.promises.mkdir(_path.default.dirname(dest), {
recursive: true
});
await _fs.default.promises.copyFile(options.path, dest);
const contentType = (_options$contentType = options.contentType) !== null && _options$contentType !== void 0 ? _options$contentType : _utilsBundle.mime.getType(_path.default.basename(options.path)) || 'application/octet-stream';
return {
name,
contentType,
path: dest
};
} else {
var _options$contentType2;
const contentType = (_options$contentType2 = options.contentType) !== null && _options$contentType2 !== void 0 ? _options$contentType2 : typeof options.body === 'string' ? 'text/plain' : 'application/octet-stream';
return {
name,
contentType,
body: typeof options.body === 'string' ? Buffer.from(options.body) : options.body
};
}
}
function fileIsModule(file) {
if (file.endsWith('.mjs') || file.endsWith('.mts')) return true;
if (file.endsWith('.cjs') || file.endsWith('.cts')) return false;
const folder = _path.default.dirname(file);
return folderIsModule(folder);
}
function folderIsModule(folder) {
const packageJsonPath = getPackageJsonPath(folder);
if (!packageJsonPath) return false;
// Rely on `require` internal caching logic.
return require(packageJsonPath).type === 'module';
}
const packageJsonMainFieldCache = new Map();
function getMainFieldFromPackageJson(packageJsonPath) {
if (!packageJsonMainFieldCache.has(packageJsonPath)) {
let mainField;
try {
mainField = JSON.parse(_fs.default.readFileSync(packageJsonPath, 'utf8')).main;
} catch {}
packageJsonMainFieldCache.set(packageJsonPath, mainField);
}
return packageJsonMainFieldCache.get(packageJsonPath);
}
// This method performs "file extension subsitution" to find the ts, js or similar source file
// based on the import specifier, which might or might not have an extension. See TypeScript docs:
// https://www.typescriptlang.org/docs/handbook/modules/reference.html#file-extension-substitution.
const kExtLookups = new Map([['.js', ['.jsx', '.ts', '.tsx']], ['.jsx', ['.tsx']], ['.cjs', ['.cts']], ['.mjs', ['.mts']], ['', ['.js', '.ts', '.jsx', '.tsx', '.cjs', '.mjs', '.cts', '.mts']]]);
function resolveImportSpecifierExtension(resolved) {
if (fileExists(resolved)) return resolved;
for (const [ext, others] of kExtLookups) {
if (!resolved.endsWith(ext)) continue;
for (const other of others) {
const modified = resolved.substring(0, resolved.length - ext.length) + other;
if (fileExists(modified)) return modified;
}
break; // Do not try '' when a more specific extension like '.jsx' matched.
}
}
// This method resolves directory imports and performs "file extension subsitution".
// It is intended to be called after the path mapping resolution.
//
// Directory imports follow the --moduleResolution=bundler strategy from tsc.
// https://www.typescriptlang.org/docs/handbook/modules/reference.html#directory-modules-index-file-resolution
// https://www.typescriptlang.org/docs/handbook/modules/reference.html#bundler
//
// See also Node.js "folder as module" behavior:
// https://nodejs.org/dist/latest-v20.x/docs/api/modules.html#folders-as-modules.
function resolveImportSpecifierAfterMapping(resolved, afterPathMapping) {
const resolvedFile = resolveImportSpecifierExtension(resolved);
if (resolvedFile) return resolvedFile;
if (dirExists(resolved)) {
const packageJsonPath = _path.default.join(resolved, 'package.json');
if (afterPathMapping) {
// Most notably, the module resolution algorithm is not performed after the path mapping.
// This means no node_modules lookup or package.json#exports.
//
// Only the "folder as module" Node.js behavior is respected:
// - consult `package.json#main`;
// - look for `index.js` or similar.
const mainField = getMainFieldFromPackageJson(packageJsonPath);
const mainFieldResolved = mainField ? resolveImportSpecifierExtension(_path.default.resolve(resolved, mainField)) : undefined;
return mainFieldResolved || resolveImportSpecifierExtension(_path.default.join(resolved, 'index'));
}
// If we import a package, let Node.js figure out the correct import based on package.json.
// This also covers the "main" field for "folder as module".
if (fileExists(packageJsonPath)) return resolved;
// Implement the "folder as module" Node.js behavior.
// Note that we do not delegate to Node.js, because we support this for ESM as well,
// following the TypeScript "bundler" mode.
const dirImport = _path.default.join(resolved, 'index');
return resolveImportSpecifierExtension(dirImport);
}
}
function fileExists(resolved) {
var _fs$statSync;
return (_fs$statSync = _fs.default.statSync(resolved, {
throwIfNoEntry: false
})) === null || _fs$statSync === void 0 ? void 0 : _fs$statSync.isFile();
}
function dirExists(resolved) {
var _fs$statSync2;
return (_fs$statSync2 = _fs.default.statSync(resolved, {
throwIfNoEntry: false
})) === null || _fs$statSync2 === void 0 ? void 0 : _fs$statSync2.isDirectory();
}
async function removeDirAndLogToConsole(dir) {
try {
if (!_fs.default.existsSync(dir)) return;
// eslint-disable-next-line no-console
console.log(`Removing ${await _fs.default.promises.realpath(dir)}`);
await _fs.default.promises.rm(dir, {
recursive: true,
force: true
});
} catch {}
}

29
node_modules/playwright/lib/utilsBundle.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.stoppable = exports.sourceMapSupport = exports.pirates = exports.json5 = exports.getEastAsianWidth = exports.enquirer = exports.chokidar = void 0;
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const json5 = exports.json5 = require('./utilsBundleImpl').json5;
const pirates = exports.pirates = require('./utilsBundleImpl').pirates;
const sourceMapSupport = exports.sourceMapSupport = require('./utilsBundleImpl').sourceMapSupport;
const stoppable = exports.stoppable = require('./utilsBundleImpl').stoppable;
const enquirer = exports.enquirer = require('./utilsBundleImpl').enquirer;
const chokidar = exports.chokidar = require('./utilsBundleImpl').chokidar;
const getEastAsianWidth = exports.getEastAsianWidth = require('./utilsBundleImpl').getEastAsianWidth;

102
node_modules/playwright/lib/utilsBundleImpl.js generated vendored Normal file

File diff suppressed because one or more lines are too long

279
node_modules/playwright/lib/worker/fixtureRunner.js generated vendored Normal file
View File

@@ -0,0 +1,279 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FixtureRunner = void 0;
var _util = require("../util");
var _utils = require("playwright-core/lib/utils");
var _fixtures = require("../common/fixtures");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Fixture {
constructor(runner, registration) {
this.runner = void 0;
this.registration = void 0;
this.value = void 0;
this.failed = false;
this._useFuncFinished = void 0;
this._selfTeardownComplete = void 0;
this._setupDescription = void 0;
this._teardownDescription = void 0;
this._stepInfo = void 0;
this._deps = new Set();
this._usages = new Set();
this.runner = runner;
this.registration = registration;
this.value = null;
const shouldGenerateStep = !this.registration.box && !this.registration.option;
const isUserFixture = this.registration.location && (0, _util.filterStackFile)(this.registration.location.file);
const title = this.registration.customTitle || this.registration.name;
const location = isUserFixture ? this.registration.location : undefined;
this._stepInfo = shouldGenerateStep ? {
category: 'fixture',
location
} : undefined;
this._setupDescription = {
title,
phase: 'setup',
location,
slot: this.registration.timeout === undefined ? undefined : {
timeout: this.registration.timeout,
elapsed: 0
}
};
this._teardownDescription = {
...this._setupDescription,
phase: 'teardown'
};
}
async setup(testInfo, runnable) {
this.runner.instanceForId.set(this.registration.id, this);
if (typeof this.registration.fn !== 'function') {
this.value = this.registration.fn;
return;
}
await testInfo._runAsStage({
title: `fixture: ${this.registration.name}`,
runnable: {
...runnable,
fixture: this._setupDescription
},
stepInfo: this._stepInfo
}, async () => {
await this._setupInternal(testInfo);
});
}
async _setupInternal(testInfo) {
const params = {};
for (const name of this.registration.deps) {
const registration = this.runner.pool.resolve(name, this.registration);
const dep = this.runner.instanceForId.get(registration.id);
if (!dep) {
this.failed = true;
return;
}
// Fixture teardown is root => leaves, when we need to teardown a fixture,
// it recursively tears down its usages first.
dep._usages.add(this);
// Don't forget to decrement all usages when fixture goes.
// Otherwise worker-scope fixtures will retain test-scope fixtures forever.
this._deps.add(dep);
params[name] = dep.value;
if (dep.failed) {
this.failed = true;
return;
}
}
let called = false;
const useFuncStarted = new _utils.ManualPromise();
const useFunc = async value => {
if (called) throw new Error(`Cannot provide fixture value for the second time`);
called = true;
this.value = value;
this._useFuncFinished = new _utils.ManualPromise();
useFuncStarted.resolve();
await this._useFuncFinished;
};
const workerInfo = {
config: testInfo.config,
parallelIndex: testInfo.parallelIndex,
workerIndex: testInfo.workerIndex,
project: testInfo.project
};
const info = this.registration.scope === 'worker' ? workerInfo : testInfo;
this._selfTeardownComplete = (async () => {
try {
await this.registration.fn(params, useFunc, info);
} catch (error) {
this.failed = true;
if (!useFuncStarted.isDone()) useFuncStarted.reject(error);else throw error;
}
})();
await useFuncStarted;
}
async teardown(testInfo, runnable) {
try {
const fixtureRunnable = {
...runnable,
fixture: this._teardownDescription
};
// Do not even start the teardown for a fixture that does not have any
// time remaining in the time slot. This avoids cascading timeouts.
if (!testInfo._timeoutManager.isTimeExhaustedFor(fixtureRunnable)) {
await testInfo._runAsStage({
title: `fixture: ${this.registration.name}`,
runnable: fixtureRunnable,
stepInfo: this._stepInfo
}, async () => {
await this._teardownInternal();
});
}
} finally {
// To preserve fixtures integrity, forcefully cleanup fixtures
// that cannnot teardown due to a timeout or an error.
for (const dep of this._deps) dep._usages.delete(this);
this.runner.instanceForId.delete(this.registration.id);
}
}
async _teardownInternal() {
if (typeof this.registration.fn !== 'function') return;
if (this._usages.size !== 0) {
// TODO: replace with assert.
console.error('Internal error: fixture integrity at', this._teardownDescription.title); // eslint-disable-line no-console
this._usages.clear();
}
if (this._useFuncFinished) {
this._useFuncFinished.resolve();
this._useFuncFinished = undefined;
await this._selfTeardownComplete;
}
}
_collectFixturesInTeardownOrder(scope, collector) {
if (this.registration.scope !== scope) return;
for (const fixture of this._usages) fixture._collectFixturesInTeardownOrder(scope, collector);
collector.add(this);
}
}
class FixtureRunner {
constructor() {
this.testScopeClean = true;
this.pool = void 0;
this.instanceForId = new Map();
}
setPool(pool) {
if (!this.testScopeClean) throw new Error('Did not teardown test scope');
if (this.pool && pool.digest !== this.pool.digest) {
throw new Error([`Playwright detected inconsistent test.use() options.`, `Most common mistakes that lead to this issue:`, ` - Calling test.use() outside of the test file, for example in a common helper.`, ` - One test file imports from another test file.`].join('\n'));
}
this.pool = pool;
}
_collectFixturesInSetupOrder(registration, collector) {
if (collector.has(registration)) return;
for (const name of registration.deps) {
const dep = this.pool.resolve(name, registration);
this._collectFixturesInSetupOrder(dep, collector);
}
collector.add(registration);
}
async teardownScope(scope, testInfo, runnable) {
// Teardown fixtures in the reverse order.
const fixtures = Array.from(this.instanceForId.values()).reverse();
const collector = new Set();
for (const fixture of fixtures) fixture._collectFixturesInTeardownOrder(scope, collector);
let firstError;
for (const fixture of collector) {
try {
await fixture.teardown(testInfo, runnable);
} catch (error) {
var _firstError;
firstError = (_firstError = firstError) !== null && _firstError !== void 0 ? _firstError : error;
}
}
if (scope === 'test') this.testScopeClean = true;
if (firstError) throw firstError;
}
async resolveParametersForFunction(fn, testInfo, autoFixtures, runnable) {
const collector = new Set();
// Collect automatic fixtures.
const auto = [];
for (const registration of this.pool.autoFixtures()) {
let shouldRun = true;
if (autoFixtures === 'all-hooks-only') shouldRun = registration.scope === 'worker' || registration.auto === 'all-hooks-included';else if (autoFixtures === 'worker') shouldRun = registration.scope === 'worker';
if (shouldRun) auto.push(registration);
}
auto.sort((r1, r2) => (r1.scope === 'worker' ? 0 : 1) - (r2.scope === 'worker' ? 0 : 1));
for (const registration of auto) this._collectFixturesInSetupOrder(registration, collector);
// Collect used fixtures.
const names = getRequiredFixtureNames(fn);
for (const name of names) this._collectFixturesInSetupOrder(this.pool.resolve(name), collector);
// Setup fixtures.
for (const registration of collector) await this._setupFixtureForRegistration(registration, testInfo, runnable);
// Create params object.
const params = {};
for (const name of names) {
const registration = this.pool.resolve(name);
const fixture = this.instanceForId.get(registration.id);
if (!fixture || fixture.failed) return null;
params[name] = fixture.value;
}
return params;
}
async resolveParametersAndRunFunction(fn, testInfo, autoFixtures, runnable) {
const params = await this.resolveParametersForFunction(fn, testInfo, autoFixtures, runnable);
if (params === null) {
// Do not run the function when fixture setup has already failed.
return null;
}
await testInfo._runAsStage({
title: 'run function',
runnable
}, async () => {
await fn(params, testInfo);
});
}
async _setupFixtureForRegistration(registration, testInfo, runnable) {
if (registration.scope === 'test') this.testScopeClean = false;
let fixture = this.instanceForId.get(registration.id);
if (fixture) return fixture;
fixture = new Fixture(this, registration);
await fixture.setup(testInfo, runnable);
return fixture;
}
dependsOnWorkerFixturesOnly(fn, location) {
const names = getRequiredFixtureNames(fn, location);
for (const name of names) {
const registration = this.pool.resolve(name);
if (registration.scope !== 'worker') return false;
}
return true;
}
}
exports.FixtureRunner = FixtureRunner;
function getRequiredFixtureNames(fn, location) {
return (0, _fixtures.fixtureParameterNames)(fn, location !== null && location !== void 0 ? location : {
file: '<unknown>',
line: 1,
column: 1
}, e => {
throw new Error(`${(0, _util.formatLocation)(e.location)}: ${e.message}`);
});
}

398
node_modules/playwright/lib/worker/testInfo.js generated vendored Normal file
View File

@@ -0,0 +1,398 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TestInfoImpl = exports.SkipError = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _utils = require("playwright-core/lib/utils");
var _timeoutManager = require("./timeoutManager");
var _util = require("../util");
var _testTracing = require("./testTracing");
var _util2 = require("./util");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class TestInfoImpl {
get error() {
return this.errors[0];
}
set error(e) {
if (e === undefined) throw new Error('Cannot assign testInfo.error undefined value!');
this.errors[0] = e;
}
get timeout() {
return this._timeoutManager.defaultSlot().timeout;
}
set timeout(timeout) {
// Ignored.
}
_deadlineForMatcher(timeout) {
const startTime = (0, _utils.monotonicTime)();
const matcherDeadline = timeout ? startTime + timeout : _timeoutManager.kMaxDeadline;
const testDeadline = this._timeoutManager.currentSlotDeadline() - 250;
const matcherMessage = `Timeout ${timeout}ms exceeded while waiting on the predicate`;
const testMessage = `Test timeout of ${this.timeout}ms exceeded`;
return {
deadline: Math.min(testDeadline, matcherDeadline),
timeoutMessage: testDeadline < matcherDeadline ? testMessage : matcherMessage
};
}
static _defaultDeadlineForMatcher(timeout) {
return {
deadline: timeout ? (0, _utils.monotonicTime)() + timeout : 0,
timeoutMessage: `Timeout ${timeout}ms exceeded while waiting on the predicate`
};
}
constructor(configInternal, projectInternal, workerParams, test, retry, onStepBegin, onStepEnd, onAttach) {
var _test$id, _test$_requireFile, _test$title, _test$titlePath, _test$location$file, _test$location$line, _test$location$column, _test$tags, _test$fn, _test$expectedStatus;
this._onStepBegin = void 0;
this._onStepEnd = void 0;
this._onAttach = void 0;
this._timeoutManager = void 0;
this._startTime = void 0;
this._startWallTime = void 0;
this._tracing = void 0;
this._wasInterrupted = false;
this._lastStepId = 0;
this._requireFile = void 0;
this._projectInternal = void 0;
this._configInternal = void 0;
this._steps = [];
this._onDidFinishTestFunction = void 0;
this._hasNonRetriableError = false;
this._hasUnhandledError = false;
this._allowSkips = false;
// ------------ TestInfo fields ------------
this.testId = void 0;
this.repeatEachIndex = void 0;
this.retry = void 0;
this.workerIndex = void 0;
this.parallelIndex = void 0;
this.project = void 0;
this.config = void 0;
this.title = void 0;
this.titlePath = void 0;
this.file = void 0;
this.line = void 0;
this.tags = void 0;
this.column = void 0;
this.fn = void 0;
this.expectedStatus = void 0;
this.duration = 0;
this.annotations = [];
this.attachments = [];
this.status = 'passed';
this.snapshotSuffix = '';
this.outputDir = void 0;
this.snapshotDir = void 0;
this.errors = [];
this._attachmentsPush = void 0;
this.testId = (_test$id = test === null || test === void 0 ? void 0 : test.id) !== null && _test$id !== void 0 ? _test$id : '';
this._onStepBegin = onStepBegin;
this._onStepEnd = onStepEnd;
this._onAttach = onAttach;
this._startTime = (0, _utils.monotonicTime)();
this._startWallTime = Date.now();
this._requireFile = (_test$_requireFile = test === null || test === void 0 ? void 0 : test._requireFile) !== null && _test$_requireFile !== void 0 ? _test$_requireFile : '';
this.repeatEachIndex = workerParams.repeatEachIndex;
this.retry = retry;
this.workerIndex = workerParams.workerIndex;
this.parallelIndex = workerParams.parallelIndex;
this._projectInternal = projectInternal;
this.project = projectInternal.project;
this._configInternal = configInternal;
this.config = configInternal.config;
this.title = (_test$title = test === null || test === void 0 ? void 0 : test.title) !== null && _test$title !== void 0 ? _test$title : '';
this.titlePath = (_test$titlePath = test === null || test === void 0 ? void 0 : test.titlePath()) !== null && _test$titlePath !== void 0 ? _test$titlePath : [];
this.file = (_test$location$file = test === null || test === void 0 ? void 0 : test.location.file) !== null && _test$location$file !== void 0 ? _test$location$file : '';
this.line = (_test$location$line = test === null || test === void 0 ? void 0 : test.location.line) !== null && _test$location$line !== void 0 ? _test$location$line : 0;
this.column = (_test$location$column = test === null || test === void 0 ? void 0 : test.location.column) !== null && _test$location$column !== void 0 ? _test$location$column : 0;
this.tags = (_test$tags = test === null || test === void 0 ? void 0 : test.tags) !== null && _test$tags !== void 0 ? _test$tags : [];
this.fn = (_test$fn = test === null || test === void 0 ? void 0 : test.fn) !== null && _test$fn !== void 0 ? _test$fn : () => {};
this.expectedStatus = (_test$expectedStatus = test === null || test === void 0 ? void 0 : test.expectedStatus) !== null && _test$expectedStatus !== void 0 ? _test$expectedStatus : 'skipped';
this._timeoutManager = new _timeoutManager.TimeoutManager(this.project.timeout);
if (configInternal.configCLIOverrides.debug) this._setDebugMode();
this.outputDir = (() => {
const relativeTestFilePath = _path.default.relative(this.project.testDir, this._requireFile.replace(/\.(spec|test)\.(js|ts|jsx|tsx|mjs|mts|cjs|cts)$/, ''));
const sanitizedRelativePath = relativeTestFilePath.replace(process.platform === 'win32' ? new RegExp('\\\\', 'g') : new RegExp('/', 'g'), '-');
const fullTitleWithoutSpec = this.titlePath.slice(1).join(' ');
let testOutputDir = (0, _util.trimLongString)(sanitizedRelativePath + '-' + (0, _utils.sanitizeForFilePath)(fullTitleWithoutSpec), _util.windowsFilesystemFriendlyLength);
if (projectInternal.id) testOutputDir += '-' + (0, _utils.sanitizeForFilePath)(projectInternal.id);
if (this.retry) testOutputDir += '-retry' + this.retry;
if (this.repeatEachIndex) testOutputDir += '-repeat' + this.repeatEachIndex;
return _path.default.join(this.project.outputDir, testOutputDir);
})();
this.snapshotDir = (() => {
const relativeTestFilePath = _path.default.relative(this.project.testDir, this._requireFile);
return _path.default.join(this.project.snapshotDir, relativeTestFilePath + '-snapshots');
})();
this._attachmentsPush = this.attachments.push.bind(this.attachments);
this.attachments.push = (...attachments) => {
for (const a of attachments) this._attach(a.name, a);
return this.attachments.length;
};
this._tracing = new _testTracing.TestTracing(this, workerParams.artifactsDir);
}
_modifier(type, modifierArgs) {
if (typeof modifierArgs[1] === 'function') {
throw new Error(['It looks like you are calling test.skip() inside the test and pass a callback.', 'Pass a condition instead and optional description instead:', `test('my test', async ({ page, isMobile }) => {`, ` test.skip(isMobile, 'This test is not applicable on mobile');`, `});`].join('\n'));
}
if (modifierArgs.length >= 1 && !modifierArgs[0]) return;
const description = modifierArgs[1];
this.annotations.push({
type,
description
});
if (type === 'slow') {
this._timeoutManager.slow();
} else if (type === 'skip' || type === 'fixme') {
this.expectedStatus = 'skipped';
throw new SkipError('Test is skipped: ' + (description || ''));
} else if (type === 'fail') {
if (this.expectedStatus !== 'skipped') this.expectedStatus = 'failed';
}
}
_findLastStageStep(steps) {
// Find the deepest step that is marked as isStage and has not finished yet.
for (let i = steps.length - 1; i >= 0; i--) {
const child = this._findLastStageStep(steps[i].steps);
if (child) return child;
if (steps[i].isStage && !steps[i].endWallTime) return steps[i];
}
}
_addStep(data, parentStep) {
var _parentStep, _parentStep2;
const stepId = `${data.category}@${++this._lastStepId}`;
if (data.isStage) {
// Predefined stages form a fixed hierarchy - use the current one as parent.
parentStep = this._findLastStageStep(this._steps);
} else {
if (!parentStep) parentStep = _utils.zones.zoneData('stepZone');
if (!parentStep) {
// If no parent step on stack, assume the current stage as parent.
parentStep = this._findLastStageStep(this._steps);
}
}
const filteredStack = (0, _util.filteredStackTrace)((0, _utils.captureRawStack)());
data.boxedStack = (_parentStep = parentStep) === null || _parentStep === void 0 ? void 0 : _parentStep.boxedStack;
if (!data.boxedStack && data.box) {
data.boxedStack = filteredStack.slice(1);
data.location = data.location || data.boxedStack[0];
}
data.location = data.location || filteredStack[0];
const step = {
stepId,
...data,
steps: [],
complete: result => {
if (step.endWallTime) return;
step.endWallTime = Date.now();
if (result.error) {
var _result$error;
if (typeof result.error === 'object' && !((_result$error = result.error) !== null && _result$error !== void 0 && _result$error[stepSymbol])) result.error[stepSymbol] = step;
const error = (0, _util2.testInfoError)(result.error);
if (data.boxedStack) error.stack = `${error.message}\n${(0, _utils.stringifyStackFrames)(data.boxedStack).join('\n')}`;
step.error = error;
}
if (!step.error) {
// Soft errors inside try/catch will make the test fail.
// In order to locate the failing step, we are marking all the parent
// steps as failing unconditionally.
for (const childStep of step.steps) {
if (childStep.error && childStep.infectParentStepsWithError) {
step.error = childStep.error;
step.infectParentStepsWithError = true;
break;
}
}
}
const payload = {
testId: this.testId,
stepId,
wallTime: step.endWallTime,
error: step.error,
suggestedRebaseline: result.suggestedRebaseline
};
this._onStepEnd(payload);
const errorForTrace = step.error ? {
name: '',
message: step.error.message || '',
stack: step.error.stack
} : undefined;
this._tracing.appendAfterActionForStep(stepId, errorForTrace, result.attachments);
}
};
const parentStepList = parentStep ? parentStep.steps : this._steps;
parentStepList.push(step);
const payload = {
testId: this.testId,
stepId,
parentStepId: parentStep ? parentStep.stepId : undefined,
title: data.title,
category: data.category,
wallTime: Date.now(),
location: data.location
};
this._onStepBegin(payload);
this._tracing.appendBeforeActionForStep(stepId, (_parentStep2 = parentStep) === null || _parentStep2 === void 0 ? void 0 : _parentStep2.stepId, data.apiName || data.title, data.params, data.location ? [data.location] : []);
return step;
}
_interrupt() {
// Mark as interrupted so we can ignore TimeoutError thrown by interrupt() call.
this._wasInterrupted = true;
this._timeoutManager.interrupt();
// Do not overwrite existing failure (for example, unhandled rejection) with "interrupted".
if (this.status === 'passed') this.status = 'interrupted';
}
_failWithError(error) {
if (this.status === 'passed' || this.status === 'skipped') this.status = error instanceof _timeoutManager.TimeoutManagerError ? 'timedOut' : 'failed';
const serialized = (0, _util2.testInfoError)(error);
const step = typeof error === 'object' ? error === null || error === void 0 ? void 0 : error[stepSymbol] : undefined;
if (step && step.boxedStack) serialized.stack = `${error.name}: ${error.message}\n${(0, _utils.stringifyStackFrames)(step.boxedStack).join('\n')}`;
this.errors.push(serialized);
this._tracing.appendForError(serialized);
}
async _runAsStage(stage, cb) {
if (_util.debugTest.enabled) {
var _stage$runnable;
const location = (_stage$runnable = stage.runnable) !== null && _stage$runnable !== void 0 && _stage$runnable.location ? ` at "${(0, _util.formatLocation)(stage.runnable.location)}"` : ``;
(0, _util.debugTest)(`started stage "${stage.title}"${location}`);
}
stage.step = stage.stepInfo ? this._addStep({
...stage.stepInfo,
title: stage.title,
isStage: true
}) : undefined;
try {
var _stage$step;
await this._timeoutManager.withRunnable(stage.runnable, async () => {
try {
await cb();
} catch (e) {
// Only handle errors directly thrown by the user code.
if (!stage.runnable) throw e;
if (this._allowSkips && e instanceof SkipError) {
if (this.status === 'passed') this.status = 'skipped';
} else {
// Unfortunately, we have to handle user errors and timeout errors differently.
// Consider the following scenario:
// - locator.click times out
// - all stages containing the test function finish with TimeoutManagerError
// - test finishes, the page is closed and this triggers locator.click error
// - we would like to present the locator.click error to the user
// - therefore, we need a try/catch inside the "run with timeout" block and capture the error
this._failWithError(e);
}
throw e;
}
});
(_stage$step = stage.step) === null || _stage$step === void 0 || _stage$step.complete({});
} catch (error) {
var _stage$step2;
// When interrupting, we arrive here with a TimeoutManagerError, but we should not
// consider it a timeout.
if (!this._wasInterrupted && error instanceof _timeoutManager.TimeoutManagerError && stage.runnable) this._failWithError(error);
(_stage$step2 = stage.step) === null || _stage$step2 === void 0 || _stage$step2.complete({
error
});
throw error;
} finally {
(0, _util.debugTest)(`finished stage "${stage.title}"`);
}
}
_isFailure() {
return this.status !== 'skipped' && this.status !== this.expectedStatus;
}
_currentHookType() {
const type = this._timeoutManager.currentSlotType();
return ['beforeAll', 'afterAll', 'beforeEach', 'afterEach'].includes(type) ? type : undefined;
}
_setDebugMode() {
this._timeoutManager.setIgnoreTimeouts();
}
// ------------ TestInfo methods ------------
async attach(name, options = {}) {
this._attach(name, await (0, _util.normalizeAndSaveAttachment)(this.outputPath(), name, options));
}
_attach(name, attachment) {
var _attachment$body;
const step = this._addStep({
title: `attach "${name}"`,
category: 'attach'
});
this._attachmentsPush(attachment);
this._onAttach({
testId: this.testId,
name: attachment.name,
contentType: attachment.contentType,
path: attachment.path,
body: (_attachment$body = attachment.body) === null || _attachment$body === void 0 ? void 0 : _attachment$body.toString('base64')
});
step.complete({
attachments: [attachment]
});
}
outputPath(...pathSegments) {
const outputPath = this._getOutputPath(...pathSegments);
_fs.default.mkdirSync(this.outputDir, {
recursive: true
});
return outputPath;
}
_getOutputPath(...pathSegments) {
const joinedPath = _path.default.join(...pathSegments);
const outputPath = (0, _util.getContainedPath)(this.outputDir, joinedPath);
if (outputPath) return outputPath;
throw new Error(`The outputPath is not allowed outside of the parent directory. Please fix the defined path.\n\n\toutputPath: ${joinedPath}`);
}
_fsSanitizedTestName() {
const fullTitleWithoutSpec = this.titlePath.slice(1).join(' ');
return (0, _utils.sanitizeForFilePath)((0, _util.trimLongString)(fullTitleWithoutSpec));
}
snapshotPath(...pathSegments) {
const subPath = _path.default.join(...pathSegments);
const parsedSubPath = _path.default.parse(subPath);
const relativeTestFilePath = _path.default.relative(this.project.testDir, this._requireFile);
const parsedRelativeTestFilePath = _path.default.parse(relativeTestFilePath);
const projectNamePathSegment = (0, _utils.sanitizeForFilePath)(this.project.name);
const snapshotPath = (this._projectInternal.snapshotPathTemplate || '').replace(/\{(.)?testDir\}/g, '$1' + this.project.testDir).replace(/\{(.)?snapshotDir\}/g, '$1' + this.project.snapshotDir).replace(/\{(.)?snapshotSuffix\}/g, this.snapshotSuffix ? '$1' + this.snapshotSuffix : '').replace(/\{(.)?testFileDir\}/g, '$1' + parsedRelativeTestFilePath.dir).replace(/\{(.)?platform\}/g, '$1' + process.platform).replace(/\{(.)?projectName\}/g, projectNamePathSegment ? '$1' + projectNamePathSegment : '').replace(/\{(.)?testName\}/g, '$1' + this._fsSanitizedTestName()).replace(/\{(.)?testFileName\}/g, '$1' + parsedRelativeTestFilePath.base).replace(/\{(.)?testFilePath\}/g, '$1' + relativeTestFilePath).replace(/\{(.)?arg\}/g, '$1' + _path.default.join(parsedSubPath.dir, parsedSubPath.name)).replace(/\{(.)?ext\}/g, parsedSubPath.ext ? '$1' + parsedSubPath.ext : '');
return _path.default.normalize(_path.default.resolve(this._configInternal.configDir, snapshotPath));
}
skip(...args) {
this._modifier('skip', args);
}
fixme(...args) {
this._modifier('fixme', args);
}
fail(...args) {
this._modifier('fail', args);
}
slow(...args) {
this._modifier('slow', args);
}
setTimeout(timeout) {
this._timeoutManager.setTimeout(timeout);
}
}
exports.TestInfoImpl = TestInfoImpl;
class SkipError extends Error {}
exports.SkipError = SkipError;
const stepSymbol = Symbol('step');

319
node_modules/playwright/lib/worker/testTracing.js generated vendored Normal file
View File

@@ -0,0 +1,319 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.testTraceEntryName = exports.TestTracing = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _utils = require("playwright-core/lib/utils");
var _zipBundle = require("playwright-core/lib/zipBundle");
var _util = require("../util");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const testTraceEntryName = exports.testTraceEntryName = 'test.trace';
const version = 7;
let traceOrdinal = 0;
class TestTracing {
constructor(testInfo, artifactsDir) {
this._testInfo = void 0;
this._options = void 0;
this._liveTraceFile = void 0;
this._traceEvents = [];
this._temporaryTraceFiles = [];
this._artifactsDir = void 0;
this._tracesDir = void 0;
this._contextCreatedEvent = void 0;
this._testInfo = testInfo;
this._artifactsDir = artifactsDir;
this._tracesDir = _path.default.join(this._artifactsDir, 'traces');
this._contextCreatedEvent = {
version,
type: 'context-options',
origin: 'testRunner',
browserName: '',
options: {},
platform: process.platform,
wallTime: Date.now(),
monotonicTime: (0, _utils.monotonicTime)(),
sdkLanguage: 'javascript'
};
this._appendTraceEvent(this._contextCreatedEvent);
}
_shouldCaptureTrace() {
var _this$_options, _this$_options2, _this$_options3, _this$_options4, _this$_options5;
if (process.env.PW_TEST_DISABLE_TRACING) return false;
if (((_this$_options = this._options) === null || _this$_options === void 0 ? void 0 : _this$_options.mode) === 'on') return true;
if (((_this$_options2 = this._options) === null || _this$_options2 === void 0 ? void 0 : _this$_options2.mode) === 'retain-on-failure') return true;
if (((_this$_options3 = this._options) === null || _this$_options3 === void 0 ? void 0 : _this$_options3.mode) === 'on-first-retry' && this._testInfo.retry === 1) return true;
if (((_this$_options4 = this._options) === null || _this$_options4 === void 0 ? void 0 : _this$_options4.mode) === 'on-all-retries' && this._testInfo.retry > 0) return true;
if (((_this$_options5 = this._options) === null || _this$_options5 === void 0 ? void 0 : _this$_options5.mode) === 'retain-on-first-failure' && this._testInfo.retry === 0) return true;
return false;
}
async startIfNeeded(value) {
const defaultTraceOptions = {
screenshots: true,
snapshots: true,
sources: true,
attachments: true,
_live: false,
mode: 'off'
};
if (!value) {
this._options = defaultTraceOptions;
} else if (typeof value === 'string') {
this._options = {
...defaultTraceOptions,
mode: value === 'retry-with-trace' ? 'on-first-retry' : value
};
} else {
const mode = value.mode || 'off';
this._options = {
...defaultTraceOptions,
...value,
mode: mode === 'retry-with-trace' ? 'on-first-retry' : mode
};
}
if (!this._shouldCaptureTrace()) {
this._options = undefined;
return;
}
if (!this._liveTraceFile && this._options._live) {
// Note that trace name must start with testId for live tracing to work.
this._liveTraceFile = {
file: _path.default.join(this._tracesDir, `${this._testInfo.testId}-test.trace`),
fs: new _utils.SerializedFS()
};
this._liveTraceFile.fs.mkdir(_path.default.dirname(this._liveTraceFile.file));
const data = this._traceEvents.map(e => JSON.stringify(e)).join('\n') + '\n';
this._liveTraceFile.fs.writeFile(this._liveTraceFile.file, data);
}
}
artifactsDir() {
return this._artifactsDir;
}
tracesDir() {
return this._tracesDir;
}
traceTitle() {
return [_path.default.relative(this._testInfo.project.testDir, this._testInfo.file) + ':' + this._testInfo.line, ...this._testInfo.titlePath.slice(1)].join(' ');
}
generateNextTraceRecordingName() {
const ordinalSuffix = traceOrdinal ? `-recording${traceOrdinal}` : '';
++traceOrdinal;
const retrySuffix = this._testInfo.retry ? `-retry${this._testInfo.retry}` : '';
// Note that trace name must start with testId for live tracing to work.
return `${this._testInfo.testId}${retrySuffix}${ordinalSuffix}`;
}
generateNextTraceRecordingPath() {
const file = _path.default.join(this._artifactsDir, (0, _utils.createGuid)() + '.zip');
this._temporaryTraceFiles.push(file);
return file;
}
traceOptions() {
return this._options;
}
async stopIfNeeded() {
var _this$_liveTraceFile, _this$_options6, _this$_options7;
if (!this._options) return;
const error = await ((_this$_liveTraceFile = this._liveTraceFile) === null || _this$_liveTraceFile === void 0 ? void 0 : _this$_liveTraceFile.fs.syncAndGetError());
if (error) throw error;
const testFailed = this._testInfo.status !== this._testInfo.expectedStatus;
const shouldAbandonTrace = !testFailed && (this._options.mode === 'retain-on-failure' || this._options.mode === 'retain-on-first-failure');
if (shouldAbandonTrace) {
for (const file of this._temporaryTraceFiles) await _fs.default.promises.unlink(file).catch(() => {});
return;
}
const zipFile = new _zipBundle.yazl.ZipFile();
if (!((_this$_options6 = this._options) !== null && _this$_options6 !== void 0 && _this$_options6.attachments)) {
for (const event of this._traceEvents) {
if (event.type === 'after') delete event.attachments;
}
}
if ((_this$_options7 = this._options) !== null && _this$_options7 !== void 0 && _this$_options7.sources) {
const sourceFiles = new Set();
for (const event of this._traceEvents) {
if (event.type === 'before') {
for (const frame of event.stack || []) sourceFiles.add(frame.file);
}
}
for (const sourceFile of sourceFiles) {
await _fs.default.promises.readFile(sourceFile, 'utf8').then(source => {
zipFile.addBuffer(Buffer.from(source), 'resources/src@' + (0, _utils.calculateSha1)(sourceFile) + '.txt');
}).catch(() => {});
}
}
const sha1s = new Set();
for (const event of this._traceEvents.filter(e => e.type === 'after')) {
for (const attachment of event.attachments || []) {
let contentPromise;
if (attachment.path) contentPromise = _fs.default.promises.readFile(attachment.path).catch(() => undefined);else if (attachment.base64) contentPromise = Promise.resolve(Buffer.from(attachment.base64, 'base64'));
const content = await contentPromise;
if (content === undefined) continue;
const sha1 = (0, _utils.calculateSha1)(content);
attachment.sha1 = sha1;
delete attachment.path;
delete attachment.base64;
if (sha1s.has(sha1)) continue;
sha1s.add(sha1);
zipFile.addBuffer(content, 'resources/' + sha1);
}
}
const traceContent = Buffer.from(this._traceEvents.map(e => JSON.stringify(e)).join('\n'));
zipFile.addBuffer(traceContent, testTraceEntryName);
await new Promise(f => {
zipFile.end(undefined, () => {
zipFile.outputStream.pipe(_fs.default.createWriteStream(this.generateNextTraceRecordingPath())).on('close', f);
});
});
const tracePath = this._testInfo.outputPath('trace.zip');
await mergeTraceFiles(tracePath, this._temporaryTraceFiles);
this._testInfo.attachments.push({
name: 'trace',
path: tracePath,
contentType: 'application/zip'
});
}
appendForError(error) {
var _error$stack;
const rawStack = ((_error$stack = error.stack) === null || _error$stack === void 0 ? void 0 : _error$stack.split('\n')) || [];
const stack = rawStack ? (0, _util.filteredStackTrace)(rawStack) : [];
this._appendTraceEvent({
type: 'error',
message: this._formatError(error),
stack
});
}
_formatError(error) {
const parts = [error.message || String(error.value)];
if (error.cause) parts.push('[cause]: ' + this._formatError(error.cause));
return parts.join('\n');
}
appendStdioToTrace(type, chunk) {
this._appendTraceEvent({
type,
timestamp: (0, _utils.monotonicTime)(),
text: typeof chunk === 'string' ? chunk : undefined,
base64: typeof chunk === 'string' ? undefined : chunk.toString('base64')
});
}
appendBeforeActionForStep(callId, parentId, apiName, params, stack) {
this._appendTraceEvent({
type: 'before',
callId,
parentId,
startTime: (0, _utils.monotonicTime)(),
class: 'Test',
method: 'step',
apiName,
params: Object.fromEntries(Object.entries(params || {}).map(([name, value]) => [name, generatePreview(value)])),
stack
});
}
appendAfterActionForStep(callId, error, attachments = []) {
this._appendTraceEvent({
type: 'after',
callId,
endTime: (0, _utils.monotonicTime)(),
attachments: serializeAttachments(attachments),
error
});
}
_appendTraceEvent(event) {
this._traceEvents.push(event);
if (this._liveTraceFile) this._liveTraceFile.fs.appendFile(this._liveTraceFile.file, JSON.stringify(event) + '\n', true);
}
}
exports.TestTracing = TestTracing;
function serializeAttachments(attachments) {
return attachments.filter(a => a.name !== 'trace').map(a => {
var _a$body;
return {
name: a.name,
contentType: a.contentType,
path: a.path,
base64: (_a$body = a.body) === null || _a$body === void 0 ? void 0 : _a$body.toString('base64')
};
});
}
function generatePreview(value, visited = new Set()) {
if (visited.has(value)) return '';
visited.add(value);
if (typeof value === 'string') return value;
if (typeof value === 'number') return value.toString();
if (typeof value === 'boolean') return value.toString();
if (value === null) return 'null';
if (value === undefined) return 'undefined';
if (Array.isArray(value)) return '[' + value.map(v => generatePreview(v, visited)).join(', ') + ']';
if (typeof value === 'object') return 'Object';
return String(value);
}
async function mergeTraceFiles(fileName, temporaryTraceFiles) {
temporaryTraceFiles = temporaryTraceFiles.filter(file => _fs.default.existsSync(file));
if (temporaryTraceFiles.length === 1) {
await _fs.default.promises.rename(temporaryTraceFiles[0], fileName);
return;
}
const mergePromise = new _utils.ManualPromise();
const zipFile = new _zipBundle.yazl.ZipFile();
const entryNames = new Set();
zipFile.on('error', error => mergePromise.reject(error));
for (let i = temporaryTraceFiles.length - 1; i >= 0; --i) {
const tempFile = temporaryTraceFiles[i];
const promise = new _utils.ManualPromise();
_zipBundle.yauzl.open(tempFile, (err, inZipFile) => {
if (err) {
promise.reject(err);
return;
}
let pendingEntries = inZipFile.entryCount;
inZipFile.on('entry', entry => {
let entryName = entry.fileName;
if (entry.fileName === testTraceEntryName) {
// Keep the name for test traces so that the last test trace
// that contains most of the information is kept in the trace.
// Note the reverse order of the iteration (from new traces to old).
} else if (entry.fileName.match(/[\d-]*trace\./)) {
entryName = i + '-' + entry.fileName;
}
if (entryNames.has(entryName)) {
if (--pendingEntries === 0) promise.resolve();
return;
}
entryNames.add(entryName);
inZipFile.openReadStream(entry, (err, readStream) => {
if (err) {
promise.reject(err);
return;
}
zipFile.addReadStream(readStream, entryName);
if (--pendingEntries === 0) promise.resolve();
});
});
});
await promise;
}
zipFile.end(undefined, () => {
zipFile.outputStream.pipe(_fs.default.createWriteStream(fileName)).on('close', () => {
void Promise.all(temporaryTraceFiles.map(tempFile => _fs.default.promises.unlink(tempFile))).then(() => {
mergePromise.resolve();
}).catch(error => mergePromise.reject(error));
}).on('error', error => mergePromise.reject(error));
});
await mergePromise;
}

153
node_modules/playwright/lib/worker/timeoutManager.js generated vendored Normal file
View File

@@ -0,0 +1,153 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.kMaxDeadline = exports.TimeoutManagerError = exports.TimeoutManager = void 0;
var _utilsBundle = require("playwright-core/lib/utilsBundle");
var _utils = require("playwright-core/lib/utils");
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const kMaxDeadline = exports.kMaxDeadline = 2147483647; // 2^31-1
class TimeoutManager {
constructor(timeout) {
this._defaultSlot = void 0;
this._running = void 0;
this._ignoreTimeouts = false;
this._defaultSlot = {
timeout,
elapsed: 0
};
}
setIgnoreTimeouts() {
this._ignoreTimeouts = true;
if (this._running) this._updateTimeout(this._running);
}
interrupt() {
if (this._running) this._running.timeoutPromise.reject(this._createTimeoutError(this._running));
}
isTimeExhaustedFor(runnable) {
var _runnable$fixture;
const slot = ((_runnable$fixture = runnable.fixture) === null || _runnable$fixture === void 0 ? void 0 : _runnable$fixture.slot) || runnable.slot || this._defaultSlot;
// Note: the "-1" here matches the +1 in _updateTimeout.
return slot.timeout > 0 && slot.elapsed >= slot.timeout - 1;
}
async withRunnable(runnable, cb) {
var _runnable$fixture2;
if (!runnable) return await cb();
if (this._running) throw new Error(`Internal error: duplicate runnable`);
const running = this._running = {
runnable,
slot: ((_runnable$fixture2 = runnable.fixture) === null || _runnable$fixture2 === void 0 ? void 0 : _runnable$fixture2.slot) || runnable.slot || this._defaultSlot,
start: (0, _utils.monotonicTime)(),
deadline: kMaxDeadline,
timer: undefined,
timeoutPromise: new _utils.ManualPromise()
};
try {
this._updateTimeout(running);
return await Promise.race([cb(), running.timeoutPromise]);
} finally {
if (running.timer) clearTimeout(running.timer);
running.timer = undefined;
running.slot.elapsed += (0, _utils.monotonicTime)() - running.start;
this._running = undefined;
}
}
_updateTimeout(running) {
if (running.timer) clearTimeout(running.timer);
running.timer = undefined;
if (this._ignoreTimeouts || !running.slot.timeout) {
running.deadline = kMaxDeadline;
return;
}
running.deadline = running.start + (running.slot.timeout - running.slot.elapsed);
// Compensate for Node.js troubles with timeouts that can fire too early.
// We add an extra millisecond which seems to be enough.
// See https://github.com/nodejs/node/issues/26578.
const timeout = running.deadline - (0, _utils.monotonicTime)() + 1;
if (timeout <= 0) running.timeoutPromise.reject(this._createTimeoutError(running));else running.timer = setTimeout(() => running.timeoutPromise.reject(this._createTimeoutError(running)), timeout);
}
defaultSlot() {
return this._defaultSlot;
}
slow() {
const slot = this._running ? this._running.slot : this._defaultSlot;
slot.timeout = slot.timeout * 3;
if (this._running) this._updateTimeout(this._running);
}
setTimeout(timeout) {
const slot = this._running ? this._running.slot : this._defaultSlot;
slot.timeout = timeout;
if (this._running) this._updateTimeout(this._running);
}
currentSlotDeadline() {
return this._running ? this._running.deadline : kMaxDeadline;
}
currentSlotType() {
return this._running ? this._running.runnable.type : 'test';
}
_createTimeoutError(running) {
var _runnable$fixture3;
let message = '';
const timeout = running.slot.timeout;
const runnable = running.runnable;
switch (runnable.type) {
case 'test':
{
if (runnable.fixture) {
if (runnable.fixture.phase === 'setup') message = `Test timeout of ${timeout}ms exceeded while setting up "${runnable.fixture.title}".`;else message = `Tearing down "${runnable.fixture.title}" exceeded the test timeout of ${timeout}ms.`;
} else {
message = `Test timeout of ${timeout}ms exceeded.`;
}
break;
}
case 'afterEach':
case 'beforeEach':
message = `Test timeout of ${timeout}ms exceeded while running "${runnable.type}" hook.`;
break;
case 'beforeAll':
case 'afterAll':
message = `"${runnable.type}" hook timeout of ${timeout}ms exceeded.`;
break;
case 'teardown':
{
if (runnable.fixture) message = `Worker teardown timeout of ${timeout}ms exceeded while ${runnable.fixture.phase === 'setup' ? 'setting up' : 'tearing down'} "${runnable.fixture.title}".`;else message = `Worker teardown timeout of ${timeout}ms exceeded.`;
break;
}
case 'skip':
case 'slow':
case 'fixme':
case 'fail':
message = `"${runnable.type}" modifier timeout of ${timeout}ms exceeded.`;
break;
}
const fixtureWithSlot = (_runnable$fixture3 = runnable.fixture) !== null && _runnable$fixture3 !== void 0 && _runnable$fixture3.slot ? runnable.fixture : undefined;
if (fixtureWithSlot) message = `Fixture "${fixtureWithSlot.title}" timeout of ${timeout}ms exceeded during ${fixtureWithSlot.phase}.`;
message = _utilsBundle.colors.red(message);
const location = (fixtureWithSlot || runnable).location;
const error = new TimeoutManagerError(message);
error.name = '';
// Include location for hooks, modifiers and fixtures to distinguish between them.
error.stack = message + (location ? `\n at ${location.file}:${location.line}:${location.column}` : '');
return error;
}
}
exports.TimeoutManager = TimeoutManager;
class TimeoutManagerError extends Error {}
exports.TimeoutManagerError = TimeoutManagerError;

29
node_modules/playwright/lib/worker/util.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.testInfoError = testInfoError;
var _matcherHint = require("../matchers/matcherHint");
var _util = require("../util");
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function testInfoError(error) {
const result = (0, _util.serializeError)(error);
if (error instanceof _matcherHint.ExpectError) result.matcherResult = error.matcherResult;
return result;
}

Some files were not shown because too many files have changed in this diff Show More