302 lines
14 KiB
Plaintext
302 lines
14 KiB
Plaintext
"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 testType_exports = {};
|
|
__export(testType_exports, {
|
|
TestTypeImpl: () => TestTypeImpl,
|
|
mergeTests: () => mergeTests,
|
|
rootTestType: () => rootTestType
|
|
});
|
|
module.exports = __toCommonJS(testType_exports);
|
|
var import_playwright_core = require("playwright-core");
|
|
var import_utils = require("playwright-core/lib/utils");
|
|
var import_globals = require("./globals");
|
|
var import_test = require("./test");
|
|
var import_expect = require("../matchers/expect");
|
|
var import_transform = require("../transform/transform");
|
|
var import_validators = require("./validators");
|
|
const testTypeSymbol = Symbol("testType");
|
|
class TestTypeImpl {
|
|
constructor(fixtures) {
|
|
this.fixtures = fixtures;
|
|
const test = (0, import_transform.wrapFunctionWithLocation)(this._createTest.bind(this, "default"));
|
|
test[testTypeSymbol] = this;
|
|
test.expect = import_expect.expect;
|
|
test.only = (0, import_transform.wrapFunctionWithLocation)(this._createTest.bind(this, "only"));
|
|
test.describe = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "default"));
|
|
test.describe.only = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "only"));
|
|
test.describe.configure = (0, import_transform.wrapFunctionWithLocation)(this._configure.bind(this));
|
|
test.describe.fixme = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "fixme"));
|
|
test.describe.parallel = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "parallel"));
|
|
test.describe.parallel.only = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "parallel.only"));
|
|
test.describe.serial = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "serial"));
|
|
test.describe.serial.only = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "serial.only"));
|
|
test.describe.skip = (0, import_transform.wrapFunctionWithLocation)(this._describe.bind(this, "skip"));
|
|
test.beforeEach = (0, import_transform.wrapFunctionWithLocation)(this._hook.bind(this, "beforeEach"));
|
|
test.afterEach = (0, import_transform.wrapFunctionWithLocation)(this._hook.bind(this, "afterEach"));
|
|
test.beforeAll = (0, import_transform.wrapFunctionWithLocation)(this._hook.bind(this, "beforeAll"));
|
|
test.afterAll = (0, import_transform.wrapFunctionWithLocation)(this._hook.bind(this, "afterAll"));
|
|
test.skip = (0, import_transform.wrapFunctionWithLocation)(this._modifier.bind(this, "skip"));
|
|
test.fixme = (0, import_transform.wrapFunctionWithLocation)(this._modifier.bind(this, "fixme"));
|
|
test.fail = (0, import_transform.wrapFunctionWithLocation)(this._modifier.bind(this, "fail"));
|
|
test.fail.only = (0, import_transform.wrapFunctionWithLocation)(this._createTest.bind(this, "fail.only"));
|
|
test.slow = (0, import_transform.wrapFunctionWithLocation)(this._modifier.bind(this, "slow"));
|
|
test.setTimeout = (0, import_transform.wrapFunctionWithLocation)(this._setTimeout.bind(this));
|
|
test.step = this._step.bind(this, "pass");
|
|
test.step.skip = this._step.bind(this, "skip");
|
|
test.use = (0, import_transform.wrapFunctionWithLocation)(this._use.bind(this));
|
|
test.extend = (0, import_transform.wrapFunctionWithLocation)(this._extend.bind(this));
|
|
test.info = () => {
|
|
const result = (0, import_globals.currentTestInfo)();
|
|
if (!result)
|
|
throw new Error("test.info() can only be called while test is running");
|
|
return result;
|
|
};
|
|
this.test = test;
|
|
}
|
|
_currentSuite(location, title) {
|
|
const suite = (0, import_globals.currentlyLoadingFileSuite)();
|
|
if (!suite) {
|
|
throw new Error([
|
|
`Playwright Test did not expect ${title} to be called here.`,
|
|
`Most common reasons include:`,
|
|
`- You are calling ${title} in a configuration file.`,
|
|
`- You are calling ${title} in a file that is imported by the configuration file.`,
|
|
`- You have two different versions of @playwright/test. This usually happens`,
|
|
` when one of the dependencies in your package.json depends on @playwright/test.`
|
|
].join("\n"));
|
|
}
|
|
return suite;
|
|
}
|
|
_createTest(type, location, title, fnOrDetails, fn) {
|
|
throwIfRunningInsideJest();
|
|
const suite = this._currentSuite(location, "test()");
|
|
if (!suite)
|
|
return;
|
|
let details;
|
|
let body;
|
|
if (typeof fnOrDetails === "function") {
|
|
body = fnOrDetails;
|
|
details = {};
|
|
} else {
|
|
body = fn;
|
|
details = fnOrDetails;
|
|
}
|
|
const validatedDetails = (0, import_validators.validateTestDetails)(details, location);
|
|
const test = new import_test.TestCase(title, body, this, location);
|
|
test._requireFile = suite._requireFile;
|
|
test.annotations.push(...validatedDetails.annotations);
|
|
test._tags.push(...validatedDetails.tags);
|
|
suite._addTest(test);
|
|
if (type === "only" || type === "fail.only")
|
|
test._only = true;
|
|
if (type === "skip" || type === "fixme" || type === "fail")
|
|
test.annotations.push({ type, location });
|
|
else if (type === "fail.only")
|
|
test.annotations.push({ type: "fail", location });
|
|
}
|
|
_describe(type, location, titleOrFn, fnOrDetails, fn) {
|
|
throwIfRunningInsideJest();
|
|
const suite = this._currentSuite(location, "test.describe()");
|
|
if (!suite)
|
|
return;
|
|
let title;
|
|
let body;
|
|
let details;
|
|
if (typeof titleOrFn === "function") {
|
|
title = "";
|
|
details = {};
|
|
body = titleOrFn;
|
|
} else if (typeof fnOrDetails === "function") {
|
|
title = titleOrFn;
|
|
details = {};
|
|
body = fnOrDetails;
|
|
} else {
|
|
title = titleOrFn;
|
|
details = fnOrDetails;
|
|
body = fn;
|
|
}
|
|
const validatedDetails = (0, import_validators.validateTestDetails)(details, location);
|
|
const child = new import_test.Suite(title, "describe");
|
|
child._requireFile = suite._requireFile;
|
|
child.location = location;
|
|
child._staticAnnotations.push(...validatedDetails.annotations);
|
|
child._tags.push(...validatedDetails.tags);
|
|
suite._addSuite(child);
|
|
if (type === "only" || type === "serial.only" || type === "parallel.only")
|
|
child._only = true;
|
|
if (type === "serial" || type === "serial.only")
|
|
child._parallelMode = "serial";
|
|
if (type === "parallel" || type === "parallel.only")
|
|
child._parallelMode = "parallel";
|
|
if (type === "skip" || type === "fixme")
|
|
child._staticAnnotations.push({ type, location });
|
|
for (let parent = suite; parent; parent = parent.parent) {
|
|
if (parent._parallelMode === "serial" && child._parallelMode === "parallel")
|
|
throw new Error("describe.parallel cannot be nested inside describe.serial");
|
|
if (parent._parallelMode === "default" && child._parallelMode === "parallel")
|
|
throw new Error("describe.parallel cannot be nested inside describe with default mode");
|
|
}
|
|
(0, import_globals.setCurrentlyLoadingFileSuite)(child);
|
|
body();
|
|
(0, import_globals.setCurrentlyLoadingFileSuite)(suite);
|
|
}
|
|
_hook(name, location, title, fn) {
|
|
const suite = this._currentSuite(location, `test.${name}()`);
|
|
if (!suite)
|
|
return;
|
|
if (typeof title === "function") {
|
|
fn = title;
|
|
title = `${name} hook`;
|
|
}
|
|
suite._hooks.push({ type: name, fn, title, location });
|
|
}
|
|
_configure(location, options) {
|
|
throwIfRunningInsideJest();
|
|
const suite = this._currentSuite(location, `test.describe.configure()`);
|
|
if (!suite)
|
|
return;
|
|
if (options.timeout !== void 0)
|
|
suite._timeout = options.timeout;
|
|
if (options.retries !== void 0)
|
|
suite._retries = options.retries;
|
|
if (options.mode !== void 0) {
|
|
if (suite._parallelMode !== "none")
|
|
throw new Error(`"${suite._parallelMode}" mode is already assigned for the enclosing scope.`);
|
|
suite._parallelMode = options.mode;
|
|
for (let parent = suite.parent; parent; parent = parent.parent) {
|
|
if (parent._parallelMode === "serial" && suite._parallelMode === "parallel")
|
|
throw new Error("describe with parallel mode cannot be nested inside describe with serial mode");
|
|
if (parent._parallelMode === "default" && suite._parallelMode === "parallel")
|
|
throw new Error("describe with parallel mode cannot be nested inside describe with default mode");
|
|
}
|
|
}
|
|
}
|
|
_modifier(type, location, ...modifierArgs) {
|
|
const suite = (0, import_globals.currentlyLoadingFileSuite)();
|
|
if (suite) {
|
|
if (typeof modifierArgs[0] === "string" && typeof modifierArgs[1] === "function" && (type === "skip" || type === "fixme" || type === "fail")) {
|
|
this._createTest(type, location, modifierArgs[0], modifierArgs[1]);
|
|
return;
|
|
}
|
|
if (typeof modifierArgs[0] === "string" && typeof modifierArgs[1] === "object" && typeof modifierArgs[2] === "function" && (type === "skip" || type === "fixme" || type === "fail")) {
|
|
this._createTest(type, location, modifierArgs[0], modifierArgs[1], modifierArgs[2]);
|
|
return;
|
|
}
|
|
if (typeof modifierArgs[0] === "function") {
|
|
suite._modifiers.push({ type, fn: modifierArgs[0], location, description: modifierArgs[1] });
|
|
} else {
|
|
if (modifierArgs.length >= 1 && !modifierArgs[0])
|
|
return;
|
|
const description = modifierArgs[1];
|
|
suite._staticAnnotations.push({ type, description, location });
|
|
}
|
|
return;
|
|
}
|
|
const testInfo = (0, import_globals.currentTestInfo)();
|
|
if (!testInfo)
|
|
throw new Error(`test.${type}() can only be called inside test, describe block or fixture`);
|
|
if (typeof modifierArgs[0] === "function")
|
|
throw new Error(`test.${type}() with a function can only be called inside describe block`);
|
|
testInfo._modifier(type, location, modifierArgs);
|
|
}
|
|
_setTimeout(location, timeout) {
|
|
const suite = (0, import_globals.currentlyLoadingFileSuite)();
|
|
if (suite) {
|
|
suite._timeout = timeout;
|
|
return;
|
|
}
|
|
const testInfo = (0, import_globals.currentTestInfo)();
|
|
if (!testInfo)
|
|
throw new Error(`test.setTimeout() can only be called from a test`);
|
|
testInfo.setTimeout(timeout);
|
|
}
|
|
_use(location, fixtures) {
|
|
const suite = this._currentSuite(location, `test.use()`);
|
|
if (!suite)
|
|
return;
|
|
suite._use.push({ fixtures, location });
|
|
}
|
|
async _step(expectation, title, body, options = {}) {
|
|
const testInfo = (0, import_globals.currentTestInfo)();
|
|
if (!testInfo)
|
|
throw new Error(`test.step() can only be called from a test`);
|
|
await testInfo._onUserStepBegin?.(title);
|
|
const step = testInfo._addStep({ category: "test.step", title, location: options.location, box: options.box });
|
|
return await (0, import_utils.currentZone)().with("stepZone", step).run(async () => {
|
|
try {
|
|
let result = void 0;
|
|
result = await (0, import_utils.raceAgainstDeadline)(async () => {
|
|
try {
|
|
return await step.info._runStepBody(expectation === "skip", body, step.location);
|
|
} catch (e) {
|
|
if (result?.timedOut)
|
|
testInfo._failWithError(e);
|
|
throw e;
|
|
}
|
|
}, options.timeout ? (0, import_utils.monotonicTime)() + options.timeout : 0);
|
|
if (result.timedOut)
|
|
throw new import_playwright_core.errors.TimeoutError(`Step timeout of ${options.timeout}ms exceeded.`);
|
|
step.complete({});
|
|
return result.result;
|
|
} catch (error) {
|
|
step.complete({ error });
|
|
throw error;
|
|
} finally {
|
|
await testInfo._onUserStepEnd?.();
|
|
}
|
|
});
|
|
}
|
|
_extend(location, fixtures) {
|
|
if (fixtures[testTypeSymbol])
|
|
throw new Error(`test.extend() accepts fixtures object, not a test object.
|
|
Did you mean to call mergeTests()?`);
|
|
const fixturesWithLocation = { fixtures, location };
|
|
return new TestTypeImpl([...this.fixtures, fixturesWithLocation]).test;
|
|
}
|
|
}
|
|
function throwIfRunningInsideJest() {
|
|
if (process.env.JEST_WORKER_ID) {
|
|
const packageManagerCommand = (0, import_utils.getPackageManagerExecCommand)();
|
|
throw new Error(
|
|
`Playwright Test needs to be invoked via '${packageManagerCommand} playwright test' and excluded from Jest test runs.
|
|
Creating one directory for Playwright tests and one for Jest is the recommended way of doing it.
|
|
See https://playwright.dev/docs/intro for more information about Playwright Test.`
|
|
);
|
|
}
|
|
}
|
|
const rootTestType = new TestTypeImpl([]);
|
|
function mergeTests(...tests) {
|
|
let result = rootTestType;
|
|
for (const t of tests) {
|
|
const testTypeImpl = t[testTypeSymbol];
|
|
if (!testTypeImpl)
|
|
throw new Error(`mergeTests() accepts "test" functions as parameters.
|
|
Did you mean to call test.extend() with fixtures instead?`);
|
|
const newFixtures = testTypeImpl.fixtures.filter((theirs) => !result.fixtures.find((ours) => ours.fixtures === theirs.fixtures));
|
|
result = new TestTypeImpl([...result.fixtures, ...newFixtures]);
|
|
}
|
|
return result.test;
|
|
}
|
|
// Annotate the CommonJS export names for ESM import in node:
|
|
0 && (module.exports = {
|
|
TestTypeImpl,
|
|
mergeTests,
|
|
rootTestType
|
|
});
|