ScuttleBot

scuttlebot / tests / e2e / node_modules / playwright / lib / worker / testInfo.js
Source Blame History 536 lines
f7eb47b… lmata 1 "use strict";
f7eb47b… lmata 2 var __create = Object.create;
f7eb47b… lmata 3 var __defProp = Object.defineProperty;
f7eb47b… lmata 4 var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
f7eb47b… lmata 5 var __getOwnPropNames = Object.getOwnPropertyNames;
f7eb47b… lmata 6 var __getProtoOf = Object.getPrototypeOf;
f7eb47b… lmata 7 var __hasOwnProp = Object.prototype.hasOwnProperty;
f7eb47b… lmata 8 var __export = (target, all) => {
f7eb47b… lmata 9 for (var name in all)
f7eb47b… lmata 10 __defProp(target, name, { get: all[name], enumerable: true });
f7eb47b… lmata 11 };
f7eb47b… lmata 12 var __copyProps = (to, from, except, desc) => {
f7eb47b… lmata 13 if (from && typeof from === "object" || typeof from === "function") {
f7eb47b… lmata 14 for (let key of __getOwnPropNames(from))
f7eb47b… lmata 15 if (!__hasOwnProp.call(to, key) && key !== except)
f7eb47b… lmata 16 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
f7eb47b… lmata 17 }
f7eb47b… lmata 18 return to;
f7eb47b… lmata 19 };
f7eb47b… lmata 20 var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
f7eb47b… lmata 21 // If the importer is in node compatibility mode or this is not an ESM
f7eb47b… lmata 22 // file that has been converted to a CommonJS file using a Babel-
f7eb47b… lmata 23 // compatible transform (i.e. "__esModule" has not been set), then set
f7eb47b… lmata 24 // "default" to the CommonJS "module.exports" for node compatibility.
f7eb47b… lmata 25 isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
f7eb47b… lmata 26 mod
f7eb47b… lmata 27 ));
f7eb47b… lmata 28 var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
f7eb47b… lmata 29 var testInfo_exports = {};
f7eb47b… lmata 30 __export(testInfo_exports, {
f7eb47b… lmata 31 StepSkipError: () => StepSkipError,
f7eb47b… lmata 32 TestInfoImpl: () => TestInfoImpl,
f7eb47b… lmata 33 TestSkipError: () => TestSkipError,
f7eb47b… lmata 34 TestStepInfoImpl: () => TestStepInfoImpl,
f7eb47b… lmata 35 emtpyTestInfoCallbacks: () => emtpyTestInfoCallbacks
f7eb47b… lmata 36 });
f7eb47b… lmata 37 module.exports = __toCommonJS(testInfo_exports);
f7eb47b… lmata 38 var import_fs = __toESM(require("fs"));
f7eb47b… lmata 39 var import_path = __toESM(require("path"));
f7eb47b… lmata 40 var import_utils = require("playwright-core/lib/utils");
f7eb47b… lmata 41 var import_timeoutManager = require("./timeoutManager");
f7eb47b… lmata 42 var import_util = require("../util");
f7eb47b… lmata 43 var import_testTracing = require("./testTracing");
f7eb47b… lmata 44 var import_util2 = require("./util");
f7eb47b… lmata 45 var import_transform = require("../transform/transform");
f7eb47b… lmata 46 const emtpyTestInfoCallbacks = {
f7eb47b… lmata 47 onStepBegin: () => {
f7eb47b… lmata 48 },
f7eb47b… lmata 49 onStepEnd: () => {
f7eb47b… lmata 50 },
f7eb47b… lmata 51 onAttach: () => {
f7eb47b… lmata 52 },
f7eb47b… lmata 53 onTestPaused: () => Promise.reject(new Error("TestInfoImpl not initialized")),
f7eb47b… lmata 54 onCloneStorage: () => Promise.reject(new Error("TestInfoImpl not initialized")),
f7eb47b… lmata 55 onUpstreamStorage: () => Promise.resolve()
f7eb47b… lmata 56 };
f7eb47b… lmata 57 class TestInfoImpl {
f7eb47b… lmata 58 constructor(configInternal, projectInternal, workerParams, test, retry, callbacks) {
f7eb47b… lmata 59 this._snapshotNames = { lastAnonymousSnapshotIndex: 0, lastNamedSnapshotIndex: {} };
f7eb47b… lmata 60 this._ariaSnapshotNames = { lastAnonymousSnapshotIndex: 0, lastNamedSnapshotIndex: {} };
f7eb47b… lmata 61 this._interruptedPromise = new import_utils.ManualPromise();
f7eb47b… lmata 62 this._lastStepId = 0;
f7eb47b… lmata 63 this._steps = [];
f7eb47b… lmata 64 this._stepMap = /* @__PURE__ */ new Map();
f7eb47b… lmata 65 this._hasNonRetriableError = false;
f7eb47b… lmata 66 this._hasUnhandledError = false;
f7eb47b… lmata 67 this._allowSkips = false;
f7eb47b… lmata 68 this.duration = 0;
f7eb47b… lmata 69 this.annotations = [];
f7eb47b… lmata 70 this.attachments = [];
f7eb47b… lmata 71 this.status = "passed";
f7eb47b… lmata 72 this.snapshotSuffix = "";
f7eb47b… lmata 73 this.errors = [];
f7eb47b… lmata 74 this.testId = test?.id ?? "";
f7eb47b… lmata 75 this._callbacks = callbacks;
f7eb47b… lmata 76 this._startTime = (0, import_utils.monotonicTime)();
f7eb47b… lmata 77 this._startWallTime = Date.now();
f7eb47b… lmata 78 this._requireFile = test?._requireFile ?? "";
f7eb47b… lmata 79 this._uniqueSymbol = Symbol("testInfoUniqueSymbol");
f7eb47b… lmata 80 this._workerParams = workerParams;
f7eb47b… lmata 81 this.repeatEachIndex = workerParams.repeatEachIndex;
f7eb47b… lmata 82 this.retry = retry;
f7eb47b… lmata 83 this.workerIndex = workerParams.workerIndex;
f7eb47b… lmata 84 this.parallelIndex = workerParams.parallelIndex;
f7eb47b… lmata 85 this._projectInternal = projectInternal;
f7eb47b… lmata 86 this.project = projectInternal.project;
f7eb47b… lmata 87 this._configInternal = configInternal;
f7eb47b… lmata 88 this.config = configInternal.config;
f7eb47b… lmata 89 this.title = test?.title ?? "";
f7eb47b… lmata 90 this.titlePath = test?.titlePath() ?? [];
f7eb47b… lmata 91 this.file = test?.location.file ?? "";
f7eb47b… lmata 92 this.line = test?.location.line ?? 0;
f7eb47b… lmata 93 this.column = test?.location.column ?? 0;
f7eb47b… lmata 94 this.tags = test?.tags ?? [];
f7eb47b… lmata 95 this.fn = test?.fn ?? (() => {
f7eb47b… lmata 96 });
f7eb47b… lmata 97 this.expectedStatus = test?.expectedStatus ?? "skipped";
f7eb47b… lmata 98 this._timeoutManager = new import_timeoutManager.TimeoutManager(this.project.timeout);
f7eb47b… lmata 99 if (configInternal.configCLIOverrides.debug)
f7eb47b… lmata 100 this._setDebugMode();
f7eb47b… lmata 101 this.outputDir = (() => {
f7eb47b… lmata 102 const relativeTestFilePath = import_path.default.relative(this.project.testDir, this._requireFile.replace(/\.(spec|test)\.(js|ts|jsx|tsx|mjs|mts|cjs|cts)$/, ""));
f7eb47b… lmata 103 const sanitizedRelativePath = relativeTestFilePath.replace(process.platform === "win32" ? new RegExp("\\\\", "g") : new RegExp("/", "g"), "-");
f7eb47b… lmata 104 const fullTitleWithoutSpec = this.titlePath.slice(1).join(" ");
f7eb47b… lmata 105 let testOutputDir = (0, import_util.trimLongString)(sanitizedRelativePath + "-" + (0, import_utils.sanitizeForFilePath)(fullTitleWithoutSpec), import_util.windowsFilesystemFriendlyLength);
f7eb47b… lmata 106 if (projectInternal.id)
f7eb47b… lmata 107 testOutputDir += "-" + (0, import_utils.sanitizeForFilePath)(projectInternal.id);
f7eb47b… lmata 108 if (this.retry)
f7eb47b… lmata 109 testOutputDir += "-retry" + this.retry;
f7eb47b… lmata 110 if (this.repeatEachIndex)
f7eb47b… lmata 111 testOutputDir += "-repeat" + this.repeatEachIndex;
f7eb47b… lmata 112 return import_path.default.join(this.project.outputDir, testOutputDir);
f7eb47b… lmata 113 })();
f7eb47b… lmata 114 this.snapshotDir = (() => {
f7eb47b… lmata 115 const relativeTestFilePath = import_path.default.relative(this.project.testDir, this._requireFile);
f7eb47b… lmata 116 return import_path.default.join(this.project.snapshotDir, relativeTestFilePath + "-snapshots");
f7eb47b… lmata 117 })();
f7eb47b… lmata 118 this._attachmentsPush = this.attachments.push.bind(this.attachments);
f7eb47b… lmata 119 const attachmentsPush = (...attachments) => {
f7eb47b… lmata 120 for (const a of attachments)
f7eb47b… lmata 121 this._attach(a, this._parentStep()?.stepId);
f7eb47b… lmata 122 return this.attachments.length;
f7eb47b… lmata 123 };
f7eb47b… lmata 124 Object.defineProperty(this.attachments, "push", {
f7eb47b… lmata 125 value: attachmentsPush,
f7eb47b… lmata 126 writable: true,
f7eb47b… lmata 127 enumerable: false,
f7eb47b… lmata 128 configurable: true
f7eb47b… lmata 129 });
f7eb47b… lmata 130 this._tracing = new import_testTracing.TestTracing(this, workerParams.artifactsDir);
f7eb47b… lmata 131 this.skip = (0, import_transform.wrapFunctionWithLocation)((location, ...args) => this._modifier("skip", location, args));
f7eb47b… lmata 132 this.fixme = (0, import_transform.wrapFunctionWithLocation)((location, ...args) => this._modifier("fixme", location, args));
f7eb47b… lmata 133 this.fail = (0, import_transform.wrapFunctionWithLocation)((location, ...args) => this._modifier("fail", location, args));
f7eb47b… lmata 134 this.slow = (0, import_transform.wrapFunctionWithLocation)((location, ...args) => this._modifier("slow", location, args));
f7eb47b… lmata 135 }
f7eb47b… lmata 136 get error() {
f7eb47b… lmata 137 return this.errors[0];
f7eb47b… lmata 138 }
f7eb47b… lmata 139 set error(e) {
f7eb47b… lmata 140 if (e === void 0)
f7eb47b… lmata 141 throw new Error("Cannot assign testInfo.error undefined value!");
f7eb47b… lmata 142 this.errors[0] = e;
f7eb47b… lmata 143 }
f7eb47b… lmata 144 get timeout() {
f7eb47b… lmata 145 return this._timeoutManager.defaultSlot().timeout;
f7eb47b… lmata 146 }
f7eb47b… lmata 147 set timeout(timeout) {
f7eb47b… lmata 148 }
f7eb47b… lmata 149 _deadlineForMatcher(timeout) {
f7eb47b… lmata 150 const startTime = (0, import_utils.monotonicTime)();
f7eb47b… lmata 151 const matcherDeadline = timeout ? startTime + timeout : import_timeoutManager.kMaxDeadline;
f7eb47b… lmata 152 const testDeadline = this._timeoutManager.currentSlotDeadline() - 250;
f7eb47b… lmata 153 const matcherMessage = `Timeout ${timeout}ms exceeded while waiting on the predicate`;
f7eb47b… lmata 154 const testMessage = `Test timeout of ${this.timeout}ms exceeded`;
f7eb47b… lmata 155 return { deadline: Math.min(testDeadline, matcherDeadline), timeoutMessage: testDeadline < matcherDeadline ? testMessage : matcherMessage };
f7eb47b… lmata 156 }
f7eb47b… lmata 157 static _defaultDeadlineForMatcher(timeout) {
f7eb47b… lmata 158 return { deadline: timeout ? (0, import_utils.monotonicTime)() + timeout : 0, timeoutMessage: `Timeout ${timeout}ms exceeded while waiting on the predicate` };
f7eb47b… lmata 159 }
f7eb47b… lmata 160 _modifier(type, location, modifierArgs) {
f7eb47b… lmata 161 if (typeof modifierArgs[1] === "function") {
f7eb47b… lmata 162 throw new Error([
f7eb47b… lmata 163 "It looks like you are calling test.skip() inside the test and pass a callback.",
f7eb47b… lmata 164 "Pass a condition instead and optional description instead:",
f7eb47b… lmata 165 `test('my test', async ({ page, isMobile }) => {`,
f7eb47b… lmata 166 ` test.skip(isMobile, 'This test is not applicable on mobile');`,
f7eb47b… lmata 167 `});`
f7eb47b… lmata 168 ].join("\n"));
f7eb47b… lmata 169 }
f7eb47b… lmata 170 if (modifierArgs.length >= 1 && !modifierArgs[0])
f7eb47b… lmata 171 return;
f7eb47b… lmata 172 const description = modifierArgs[1];
f7eb47b… lmata 173 this.annotations.push({ type, description, location });
f7eb47b… lmata 174 if (type === "slow") {
f7eb47b… lmata 175 this._timeoutManager.slow();
f7eb47b… lmata 176 } else if (type === "skip" || type === "fixme") {
f7eb47b… lmata 177 this.expectedStatus = "skipped";
f7eb47b… lmata 178 throw new TestSkipError("Test is skipped: " + (description || ""));
f7eb47b… lmata 179 } else if (type === "fail") {
f7eb47b… lmata 180 if (this.expectedStatus !== "skipped")
f7eb47b… lmata 181 this.expectedStatus = "failed";
f7eb47b… lmata 182 }
f7eb47b… lmata 183 }
f7eb47b… lmata 184 _findLastPredefinedStep(steps) {
f7eb47b… lmata 185 for (let i = steps.length - 1; i >= 0; i--) {
f7eb47b… lmata 186 const child = this._findLastPredefinedStep(steps[i].steps);
f7eb47b… lmata 187 if (child)
f7eb47b… lmata 188 return child;
f7eb47b… lmata 189 if ((steps[i].category === "hook" || steps[i].category === "fixture") && !steps[i].endWallTime)
f7eb47b… lmata 190 return steps[i];
f7eb47b… lmata 191 }
f7eb47b… lmata 192 }
f7eb47b… lmata 193 _parentStep() {
f7eb47b… lmata 194 return (0, import_utils.currentZone)().data("stepZone") ?? this._findLastPredefinedStep(this._steps);
f7eb47b… lmata 195 }
f7eb47b… lmata 196 _addStep(data, parentStep) {
f7eb47b… lmata 197 const stepId = `${data.category}@${++this._lastStepId}`;
f7eb47b… lmata 198 if (data.category === "hook" || data.category === "fixture") {
f7eb47b… lmata 199 parentStep = this._findLastPredefinedStep(this._steps);
f7eb47b… lmata 200 } else {
f7eb47b… lmata 201 if (!parentStep)
f7eb47b… lmata 202 parentStep = this._parentStep();
f7eb47b… lmata 203 }
f7eb47b… lmata 204 const filteredStack = (0, import_util.filteredStackTrace)((0, import_utils.captureRawStack)());
f7eb47b… lmata 205 let boxedStack = parentStep?.boxedStack;
f7eb47b… lmata 206 let location = data.location;
f7eb47b… lmata 207 if (!boxedStack && data.box) {
f7eb47b… lmata 208 boxedStack = filteredStack.slice(1);
f7eb47b… lmata 209 location = location || boxedStack[0];
f7eb47b… lmata 210 }
f7eb47b… lmata 211 location = location || filteredStack[0];
f7eb47b… lmata 212 const step = {
f7eb47b… lmata 213 ...data,
f7eb47b… lmata 214 stepId,
f7eb47b… lmata 215 group: parentStep?.group ?? data.group,
f7eb47b… lmata 216 boxedStack,
f7eb47b… lmata 217 location,
f7eb47b… lmata 218 steps: [],
f7eb47b… lmata 219 attachmentIndices: [],
f7eb47b… lmata 220 info: new TestStepInfoImpl(this, stepId, data.title, parentStep?.info),
f7eb47b… lmata 221 complete: (result) => {
f7eb47b… lmata 222 if (step.endWallTime)
f7eb47b… lmata 223 return;
f7eb47b… lmata 224 step.endWallTime = Date.now();
f7eb47b… lmata 225 if (result.error) {
f7eb47b… lmata 226 if (typeof result.error === "object" && !result.error?.[stepSymbol])
f7eb47b… lmata 227 result.error[stepSymbol] = step;
f7eb47b… lmata 228 const error = (0, import_util2.testInfoError)(result.error);
f7eb47b… lmata 229 if (step.boxedStack)
f7eb47b… lmata 230 error.stack = `${error.message}
f7eb47b… lmata 231 ${(0, import_utils.stringifyStackFrames)(step.boxedStack).join("\n")}`;
f7eb47b… lmata 232 step.error = error;
f7eb47b… lmata 233 }
f7eb47b… lmata 234 if (!step.error) {
f7eb47b… lmata 235 for (const childStep of step.steps) {
f7eb47b… lmata 236 if (childStep.error && childStep.infectParentStepsWithError) {
f7eb47b… lmata 237 step.error = childStep.error;
f7eb47b… lmata 238 step.infectParentStepsWithError = true;
f7eb47b… lmata 239 break;
f7eb47b… lmata 240 }
f7eb47b… lmata 241 }
f7eb47b… lmata 242 }
f7eb47b… lmata 243 if (!step.group) {
f7eb47b… lmata 244 const payload = {
f7eb47b… lmata 245 testId: this.testId,
f7eb47b… lmata 246 stepId,
f7eb47b… lmata 247 wallTime: step.endWallTime,
f7eb47b… lmata 248 error: step.error,
f7eb47b… lmata 249 suggestedRebaseline: result.suggestedRebaseline,
f7eb47b… lmata 250 annotations: step.info.annotations
f7eb47b… lmata 251 };
f7eb47b… lmata 252 this._callbacks.onStepEnd(payload);
f7eb47b… lmata 253 }
f7eb47b… lmata 254 if (step.group !== "internal") {
f7eb47b… lmata 255 const errorForTrace = step.error ? { name: "", message: step.error.message || "", stack: step.error.stack } : void 0;
f7eb47b… lmata 256 const attachments = step.attachmentIndices.map((i) => this.attachments[i]);
f7eb47b… lmata 257 this._tracing.appendAfterActionForStep(stepId, errorForTrace, attachments, step.info.annotations);
f7eb47b… lmata 258 }
f7eb47b… lmata 259 }
f7eb47b… lmata 260 };
f7eb47b… lmata 261 const parentStepList = parentStep ? parentStep.steps : this._steps;
f7eb47b… lmata 262 parentStepList.push(step);
f7eb47b… lmata 263 this._stepMap.set(stepId, step);
f7eb47b… lmata 264 if (!step.group) {
f7eb47b… lmata 265 const payload = {
f7eb47b… lmata 266 testId: this.testId,
f7eb47b… lmata 267 stepId,
f7eb47b… lmata 268 parentStepId: parentStep ? parentStep.stepId : void 0,
f7eb47b… lmata 269 title: step.title,
f7eb47b… lmata 270 category: step.category,
f7eb47b… lmata 271 wallTime: Date.now(),
f7eb47b… lmata 272 location: step.location
f7eb47b… lmata 273 };
f7eb47b… lmata 274 this._callbacks.onStepBegin(payload);
f7eb47b… lmata 275 }
f7eb47b… lmata 276 if (step.group !== "internal") {
f7eb47b… lmata 277 this._tracing.appendBeforeActionForStep({
f7eb47b… lmata 278 stepId,
f7eb47b… lmata 279 parentId: parentStep?.stepId,
f7eb47b… lmata 280 title: step.shortTitle ?? step.title,
f7eb47b… lmata 281 category: step.category,
f7eb47b… lmata 282 params: step.params,
f7eb47b… lmata 283 stack: step.location ? [step.location] : [],
f7eb47b… lmata 284 group: step.group
f7eb47b… lmata 285 });
f7eb47b… lmata 286 }
f7eb47b… lmata 287 return step;
f7eb47b… lmata 288 }
f7eb47b… lmata 289 _interrupt() {
f7eb47b… lmata 290 this._interruptedPromise.resolve();
f7eb47b… lmata 291 this._timeoutManager.interrupt();
f7eb47b… lmata 292 if (this.status === "passed")
f7eb47b… lmata 293 this.status = "interrupted";
f7eb47b… lmata 294 }
f7eb47b… lmata 295 _failWithError(error) {
f7eb47b… lmata 296 if (this.status === "passed" || this.status === "skipped")
f7eb47b… lmata 297 this.status = error instanceof import_timeoutManager.TimeoutManagerError ? "timedOut" : "failed";
f7eb47b… lmata 298 const serialized = (0, import_util2.testInfoError)(error);
f7eb47b… lmata 299 const step = typeof error === "object" ? error?.[stepSymbol] : void 0;
f7eb47b… lmata 300 if (step && step.boxedStack)
f7eb47b… lmata 301 serialized.stack = `${error.name}: ${error.message}
f7eb47b… lmata 302 ${(0, import_utils.stringifyStackFrames)(step.boxedStack).join("\n")}`;
f7eb47b… lmata 303 this.errors.push(serialized);
f7eb47b… lmata 304 this._tracing.appendForError(serialized);
f7eb47b… lmata 305 }
f7eb47b… lmata 306 async _runAsStep(stepInfo, cb) {
f7eb47b… lmata 307 const step = this._addStep(stepInfo);
f7eb47b… lmata 308 try {
f7eb47b… lmata 309 await cb();
f7eb47b… lmata 310 step.complete({});
f7eb47b… lmata 311 } catch (error) {
f7eb47b… lmata 312 step.complete({ error });
f7eb47b… lmata 313 throw error;
f7eb47b… lmata 314 }
f7eb47b… lmata 315 }
f7eb47b… lmata 316 async _runWithTimeout(runnable, cb) {
f7eb47b… lmata 317 try {
f7eb47b… lmata 318 await this._timeoutManager.withRunnable(runnable, async () => {
f7eb47b… lmata 319 try {
f7eb47b… lmata 320 await cb();
f7eb47b… lmata 321 } catch (e) {
f7eb47b… lmata 322 if (this._allowSkips && e instanceof TestSkipError) {
f7eb47b… lmata 323 if (this.status === "passed")
f7eb47b… lmata 324 this.status = "skipped";
f7eb47b… lmata 325 } else {
f7eb47b… lmata 326 this._failWithError(e);
f7eb47b… lmata 327 }
f7eb47b… lmata 328 throw e;
f7eb47b… lmata 329 }
f7eb47b… lmata 330 });
f7eb47b… lmata 331 } catch (error) {
f7eb47b… lmata 332 if (!this._interruptedPromise.isDone() && error instanceof import_timeoutManager.TimeoutManagerError)
f7eb47b… lmata 333 this._failWithError(error);
f7eb47b… lmata 334 throw error;
f7eb47b… lmata 335 }
f7eb47b… lmata 336 }
f7eb47b… lmata 337 _isFailure() {
f7eb47b… lmata 338 return this.status !== "skipped" && this.status !== this.expectedStatus;
f7eb47b… lmata 339 }
f7eb47b… lmata 340 _currentHookType() {
f7eb47b… lmata 341 const type = this._timeoutManager.currentSlotType();
f7eb47b… lmata 342 return ["beforeAll", "afterAll", "beforeEach", "afterEach"].includes(type) ? type : void 0;
f7eb47b… lmata 343 }
f7eb47b… lmata 344 _setDebugMode() {
f7eb47b… lmata 345 this._timeoutManager.setIgnoreTimeouts();
f7eb47b… lmata 346 }
f7eb47b… lmata 347 async _didFinishTestFunction() {
f7eb47b… lmata 348 const shouldPause = this._workerParams.pauseAtEnd && !this._isFailure() || this._workerParams.pauseOnError && this._isFailure();
f7eb47b… lmata 349 if (shouldPause) {
f7eb47b… lmata 350 await Promise.race([
f7eb47b… lmata 351 this._callbacks.onTestPaused({ testId: this.testId, errors: this._isFailure() ? this.errors : [], status: this.status }),
f7eb47b… lmata 352 this._interruptedPromise
f7eb47b… lmata 353 ]);
f7eb47b… lmata 354 }
f7eb47b… lmata 355 await this._onDidFinishTestFunctionCallback?.();
f7eb47b… lmata 356 }
f7eb47b… lmata 357 // ------------ TestInfo methods ------------
f7eb47b… lmata 358 async attach(name, options = {}) {
f7eb47b… lmata 359 const step = this._addStep({
f7eb47b… lmata 360 title: `Attach ${(0, import_utils.escapeWithQuotes)(name, '"')}`,
f7eb47b… lmata 361 category: "test.attach"
f7eb47b… lmata 362 });
f7eb47b… lmata 363 this._attach(
f7eb47b… lmata 364 await (0, import_util.normalizeAndSaveAttachment)(this.outputPath(), name, options),
f7eb47b… lmata 365 step.stepId
f7eb47b… lmata 366 );
f7eb47b… lmata 367 step.complete({});
f7eb47b… lmata 368 }
f7eb47b… lmata 369 _attach(attachment, stepId) {
f7eb47b… lmata 370 const index = this._attachmentsPush(attachment) - 1;
f7eb47b… lmata 371 let step = stepId ? this._stepMap.get(stepId) : void 0;
f7eb47b… lmata 372 if (!!step?.group)
f7eb47b… lmata 373 step = void 0;
f7eb47b… lmata 374 if (step) {
f7eb47b… lmata 375 step.attachmentIndices.push(index);
f7eb47b… lmata 376 } else {
f7eb47b… lmata 377 const stepId2 = `attach@${(0, import_utils.createGuid)()}`;
f7eb47b… lmata 378 this._tracing.appendBeforeActionForStep({ stepId: stepId2, title: `Attach ${(0, import_utils.escapeWithQuotes)(attachment.name, '"')}`, category: "test.attach", stack: [] });
f7eb47b… lmata 379 this._tracing.appendAfterActionForStep(stepId2, void 0, [attachment]);
f7eb47b… lmata 380 }
f7eb47b… lmata 381 this._callbacks.onAttach({
f7eb47b… lmata 382 testId: this.testId,
f7eb47b… lmata 383 name: attachment.name,
f7eb47b… lmata 384 contentType: attachment.contentType,
f7eb47b… lmata 385 path: attachment.path,
f7eb47b… lmata 386 body: attachment.body?.toString("base64"),
f7eb47b… lmata 387 stepId: step?.stepId
f7eb47b… lmata 388 });
f7eb47b… lmata 389 }
f7eb47b… lmata 390 outputPath(...pathSegments) {
f7eb47b… lmata 391 const outputPath = this._getOutputPath(...pathSegments);
f7eb47b… lmata 392 import_fs.default.mkdirSync(this.outputDir, { recursive: true });
f7eb47b… lmata 393 return outputPath;
f7eb47b… lmata 394 }
f7eb47b… lmata 395 _getOutputPath(...pathSegments) {
f7eb47b… lmata 396 const joinedPath = import_path.default.join(...pathSegments);
f7eb47b… lmata 397 const outputPath = (0, import_util.getContainedPath)(this.outputDir, joinedPath);
f7eb47b… lmata 398 if (outputPath)
f7eb47b… lmata 399 return outputPath;
f7eb47b… lmata 400 throw new Error(`The outputPath is not allowed outside of the parent directory. Please fix the defined path.
f7eb47b… lmata 401
f7eb47b… lmata 402 outputPath: ${joinedPath}`);
f7eb47b… lmata 403 }
f7eb47b… lmata 404 _fsSanitizedTestName() {
f7eb47b… lmata 405 const fullTitleWithoutSpec = this.titlePath.slice(1).join(" ");
f7eb47b… lmata 406 return (0, import_utils.sanitizeForFilePath)((0, import_util.trimLongString)(fullTitleWithoutSpec));
f7eb47b… lmata 407 }
f7eb47b… lmata 408 _resolveSnapshotPaths(kind, name, updateSnapshotIndex, anonymousExtension) {
f7eb47b… lmata 409 const snapshotNames = kind === "aria" ? this._ariaSnapshotNames : this._snapshotNames;
f7eb47b… lmata 410 const defaultExtensions = { "aria": ".aria.yml", "screenshot": ".png", "snapshot": ".txt" };
f7eb47b… lmata 411 const ariaAwareExtname = (filePath) => kind === "aria" && filePath.endsWith(".aria.yml") ? ".aria.yml" : import_path.default.extname(filePath);
f7eb47b… lmata 412 let subPath;
f7eb47b… lmata 413 let ext;
f7eb47b… lmata 414 let relativeOutputPath;
f7eb47b… lmata 415 if (!name) {
f7eb47b… lmata 416 const index = snapshotNames.lastAnonymousSnapshotIndex + 1;
f7eb47b… lmata 417 if (updateSnapshotIndex === "updateSnapshotIndex")
f7eb47b… lmata 418 snapshotNames.lastAnonymousSnapshotIndex = index;
f7eb47b… lmata 419 const fullTitleWithoutSpec = [...this.titlePath.slice(1), index].join(" ");
f7eb47b… lmata 420 ext = anonymousExtension ?? defaultExtensions[kind];
f7eb47b… lmata 421 subPath = (0, import_util.sanitizeFilePathBeforeExtension)((0, import_util.trimLongString)(fullTitleWithoutSpec) + ext, ext);
f7eb47b… lmata 422 relativeOutputPath = (0, import_util.sanitizeFilePathBeforeExtension)((0, import_util.trimLongString)(fullTitleWithoutSpec, import_util.windowsFilesystemFriendlyLength) + ext, ext);
f7eb47b… lmata 423 } else {
f7eb47b… lmata 424 if (Array.isArray(name)) {
f7eb47b… lmata 425 subPath = import_path.default.join(...name);
f7eb47b… lmata 426 relativeOutputPath = import_path.default.join(...name);
f7eb47b… lmata 427 ext = ariaAwareExtname(subPath);
f7eb47b… lmata 428 } else {
f7eb47b… lmata 429 ext = ariaAwareExtname(name);
f7eb47b… lmata 430 subPath = (0, import_util.sanitizeFilePathBeforeExtension)(name, ext);
f7eb47b… lmata 431 relativeOutputPath = (0, import_util.sanitizeFilePathBeforeExtension)((0, import_util.trimLongString)(name, import_util.windowsFilesystemFriendlyLength), ext);
f7eb47b… lmata 432 }
f7eb47b… lmata 433 const index = (snapshotNames.lastNamedSnapshotIndex[relativeOutputPath] || 0) + 1;
f7eb47b… lmata 434 if (updateSnapshotIndex === "updateSnapshotIndex")
f7eb47b… lmata 435 snapshotNames.lastNamedSnapshotIndex[relativeOutputPath] = index;
f7eb47b… lmata 436 if (index > 1)
f7eb47b… lmata 437 relativeOutputPath = (0, import_util.addSuffixToFilePath)(relativeOutputPath, `-${index - 1}`);
f7eb47b… lmata 438 }
f7eb47b… lmata 439 const legacyTemplate = "{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{-projectName}{-snapshotSuffix}{ext}";
f7eb47b… lmata 440 let template;
f7eb47b… lmata 441 if (kind === "screenshot") {
f7eb47b… lmata 442 template = this._projectInternal.expect?.toHaveScreenshot?.pathTemplate || this._projectInternal.snapshotPathTemplate || legacyTemplate;
f7eb47b… lmata 443 } else if (kind === "aria") {
f7eb47b… lmata 444 const ariaDefaultTemplate = "{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{ext}";
f7eb47b… lmata 445 template = this._projectInternal.expect?.toMatchAriaSnapshot?.pathTemplate || this._projectInternal.snapshotPathTemplate || ariaDefaultTemplate;
f7eb47b… lmata 446 } else {
f7eb47b… lmata 447 template = this._projectInternal.snapshotPathTemplate || legacyTemplate;
f7eb47b… lmata 448 }
f7eb47b… lmata 449 const nameArgument = import_path.default.join(import_path.default.dirname(subPath), import_path.default.basename(subPath, ext));
f7eb47b… lmata 450 const absoluteSnapshotPath = this._applyPathTemplate(template, nameArgument, ext);
f7eb47b… lmata 451 return { absoluteSnapshotPath, relativeOutputPath };
f7eb47b… lmata 452 }
f7eb47b… lmata 453 _applyPathTemplate(template, nameArgument, ext) {
f7eb47b… lmata 454 const relativeTestFilePath = import_path.default.relative(this.project.testDir, this._requireFile);
f7eb47b… lmata 455 const parsedRelativeTestFilePath = import_path.default.parse(relativeTestFilePath);
f7eb47b… lmata 456 const projectNamePathSegment = (0, import_utils.sanitizeForFilePath)(this.project.name);
f7eb47b… lmata 457 const snapshotPath = template.replace(/\{(.)?testDir\}/g, "$1" + this.project.testDir).replace(/\{(.)?snapshotDir\}/g, "$1" + this.project.snapshotDir).replace(/\{(.)?snapshotSuffix\}/g, this.snapshotSuffix ? "$1" + this.snapshotSuffix : "").replace(/\{(.)?testFileDir\}/g, "$1" + parsedRelativeTestFilePath.dir).replace(/\{(.)?platform\}/g, "$1" + process.platform).replace(/\{(.)?projectName\}/g, projectNamePathSegment ? "$1" + projectNamePathSegment : "").replace(/\{(.)?testName\}/g, "$1" + this._fsSanitizedTestName()).replace(/\{(.)?testFileName\}/g, "$1" + parsedRelativeTestFilePath.base).replace(/\{(.)?testFilePath\}/g, "$1" + relativeTestFilePath).replace(/\{(.)?arg\}/g, "$1" + nameArgument).replace(/\{(.)?ext\}/g, ext ? "$1" + ext : "");
f7eb47b… lmata 458 return import_path.default.normalize(import_path.default.resolve(this._configInternal.configDir, snapshotPath));
f7eb47b… lmata 459 }
f7eb47b… lmata 460 snapshotPath(...args) {
f7eb47b… lmata 461 let name = args;
f7eb47b… lmata 462 let kind = "snapshot";
f7eb47b… lmata 463 const options = args[args.length - 1];
f7eb47b… lmata 464 if (options && typeof options === "object") {
f7eb47b… lmata 465 kind = options.kind ?? kind;
f7eb47b… lmata 466 name = args.slice(0, -1);
f7eb47b… lmata 467 }
f7eb47b… lmata 468 if (!["snapshot", "screenshot", "aria"].includes(kind))
f7eb47b… lmata 469 throw new Error(`testInfo.snapshotPath: unknown kind "${kind}", must be one of "snapshot", "screenshot" or "aria"`);
f7eb47b… lmata 470 return this._resolveSnapshotPaths(kind, name.length <= 1 ? name[0] : name, "dontUpdateSnapshotIndex").absoluteSnapshotPath;
f7eb47b… lmata 471 }
f7eb47b… lmata 472 setTimeout(timeout) {
f7eb47b… lmata 473 this._timeoutManager.setTimeout(timeout);
f7eb47b… lmata 474 }
f7eb47b… lmata 475 async _cloneStorage(storageFile) {
f7eb47b… lmata 476 return await this._callbacks.onCloneStorage({ storageFile });
f7eb47b… lmata 477 }
f7eb47b… lmata 478 async _upstreamStorage(storageFile, storageOutFile) {
f7eb47b… lmata 479 await this._callbacks.onUpstreamStorage({ storageFile, storageOutFile });
f7eb47b… lmata 480 }
f7eb47b… lmata 481 artifactsDir() {
f7eb47b… lmata 482 return this._workerParams.artifactsDir;
f7eb47b… lmata 483 }
f7eb47b… lmata 484 }
f7eb47b… lmata 485 class TestStepInfoImpl {
f7eb47b… lmata 486 constructor(testInfo, stepId, title, parentStep) {
f7eb47b… lmata 487 this.annotations = [];
f7eb47b… lmata 488 this._testInfo = testInfo;
f7eb47b… lmata 489 this._stepId = stepId;
f7eb47b… lmata 490 this._title = title;
f7eb47b… lmata 491 this._parentStep = parentStep;
f7eb47b… lmata 492 this.skip = (0, import_transform.wrapFunctionWithLocation)((location, ...args) => {
f7eb47b… lmata 493 if (args.length > 0 && !args[0])
f7eb47b… lmata 494 return;
f7eb47b… lmata 495 const description = args[1];
f7eb47b… lmata 496 this.annotations.push({ type: "skip", description, location });
f7eb47b… lmata 497 throw new StepSkipError(description);
f7eb47b… lmata 498 });
f7eb47b… lmata 499 }
f7eb47b… lmata 500 async _runStepBody(skip, body, location) {
f7eb47b… lmata 501 if (skip) {
f7eb47b… lmata 502 this.annotations.push({ type: "skip", location });
f7eb47b… lmata 503 return void 0;
f7eb47b… lmata 504 }
f7eb47b… lmata 505 try {
f7eb47b… lmata 506 return await body(this);
f7eb47b… lmata 507 } catch (e) {
f7eb47b… lmata 508 if (e instanceof StepSkipError)
f7eb47b… lmata 509 return void 0;
f7eb47b… lmata 510 throw e;
f7eb47b… lmata 511 }
f7eb47b… lmata 512 }
f7eb47b… lmata 513 _attachToStep(attachment) {
f7eb47b… lmata 514 this._testInfo._attach(attachment, this._stepId);
f7eb47b… lmata 515 }
f7eb47b… lmata 516 async attach(name, options) {
f7eb47b… lmata 517 this._attachToStep(await (0, import_util.normalizeAndSaveAttachment)(this._testInfo.outputPath(), name, options));
f7eb47b… lmata 518 }
f7eb47b… lmata 519 get titlePath() {
f7eb47b… lmata 520 const parent = this._parentStep ?? this._testInfo;
f7eb47b… lmata 521 return [...parent.titlePath, this._title];
f7eb47b… lmata 522 }
f7eb47b… lmata 523 }
f7eb47b… lmata 524 class TestSkipError extends Error {
f7eb47b… lmata 525 }
f7eb47b… lmata 526 class StepSkipError extends Error {
f7eb47b… lmata 527 }
f7eb47b… lmata 528 const stepSymbol = Symbol("step");
f7eb47b… lmata 529 // Annotate the CommonJS export names for ESM import in node:
f7eb47b… lmata 530 0 && (module.exports = {
f7eb47b… lmata 531 StepSkipError,
f7eb47b… lmata 532 TestInfoImpl,
f7eb47b… lmata 533 TestSkipError,
f7eb47b… lmata 534 TestStepInfoImpl,
f7eb47b… lmata 535 emtpyTestInfoCallbacks
f7eb47b… lmata 536 });

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button