First Commit
This commit is contained in:
505
node_modules/playwright/lib/runner/dispatcher.js
generated
vendored
Normal file
505
node_modules/playwright/lib/runner/dispatcher.js
generated
vendored
Normal file
@@ -0,0 +1,505 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var dispatcher_exports = {};
|
||||
__export(dispatcher_exports, {
|
||||
Dispatcher: () => Dispatcher
|
||||
});
|
||||
module.exports = __toCommonJS(dispatcher_exports);
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utils2 = require("playwright-core/lib/utils");
|
||||
var import_rebase = require("./rebase");
|
||||
var import_workerHost = require("./workerHost");
|
||||
var import_ipc = require("../common/ipc");
|
||||
class Dispatcher {
|
||||
constructor(config, reporter, failureTracker) {
|
||||
this._workerSlots = [];
|
||||
this._queue = [];
|
||||
this._workerLimitPerProjectId = /* @__PURE__ */ new Map();
|
||||
this._queuedOrRunningHashCount = /* @__PURE__ */ new Map();
|
||||
this._finished = new import_utils.ManualPromise();
|
||||
this._isStopped = true;
|
||||
this._extraEnvByProjectId = /* @__PURE__ */ new Map();
|
||||
this._producedEnvByProjectId = /* @__PURE__ */ new Map();
|
||||
this._config = config;
|
||||
this._reporter = reporter;
|
||||
this._failureTracker = failureTracker;
|
||||
for (const project of config.projects) {
|
||||
if (project.workers)
|
||||
this._workerLimitPerProjectId.set(project.id, project.workers);
|
||||
}
|
||||
}
|
||||
_findFirstJobToRun() {
|
||||
for (let index = 0; index < this._queue.length; index++) {
|
||||
const job = this._queue[index];
|
||||
const projectIdWorkerLimit = this._workerLimitPerProjectId.get(job.projectId);
|
||||
if (!projectIdWorkerLimit)
|
||||
return index;
|
||||
const runningWorkersWithSameProjectId = this._workerSlots.filter((w) => w.busy && w.worker && w.worker.projectId() === job.projectId).length;
|
||||
if (runningWorkersWithSameProjectId < projectIdWorkerLimit)
|
||||
return index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
_scheduleJob() {
|
||||
if (this._isStopped)
|
||||
return;
|
||||
const jobIndex = this._findFirstJobToRun();
|
||||
if (jobIndex === -1)
|
||||
return;
|
||||
const job = this._queue[jobIndex];
|
||||
let workerIndex = this._workerSlots.findIndex((w) => !w.busy && w.worker && w.worker.hash() === job.workerHash && !w.worker.didSendStop());
|
||||
if (workerIndex === -1)
|
||||
workerIndex = this._workerSlots.findIndex((w) => !w.busy);
|
||||
if (workerIndex === -1) {
|
||||
return;
|
||||
}
|
||||
this._queue.splice(jobIndex, 1);
|
||||
const jobDispatcher = new JobDispatcher(job, this._reporter, this._failureTracker, () => this.stop().catch(() => {
|
||||
}));
|
||||
this._workerSlots[workerIndex].busy = true;
|
||||
this._workerSlots[workerIndex].jobDispatcher = jobDispatcher;
|
||||
void this._runJobInWorker(workerIndex, jobDispatcher).then(() => {
|
||||
this._workerSlots[workerIndex].jobDispatcher = void 0;
|
||||
this._workerSlots[workerIndex].busy = false;
|
||||
this._checkFinished();
|
||||
this._scheduleJob();
|
||||
});
|
||||
}
|
||||
async _runJobInWorker(index, jobDispatcher) {
|
||||
const job = jobDispatcher.job;
|
||||
if (jobDispatcher.skipWholeJob())
|
||||
return;
|
||||
let worker = this._workerSlots[index].worker;
|
||||
if (worker && (worker.hash() !== job.workerHash || worker.didSendStop())) {
|
||||
await worker.stop();
|
||||
worker = void 0;
|
||||
if (this._isStopped)
|
||||
return;
|
||||
}
|
||||
let startError;
|
||||
if (!worker) {
|
||||
worker = this._createWorker(job, index, (0, import_ipc.serializeConfig)(this._config, true));
|
||||
this._workerSlots[index].worker = worker;
|
||||
worker.on("exit", () => this._workerSlots[index].worker = void 0);
|
||||
startError = await worker.start();
|
||||
if (this._isStopped)
|
||||
return;
|
||||
}
|
||||
if (startError)
|
||||
jobDispatcher.onExit(startError);
|
||||
else
|
||||
jobDispatcher.runInWorker(worker);
|
||||
const result = await jobDispatcher.jobResult;
|
||||
this._updateCounterForWorkerHash(job.workerHash, -1);
|
||||
if (result.didFail)
|
||||
void worker.stop(
|
||||
true
|
||||
/* didFail */
|
||||
);
|
||||
else if (this._isWorkerRedundant(worker))
|
||||
void worker.stop();
|
||||
if (!this._isStopped && result.newJob) {
|
||||
this._queue.unshift(result.newJob);
|
||||
this._updateCounterForWorkerHash(result.newJob.workerHash, 1);
|
||||
}
|
||||
}
|
||||
_checkFinished() {
|
||||
if (this._finished.isDone())
|
||||
return;
|
||||
if (this._queue.length && !this._isStopped)
|
||||
return;
|
||||
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 = [];
|
||||
if (this._failureTracker.hasReachedMaxFailures())
|
||||
void this.stop();
|
||||
for (let i = 0; i < this._config.config.workers; i++)
|
||||
this._workerSlots.push({ busy: false });
|
||||
for (let i = 0; i < this._workerSlots.length; i++)
|
||||
this._scheduleJob();
|
||||
this._checkFinished();
|
||||
await this._finished;
|
||||
}
|
||||
_createWorker(testGroup, parallelIndex, loaderData) {
|
||||
const projectConfig = this._config.projects.find((p) => p.id === testGroup.projectId);
|
||||
const outputDir = projectConfig.project.outputDir;
|
||||
const recoverFromStepErrors = this._failureTracker.canRecoverFromStepError();
|
||||
const worker = new import_workerHost.WorkerHost(testGroup, parallelIndex, loaderData, recoverFromStepErrors, this._extraEnvByProjectId.get(testGroup.projectId) || {}, outputDir);
|
||||
const handleOutput = (params) => {
|
||||
const chunk = chunkFromParams(params);
|
||||
if (worker.didFail()) {
|
||||
return { chunk };
|
||||
}
|
||||
const currentlyRunning = this._workerSlots[parallelIndex].jobDispatcher?.currentlyRunning();
|
||||
if (!currentlyRunning)
|
||||
return { chunk };
|
||||
return { chunk, test: currentlyRunning.test, result: currentlyRunning.result };
|
||||
};
|
||||
worker.on("stdOut", (params) => {
|
||||
const { chunk, test, result } = handleOutput(params);
|
||||
result?.stdout.push(chunk);
|
||||
this._reporter.onStdOut?.(chunk, test, result);
|
||||
});
|
||||
worker.on("stdErr", (params) => {
|
||||
const { chunk, test, result } = handleOutput(params);
|
||||
result?.stderr.push(chunk);
|
||||
this._reporter.onStdErr?.(chunk, test, result);
|
||||
});
|
||||
worker.on("teardownErrors", (params) => {
|
||||
this._failureTracker.onWorkerError();
|
||||
for (const error of params.fatalErrors)
|
||||
this._reporter.onError?.(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?.stop()));
|
||||
this._checkFinished();
|
||||
}
|
||||
}
|
||||
class JobDispatcher {
|
||||
constructor(job, reporter, failureTracker, stopCallback) {
|
||||
this.jobResult = new import_utils.ManualPromise();
|
||||
this._listeners = [];
|
||||
this._failedTests = /* @__PURE__ */ new Set();
|
||||
this._failedWithNonRetriableError = /* @__PURE__ */ new Set();
|
||||
this._remainingByTestId = /* @__PURE__ */ new Map();
|
||||
this._dataByTestId = /* @__PURE__ */ new Map();
|
||||
this._parallelIndex = 0;
|
||||
this._workerIndex = 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) {
|
||||
const test = this._remainingByTestId.get(params.testId);
|
||||
if (!test) {
|
||||
return;
|
||||
}
|
||||
const result = test._appendTestResult();
|
||||
this._dataByTestId.set(test.id, { test, result, steps: /* @__PURE__ */ new Map() });
|
||||
result.parallelIndex = this._parallelIndex;
|
||||
result.workerIndex = this._workerIndex;
|
||||
result.startTime = new Date(params.startWallTime);
|
||||
this._reporter.onTestBegin?.(test, result);
|
||||
this._currentlyRunning = { test, result };
|
||||
}
|
||||
_onTestEnd(params) {
|
||||
if (this._failureTracker.hasReachedMaxFailures()) {
|
||||
params.status = "interrupted";
|
||||
params.errors = [];
|
||||
}
|
||||
const data = this._dataByTestId.get(params.testId);
|
||||
if (!data) {
|
||||
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;
|
||||
result.annotations = params.annotations;
|
||||
test.annotations = [...params.annotations];
|
||||
test.expectedStatus = params.expectedStatus;
|
||||
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 = void 0;
|
||||
}
|
||||
_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) {
|
||||
const data = this._dataByTestId.get(params.testId);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
const { result, steps, test } = data;
|
||||
const parentStep = params.parentStepId ? steps.get(params.parentStepId) : void 0;
|
||||
const step = {
|
||||
title: params.title,
|
||||
titlePath: () => {
|
||||
const parentPath = parentStep?.titlePath() || [];
|
||||
return [...parentPath, params.title];
|
||||
},
|
||||
parent: parentStep,
|
||||
category: params.category,
|
||||
startTime: new Date(params.wallTime),
|
||||
duration: -1,
|
||||
steps: [],
|
||||
attachments: [],
|
||||
annotations: [],
|
||||
location: params.location
|
||||
};
|
||||
steps.set(params.stepId, step);
|
||||
(parentStep || result).steps.push(step);
|
||||
this._reporter.onStepBegin?.(test, result, step);
|
||||
}
|
||||
_onStepEnd(params) {
|
||||
const data = this._dataByTestId.get(params.testId);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
const { result, steps, test } = data;
|
||||
const step = steps.get(params.stepId);
|
||||
if (!step) {
|
||||
this._reporter.onStdErr?.("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, import_rebase.addSuggestedRebaseline)(step.location, params.suggestedRebaseline);
|
||||
step.annotations = params.annotations;
|
||||
steps.delete(params.stepId);
|
||||
this._reporter.onStepEnd?.(test, result, step);
|
||||
}
|
||||
_onStepRecoverFromError(resumeAfterStepError, params) {
|
||||
const data = this._dataByTestId.get(params.testId);
|
||||
if (!data) {
|
||||
resumeAfterStepError({ stepId: params.stepId, status: "failed" });
|
||||
return;
|
||||
}
|
||||
const { steps } = data;
|
||||
const step = steps.get(params.stepId);
|
||||
if (!step) {
|
||||
resumeAfterStepError({ stepId: params.stepId, status: "failed" });
|
||||
return;
|
||||
}
|
||||
const testError = {
|
||||
...params.error,
|
||||
location: step.location
|
||||
};
|
||||
this._failureTracker.recoverFromStepError(params.stepId, testError, resumeAfterStepError);
|
||||
}
|
||||
_onAttach(params) {
|
||||
const data = this._dataByTestId.get(params.testId);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
const attachment = {
|
||||
name: params.name,
|
||||
path: params.path,
|
||||
contentType: params.contentType,
|
||||
body: params.body !== void 0 ? Buffer.from(params.body, "base64") : void 0
|
||||
};
|
||||
data.result.attachments.push(attachment);
|
||||
if (params.stepId) {
|
||||
const step = data.steps.get(params.stepId);
|
||||
if (step)
|
||||
step.attachments.push(attachment);
|
||||
else
|
||||
this._reporter.onStdErr?.("Internal error: step id not found: " + params.stepId);
|
||||
}
|
||||
}
|
||||
_failTestWithErrors(test, errors) {
|
||||
const runData = this._dataByTestId.get(test.id);
|
||||
let result;
|
||||
if (runData) {
|
||||
result = runData.result;
|
||||
} else {
|
||||
result = test._appendTestResult();
|
||||
this._reporter.onTestBegin?.(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 = [];
|
||||
}
|
||||
this._remainingByTestId.delete(test.id);
|
||||
}
|
||||
if (errors.length) {
|
||||
this._failureTracker.onWorkerError();
|
||||
for (const error of errors)
|
||||
this._reporter.onError?.(error);
|
||||
}
|
||||
}
|
||||
_onDone(params) {
|
||||
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) {
|
||||
this._massSkipTestsFromRemaining(new Set(this._remainingByTestId.keys()), params.fatalErrors);
|
||||
}
|
||||
this._massSkipTestsFromRemaining(new Set(params.skipTestsDueToSetupFailure), []);
|
||||
if (params.unexpectedExitError) {
|
||||
if (this._currentlyRunning)
|
||||
this._massSkipTestsFromRemaining(/* @__PURE__ */ new Set([this._currentlyRunning.test.id]), [params.unexpectedExitError]);
|
||||
else
|
||||
this._massSkipTestsFromRemaining(new Set(this._remainingByTestId.keys()), [params.unexpectedExitError]);
|
||||
}
|
||||
const retryCandidates = /* @__PURE__ */ new Set();
|
||||
const serialSuitesWithFailures = /* @__PURE__ */ 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);
|
||||
}
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
const newJob = remaining.length ? { ...this.job, tests: remaining } : void 0;
|
||||
this._finished({ didFail: true, newJob });
|
||||
}
|
||||
onExit(data) {
|
||||
const unexpectedExitError = data.unexpectedly ? {
|
||||
message: `Error: worker process exited unexpectedly (code=${data.code}, signal=${data.signal})`
|
||||
} : void 0;
|
||||
this._onDone({ skipTestsDueToSetupFailure: [], fatalErrors: [], unexpectedExitError });
|
||||
}
|
||||
_finished(result) {
|
||||
import_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);
|
||||
const resumeAfterStepError = worker.resumeAfterStepError.bind(worker);
|
||||
this._listeners = [
|
||||
import_utils.eventsHelper.addEventListener(worker, "testBegin", this._onTestBegin.bind(this)),
|
||||
import_utils.eventsHelper.addEventListener(worker, "testEnd", this._onTestEnd.bind(this)),
|
||||
import_utils.eventsHelper.addEventListener(worker, "stepBegin", this._onStepBegin.bind(this)),
|
||||
import_utils.eventsHelper.addEventListener(worker, "stepEnd", this._onStepEnd.bind(this)),
|
||||
import_utils.eventsHelper.addEventListener(worker, "stepRecoverFromError", this._onStepRecoverFromError.bind(this, resumeAfterStepError)),
|
||||
import_utils.eventsHelper.addEventListener(worker, "attach", this._onAttach.bind(this)),
|
||||
import_utils.eventsHelper.addEventListener(worker, "done", this._onDone.bind(this)),
|
||||
import_utils.eventsHelper.addEventListener(worker, "exit", this.onExit.bind(this))
|
||||
];
|
||||
}
|
||||
skipWholeJob() {
|
||||
const allTestsSkipped = this.job.tests.every((test) => test.expectedStatus === "skipped");
|
||||
if (allTestsSkipped && !this._failureTracker.hasReachedMaxFailures()) {
|
||||
for (const test of this.job.tests) {
|
||||
const result = test._appendTestResult();
|
||||
this._reporter.onTestBegin?.(test, result);
|
||||
result.status = "skipped";
|
||||
this._reportTestEnd(test, result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
currentlyRunning() {
|
||||
return this._currentlyRunning;
|
||||
}
|
||||
_reportTestEnd(test, result) {
|
||||
this._reporter.onTestEnd?.(test, result);
|
||||
const hadMaxFailures = this._failureTracker.hasReachedMaxFailures();
|
||||
this._failureTracker.onTestEnd(test, result);
|
||||
if (this._failureTracker.hasReachedMaxFailures()) {
|
||||
this._stopCallback();
|
||||
if (!hadMaxFailures)
|
||||
this._reporter.onError?.({ message: import_utils2.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");
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
Dispatcher
|
||||
});
|
76
node_modules/playwright/lib/runner/failureTracker.js
generated
vendored
Normal file
76
node_modules/playwright/lib/runner/failureTracker.js
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var failureTracker_exports = {};
|
||||
__export(failureTracker_exports, {
|
||||
FailureTracker: () => FailureTracker
|
||||
});
|
||||
module.exports = __toCommonJS(failureTracker_exports);
|
||||
class FailureTracker {
|
||||
constructor(_config) {
|
||||
this._config = _config;
|
||||
this._failureCount = 0;
|
||||
this._hasWorkerErrors = false;
|
||||
}
|
||||
canRecoverFromStepError() {
|
||||
return !!this._recoverFromStepErrorHandler;
|
||||
}
|
||||
setRecoverFromStepErrorHandler(recoverFromStepErrorHandler) {
|
||||
this._recoverFromStepErrorHandler = recoverFromStepErrorHandler;
|
||||
}
|
||||
onRootSuite(rootSuite) {
|
||||
this._rootSuite = rootSuite;
|
||||
}
|
||||
onTestEnd(test, result) {
|
||||
if (test.outcome() === "unexpected" && test.results.length > test.retries)
|
||||
++this._failureCount;
|
||||
}
|
||||
recoverFromStepError(stepId, error, resumeAfterStepError) {
|
||||
if (!this._recoverFromStepErrorHandler) {
|
||||
resumeAfterStepError({ stepId, status: "failed" });
|
||||
return;
|
||||
}
|
||||
void this._recoverFromStepErrorHandler(stepId, error).then(resumeAfterStepError).catch(() => {
|
||||
});
|
||||
}
|
||||
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.failOnFlakyTests && this.hasFlakyTests() ? "failed" : "passed";
|
||||
}
|
||||
hasFailedTests() {
|
||||
return this._rootSuite?.allTests().some((test) => !test.ok());
|
||||
}
|
||||
hasFlakyTests() {
|
||||
return this._rootSuite?.allTests().some((test) => test.outcome() === "flaky");
|
||||
}
|
||||
maxFailures() {
|
||||
return this._config.config.maxFailures;
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
FailureTracker
|
||||
});
|
77
node_modules/playwright/lib/runner/lastRun.js
generated
vendored
Normal file
77
node_modules/playwright/lib/runner/lastRun.js
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var lastRun_exports = {};
|
||||
__export(lastRun_exports, {
|
||||
LastRunReporter: () => LastRunReporter
|
||||
});
|
||||
module.exports = __toCommonJS(lastRun_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_projectUtils = require("./projectUtils");
|
||||
class LastRunReporter {
|
||||
constructor(config) {
|
||||
this._config = config;
|
||||
const [project] = (0, import_projectUtils.filterProjects)(config.projects, config.cliProjectFilter);
|
||||
if (project)
|
||||
this._lastRunFile = import_path.default.join(project.project.outputDir, ".last-run.json");
|
||||
}
|
||||
async filterLastFailed() {
|
||||
if (!this._lastRunFile)
|
||||
return;
|
||||
try {
|
||||
const lastRunInfo = JSON.parse(await import_fs.default.promises.readFile(this._lastRunFile, "utf8"));
|
||||
const failedTestIds = new Set(lastRunInfo.failedTests);
|
||||
this._config.postShardTestFilters.push((test) => failedTestIds.has(test.id));
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
version() {
|
||||
return "v2";
|
||||
}
|
||||
printsToStdio() {
|
||||
return false;
|
||||
}
|
||||
onBegin(suite) {
|
||||
this._suite = suite;
|
||||
}
|
||||
async onEnd(result) {
|
||||
if (!this._lastRunFile || this._config.cliListOnly)
|
||||
return;
|
||||
const lastRunInfo = {
|
||||
status: result.status,
|
||||
failedTests: this._suite?.allTests().filter((t) => !t.ok()).map((t) => t.id) || []
|
||||
};
|
||||
await import_fs.default.promises.mkdir(import_path.default.dirname(this._lastRunFile), { recursive: true });
|
||||
await import_fs.default.promises.writeFile(this._lastRunFile, JSON.stringify(lastRunInfo, void 0, 2));
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
LastRunReporter
|
||||
});
|
297
node_modules/playwright/lib/runner/loadUtils.js
generated
vendored
Normal file
297
node_modules/playwright/lib/runner/loadUtils.js
generated
vendored
Normal file
@@ -0,0 +1,297 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var loadUtils_exports = {};
|
||||
__export(loadUtils_exports, {
|
||||
collectProjectsAndTestFiles: () => collectProjectsAndTestFiles,
|
||||
createRootSuite: () => createRootSuite,
|
||||
loadFileSuites: () => loadFileSuites,
|
||||
loadGlobalHook: () => loadGlobalHook,
|
||||
loadReporter: () => loadReporter
|
||||
});
|
||||
module.exports = __toCommonJS(loadUtils_exports);
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_loaderHost = require("./loaderHost");
|
||||
var import_util = require("../util");
|
||||
var import_projectUtils = require("./projectUtils");
|
||||
var import_testGroups = require("./testGroups");
|
||||
var import_suiteUtils = require("../common/suiteUtils");
|
||||
var import_test = require("../common/test");
|
||||
var import_compilationCache = require("../transform/compilationCache");
|
||||
var import_transform = require("../transform/transform");
|
||||
var import_utilsBundle = require("../utilsBundle");
|
||||
async function collectProjectsAndTestFiles(testRun, doNotRunTestsOutsideProjectFilter) {
|
||||
const config = testRun.config;
|
||||
const fsCache = /* @__PURE__ */ new Map();
|
||||
const sourceMapCache = /* @__PURE__ */ new Map();
|
||||
const cliFileMatcher = config.cliArgs.length ? (0, import_util.createFileMatcherFromArguments)(config.cliArgs) : null;
|
||||
const allFilesForProject = /* @__PURE__ */ new Map();
|
||||
const filteredProjects = (0, import_projectUtils.filterProjects)(config.projects, config.cliProjectFilter);
|
||||
for (const project of filteredProjects) {
|
||||
const files = await (0, import_projectUtils.collectFilesForProject)(project, fsCache);
|
||||
allFilesForProject.set(project, files);
|
||||
}
|
||||
const filesToRunByProject = /* @__PURE__ */ 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);
|
||||
}
|
||||
const projectClosure = (0, import_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, import_projectUtils.collectFilesForProject)(project, fsCache);
|
||||
filesToRunByProject.set(project, files);
|
||||
}
|
||||
}
|
||||
testRun.projectFiles = filesToRunByProject;
|
||||
testRun.projectSuites = /* @__PURE__ */ new Map();
|
||||
}
|
||||
async function loadFileSuites(testRun, mode, errors) {
|
||||
const config = testRun.config;
|
||||
const allTestFiles = /* @__PURE__ */ new Set();
|
||||
for (const files of testRun.projectFiles.values())
|
||||
files.forEach((file) => allTestFiles.add(file));
|
||||
const fileSuiteByFile = /* @__PURE__ */ new Map();
|
||||
const loaderHost = mode === "out-of-process" ? new import_loaderHost.OutOfProcessLoaderHost(config) : new import_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();
|
||||
}
|
||||
for (const file of allTestFiles) {
|
||||
for (const dependency of (0, import_compilationCache.dependenciesForTestFile)(file)) {
|
||||
if (allTestFiles.has(dependency)) {
|
||||
const importer = import_path.default.relative(config.config.rootDir, file);
|
||||
const importee = import_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 }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
const config = testRun.config;
|
||||
const rootSuite = new import_test.Suite("", "root");
|
||||
const projectSuites = /* @__PURE__ */ new Map();
|
||||
const filteredProjectSuites = /* @__PURE__ */ new Map();
|
||||
{
|
||||
const cliFileFilters = (0, import_util.createFileFiltersFromArguments)(config.cliArgs);
|
||||
const grepMatcher = config.cliGrep ? (0, import_util.createTitleMatcher)((0, import_util.forceRegExp)(config.cliGrep)) : () => true;
|
||||
const grepInvertMatcher = config.cliGrepInvert ? (0, import_util.createTitleMatcher)((0, import_util.forceRegExp)(config.cliGrepInvert)) : () => false;
|
||||
const cliTitleMatcher = (title) => !grepInvertMatcher(title) && grepMatcher(title);
|
||||
for (const [project, fileSuites] of testRun.projectSuites) {
|
||||
const projectSuite = createProjectSuite(project, fileSuites);
|
||||
projectSuites.set(project, projectSuite);
|
||||
const filteredProjectSuite = filterProjectSuite(projectSuite, { cliFileFilters, cliTitleMatcher, testFilters: config.preOnlyTestFilters });
|
||||
filteredProjectSuites.set(project, filteredProjectSuite);
|
||||
}
|
||||
}
|
||||
if (shouldFilterOnly) {
|
||||
const filteredRoot = new import_test.Suite("", "root");
|
||||
for (const filteredProjectSuite of filteredProjectSuites.values())
|
||||
filteredRoot._addSuite(filteredProjectSuite);
|
||||
(0, import_suiteUtils.filterOnly)(filteredRoot);
|
||||
for (const [project, filteredProjectSuite] of filteredProjectSuites) {
|
||||
if (!filteredRoot.suites.includes(filteredProjectSuite))
|
||||
filteredProjectSuites.delete(project);
|
||||
}
|
||||
}
|
||||
const projectClosure = (0, import_projectUtils.buildProjectsClosure)([...filteredProjectSuites.keys()], (project) => filteredProjectSuites.get(project)._hasTests());
|
||||
for (const [project, type] of projectClosure) {
|
||||
if (type === "top-level") {
|
||||
project.project.repeatEach = project.fullConfig.configCLIOverrides.repeatEach ?? project.project.repeatEach;
|
||||
rootSuite._addSuite(buildProjectSuite(project, filteredProjectSuites.get(project)));
|
||||
}
|
||||
}
|
||||
if (config.config.forbidOnly) {
|
||||
const onlyTestsAndSuites = rootSuite._getOnlyItems();
|
||||
if (onlyTestsAndSuites.length > 0) {
|
||||
const configFilePath = config.config.configFile ? import_path.default.relative(config.config.rootDir, config.config.configFile) : void 0;
|
||||
errors.push(...createForbidOnlyErrors(onlyTestsAndSuites, config.configCLIOverrides.forbidOnly, configFilePath));
|
||||
}
|
||||
}
|
||||
if (config.config.shard) {
|
||||
const testGroups = [];
|
||||
for (const projectSuite of rootSuite.suites) {
|
||||
testGroups.push(...(0, import_testGroups.createTestGroups)(projectSuite, config.config.shard.total));
|
||||
}
|
||||
const testGroupsInThisShard = (0, import_testGroups.filterForShard)(config.config.shard, testGroups);
|
||||
const testsInThisShard = /* @__PURE__ */ new Set();
|
||||
for (const group of testGroupsInThisShard) {
|
||||
for (const test of group.tests)
|
||||
testsInThisShard.add(test);
|
||||
}
|
||||
(0, import_suiteUtils.filterTestsRemoveEmptySuites)(rootSuite, (test) => testsInThisShard.has(test));
|
||||
}
|
||||
if (config.postShardTestFilters.length)
|
||||
(0, import_suiteUtils.filterTestsRemoveEmptySuites)(rootSuite, (test) => config.postShardTestFilters.every((filter) => filter(test)));
|
||||
{
|
||||
const projectClosure2 = new Map((0, import_projectUtils.buildProjectsClosure)(rootSuite.suites.map((suite) => suite._fullProject)));
|
||||
for (const [project, level] of projectClosure2.entries()) {
|
||||
if (level === "dependency")
|
||||
rootSuite._prependSuite(buildProjectSuite(project, projectSuites.get(project)));
|
||||
}
|
||||
}
|
||||
return rootSuite;
|
||||
}
|
||||
function createProjectSuite(project, fileSuites) {
|
||||
const projectSuite = new import_test.Suite(project.project.name, "project");
|
||||
for (const fileSuite of fileSuites)
|
||||
projectSuite._addSuite((0, import_suiteUtils.bindFileSuiteToProject)(project, fileSuite));
|
||||
const grepMatcher = (0, import_util.createTitleMatcher)(project.project.grep);
|
||||
const grepInvertMatcher = project.project.grepInvert ? (0, import_util.createTitleMatcher)(project.project.grepInvert) : null;
|
||||
(0, import_suiteUtils.filterTestsRemoveEmptySuites)(projectSuite, (test) => {
|
||||
const grepTitle = test._grepTitleWithTags();
|
||||
if (grepInvertMatcher?.(grepTitle))
|
||||
return false;
|
||||
return grepMatcher(grepTitle);
|
||||
});
|
||||
return projectSuite;
|
||||
}
|
||||
function filterProjectSuite(projectSuite, options) {
|
||||
if (!options.cliFileFilters.length && !options.cliTitleMatcher && !options.testFilters.length)
|
||||
return projectSuite;
|
||||
const result = projectSuite._deepClone();
|
||||
if (options.cliFileFilters.length)
|
||||
(0, import_suiteUtils.filterByFocusedLine)(result, options.cliFileFilters);
|
||||
(0, import_suiteUtils.filterTestsRemoveEmptySuites)(result, (test) => {
|
||||
if (!options.testFilters.every((filter) => filter(test)))
|
||||
return false;
|
||||
if (options.cliTitleMatcher && !options.cliTitleMatcher(test._grepTitleWithTags()))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
function buildProjectSuite(project, projectSuite) {
|
||||
const result = new import_test.Suite(project.project.name, "project");
|
||||
result._fullProject = project;
|
||||
if (project.fullyParallel)
|
||||
result._parallelMode = "parallel";
|
||||
for (const fileSuite of projectSuite.suites) {
|
||||
result._addSuite(fileSuite);
|
||||
for (let repeatEachIndex = 1; repeatEachIndex < project.project.repeatEach; repeatEachIndex++) {
|
||||
const clone = fileSuite._deepClone();
|
||||
(0, import_suiteUtils.applyRepeatEachIndex)(project, clone, repeatEachIndex);
|
||||
result._addSuite(clone);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function createForbidOnlyErrors(onlyTestsAndSuites, forbidOnlyCLIFlag, configFilePath) {
|
||||
const errors = [];
|
||||
for (const testOrSuite of onlyTestsAndSuites) {
|
||||
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 = /* @__PURE__ */ new Map();
|
||||
for (const test of fileSuite.allTests()) {
|
||||
const fullTitle = test.titlePath().slice(1).join(" \u203A ");
|
||||
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 `${import_path.default.relative(rootDir, testOrSuite.location.file)}:${testOrSuite.location.line}`;
|
||||
}
|
||||
async function requireOrImportDefaultFunction(file, expectConstructor) {
|
||||
let func = await (0, import_transform.requireOrImport)(file);
|
||||
if (func && typeof func === "object" && "default" in func)
|
||||
func = func["default"];
|
||||
if (typeof func !== "function")
|
||||
throw (0, import_util.errorWithFile)(file, `file must export a single ${expectConstructor ? "class" : "function"}.`);
|
||||
return func;
|
||||
}
|
||||
function loadGlobalHook(config, file) {
|
||||
return requireOrImportDefaultFunction(import_path.default.resolve(config.config.rootDir, file), false);
|
||||
}
|
||||
function loadReporter(config, file) {
|
||||
return requireOrImportDefaultFunction(config ? import_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 = import_utilsBundle.sourceMapSupport.retrieveSourceMap(file);
|
||||
const sourceMapData = typeof sourceMap?.map === "string" ? JSON.parse(sourceMap.map) : sourceMap?.map;
|
||||
if (sourceMapData?.sources)
|
||||
sources = sourceMapData.sources.map((source) => import_path.default.resolve(import_path.default.dirname(file), source));
|
||||
} finally {
|
||||
cache.set(file, sources);
|
||||
return sources;
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
collectProjectsAndTestFiles,
|
||||
createRootSuite,
|
||||
loadFileSuites,
|
||||
loadGlobalHook,
|
||||
loadReporter
|
||||
});
|
89
node_modules/playwright/lib/runner/loaderHost.js
generated
vendored
Normal file
89
node_modules/playwright/lib/runner/loaderHost.js
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var loaderHost_exports = {};
|
||||
__export(loaderHost_exports, {
|
||||
InProcessLoaderHost: () => InProcessLoaderHost,
|
||||
OutOfProcessLoaderHost: () => OutOfProcessLoaderHost
|
||||
});
|
||||
module.exports = __toCommonJS(loaderHost_exports);
|
||||
var import_processHost = require("./processHost");
|
||||
var import_esmLoaderHost = require("../common/esmLoaderHost");
|
||||
var import_ipc = require("../common/ipc");
|
||||
var import_poolBuilder = require("../common/poolBuilder");
|
||||
var import_test = require("../common/test");
|
||||
var import_testLoader = require("../common/testLoader");
|
||||
var import_compilationCache = require("../transform/compilationCache");
|
||||
class InProcessLoaderHost {
|
||||
constructor(config) {
|
||||
this._config = config;
|
||||
this._poolBuilder = import_poolBuilder.PoolBuilder.createForLoader();
|
||||
}
|
||||
async start(errors) {
|
||||
return true;
|
||||
}
|
||||
async loadTestFile(file, testErrors) {
|
||||
const result = await (0, import_testLoader.loadTestFile)(file, this._config.config.rootDir, testErrors);
|
||||
this._poolBuilder.buildPools(result, testErrors);
|
||||
return result;
|
||||
}
|
||||
async stop() {
|
||||
await (0, import_esmLoaderHost.incorporateCompilationCache)();
|
||||
}
|
||||
}
|
||||
class OutOfProcessLoaderHost {
|
||||
constructor(config) {
|
||||
this._config = config;
|
||||
this._processHost = new import_processHost.ProcessHost(require.resolve("../loader/loaderMain.js"), "loader", {});
|
||||
}
|
||||
async start(errors) {
|
||||
const startError = await this._processHost.startRunner((0, import_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 import_test.Suite._deepParse(result.fileSuite);
|
||||
}
|
||||
async stop() {
|
||||
const result = await this._processHost.sendMessage({ method: "getCompilationCacheFromLoader" });
|
||||
(0, import_compilationCache.addToCompilationCache)(result);
|
||||
await this._processHost.stop();
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
InProcessLoaderHost,
|
||||
OutOfProcessLoaderHost
|
||||
});
|
161
node_modules/playwright/lib/runner/processHost.js
generated
vendored
Normal file
161
node_modules/playwright/lib/runner/processHost.js
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var processHost_exports = {};
|
||||
__export(processHost_exports, {
|
||||
ProcessHost: () => ProcessHost
|
||||
});
|
||||
module.exports = __toCommonJS(processHost_exports);
|
||||
var import_child_process = __toESM(require("child_process"));
|
||||
var import_events = require("events");
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
||||
class ProcessHost extends import_events.EventEmitter {
|
||||
constructor(runnerScript, processName, env) {
|
||||
super();
|
||||
this._didSendStop = false;
|
||||
this._processDidExit = false;
|
||||
this._didExitAndRanOnExit = false;
|
||||
this._lastMessageId = 0;
|
||||
this._callbacks = /* @__PURE__ */ new Map();
|
||||
this._producedEnv = {};
|
||||
this._runnerScript = runnerScript;
|
||||
this._processName = processName;
|
||||
this._extraEnv = env;
|
||||
}
|
||||
async startRunner(runnerParams, options = {}) {
|
||||
(0, import_utils.assert)(!this.process, "Internal error: starting the same process twice");
|
||||
this.process = import_child_process.default.fork(require.resolve("../common/process"), {
|
||||
detached: false,
|
||||
env: {
|
||||
...process.env,
|
||||
...this._extraEnv
|
||||
},
|
||||
stdio: [
|
||||
"ignore",
|
||||
options.onStdOut ? "pipe" : "inherit",
|
||||
options.onStdErr && !process.env.PW_RUNNER_DEBUG ? "pipe" : "inherit",
|
||||
"ipc"
|
||||
]
|
||||
});
|
||||
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) => {
|
||||
});
|
||||
this.process.on("message", (message) => {
|
||||
if (import_utilsBundle.debug.enabled("pw:test:protocol"))
|
||||
(0, import_utilsBundle.debug)("pw:test:protocol")("\u25C0 RECV " + JSON.stringify(message));
|
||||
if (message.method === "__env_produced__") {
|
||||
const producedEnv = message.params;
|
||||
this._producedEnv = Object.fromEntries(producedEnv.map((e) => [e[0], e[1] ?? void 0]));
|
||||
} else if (message.method === "__dispatch__") {
|
||||
const { id, error: error2, method, params, result } = message.params;
|
||||
if (id && this._callbacks.has(id)) {
|
||||
const { resolve, reject } = this._callbacks.get(id);
|
||||
this._callbacks.delete(id);
|
||||
if (error2) {
|
||||
const errorObject = new Error(error2.message);
|
||||
errorObject.stack = error2.stack;
|
||||
reject(errorObject);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
} else {
|
||||
this.emit(method, params);
|
||||
}
|
||||
} else {
|
||||
this.emit(message.method, message.params);
|
||||
}
|
||||
});
|
||||
if (options.onStdOut)
|
||||
this.process.stdout?.on("data", options.onStdOut);
|
||||
if (options.onStdErr)
|
||||
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(void 0));
|
||||
});
|
||||
if (error)
|
||||
return error;
|
||||
const processParams = {
|
||||
processName: this._processName,
|
||||
timeOrigin: (0, import_utils.timeOrigin)()
|
||||
};
|
||||
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) {
|
||||
if (import_utilsBundle.debug.enabled("pw:test:protocol"))
|
||||
(0, import_utilsBundle.debug)("pw:test:protocol")("SEND \u25BA " + JSON.stringify(message));
|
||||
this.process?.send(message);
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
ProcessHost
|
||||
});
|
235
node_modules/playwright/lib/runner/projectUtils.js
generated
vendored
Normal file
235
node_modules/playwright/lib/runner/projectUtils.js
generated
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var projectUtils_exports = {};
|
||||
__export(projectUtils_exports, {
|
||||
buildDependentProjects: () => buildDependentProjects,
|
||||
buildProjectsClosure: () => buildProjectsClosure,
|
||||
buildTeardownToSetupsMap: () => buildTeardownToSetupsMap,
|
||||
collectFilesForProject: () => collectFilesForProject,
|
||||
filterProjects: () => filterProjects
|
||||
});
|
||||
module.exports = __toCommonJS(projectUtils_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_util = require("util");
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
||||
var import_util2 = require("../util");
|
||||
const readFileAsync = (0, import_util.promisify)(import_fs.default.readFile);
|
||||
const readDirAsync = (0, import_util.promisify)(import_fs.default.readdir);
|
||||
function wildcardPatternToRegExp(pattern) {
|
||||
return new RegExp("^" + pattern.split("*").map(import_utils.escapeRegExp).join(".*") + "$", "ig");
|
||||
}
|
||||
function filterProjects(projects, projectNames) {
|
||||
if (!projectNames)
|
||||
return [...projects];
|
||||
const projectNamesToFind = /* @__PURE__ */ new Set();
|
||||
const unmatchedProjectNames = /* @__PURE__ */ new Map();
|
||||
const patterns = /* @__PURE__ */ 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 = /* @__PURE__ */ 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 = /* @__PURE__ */ 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 = /* @__PURE__ */ 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 = /* @__PURE__ */ new Map()) {
|
||||
const extensions = /* @__PURE__ */ new Set([".js", ".ts", ".mjs", ".mts", ".cjs", ".cts", ".jsx", ".tsx", ".mjsx", ".mtsx", ".cjsx", ".ctsx"]);
|
||||
const testFileExtension = (file) => extensions.has(import_path.default.extname(file));
|
||||
const allFiles = await cachedCollectFiles(project.project.testDir, project.respectGitIgnore, fsCache);
|
||||
const testMatch = (0, import_util2.createFileMatcher)(project.project.testMatch);
|
||||
const testIgnore = (0, import_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 (!import_fs.default.existsSync(testDir))
|
||||
return [];
|
||||
if (!import_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 = import_path.default.relative(rule.dir, entryPath);
|
||||
if (rule.match("/" + relative) || rule.match(relative)) {
|
||||
status = ruleIncludes ? "included" : "ignored";
|
||||
} else if (isDirectory && (rule.match("/" + relative + "/") || rule.match(relative + "/"))) {
|
||||
status = ruleIncludes ? "included" : "ignored";
|
||||
} else if (isDirectory && ruleIncludes && (rule.match("/" + relative, true) || rule.match(relative, true))) {
|
||||
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(import_path.default.join(dir, gitignore.name), "utf8");
|
||||
const newRules = content.split(/\r?\n/).map((s) => {
|
||||
s = s.trim();
|
||||
if (!s)
|
||||
return;
|
||||
const rule = new import_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 = import_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;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
buildDependentProjects,
|
||||
buildProjectsClosure,
|
||||
buildTeardownToSetupsMap,
|
||||
collectFilesForProject,
|
||||
filterProjects
|
||||
});
|
189
node_modules/playwright/lib/runner/rebase.js
generated
vendored
Normal file
189
node_modules/playwright/lib/runner/rebase.js
generated
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var rebase_exports = {};
|
||||
__export(rebase_exports, {
|
||||
addSuggestedRebaseline: () => addSuggestedRebaseline,
|
||||
applySuggestedRebaselines: () => applySuggestedRebaselines,
|
||||
clearSuggestedRebaselines: () => clearSuggestedRebaselines
|
||||
});
|
||||
module.exports = __toCommonJS(rebase_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utils2 = require("playwright-core/lib/utils");
|
||||
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
||||
var import_projectUtils = require("./projectUtils");
|
||||
var import_babelBundle = require("../transform/babelBundle");
|
||||
const t = import_babelBundle.types;
|
||||
const suggestedRebaselines = new import_utils.MultiMap();
|
||||
function addSuggestedRebaseline(location, suggestedRebaseline) {
|
||||
suggestedRebaselines.set(location.file, { location, code: suggestedRebaseline });
|
||||
}
|
||||
function clearSuggestedRebaselines() {
|
||||
suggestedRebaselines.clear();
|
||||
}
|
||||
async function applySuggestedRebaselines(config, reporter) {
|
||||
if (config.config.updateSnapshots === "none")
|
||||
return;
|
||||
if (!suggestedRebaselines.size)
|
||||
return;
|
||||
const [project] = (0, import_projectUtils.filterProjects)(config.projects, config.cliProjectFilter);
|
||||
if (!project)
|
||||
return;
|
||||
const patches = [];
|
||||
const files = [];
|
||||
const gitCache = /* @__PURE__ */ new Map();
|
||||
const patchFile = import_path.default.join(project.project.outputDir, "rebaselines.patch");
|
||||
for (const fileName of [...suggestedRebaselines.keys()].sort()) {
|
||||
const source = await import_fs.default.promises.readFile(fileName, "utf8");
|
||||
const lines = source.split("\n");
|
||||
const replacements = suggestedRebaselines.get(fileName);
|
||||
const fileNode = (0, import_babelBundle.babelParse)(source, fileName, true);
|
||||
const ranges = [];
|
||||
(0, import_babelBundle.traverse)(fileNode, {
|
||||
CallExpression: (path2) => {
|
||||
const node = path2.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 prop = node.callee.property;
|
||||
if (!prop.loc || !argument.start || !argument.end)
|
||||
return;
|
||||
for (const replacement of replacements) {
|
||||
if (prop.loc.start.line !== replacement.location.line)
|
||||
continue;
|
||||
if (prop.loc.start.column + 1 !== replacement.location.column)
|
||||
continue;
|
||||
const indent = lines[prop.loc.start.line - 1].match(/^\s*/)[0];
|
||||
const newText = replacement.code.replace(/\{indent\}/g, indent);
|
||||
ranges.push({ start: argument.start, end: argument.end, oldText: source.substring(argument.start, argument.end), newText });
|
||||
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 = import_path.default.relative(process.cwd(), fileName);
|
||||
files.push(relativeName);
|
||||
if (config.config.updateSourceMethod === "overwrite") {
|
||||
await import_fs.default.promises.writeFile(fileName, result);
|
||||
} else if (config.config.updateSourceMethod === "3way") {
|
||||
await import_fs.default.promises.writeFile(fileName, applyPatchWithConflictMarkers(source, result));
|
||||
} else {
|
||||
const gitFolder = findGitRoot(import_path.default.dirname(fileName), gitCache);
|
||||
const relativeToGit = import_path.default.relative(gitFolder || process.cwd(), fileName);
|
||||
patches.push(createPatch(relativeToGit, source, result));
|
||||
}
|
||||
}
|
||||
const fileList = files.map((file) => " " + import_utils2.colors.dim(file)).join("\n");
|
||||
reporter.onStdErr(`
|
||||
New baselines created for:
|
||||
|
||||
${fileList}
|
||||
`);
|
||||
if (config.config.updateSourceMethod === "patch") {
|
||||
await import_fs.default.promises.mkdir(import_path.default.dirname(patchFile), { recursive: true });
|
||||
await import_fs.default.promises.writeFile(patchFile, patches.join("\n"));
|
||||
reporter.onStdErr(`
|
||||
` + import_utils2.colors.cyan("git apply " + import_path.default.relative(process.cwd(), patchFile)) + "\n");
|
||||
}
|
||||
}
|
||||
function createPatch(fileName, before, after) {
|
||||
const file = fileName.replace(/\\/g, "/");
|
||||
const text = import_utilsBundle.diff.createPatch(file, before, after, void 0, void 0, { context: 3 });
|
||||
return [
|
||||
"diff --git a/" + file + " b/" + file,
|
||||
"--- a/" + file,
|
||||
"+++ b/" + file,
|
||||
...text.split("\n").slice(4)
|
||||
].join("\n");
|
||||
}
|
||||
function findGitRoot(dir, cache) {
|
||||
const result = cache.get(dir);
|
||||
if (result !== void 0)
|
||||
return result;
|
||||
const gitPath = import_path.default.join(dir, ".git");
|
||||
if (import_fs.default.existsSync(gitPath) && import_fs.default.lstatSync(gitPath).isDirectory()) {
|
||||
cache.set(dir, dir);
|
||||
return dir;
|
||||
}
|
||||
const parentDir = import_path.default.dirname(dir);
|
||||
if (dir === parentDir) {
|
||||
cache.set(dir, null);
|
||||
return null;
|
||||
}
|
||||
const parentResult = findGitRoot(parentDir, cache);
|
||||
cache.set(dir, parentResult);
|
||||
return parentResult;
|
||||
}
|
||||
function applyPatchWithConflictMarkers(oldText, newText) {
|
||||
const diffResult = import_utilsBundle.diff.diffLines(oldText, newText);
|
||||
let result = "";
|
||||
let conflict = false;
|
||||
diffResult.forEach((part) => {
|
||||
if (part.added) {
|
||||
if (conflict) {
|
||||
result += part.value;
|
||||
result += ">>>>>>> SNAPSHOT\n";
|
||||
conflict = false;
|
||||
} else {
|
||||
result += "<<<<<<< HEAD\n";
|
||||
result += part.value;
|
||||
result += "=======\n";
|
||||
conflict = true;
|
||||
}
|
||||
} else if (part.removed) {
|
||||
result += "<<<<<<< HEAD\n";
|
||||
result += part.value;
|
||||
result += "=======\n";
|
||||
conflict = true;
|
||||
} else {
|
||||
if (conflict) {
|
||||
result += ">>>>>>> SNAPSHOT\n";
|
||||
conflict = false;
|
||||
}
|
||||
result += part.value;
|
||||
}
|
||||
});
|
||||
if (conflict)
|
||||
result += ">>>>>>> SNAPSHOT\n";
|
||||
return result;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
addSuggestedRebaseline,
|
||||
applySuggestedRebaselines,
|
||||
clearSuggestedRebaselines
|
||||
});
|
137
node_modules/playwright/lib/runner/reporters.js
generated
vendored
Normal file
137
node_modules/playwright/lib/runner/reporters.js
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var reporters_exports = {};
|
||||
__export(reporters_exports, {
|
||||
createErrorCollectingReporter: () => createErrorCollectingReporter,
|
||||
createReporterForTestServer: () => createReporterForTestServer,
|
||||
createReporters: () => createReporters
|
||||
});
|
||||
module.exports = __toCommonJS(reporters_exports);
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_loadUtils = require("./loadUtils");
|
||||
var import_base = require("../reporters/base");
|
||||
var import_blob = require("../reporters/blob");
|
||||
var import_dot = __toESM(require("../reporters/dot"));
|
||||
var import_empty = __toESM(require("../reporters/empty"));
|
||||
var import_github = __toESM(require("../reporters/github"));
|
||||
var import_html = __toESM(require("../reporters/html"));
|
||||
var import_json = __toESM(require("../reporters/json"));
|
||||
var import_junit = __toESM(require("../reporters/junit"));
|
||||
var import_line = __toESM(require("../reporters/line"));
|
||||
var import_list = __toESM(require("../reporters/list"));
|
||||
var import_listModeReporter = __toESM(require("../reporters/listModeReporter"));
|
||||
var import_reporterV2 = require("../reporters/reporterV2");
|
||||
async function createReporters(config, mode, isTestServer, descriptions) {
|
||||
const defaultReporters = {
|
||||
blob: import_blob.BlobReporter,
|
||||
dot: mode === "list" ? import_listModeReporter.default : import_dot.default,
|
||||
line: mode === "list" ? import_listModeReporter.default : import_line.default,
|
||||
list: mode === "list" ? import_listModeReporter.default : import_list.default,
|
||||
github: import_github.default,
|
||||
json: import_json.default,
|
||||
junit: import_junit.default,
|
||||
null: import_empty.default,
|
||||
html: import_html.default
|
||||
};
|
||||
const reporters = [];
|
||||
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, import_loadUtils.loadReporter)(config, name);
|
||||
reporters.push((0, import_reporterV2.wrapReporterAsV2)(new reporterConstructor(options)));
|
||||
}
|
||||
}
|
||||
if (process.env.PW_TEST_REPORTER) {
|
||||
const reporterConstructor = await (0, import_loadUtils.loadReporter)(config, process.env.PW_TEST_REPORTER);
|
||||
reporters.push((0, import_reporterV2.wrapReporterAsV2)(new reporterConstructor(runOptions)));
|
||||
}
|
||||
const someReporterPrintsToStdio = reporters.some((r) => r.printsToStdio ? r.printsToStdio() : true);
|
||||
if (reporters.length && !someReporterPrintsToStdio) {
|
||||
if (mode === "list")
|
||||
reporters.unshift(new import_listModeReporter.default());
|
||||
else if (mode !== "merge")
|
||||
reporters.unshift(!process.env.CI ? new import_line.default() : new import_dot.default());
|
||||
}
|
||||
return reporters;
|
||||
}
|
||||
async function createReporterForTestServer(file, messageSink) {
|
||||
const reporterConstructor = await (0, import_loadUtils.loadReporter)(null, file);
|
||||
return (0, import_reporterV2.wrapReporterAsV2)(new reporterConstructor({
|
||||
_send: messageSink
|
||||
}));
|
||||
}
|
||||
function createErrorCollectingReporter(screen) {
|
||||
const errors = [];
|
||||
return {
|
||||
version: () => "v2",
|
||||
onError(error) {
|
||||
errors.push(error);
|
||||
screen.stderr?.write((0, import_base.formatError)(screen, error).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 = [];
|
||||
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, import_utils.calculateSha1)(JSON.stringify(command)).substring(0, 7));
|
||||
return parts.join("-");
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
createErrorCollectingReporter,
|
||||
createReporterForTestServer,
|
||||
createReporters
|
||||
});
|
96
node_modules/playwright/lib/runner/sigIntWatcher.js
generated
vendored
Normal file
96
node_modules/playwright/lib/runner/sigIntWatcher.js
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var sigIntWatcher_exports = {};
|
||||
__export(sigIntWatcher_exports, {
|
||||
SigIntWatcher: () => SigIntWatcher
|
||||
});
|
||||
module.exports = __toCommonJS(sigIntWatcher_exports);
|
||||
class SigIntWatcher {
|
||||
constructor() {
|
||||
this._hadSignal = false;
|
||||
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);
|
||||
}
|
||||
}
|
||||
class FixedNodeSIGINTHandler {
|
||||
static {
|
||||
this._handlers = [];
|
||||
}
|
||||
static {
|
||||
this._ignoreNextSIGINTs = false;
|
||||
}
|
||||
static {
|
||||
this._handlerInstalled = false;
|
||||
}
|
||||
static {
|
||||
this._dispatch = () => {
|
||||
if (this._ignoreNextSIGINTs)
|
||||
return;
|
||||
this._ignoreNextSIGINTs = true;
|
||||
setTimeout(() => {
|
||||
this._ignoreNextSIGINTs = false;
|
||||
if (!this._handlers.length)
|
||||
this._uninstall();
|
||||
}, 1e3);
|
||||
for (const handler of this._handlers)
|
||||
handler();
|
||||
};
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
SigIntWatcher
|
||||
});
|
127
node_modules/playwright/lib/runner/taskRunner.js
generated
vendored
Normal file
127
node_modules/playwright/lib/runner/taskRunner.js
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var taskRunner_exports = {};
|
||||
__export(taskRunner_exports, {
|
||||
TaskRunner: () => TaskRunner
|
||||
});
|
||||
module.exports = __toCommonJS(taskRunner_exports);
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utils2 = require("playwright-core/lib/utils");
|
||||
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
||||
var import_sigIntWatcher = require("./sigIntWatcher");
|
||||
var import_util = require("../util");
|
||||
class TaskRunner {
|
||||
constructor(reporter, globalTimeoutForError) {
|
||||
this._tasks = [];
|
||||
this._hasErrors = false;
|
||||
this._interrupted = false;
|
||||
this._isTearDown = false;
|
||||
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 import_utils.ManualPromise()) {
|
||||
const sigintWatcher = new import_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, import_utilsBundle.debug)("pw:test:task")(`"${task.title}" started`);
|
||||
const errors = [];
|
||||
const softErrors = [];
|
||||
try {
|
||||
teardownRunner._tasks.unshift({ title: `teardown for ${task.title}`, setup: task.teardown });
|
||||
await task.setup?.(context, errors, softErrors);
|
||||
} catch (e) {
|
||||
(0, import_utilsBundle.debug)("pw:test:task")(`error in "${task.title}": `, e);
|
||||
errors.push((0, import_util.serializeError)(e));
|
||||
} finally {
|
||||
for (const error of [...softErrors, ...errors])
|
||||
this._reporter.onError?.(error);
|
||||
if (errors.length) {
|
||||
if (!this._isTearDown)
|
||||
this._interrupted = true;
|
||||
this._hasErrors = true;
|
||||
}
|
||||
}
|
||||
(0, import_utilsBundle.debug)("pw:test:task")(`"${task.title}" finished`);
|
||||
}
|
||||
};
|
||||
await Promise.race([
|
||||
taskLoop(),
|
||||
cancelPromise,
|
||||
sigintWatcher.promise(),
|
||||
timeoutWatcher.promise
|
||||
]);
|
||||
sigintWatcher.disarm();
|
||||
timeoutWatcher.disarm();
|
||||
this._interrupted = true;
|
||||
let status = "passed";
|
||||
if (sigintWatcher.hadSignal() || cancelPromise?.isDone()) {
|
||||
status = "interrupted";
|
||||
} else if (timeoutWatcher.timedOut()) {
|
||||
this._reporter.onError?.({ message: import_utils2.colors.red(`Timed out waiting ${this._globalTimeoutForError / 1e3}s for the ${currentTaskName} to run`) });
|
||||
status = "timedout";
|
||||
} else if (this._hasErrors) {
|
||||
status = "failed";
|
||||
}
|
||||
cancelPromise?.resolve();
|
||||
const cleanup = () => teardownRunner.runDeferCleanup(context, deadline).then((r) => r.status);
|
||||
return { status, cleanup };
|
||||
}
|
||||
}
|
||||
class TimeoutWatcher {
|
||||
constructor(deadline) {
|
||||
this._timedOut = false;
|
||||
this.promise = new import_utils.ManualPromise();
|
||||
if (!deadline)
|
||||
return;
|
||||
if (deadline - (0, import_utils.monotonicTime)() <= 0) {
|
||||
this._timedOut = true;
|
||||
this.promise.resolve();
|
||||
return;
|
||||
}
|
||||
this._timer = setTimeout(() => {
|
||||
this._timedOut = true;
|
||||
this.promise.resolve();
|
||||
}, deadline - (0, import_utils.monotonicTime)());
|
||||
}
|
||||
timedOut() {
|
||||
return this._timedOut;
|
||||
}
|
||||
disarm() {
|
||||
clearTimeout(this._timer);
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
TaskRunner
|
||||
});
|
399
node_modules/playwright/lib/runner/tasks.js
generated
vendored
Normal file
399
node_modules/playwright/lib/runner/tasks.js
generated
vendored
Normal file
@@ -0,0 +1,399 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var tasks_exports = {};
|
||||
__export(tasks_exports, {
|
||||
TestRun: () => TestRun,
|
||||
createApplyRebaselinesTask: () => createApplyRebaselinesTask,
|
||||
createClearCacheTask: () => createClearCacheTask,
|
||||
createGlobalSetupTasks: () => createGlobalSetupTasks,
|
||||
createListFilesTask: () => createListFilesTask,
|
||||
createLoadTask: () => createLoadTask,
|
||||
createPluginSetupTasks: () => createPluginSetupTasks,
|
||||
createReportBeginTask: () => createReportBeginTask,
|
||||
createRunTestsTasks: () => createRunTestsTasks,
|
||||
createStartDevServerTask: () => createStartDevServerTask,
|
||||
runTasks: () => runTasks,
|
||||
runTasksDeferCleanup: () => runTasksDeferCleanup
|
||||
});
|
||||
module.exports = __toCommonJS(tasks_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_util = require("util");
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
||||
var import_dispatcher = require("./dispatcher");
|
||||
var import_failureTracker = require("./failureTracker");
|
||||
var import_loadUtils = require("./loadUtils");
|
||||
var import_projectUtils = require("./projectUtils");
|
||||
var import_rebase = require("./rebase");
|
||||
var import_taskRunner = require("./taskRunner");
|
||||
var import_vcs = require("./vcs");
|
||||
var import_test = require("../common/test");
|
||||
var import_testGroups = require("../runner/testGroups");
|
||||
var import_compilationCache = require("../transform/compilationCache");
|
||||
var import_util2 = require("../util");
|
||||
const readDirAsync = (0, import_util.promisify)(import_fs.default.readdir);
|
||||
class TestRun {
|
||||
constructor(config, reporter) {
|
||||
this.rootSuite = void 0;
|
||||
this.phases = [];
|
||||
this.projectFiles = /* @__PURE__ */ new Map();
|
||||
this.projectSuites = /* @__PURE__ */ new Map();
|
||||
this.config = config;
|
||||
this.reporter = reporter;
|
||||
this.failureTracker = new import_failureTracker.FailureTracker(config);
|
||||
}
|
||||
}
|
||||
async function runTasks(testRun, tasks, globalTimeout, cancelPromise) {
|
||||
const deadline = globalTimeout ? (0, import_utils.monotonicTime)() + globalTimeout : 0;
|
||||
const taskRunner = new import_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 import_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)
|
||||
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, import_util2.removeDirAndLogToConsole)(import_compilationCache.cacheDir);
|
||||
for (const plugin of config.plugins)
|
||||
await plugin.instance?.clearCache?.();
|
||||
}
|
||||
};
|
||||
}
|
||||
function createReportBeginTask() {
|
||||
return {
|
||||
title: "report begin",
|
||||
setup: async (testRun) => {
|
||||
testRun.reporter.onBegin?.(testRun.rootSuite);
|
||||
},
|
||||
teardown: async ({}) => {
|
||||
}
|
||||
};
|
||||
}
|
||||
function createPluginSetupTasks(config) {
|
||||
return config.plugins.map((plugin) => ({
|
||||
title: "plugin setup",
|
||||
setup: async ({ reporter }) => {
|
||||
if (typeof plugin.factory === "function")
|
||||
plugin.instance = await plugin.factory();
|
||||
else
|
||||
plugin.instance = plugin.factory;
|
||||
await plugin.instance?.setup?.(config.config, config.configDir, reporter);
|
||||
},
|
||||
teardown: async () => {
|
||||
await plugin.instance?.teardown?.();
|
||||
}
|
||||
}));
|
||||
}
|
||||
function createPluginBeginTask(plugin) {
|
||||
return {
|
||||
title: "plugin begin",
|
||||
setup: async (testRun) => {
|
||||
await plugin.instance?.begin?.(testRun.rootSuite);
|
||||
},
|
||||
teardown: async () => {
|
||||
await plugin.instance?.end?.();
|
||||
}
|
||||
};
|
||||
}
|
||||
function createGlobalSetupTask(file, config) {
|
||||
let title = "global setup";
|
||||
if (config.globalSetups.length > 1)
|
||||
title += ` (${file})`;
|
||||
let globalSetupResult;
|
||||
return {
|
||||
title,
|
||||
setup: async ({ config: config2 }) => {
|
||||
const setupHook = await (0, import_loadUtils.loadGlobalHook)(config2, file);
|
||||
globalSetupResult = await setupHook(config2.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: config2 }) => {
|
||||
const teardownHook = await (0, import_loadUtils.loadGlobalHook)(config2, file);
|
||||
await teardownHook(config2.config);
|
||||
}
|
||||
};
|
||||
}
|
||||
function createRemoveOutputDirsTask() {
|
||||
return {
|
||||
title: "clear output",
|
||||
setup: async ({ config }) => {
|
||||
const outputDirs = /* @__PURE__ */ new Set();
|
||||
const projects = (0, import_projectUtils.filterProjects)(config.projects, config.cliProjectFilter);
|
||||
projects.forEach((p) => outputDirs.add(p.project.outputDir));
|
||||
await Promise.all(Array.from(outputDirs).map((outputDir) => (0, import_utils.removeFolders)([outputDir]).then(async ([error]) => {
|
||||
if (!error)
|
||||
return;
|
||||
if (error.code === "EBUSY") {
|
||||
const entries = await readDirAsync(outputDir).catch((e) => []);
|
||||
await Promise.all(entries.map((entry) => (0, import_utils.removeFolders)([import_path.default.join(outputDir, entry)])));
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
})));
|
||||
}
|
||||
};
|
||||
}
|
||||
function createListFilesTask() {
|
||||
return {
|
||||
title: "load tests",
|
||||
setup: async (testRun, errors) => {
|
||||
testRun.rootSuite = await (0, import_loadUtils.createRootSuite)(testRun, errors, false);
|
||||
testRun.failureTracker.onRootSuite(testRun.rootSuite);
|
||||
await (0, import_loadUtils.collectProjectsAndTestFiles)(testRun, false);
|
||||
for (const [project, files] of testRun.projectFiles) {
|
||||
const projectSuite = new import_test.Suite(project.project.name, "project");
|
||||
projectSuite._fullProject = project;
|
||||
testRun.rootSuite._addSuite(projectSuite);
|
||||
const suites = files.map((file) => {
|
||||
const title = import_path.default.relative(testRun.config.config.rootDir, file);
|
||||
const suite = new import_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, import_loadUtils.collectProjectsAndTestFiles)(testRun, !!options.doNotRunDepsOutsideProjectFilter);
|
||||
await (0, import_loadUtils.loadFileSuites)(testRun, mode, options.failOnLoadErrors ? errors : softErrors);
|
||||
if (testRun.config.cliOnlyChanged || options.populateDependencies) {
|
||||
for (const plugin of testRun.config.plugins)
|
||||
await plugin.instance?.populateDependencies?.();
|
||||
}
|
||||
if (testRun.config.cliOnlyChanged) {
|
||||
const changedFiles = await (0, import_vcs.detectChangedTestFiles)(testRun.config.cliOnlyChanged, testRun.config.configDir);
|
||||
testRun.config.preOnlyTestFilters.push((test) => changedFiles.has(test.location.file));
|
||||
}
|
||||
testRun.rootSuite = await (0, import_loadUtils.createRootSuite)(testRun, options.failOnLoadErrors ? errors : softErrors, !!options.filterOnly);
|
||||
testRun.failureTracker.onRootSuite(testRun.rootSuite);
|
||||
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",
|
||||
setup: async () => {
|
||||
(0, import_rebase.clearSuggestedRebaselines)();
|
||||
},
|
||||
teardown: async ({ config, reporter }) => {
|
||||
await (0, import_rebase.applySuggestedRebaselines)(config, reporter);
|
||||
}
|
||||
};
|
||||
}
|
||||
function createPhasesTask() {
|
||||
return {
|
||||
title: "create phases",
|
||||
setup: async (testRun) => {
|
||||
let maxConcurrentTestGroups = 0;
|
||||
const processed = /* @__PURE__ */ new Set();
|
||||
const projectToSuite = new Map(testRun.rootSuite.suites.map((suite) => [suite._fullProject, suite]));
|
||||
const allProjects = [...projectToSuite.keys()];
|
||||
const teardownToSetups = (0, import_projectUtils.buildTeardownToSetupsMap)(allProjects);
|
||||
const teardownToSetupsDependents = /* @__PURE__ */ new Map();
|
||||
for (const [teardown, setups] of teardownToSetups) {
|
||||
const closure = (0, import_projectUtils.buildDependentProjects)(setups, allProjects);
|
||||
closure.delete(teardown);
|
||||
teardownToSetupsDependents.set(teardown, [...closure]);
|
||||
}
|
||||
for (let i = 0; i < projectToSuite.size; i++) {
|
||||
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);
|
||||
}
|
||||
for (const project of phaseProjects)
|
||||
processed.add(project);
|
||||
if (phaseProjects.length) {
|
||||
let testGroupsInPhase = 0;
|
||||
const phase = { dispatcher: new import_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, import_testGroups.createTestGroups)(projectSuite, testRun.config.config.workers);
|
||||
phase.projects.push({ project, projectSuite, testGroups });
|
||||
testGroupsInPhase += Math.min(project.workers ?? Number.MAX_SAFE_INTEGER, testGroups.length);
|
||||
}
|
||||
(0, import_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 = /* @__PURE__ */ new Set();
|
||||
const extraEnvByProjectId = /* @__PURE__ */ new Map();
|
||||
const teardownToSetups = (0, import_projectUtils.buildTeardownToSetupsMap)(phases.map((phase) => phase.projects.map((p) => p.project)).flat());
|
||||
for (const { dispatcher, projects } of phases) {
|
||||
const phaseTestGroups = [];
|
||||
for (const { project, testGroups } of projects) {
|
||||
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 (!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)
|
||||
plugin.devServerCleanup = await plugin.instance?.startDevServer?.();
|
||||
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) {
|
||||
await plugin.devServerCleanup?.();
|
||||
plugin.devServerCleanup = void 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
TestRun,
|
||||
createApplyRebaselinesTask,
|
||||
createClearCacheTask,
|
||||
createGlobalSetupTasks,
|
||||
createListFilesTask,
|
||||
createLoadTask,
|
||||
createPluginSetupTasks,
|
||||
createReportBeginTask,
|
||||
createRunTestsTasks,
|
||||
createStartDevServerTask,
|
||||
runTasks,
|
||||
runTasksDeferCleanup
|
||||
});
|
117
node_modules/playwright/lib/runner/testGroups.js
generated
vendored
Normal file
117
node_modules/playwright/lib/runner/testGroups.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var testGroups_exports = {};
|
||||
__export(testGroups_exports, {
|
||||
createTestGroups: () => createTestGroups,
|
||||
filterForShard: () => filterForShard
|
||||
});
|
||||
module.exports = __toCommonJS(testGroups_exports);
|
||||
function createTestGroups(projectSuite, expectedParallelism) {
|
||||
const groups = /* @__PURE__ */ 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 = /* @__PURE__ */ new Map();
|
||||
groups.set(test._workerHash, withWorkerHash);
|
||||
}
|
||||
let withRequireFile = withWorkerHash.get(test._requireFile);
|
||||
if (!withRequireFile) {
|
||||
withRequireFile = {
|
||||
general: createGroup(test),
|
||||
parallel: /* @__PURE__ */ new Map(),
|
||||
parallelWithHooks: createGroup(test)
|
||||
};
|
||||
withWorkerHash.set(test._requireFile, withRequireFile);
|
||||
}
|
||||
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()) {
|
||||
if (withRequireFile.general.tests.length)
|
||||
result.push(withRequireFile.general);
|
||||
result.push(...withRequireFile.parallel.values());
|
||||
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) {
|
||||
let shardableTotal = 0;
|
||||
for (const group of testGroups)
|
||||
shardableTotal += group.tests.length;
|
||||
const shardSize = Math.floor(shardableTotal / shard.total);
|
||||
const extraOne = shardableTotal - shardSize * shard.total;
|
||||
const currentShard = shard.current - 1;
|
||||
const from = shardSize * currentShard + Math.min(extraOne, currentShard);
|
||||
const to = from + shardSize + (currentShard < extraOne ? 1 : 0);
|
||||
let current = 0;
|
||||
const result = /* @__PURE__ */ new Set();
|
||||
for (const group of testGroups) {
|
||||
if (current >= from && current < to)
|
||||
result.add(group);
|
||||
current += group.tests.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
createTestGroups,
|
||||
filterForShard
|
||||
});
|
402
node_modules/playwright/lib/runner/testRunner.js
generated
vendored
Normal file
402
node_modules/playwright/lib/runner/testRunner.js
generated
vendored
Normal file
@@ -0,0 +1,402 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var testRunner_exports = {};
|
||||
__export(testRunner_exports, {
|
||||
TestRunner: () => TestRunner,
|
||||
TestRunnerEvent: () => TestRunnerEvent,
|
||||
runAllTestsWithConfig: () => runAllTestsWithConfig
|
||||
});
|
||||
module.exports = __toCommonJS(testRunner_exports);
|
||||
var import_events = __toESM(require("events"));
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_server = require("playwright-core/lib/server");
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_configLoader = require("../common/configLoader");
|
||||
var import_fsWatcher = require("../fsWatcher");
|
||||
var import_teleReceiver = require("../isomorphic/teleReceiver");
|
||||
var import_gitCommitInfoPlugin = require("../plugins/gitCommitInfoPlugin");
|
||||
var import_webServerPlugin = require("../plugins/webServerPlugin");
|
||||
var import_base = require("../reporters/base");
|
||||
var import_internalReporter = require("../reporters/internalReporter");
|
||||
var import_compilationCache = require("../transform/compilationCache");
|
||||
var import_util = require("../util");
|
||||
var import_reporters = require("./reporters");
|
||||
var import_tasks = require("./tasks");
|
||||
var import_lastRun = require("./lastRun");
|
||||
const TestRunnerEvent = {
|
||||
TestFilesChanged: "testFilesChanged",
|
||||
RecoverFromStepError: "recoverFromStepError"
|
||||
};
|
||||
class TestRunner extends import_events.default {
|
||||
constructor(configLocation, configCLIOverrides) {
|
||||
super();
|
||||
this._watchedProjectDirs = /* @__PURE__ */ new Set();
|
||||
this._ignoredProjectOutputs = /* @__PURE__ */ new Set();
|
||||
this._watchedTestDependencies = /* @__PURE__ */ new Set();
|
||||
this._queue = Promise.resolve();
|
||||
this._watchTestDirs = false;
|
||||
this._populateDependenciesOnList = false;
|
||||
this._recoverFromStepErrors = false;
|
||||
this._resumeAfterStepErrors = /* @__PURE__ */ new Map();
|
||||
this.configLocation = configLocation;
|
||||
this._configCLIOverrides = configCLIOverrides;
|
||||
this._watcher = new import_fsWatcher.Watcher((events) => {
|
||||
const collector = /* @__PURE__ */ new Set();
|
||||
events.forEach((f) => (0, import_compilationCache.collectAffectedTestFiles)(f.file, collector));
|
||||
this.emit(TestRunnerEvent.TestFilesChanged, [...collector]);
|
||||
});
|
||||
}
|
||||
async initialize(params) {
|
||||
this._watchTestDirs = !!params.watchTestDirs;
|
||||
this._populateDependenciesOnList = !!params.populateDependenciesOnList;
|
||||
this._recoverFromStepErrors = !!params.recoverFromStepErrors;
|
||||
}
|
||||
resizeTerminal(params) {
|
||||
process.stdout.columns = params.cols;
|
||||
process.stdout.rows = params.rows;
|
||||
process.stderr.columns = params.cols;
|
||||
process.stderr.rows = params.rows;
|
||||
}
|
||||
hasSomeBrowsers() {
|
||||
for (const browserName of ["chromium", "webkit", "firefox"]) {
|
||||
try {
|
||||
import_server.registry.findExecutable(browserName).executablePathOrDie("javascript");
|
||||
return true;
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
async installBrowsers() {
|
||||
const executables = import_server.registry.defaultExecutables();
|
||||
await import_server.registry.install(executables, false);
|
||||
}
|
||||
async runGlobalSetup(userReporters) {
|
||||
await this.runGlobalTeardown();
|
||||
const reporter = new import_internalReporter.InternalReporter(userReporters);
|
||||
const config = await this._loadConfigOrReportError(reporter, this._configCLIOverrides);
|
||||
if (!config)
|
||||
return { status: "failed" };
|
||||
const { status, cleanup } = await (0, import_tasks.runTasksDeferCleanup)(new import_tasks.TestRun(config, reporter), [
|
||||
...(0, import_tasks.createGlobalSetupTasks)(config)
|
||||
]);
|
||||
if (status !== "passed")
|
||||
await cleanup();
|
||||
else
|
||||
this._globalSetup = { cleanup };
|
||||
return { status };
|
||||
}
|
||||
async runGlobalTeardown() {
|
||||
const globalSetup = this._globalSetup;
|
||||
const status = await globalSetup?.cleanup();
|
||||
this._globalSetup = void 0;
|
||||
return { status };
|
||||
}
|
||||
async startDevServer(userReporter, mode) {
|
||||
await this.stopDevServer();
|
||||
const reporter = new import_internalReporter.InternalReporter([userReporter]);
|
||||
const config = await this._loadConfigOrReportError(reporter);
|
||||
if (!config)
|
||||
return { status: "failed" };
|
||||
const { status, cleanup } = await (0, import_tasks.runTasksDeferCleanup)(new import_tasks.TestRun(config, reporter), [
|
||||
...(0, import_tasks.createPluginSetupTasks)(config),
|
||||
(0, import_tasks.createLoadTask)(mode, { failOnLoadErrors: true, filterOnly: false }),
|
||||
(0, import_tasks.createStartDevServerTask)()
|
||||
]);
|
||||
if (status !== "passed")
|
||||
await cleanup();
|
||||
else
|
||||
this._devServer = { cleanup };
|
||||
return { status };
|
||||
}
|
||||
async stopDevServer() {
|
||||
const devServer = this._devServer;
|
||||
const status = await devServer?.cleanup();
|
||||
this._devServer = void 0;
|
||||
return { status };
|
||||
}
|
||||
async clearCache(userReporter) {
|
||||
const reporter = new import_internalReporter.InternalReporter(userReporter ? [userReporter] : []);
|
||||
const config = await this._loadConfigOrReportError(reporter);
|
||||
if (!config)
|
||||
return { status: "failed" };
|
||||
const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), [
|
||||
...(0, import_tasks.createPluginSetupTasks)(config),
|
||||
(0, import_tasks.createClearCacheTask)(config)
|
||||
]);
|
||||
return { status };
|
||||
}
|
||||
async listFiles(userReporter, projects) {
|
||||
const reporter = new import_internalReporter.InternalReporter([userReporter]);
|
||||
const config = await this._loadConfigOrReportError(reporter);
|
||||
if (!config)
|
||||
return { status: "failed" };
|
||||
config.cliProjectFilter = projects?.length ? projects : void 0;
|
||||
const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), [
|
||||
(0, import_tasks.createListFilesTask)(),
|
||||
(0, import_tasks.createReportBeginTask)()
|
||||
]);
|
||||
return { status };
|
||||
}
|
||||
async listTests(userReporter, params) {
|
||||
let result;
|
||||
this._queue = this._queue.then(async () => {
|
||||
const { config, status } = await this._innerListTests(userReporter, params);
|
||||
if (config)
|
||||
await this._updateWatchedDirs(config);
|
||||
result = { status };
|
||||
}).catch(printInternalError);
|
||||
await this._queue;
|
||||
return result;
|
||||
}
|
||||
async _innerListTests(userReporter, params) {
|
||||
const overrides = {
|
||||
...this._configCLIOverrides,
|
||||
repeatEach: 1,
|
||||
retries: 0
|
||||
};
|
||||
const reporter = new import_internalReporter.InternalReporter([userReporter]);
|
||||
const config = await this._loadConfigOrReportError(reporter, overrides);
|
||||
if (!config)
|
||||
return { status: "failed" };
|
||||
config.cliArgs = params.locations || [];
|
||||
config.cliGrep = params.grep;
|
||||
config.cliGrepInvert = params.grepInvert;
|
||||
config.cliProjectFilter = params.projects?.length ? params.projects : void 0;
|
||||
config.cliListOnly = true;
|
||||
const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), [
|
||||
(0, import_tasks.createLoadTask)("out-of-process", { failOnLoadErrors: false, filterOnly: false, populateDependencies: this._populateDependenciesOnList }),
|
||||
(0, import_tasks.createReportBeginTask)()
|
||||
]);
|
||||
return { config, status };
|
||||
}
|
||||
async _updateWatchedDirs(config) {
|
||||
this._watchedProjectDirs = /* @__PURE__ */ new Set();
|
||||
this._ignoredProjectOutputs = /* @__PURE__ */ 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(userReporter, params) {
|
||||
let result = { status: "passed" };
|
||||
this._queue = this._queue.then(async () => {
|
||||
result = await this._innerRunTests(userReporter, params).catch((e) => {
|
||||
printInternalError(e);
|
||||
return { status: "failed" };
|
||||
});
|
||||
});
|
||||
await this._queue;
|
||||
return result;
|
||||
}
|
||||
async _innerRunTests(userReporter, params) {
|
||||
await this.stopTests();
|
||||
const overrides = {
|
||||
...this._configCLIOverrides,
|
||||
repeatEach: 1,
|
||||
retries: 0,
|
||||
preserveOutputDir: true,
|
||||
reporter: params.reporters ? params.reporters.map((r) => [r]) : void 0,
|
||||
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 !== void 0 ? { headless: !params.headed } : {},
|
||||
_optionContextReuseMode: params.reuseContext ? "when-possible" : void 0,
|
||||
_optionConnectOptions: params.connectWsEndpoint ? { wsEndpoint: params.connectWsEndpoint } : void 0
|
||||
},
|
||||
...params.updateSnapshots ? { updateSnapshots: params.updateSnapshots } : {},
|
||||
...params.updateSourceMethod ? { updateSourceMethod: params.updateSourceMethod } : {},
|
||||
...params.workers ? { workers: params.workers } : {}
|
||||
};
|
||||
if (params.trace === "on")
|
||||
process.env.PW_LIVE_TRACE_STACKS = "1";
|
||||
else
|
||||
process.env.PW_LIVE_TRACE_STACKS = void 0;
|
||||
const config = await this._loadConfigOrReportError(new import_internalReporter.InternalReporter([userReporter]), overrides);
|
||||
if (!config)
|
||||
return { status: "failed" };
|
||||
config.cliListOnly = false;
|
||||
config.cliPassWithNoTests = true;
|
||||
config.cliArgs = params.locations || [];
|
||||
config.cliGrep = params.grep;
|
||||
config.cliGrepInvert = params.grepInvert;
|
||||
config.cliProjectFilter = params.projects?.length ? params.projects : void 0;
|
||||
config.preOnlyTestFilters = [];
|
||||
if (params.testIds) {
|
||||
const testIdSet = new Set(params.testIds);
|
||||
config.preOnlyTestFilters.push((test) => testIdSet.has(test.id));
|
||||
}
|
||||
const configReporters = await (0, import_reporters.createReporters)(config, "test", true);
|
||||
const reporter = new import_internalReporter.InternalReporter([...configReporters, userReporter]);
|
||||
const stop = new import_utils.ManualPromise();
|
||||
const tasks = [
|
||||
(0, import_tasks.createApplyRebaselinesTask)(),
|
||||
(0, import_tasks.createLoadTask)("out-of-process", { filterOnly: true, failOnLoadErrors: false, doNotRunDepsOutsideProjectFilter: true }),
|
||||
...(0, import_tasks.createRunTestsTasks)(config)
|
||||
];
|
||||
const testRun = new import_tasks.TestRun(config, reporter);
|
||||
testRun.failureTracker.setRecoverFromStepErrorHandler(this._recoverFromStepError.bind(this));
|
||||
const run = (0, import_tasks.runTasks)(testRun, tasks, 0, stop).then(async (status) => {
|
||||
this._testRun = void 0;
|
||||
return status;
|
||||
});
|
||||
this._testRun = { run, stop };
|
||||
return { status: await run };
|
||||
}
|
||||
async _recoverFromStepError(stepId, error) {
|
||||
if (!this._recoverFromStepErrors)
|
||||
return { stepId, status: "failed" };
|
||||
const recoveryPromise = new import_utils.ManualPromise();
|
||||
this._resumeAfterStepErrors.set(stepId, recoveryPromise);
|
||||
if (!error?.message || !error?.location)
|
||||
return { stepId, status: "failed" };
|
||||
this.emit(TestRunnerEvent.RecoverFromStepError, stepId, error.message, error.location);
|
||||
const recoveredResult = await recoveryPromise;
|
||||
if (recoveredResult.stepId !== stepId)
|
||||
return { stepId, status: "failed" };
|
||||
return recoveredResult;
|
||||
}
|
||||
async resumeAfterStepError(params) {
|
||||
const recoveryPromise = this._resumeAfterStepErrors.get(params.stepId);
|
||||
if (recoveryPromise)
|
||||
recoveryPromise.resolve(params);
|
||||
}
|
||||
async watch(fileNames) {
|
||||
this._watchedTestDependencies = /* @__PURE__ */ new Set();
|
||||
for (const fileName of fileNames) {
|
||||
this._watchedTestDependencies.add(fileName);
|
||||
(0, import_compilationCache.dependenciesForTestFile)(fileName).forEach((file) => this._watchedTestDependencies.add(file));
|
||||
}
|
||||
await this._updateWatcher(true);
|
||||
}
|
||||
async findRelatedTestFiles(files, userReporter) {
|
||||
const errorReporter = (0, import_reporters.createErrorCollectingReporter)(import_base.internalScreen);
|
||||
const reporter = new import_internalReporter.InternalReporter(userReporter ? [userReporter, errorReporter] : [errorReporter]);
|
||||
const config = await this._loadConfigOrReportError(reporter);
|
||||
if (!config)
|
||||
return { errors: errorReporter.errors(), testFiles: [] };
|
||||
const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), [
|
||||
...(0, import_tasks.createPluginSetupTasks)(config),
|
||||
(0, import_tasks.createLoadTask)("out-of-process", { failOnLoadErrors: true, filterOnly: false, populateDependencies: true })
|
||||
]);
|
||||
if (status !== "passed")
|
||||
return { errors: errorReporter.errors(), testFiles: [] };
|
||||
return { testFiles: (0, import_compilationCache.affectedTestFiles)(files) };
|
||||
}
|
||||
async stopTests() {
|
||||
this._testRun?.stop?.resolve();
|
||||
await this._testRun?.run;
|
||||
this._resumeAfterStepErrors.clear();
|
||||
}
|
||||
async closeGracefully() {
|
||||
(0, import_utils.gracefullyProcessExitDoNotHang)(0);
|
||||
}
|
||||
async _loadConfig(overrides) {
|
||||
try {
|
||||
const config = await (0, import_configLoader.loadConfig)(this.configLocation, overrides);
|
||||
if (!this._plugins) {
|
||||
(0, import_webServerPlugin.webServerPluginsForConfig)(config).forEach((p) => config.plugins.push({ factory: p }));
|
||||
(0, import_gitCommitInfoPlugin.addGitCommitInfoPlugin)(config);
|
||||
this._plugins = config.plugins || [];
|
||||
} else {
|
||||
config.plugins.splice(0, config.plugins.length, ...this._plugins);
|
||||
}
|
||||
return { config };
|
||||
} catch (e) {
|
||||
return { config: null, error: (0, import_util.serializeError)(e) };
|
||||
}
|
||||
}
|
||||
async _loadConfigOrReportError(reporter, overrides) {
|
||||
const { config, error } = await this._loadConfig(overrides);
|
||||
if (config)
|
||||
return config;
|
||||
reporter.onConfigure(import_teleReceiver.baseFullConfig);
|
||||
reporter.onError(error);
|
||||
await reporter.onEnd({ status: "failed" });
|
||||
await reporter.onExit();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function printInternalError(e) {
|
||||
console.error("Internal error:", e);
|
||||
}
|
||||
async function resolveCtDirs(config) {
|
||||
const use = config.config.projects[0].use;
|
||||
const relativeTemplateDir = use.ctTemplateDir || "playwright";
|
||||
const templateDir = await import_fs.default.promises.realpath(import_path.default.normalize(import_path.default.join(config.configDir, relativeTemplateDir))).catch(() => void 0);
|
||||
if (!templateDir)
|
||||
return null;
|
||||
const outDir = use.ctCacheDir ? import_path.default.resolve(config.configDir, use.ctCacheDir) : import_path.default.resolve(templateDir, ".cache");
|
||||
return {
|
||||
outDir,
|
||||
templateDir
|
||||
};
|
||||
}
|
||||
async function runAllTestsWithConfig(config) {
|
||||
const listOnly = config.cliListOnly;
|
||||
(0, import_gitCommitInfoPlugin.addGitCommitInfoPlugin)(config);
|
||||
(0, import_webServerPlugin.webServerPluginsForConfig)(config).forEach((p) => config.plugins.push({ factory: p }));
|
||||
const reporters = await (0, import_reporters.createReporters)(config, listOnly ? "list" : "test", false);
|
||||
const lastRun = new import_lastRun.LastRunReporter(config);
|
||||
if (config.cliLastFailed)
|
||||
await lastRun.filterLastFailed();
|
||||
const reporter = new import_internalReporter.InternalReporter([...reporters, lastRun]);
|
||||
const tasks = listOnly ? [
|
||||
(0, import_tasks.createLoadTask)("in-process", { failOnLoadErrors: true, filterOnly: false }),
|
||||
(0, import_tasks.createReportBeginTask)()
|
||||
] : [
|
||||
(0, import_tasks.createApplyRebaselinesTask)(),
|
||||
...(0, import_tasks.createGlobalSetupTasks)(config),
|
||||
(0, import_tasks.createLoadTask)("in-process", { filterOnly: true, failOnLoadErrors: true }),
|
||||
...(0, import_tasks.createRunTestsTasks)(config)
|
||||
];
|
||||
const status = await (0, import_tasks.runTasks)(new import_tasks.TestRun(config, reporter), tasks, config.config.globalTimeout);
|
||||
await new Promise((resolve) => process.stdout.write("", () => resolve()));
|
||||
await new Promise((resolve) => process.stderr.write("", () => resolve()));
|
||||
return status;
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
TestRunner,
|
||||
TestRunnerEvent,
|
||||
runAllTestsWithConfig
|
||||
});
|
270
node_modules/playwright/lib/runner/testServer.js
generated
vendored
Normal file
270
node_modules/playwright/lib/runner/testServer.js
generated
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var testServer_exports = {};
|
||||
__export(testServer_exports, {
|
||||
TestRunnerEvent: () => TestRunnerEvent,
|
||||
TestServerDispatcher: () => TestServerDispatcher,
|
||||
runTestServer: () => runTestServer,
|
||||
runUIMode: () => runUIMode
|
||||
});
|
||||
module.exports = __toCommonJS(testServer_exports);
|
||||
var import_util = __toESM(require("util"));
|
||||
var import_server = require("playwright-core/lib/server");
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utilsBundle = require("playwright-core/lib/utilsBundle");
|
||||
var import_configLoader = require("../common/configLoader");
|
||||
var import_list = __toESM(require("../reporters/list"));
|
||||
var import_reporters = require("./reporters");
|
||||
var import_sigIntWatcher = require("./sigIntWatcher");
|
||||
var import_testRunner = require("./testRunner");
|
||||
const originalDebugLog = import_utilsBundle.debug.log;
|
||||
const originalStdoutWrite = process.stdout.write;
|
||||
const originalStderrWrite = process.stderr.write;
|
||||
class TestServer {
|
||||
constructor(configLocation, configCLIOverrides) {
|
||||
this._configLocation = configLocation;
|
||||
this._configCLIOverrides = configCLIOverrides;
|
||||
}
|
||||
async start(options) {
|
||||
this._dispatcher = new TestServerDispatcher(this._configLocation, this._configCLIOverrides);
|
||||
return await (0, import_server.startTraceViewerServer)({ ...options, transport: this._dispatcher.transport });
|
||||
}
|
||||
async stop() {
|
||||
await this._dispatcher?._setInterceptStdio(false);
|
||||
await this._dispatcher?.runGlobalTeardown();
|
||||
}
|
||||
}
|
||||
const TestRunnerEvent = {
|
||||
TestFilesChanged: "testFilesChanged",
|
||||
RecoverFromStepError: "recoverFromStepError"
|
||||
};
|
||||
class TestServerDispatcher {
|
||||
constructor(configLocation, configCLIOverrides) {
|
||||
this._serializer = require.resolve("./uiModeReporter");
|
||||
this._closeOnDisconnect = false;
|
||||
this._testRunner = new import_testRunner.TestRunner(configLocation, configCLIOverrides);
|
||||
this.transport = {
|
||||
onconnect: () => {
|
||||
},
|
||||
dispatch: (method, params) => this[method](params),
|
||||
onclose: () => {
|
||||
if (this._closeOnDisconnect)
|
||||
(0, import_utils.gracefullyProcessExitDoNotHang)(0);
|
||||
}
|
||||
};
|
||||
this._dispatchEvent = (method, params) => this.transport.sendEvent?.(method, params);
|
||||
this._testRunner.on(TestRunnerEvent.TestFilesChanged, (testFiles) => this._dispatchEvent("testFilesChanged", { testFiles }));
|
||||
this._testRunner.on(TestRunnerEvent.RecoverFromStepError, (stepId, message, location) => this._dispatchEvent("recoverFromStepError", { stepId, message, location }));
|
||||
}
|
||||
async _wireReporter(messageSink) {
|
||||
return await (0, import_reporters.createReporterForTestServer)(this._serializer, messageSink);
|
||||
}
|
||||
async _collectingReporter() {
|
||||
const report = [];
|
||||
return {
|
||||
reporter: await (0, import_reporters.createReporterForTestServer)(this._serializer, (e) => report.push(e)),
|
||||
report
|
||||
};
|
||||
}
|
||||
async initialize(params) {
|
||||
this._serializer = params.serializer || require.resolve("./uiModeReporter");
|
||||
this._closeOnDisconnect = !!params.closeOnDisconnect;
|
||||
await this._setInterceptStdio(!!params.interceptStdio);
|
||||
await this._testRunner.initialize({
|
||||
watchTestDirs: !!params.watchTestDirs,
|
||||
populateDependenciesOnList: !!params.populateDependenciesOnList,
|
||||
recoverFromStepErrors: !!params.recoverFromStepErrors
|
||||
});
|
||||
}
|
||||
async ping() {
|
||||
}
|
||||
async open(params) {
|
||||
if ((0, import_utils.isUnderTest)())
|
||||
return;
|
||||
(0, import_utilsBundle.open)("vscode://file/" + params.location.file + ":" + params.location.line).catch((e) => console.error(e));
|
||||
}
|
||||
async resizeTerminal(params) {
|
||||
this._testRunner.resizeTerminal(params);
|
||||
}
|
||||
async checkBrowsers() {
|
||||
return { hasBrowsers: this._testRunner.hasSomeBrowsers() };
|
||||
}
|
||||
async installBrowsers() {
|
||||
await this._testRunner.installBrowsers();
|
||||
}
|
||||
async runGlobalSetup(params) {
|
||||
await this.runGlobalTeardown();
|
||||
const { reporter, report } = await this._collectingReporter();
|
||||
this._globalSetupReport = report;
|
||||
const { status } = await this._testRunner.runGlobalSetup([reporter, new import_list.default()]);
|
||||
return { report, status };
|
||||
}
|
||||
async runGlobalTeardown() {
|
||||
const { status } = await this._testRunner.runGlobalTeardown();
|
||||
const report = this._globalSetupReport || [];
|
||||
this._globalSetupReport = void 0;
|
||||
return { status, report };
|
||||
}
|
||||
async startDevServer(params) {
|
||||
await this.stopDevServer({});
|
||||
const { reporter, report } = await this._collectingReporter();
|
||||
const { status } = await this._testRunner.startDevServer(reporter, "out-of-process");
|
||||
return { report, status };
|
||||
}
|
||||
async stopDevServer(params) {
|
||||
const { status } = await this._testRunner.stopDevServer();
|
||||
const report = this._devServerReport || [];
|
||||
this._devServerReport = void 0;
|
||||
return { status, report };
|
||||
}
|
||||
async clearCache(params) {
|
||||
await this._testRunner.clearCache();
|
||||
}
|
||||
async listFiles(params) {
|
||||
const { reporter, report } = await this._collectingReporter();
|
||||
const { status } = await this._testRunner.listFiles(reporter, params.projects);
|
||||
return { report, status };
|
||||
}
|
||||
async listTests(params) {
|
||||
const { reporter, report } = await this._collectingReporter();
|
||||
const { status } = await this._testRunner.listTests(reporter, params);
|
||||
return { report, status };
|
||||
}
|
||||
async runTests(params) {
|
||||
const wireReporter = await this._wireReporter((e) => this._dispatchEvent("report", e));
|
||||
const { status } = await this._testRunner.runTests(wireReporter, params);
|
||||
return { status };
|
||||
}
|
||||
async resumeAfterStepError(params) {
|
||||
await this._testRunner.resumeAfterStepError(params);
|
||||
}
|
||||
async watch(params) {
|
||||
await this._testRunner.watch(params.fileNames);
|
||||
}
|
||||
async findRelatedTestFiles(params) {
|
||||
return this._testRunner.findRelatedTestFiles(params.files);
|
||||
}
|
||||
async stopTests() {
|
||||
await this._testRunner.stopTests();
|
||||
}
|
||||
async _setInterceptStdio(intercept) {
|
||||
if (process.env.PWTEST_DEBUG)
|
||||
return;
|
||||
if (intercept) {
|
||||
if (import_utilsBundle.debug.log === originalDebugLog) {
|
||||
import_utilsBundle.debug.log = (...args) => {
|
||||
const string = import_util.default.format(...args) + "\n";
|
||||
return originalStderrWrite.apply(process.stderr, [string]);
|
||||
};
|
||||
}
|
||||
const stdoutWrite = (chunk) => {
|
||||
this._dispatchEvent("stdio", chunkToPayload("stdout", chunk));
|
||||
return true;
|
||||
};
|
||||
const stderrWrite = (chunk) => {
|
||||
this._dispatchEvent("stdio", chunkToPayload("stderr", chunk));
|
||||
return true;
|
||||
};
|
||||
process.stdout.write = stdoutWrite;
|
||||
process.stderr.write = stderrWrite;
|
||||
} else {
|
||||
import_utilsBundle.debug.log = originalDebugLog;
|
||||
process.stdout.write = originalStdoutWrite;
|
||||
process.stderr.write = originalStderrWrite;
|
||||
}
|
||||
}
|
||||
async closeGracefully() {
|
||||
await this._testRunner.closeGracefully();
|
||||
}
|
||||
}
|
||||
async function runUIMode(configFile, configCLIOverrides, options) {
|
||||
const configLocation = (0, import_configLoader.resolveConfigLocation)(configFile);
|
||||
return await innerRunTestServer(configLocation, configCLIOverrides, options, async (server, cancelPromise) => {
|
||||
await (0, import_server.installRootRedirect)(server, [], { ...options, webApp: "uiMode.html" });
|
||||
if (options.host !== void 0 || options.port !== void 0) {
|
||||
await (0, import_server.openTraceInBrowser)(server.urlPrefix("human-readable"));
|
||||
} else {
|
||||
const channel = await installedChromiumChannelForUI(configLocation, configCLIOverrides);
|
||||
const page = await (0, import_server.openTraceViewerApp)(server.urlPrefix("precise"), "chromium", {
|
||||
headless: (0, import_utils.isUnderTest)() && process.env.PWTEST_HEADED_FOR_TEST !== "1",
|
||||
persistentContextOptions: {
|
||||
handleSIGINT: false,
|
||||
channel
|
||||
}
|
||||
});
|
||||
page.on("close", () => cancelPromise.resolve());
|
||||
}
|
||||
});
|
||||
}
|
||||
async function installedChromiumChannelForUI(configLocation, configCLIOverrides) {
|
||||
const config = await (0, import_configLoader.loadConfig)(configLocation, configCLIOverrides).catch((e) => null);
|
||||
if (!config)
|
||||
return void 0;
|
||||
if (config.projects.some((p) => (!p.project.use.browserName || p.project.use.browserName === "chromium") && !p.project.use.channel))
|
||||
return void 0;
|
||||
for (const channel of ["chromium", "chrome", "msedge"]) {
|
||||
if (config.projects.some((p) => p.project.use.channel === channel))
|
||||
return channel;
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
async function runTestServer(configFile, configCLIOverrides, options) {
|
||||
const configLocation = (0, import_configLoader.resolveConfigLocation)(configFile);
|
||||
return await innerRunTestServer(configLocation, configCLIOverrides, options, async (server) => {
|
||||
console.log("Listening on " + server.urlPrefix("precise").replace("http:", "ws:") + "/" + server.wsGuid());
|
||||
});
|
||||
}
|
||||
async function innerRunTestServer(configLocation, configCLIOverrides, options, openUI) {
|
||||
const testServer = new TestServer(configLocation, configCLIOverrides);
|
||||
const cancelPromise = new import_utils.ManualPromise();
|
||||
const sigintWatcher = new import_sigIntWatcher.SigIntWatcher();
|
||||
process.stdin.on("close", () => (0, import_utils.gracefullyProcessExitDoNotHang)(0));
|
||||
void sigintWatcher.promise().then(() => cancelPromise.resolve());
|
||||
try {
|
||||
const server = await testServer.start(options);
|
||||
await openUI(server, cancelPromise);
|
||||
await cancelPromise;
|
||||
} finally {
|
||||
await testServer.stop();
|
||||
sigintWatcher.disarm();
|
||||
}
|
||||
return sigintWatcher.hadSignal() ? "interrupted" : "passed";
|
||||
}
|
||||
function chunkToPayload(type, chunk) {
|
||||
if (chunk instanceof Uint8Array)
|
||||
return { type, buffer: chunk.toString("base64") };
|
||||
return { type, text: chunk };
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
TestRunnerEvent,
|
||||
TestServerDispatcher,
|
||||
runTestServer,
|
||||
runUIMode
|
||||
});
|
30
node_modules/playwright/lib/runner/uiModeReporter.js
generated
vendored
Normal file
30
node_modules/playwright/lib/runner/uiModeReporter.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var uiModeReporter_exports = {};
|
||||
__export(uiModeReporter_exports, {
|
||||
default: () => uiModeReporter_default
|
||||
});
|
||||
module.exports = __toCommonJS(uiModeReporter_exports);
|
||||
var import_teleEmitter = require("../reporters/teleEmitter");
|
||||
class UIModeReporter extends import_teleEmitter.TeleReporterEmitter {
|
||||
constructor(options) {
|
||||
super(options._send, { omitBuffers: true });
|
||||
}
|
||||
}
|
||||
var uiModeReporter_default = UIModeReporter;
|
72
node_modules/playwright/lib/runner/vcs.js
generated
vendored
Normal file
72
node_modules/playwright/lib/runner/vcs.js
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var vcs_exports = {};
|
||||
__export(vcs_exports, {
|
||||
detectChangedTestFiles: () => detectChangedTestFiles
|
||||
});
|
||||
module.exports = __toCommonJS(vcs_exports);
|
||||
var import_child_process = __toESM(require("child_process"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_compilationCache = require("../transform/compilationCache");
|
||||
async function detectChangedTestFiles(baseCommit, configDir) {
|
||||
function gitFileList(command) {
|
||||
try {
|
||||
return import_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?.includes("unknown revision"));
|
||||
if (unknownRevision) {
|
||||
const isShallowClone = import_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) => import_path.default.join(configDir, file));
|
||||
const [gitRoot] = gitFileList("rev-parse --show-toplevel");
|
||||
const trackedFilesWithChanges = gitFileList(`diff ${baseCommit} --name-only`).map((file) => import_path.default.join(gitRoot, file));
|
||||
return new Set((0, import_compilationCache.affectedTestFiles)([...untrackedFiles, ...trackedFilesWithChanges]));
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
detectChangedTestFiles
|
||||
});
|
447
node_modules/playwright/lib/runner/watchMode.js
generated
vendored
Normal file
447
node_modules/playwright/lib/runner/watchMode.js
generated
vendored
Normal file
@@ -0,0 +1,447 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var watchMode_exports = {};
|
||||
__export(watchMode_exports, {
|
||||
runWatchModeLoop: () => runWatchModeLoop
|
||||
});
|
||||
module.exports = __toCommonJS(watchMode_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_readline = __toESM(require("readline"));
|
||||
var import_stream = require("stream");
|
||||
var import_playwrightServer = require("playwright-core/lib/remote/playwrightServer");
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_utils2 = require("playwright-core/lib/utils");
|
||||
var import_base = require("../reporters/base");
|
||||
var import_utilsBundle = require("../utilsBundle");
|
||||
var import_testServer = require("./testServer");
|
||||
var import_teleSuiteUpdater = require("../isomorphic/teleSuiteUpdater");
|
||||
var import_testServerConnection = require("../isomorphic/testServerConnection");
|
||||
var import_util = require("../util");
|
||||
var import_babelBundle = require("../transform/babelBundle");
|
||||
class InMemoryTransport extends import_stream.EventEmitter {
|
||||
constructor(send) {
|
||||
super();
|
||||
this._send = send;
|
||||
}
|
||||
close() {
|
||||
this.emit("close");
|
||||
}
|
||||
onclose(listener) {
|
||||
this.on("close", listener);
|
||||
}
|
||||
onerror(listener) {
|
||||
}
|
||||
onmessage(listener) {
|
||||
this.on("message", listener);
|
||||
}
|
||||
onopen(listener) {
|
||||
this.on("open", listener);
|
||||
}
|
||||
send(data) {
|
||||
this._send(data);
|
||||
}
|
||||
}
|
||||
async function runWatchModeLoop(configLocation, initialOptions) {
|
||||
const options = { ...initialOptions };
|
||||
let bufferMode = false;
|
||||
const testServerDispatcher = new import_testServer.TestServerDispatcher(configLocation, {});
|
||||
const transport = new InMemoryTransport(
|
||||
async (data) => {
|
||||
const { id, method, params } = JSON.parse(data);
|
||||
try {
|
||||
const result2 = await testServerDispatcher.transport.dispatch(method, params);
|
||||
transport.emit("message", JSON.stringify({ id, result: result2 }));
|
||||
} 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 import_testServerConnection.TestServerConnection(transport);
|
||||
transport.emit("open");
|
||||
const teleSuiteUpdater = new import_teleSuiteUpdater.TeleSuiteUpdater({ pathSeparator: import_path.default.sep, onUpdate() {
|
||||
} });
|
||||
const dirtyTestFiles = /* @__PURE__ */ new Set();
|
||||
const dirtyTestIds = /* @__PURE__ */ new Set();
|
||||
let onDirtyTests = new import_utils.ManualPromise();
|
||||
let queue = Promise.resolve();
|
||||
const changedFiles = /* @__PURE__ */ new Set();
|
||||
testServerConnection.onTestFilesChanged(({ testFiles }) => {
|
||||
testFiles.forEach((file) => changedFiles.add(file));
|
||||
queue = queue.then(async () => {
|
||||
if (changedFiles.size === 0)
|
||||
return;
|
||||
const { report: report2 } = await testServerConnection.listTests({ locations: options.files, projects: options.projects, grep: options.grep });
|
||||
teleSuiteUpdater.processListReport(report2);
|
||||
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 import_utils.ManualPromise();
|
||||
}
|
||||
});
|
||||
});
|
||||
testServerConnection.onReport((report2) => teleSuiteUpdater.processTestReportEvent(report2));
|
||||
testServerConnection.onRecoverFromStepError(({ stepId, message, location }) => {
|
||||
process.stdout.write(`
|
||||
Test error occurred.
|
||||
`);
|
||||
process.stdout.write("\n" + createErrorCodeframe(message, location) + "\n");
|
||||
process.stdout.write(`
|
||||
${import_utils2.colors.dim("Try recovering from the error. Press")} ${import_utils2.colors.bold("c")} ${import_utils2.colors.dim("to continue or")} ${import_utils2.colors.bold("t")} ${import_utils2.colors.dim("to throw the error")}
|
||||
`);
|
||||
readKeyPress((text) => {
|
||||
if (text === "c") {
|
||||
process.stdout.write(`
|
||||
${import_utils2.colors.dim("Continuing after recovery...")}
|
||||
`);
|
||||
testServerConnection.resumeAfterStepError({ stepId, status: "recovered", value: void 0 }).catch(() => {
|
||||
});
|
||||
} else if (text === "t") {
|
||||
process.stdout.write(`
|
||||
${import_utils2.colors.dim("Throwing error...")}
|
||||
`);
|
||||
testServerConnection.resumeAfterStepError({ stepId, status: "failed" }).catch(() => {
|
||||
});
|
||||
}
|
||||
return text;
|
||||
});
|
||||
});
|
||||
await testServerConnection.initialize({
|
||||
interceptStdio: false,
|
||||
watchTestDirs: true,
|
||||
populateDependenciesOnList: true,
|
||||
recoverFromStepErrors: !process.env.PWTEST_RECOVERY_DISABLED
|
||||
});
|
||||
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.dispose();
|
||||
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") {
|
||||
await runTests(options, testServerConnection);
|
||||
lastRun = { type: "regular" };
|
||||
continue;
|
||||
}
|
||||
if (command === "project") {
|
||||
const { selectedProjects } = await import_utilsBundle.enquirer.prompt({
|
||||
type: "multiselect",
|
||||
name: "selectedProjects",
|
||||
message: "Select projects",
|
||||
choices: projectNames
|
||||
}).catch(() => ({ selectedProjects: null }));
|
||||
if (!selectedProjects)
|
||||
continue;
|
||||
options.projects = selectedProjects.length ? selectedProjects : void 0;
|
||||
await runTests(options, testServerConnection);
|
||||
lastRun = { type: "regular" };
|
||||
continue;
|
||||
}
|
||||
if (command === "file") {
|
||||
const { filePattern } = await import_utilsBundle.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 = void 0;
|
||||
await runTests(options, testServerConnection);
|
||||
lastRun = { type: "regular" };
|
||||
continue;
|
||||
}
|
||||
if (command === "grep") {
|
||||
const { testPattern } = await import_utilsBundle.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 = void 0;
|
||||
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 import_utils.ManualPromise();
|
||||
const rl = import_readline.default.createInterface({ input: process.stdin, escapeCodeTimeout: 50 });
|
||||
import_readline.default.emitKeypressEvents(process.stdin, rl);
|
||||
if (process.stdin.isTTY)
|
||||
process.stdin.setRawMode(true);
|
||||
const listener = import_utils.eventsHelper.addEventListener(process.stdin, "keypress", (text, key) => {
|
||||
const result = handler(text, key);
|
||||
if (result)
|
||||
promise.resolve(result);
|
||||
});
|
||||
const dispose = () => {
|
||||
import_utils.eventsHelper.removeEventListeners([listener]);
|
||||
rl.close();
|
||||
if (process.stdin.isTTY)
|
||||
process.stdin.setRawMode(false);
|
||||
};
|
||||
void promise.finally(dispose);
|
||||
return { result: promise, dispose };
|
||||
}
|
||||
const isInterrupt = (text, key) => text === "" || text === "\x1B" || key && key.name === "escape" || key && key.ctrl && key.name === "c";
|
||||
async function runTests(watchOptions, testServerConnection, options) {
|
||||
printConfiguration(watchOptions, options?.title);
|
||||
const waitForDone = readKeyPress((text, key) => {
|
||||
if (isInterrupt(text, key)) {
|
||||
testServerConnection.stopTestsNoReply({});
|
||||
return "done";
|
||||
}
|
||||
});
|
||||
await testServerConnection.runTests({
|
||||
grep: watchOptions.grep,
|
||||
testIds: options?.testIds,
|
||||
locations: watchOptions?.files,
|
||||
projects: watchOptions.projects,
|
||||
connectWsEndpoint,
|
||||
reuseContext: connectWsEndpoint ? true : void 0,
|
||||
workers: connectWsEndpoint ? 1 : void 0,
|
||||
headed: connectWsEndpoint ? true : void 0
|
||||
}).finally(() => waitForDone.dispose());
|
||||
}
|
||||
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?.name;
|
||||
if (name === "q")
|
||||
return "exit";
|
||||
if (name === "h") {
|
||||
process.stdout.write(`${(0, import_base.separator)(import_base.terminalScreen)}
|
||||
Run tests
|
||||
${import_utils2.colors.bold("enter")} ${import_utils2.colors.dim("run tests")}
|
||||
${import_utils2.colors.bold("f")} ${import_utils2.colors.dim("run failed tests")}
|
||||
${import_utils2.colors.bold("r")} ${import_utils2.colors.dim("repeat last run")}
|
||||
${import_utils2.colors.bold("q")} ${import_utils2.colors.dim("quit")}
|
||||
|
||||
Change settings
|
||||
${import_utils2.colors.bold("c")} ${import_utils2.colors.dim("set project")}
|
||||
${import_utils2.colors.bold("p")} ${import_utils2.colors.dim("set file filter")}
|
||||
${import_utils2.colors.bold("t")} ${import_utils2.colors.dim("set title filter")}
|
||||
${import_utils2.colors.bold("s")} ${import_utils2.colors.dim("toggle show & reuse the browser")}
|
||||
${import_utils2.colors.bold("b")} ${import_utils2.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 = void 0;
|
||||
let seq = 1;
|
||||
function printConfiguration(options, title) {
|
||||
const packageManagerCommand = (0, import_utils.getPackageManagerExecCommand)();
|
||||
const tokens = [];
|
||||
tokens.push(`${packageManagerCommand} playwright test`);
|
||||
if (options.projects)
|
||||
tokens.push(...options.projects.map((p) => import_utils2.colors.blue(`--project ${p}`)));
|
||||
if (options.grep)
|
||||
tokens.push(import_utils2.colors.red(`--grep ${options.grep}`));
|
||||
if (options.files)
|
||||
tokens.push(...options.files.map((a) => import_utils2.colors.bold(a)));
|
||||
if (title)
|
||||
tokens.push(import_utils2.colors.dim(`(${title})`));
|
||||
tokens.push(import_utils2.colors.dim(`#${seq++}`));
|
||||
const lines = [];
|
||||
const sep = (0, import_base.separator)(import_base.terminalScreen);
|
||||
lines.push("\x1Bc" + sep);
|
||||
lines.push(`${tokens.join(" ")}`);
|
||||
lines.push(`${import_utils2.colors.dim("Show & reuse browser:")} ${import_utils2.colors.bold(showBrowserServer ? "on" : "off")}`);
|
||||
process.stdout.write(lines.join("\n"));
|
||||
}
|
||||
function printBufferPrompt(dirtyTestFiles, rootDir) {
|
||||
const sep = (0, import_base.separator)(import_base.terminalScreen);
|
||||
process.stdout.write("\x1Bc");
|
||||
process.stdout.write(`${sep}
|
||||
`);
|
||||
if (dirtyTestFiles.size === 0) {
|
||||
process.stdout.write(`${import_utils2.colors.dim("Waiting for file changes. Press")} ${import_utils2.colors.bold("q")} ${import_utils2.colors.dim("to quit or")} ${import_utils2.colors.bold("h")} ${import_utils2.colors.dim("for more options.")}
|
||||
|
||||
`);
|
||||
return;
|
||||
}
|
||||
process.stdout.write(`${import_utils2.colors.dim(`${dirtyTestFiles.size} test ${dirtyTestFiles.size === 1 ? "file" : "files"} changed:`)}
|
||||
|
||||
`);
|
||||
for (const file of dirtyTestFiles)
|
||||
process.stdout.write(` \xB7 ${import_path.default.relative(rootDir, file)}
|
||||
`);
|
||||
process.stdout.write(`
|
||||
${import_utils2.colors.dim(`Press`)} ${import_utils2.colors.bold("enter")} ${import_utils2.colors.dim("to run")}, ${import_utils2.colors.bold("q")} ${import_utils2.colors.dim("to quit or")} ${import_utils2.colors.bold("h")} ${import_utils2.colors.dim("for more options.")}
|
||||
|
||||
`);
|
||||
}
|
||||
function printPrompt() {
|
||||
const sep = (0, import_base.separator)(import_base.terminalScreen);
|
||||
process.stdout.write(`
|
||||
${sep}
|
||||
${import_utils2.colors.dim("Waiting for file changes. Press")} ${import_utils2.colors.bold("enter")} ${import_utils2.colors.dim("to run tests")}, ${import_utils2.colors.bold("q")} ${import_utils2.colors.dim("to quit or")} ${import_utils2.colors.bold("h")} ${import_utils2.colors.dim("for more options.")}
|
||||
`);
|
||||
}
|
||||
async function toggleShowBrowser() {
|
||||
if (!showBrowserServer) {
|
||||
showBrowserServer = new import_playwrightServer.PlaywrightServer({ mode: "extension", path: "/" + (0, import_utils.createGuid)(), maxConnections: 1 });
|
||||
connectWsEndpoint = await showBrowserServer.listen();
|
||||
process.stdout.write(`${import_utils2.colors.dim("Show & reuse browser:")} ${import_utils2.colors.bold("on")}
|
||||
`);
|
||||
} else {
|
||||
await showBrowserServer?.close();
|
||||
showBrowserServer = void 0;
|
||||
connectWsEndpoint = void 0;
|
||||
process.stdout.write(`${import_utils2.colors.dim("Show & reuse browser:")} ${import_utils2.colors.bold("off")}
|
||||
`);
|
||||
}
|
||||
}
|
||||
function createErrorCodeframe(message, location) {
|
||||
let source;
|
||||
try {
|
||||
source = import_fs.default.readFileSync(location.file, "utf-8") + "\n//";
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
return (0, import_babelBundle.codeFrameColumns)(
|
||||
source,
|
||||
{
|
||||
start: {
|
||||
line: location.line,
|
||||
column: location.column
|
||||
}
|
||||
},
|
||||
{
|
||||
highlightCode: true,
|
||||
linesAbove: 5,
|
||||
linesBelow: 5,
|
||||
message: (0, import_util.stripAnsiEscapes)(message).split("\n")[0] || void 0
|
||||
}
|
||||
);
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
runWatchModeLoop
|
||||
});
|
97
node_modules/playwright/lib/runner/workerHost.js
generated
vendored
Normal file
97
node_modules/playwright/lib/runner/workerHost.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
var workerHost_exports = {};
|
||||
__export(workerHost_exports, {
|
||||
WorkerHost: () => WorkerHost
|
||||
});
|
||||
module.exports = __toCommonJS(workerHost_exports);
|
||||
var import_fs = __toESM(require("fs"));
|
||||
var import_path = __toESM(require("path"));
|
||||
var import_utils = require("playwright-core/lib/utils");
|
||||
var import_processHost = require("./processHost");
|
||||
var import_ipc = require("../common/ipc");
|
||||
var import_folders = require("../isomorphic/folders");
|
||||
let lastWorkerIndex = 0;
|
||||
class WorkerHost extends import_processHost.ProcessHost {
|
||||
constructor(testGroup, parallelIndex, config, recoverFromStepErrors, extraEnv, outputDir) {
|
||||
const workerIndex = lastWorkerIndex++;
|
||||
super(require.resolve("../worker/workerMain.js"), `worker-${workerIndex}`, {
|
||||
...extraEnv,
|
||||
FORCE_COLOR: "1",
|
||||
DEBUG_COLORS: process.env.DEBUG_COLORS === void 0 ? "1" : process.env.DEBUG_COLORS
|
||||
});
|
||||
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: import_path.default.join(outputDir, (0, import_folders.artifactsFolderName)(workerIndex)),
|
||||
recoverFromStepErrors
|
||||
};
|
||||
}
|
||||
async start() {
|
||||
await import_fs.default.promises.mkdir(this._params.artifactsDir, { recursive: true });
|
||||
return await this.startRunner(this._params, {
|
||||
onStdOut: (chunk) => this.emit("stdOut", (0, import_ipc.stdioChunkToParams)(chunk)),
|
||||
onStdErr: (chunk) => this.emit("stdErr", (0, import_ipc.stdioChunkToParams)(chunk))
|
||||
});
|
||||
}
|
||||
async onExit() {
|
||||
await (0, import_utils.removeFolders)([this._params.artifactsDir]);
|
||||
}
|
||||
async stop(didFail) {
|
||||
if (didFail)
|
||||
this._didFail = true;
|
||||
await super.stop();
|
||||
}
|
||||
runTestGroup(runPayload) {
|
||||
this.sendMessageNoReply({ method: "runTestGroup", params: runPayload });
|
||||
}
|
||||
resumeAfterStepError(result) {
|
||||
this.sendMessageNoReply({ method: "resumeAfterStepError", params: result });
|
||||
}
|
||||
hash() {
|
||||
return this._hash;
|
||||
}
|
||||
projectId() {
|
||||
return this._params.projectId;
|
||||
}
|
||||
didFail() {
|
||||
return this._didFail;
|
||||
}
|
||||
}
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
WorkerHost
|
||||
});
|
Reference in New Issue
Block a user