jest-jasmine2
Version:
1,429 lines (1,409 loc) • 43.9 kB
JavaScript
import { AssertionError } from "assert";
import { ErrorWithStack, convertDescriptorToString, formatTime, isPromise } from "jest-util";
import chalk from "chalk";
import { diff, printExpected, printReceived } from "jest-matcher-utils";
import { format } from "pretty-format";
//#region src/assertionErrorMessage.ts
const assertOperatorsMap = {
"!=": "notEqual",
"!==": "notStrictEqual",
"==": "equal",
"===": "strictEqual"
};
const humanReadableOperators = {
deepEqual: "to deeply equal",
deepStrictEqual: "to deeply and strictly equal",
equal: "to be equal",
notDeepEqual: "not to deeply equal",
notDeepStrictEqual: "not to deeply and strictly equal",
notEqual: "to not be equal",
notStrictEqual: "not be strictly equal",
strictEqual: "to strictly be equal"
};
const getOperatorName = (operator, stack) => {
if (typeof operator === "string") return assertOperatorsMap[operator] || operator;
if (stack.match(".doesNotThrow")) return "doesNotThrow";
if (stack.match(".throws")) return "throws";
return "";
};
const operatorMessage = (operator) => {
const niceOperatorName = getOperatorName(operator, "");
const humanReadableOperator = humanReadableOperators[niceOperatorName];
return typeof operator === "string" ? `${humanReadableOperator || niceOperatorName} to:\n` : "";
};
const assertThrowingMatcherHint = (operatorName) => operatorName ? chalk.dim("assert") + chalk.dim(`.${operatorName}(`) + chalk.red("function") + chalk.dim(")") : "";
const assertMatcherHint = (operator, operatorName, expected) => {
let message = "";
if (operator === "==" && expected === true) message = chalk.dim("assert") + chalk.dim("(") + chalk.red("received") + chalk.dim(")");
else if (operatorName) message = chalk.dim("assert") + chalk.dim(`.${operatorName}(`) + chalk.red("received") + chalk.dim(", ") + chalk.green("expected") + chalk.dim(")");
return message;
};
function assertionErrorMessage(error, options) {
const { expected, actual, generatedMessage, message, operator, stack } = error;
const diffString = diff(expected, actual, options);
const hasCustomMessage = !generatedMessage;
const operatorName = getOperatorName(operator, stack);
const trimmedStack = stack.replace(message, "").replaceAll(/AssertionError(.*)/g, "");
if (operatorName === "doesNotThrow") return `${buildHintString(assertThrowingMatcherHint(operatorName)) + chalk.reset("Expected the function not to throw an error.\n") + chalk.reset("Instead, it threw:\n")} ${printReceived(actual)}${chalk.reset(hasCustomMessage ? `\n\nMessage:\n ${message}` : "")}${trimmedStack}`;
if (operatorName === "throws") {
if (error.generatedMessage) return buildHintString(assertThrowingMatcherHint(operatorName)) + chalk.reset(error.message) + chalk.reset(hasCustomMessage ? `\n\nMessage:\n ${message}` : "") + trimmedStack;
return buildHintString(assertThrowingMatcherHint(operatorName)) + chalk.reset("Expected the function to throw an error.\n") + chalk.reset("But it didn't throw anything.") + chalk.reset(hasCustomMessage ? `\n\nMessage:\n ${message}` : "") + trimmedStack;
}
if (operatorName === "fail") return buildHintString(assertMatcherHint(operator, operatorName, expected)) + chalk.reset(hasCustomMessage ? `Message:\n ${message}` : "") + trimmedStack;
return `${buildHintString(assertMatcherHint(operator, operatorName, expected)) + chalk.reset(`Expected value ${operatorMessage(operator)}`)} ${printExpected(expected)}\n${chalk.reset("Received:\n")} ${printReceived(actual)}${chalk.reset(hasCustomMessage ? `\n\nMessage:\n ${message}` : "")}${diffString ? `\n\nDifference:\n\n${diffString}` : ""}${trimmedStack}`;
}
function buildHintString(hint) {
return hint ? `${hint}\n\n` : "";
}
var assertionErrorMessage_default = assertionErrorMessage;
//#endregion
//#region src/isError.ts
function isError(potentialError) {
const isError$1 = potentialError !== null && typeof potentialError === "object" && typeof potentialError.message === "string" && typeof potentialError.name === "string";
const message = isError$1 ? null : `Failed: ${format(potentialError, { maxDepth: 3 })}`;
return {
isError: isError$1,
message
};
}
//#endregion
//#region src/PCancelable.ts
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var CancelError = class extends Error {
constructor() {
super("Promise was canceled");
this.name = "CancelError";
}
};
var PCancelable = class {
_pending = true;
_canceled = false;
_promise;
_cancel;
_reject = () => {};
constructor(executor) {
this._promise = new Promise((resolve, reject) => {
this._reject = reject;
return executor((fn) => {
this._cancel = fn;
}, (val) => {
this._pending = false;
resolve(val);
}, (err) => {
this._pending = false;
reject(err);
});
});
}
then(onFulfilled, onRejected) {
return this._promise.then(onFulfilled, onRejected);
}
catch(onRejected) {
return this._promise.catch(onRejected);
}
cancel() {
if (!this._pending || this._canceled) return;
if (typeof this._cancel === "function") try {
this._cancel();
} catch (error) {
this._reject(error);
}
this._canceled = true;
this._reject(new CancelError());
}
};
//#endregion
//#region src/pTimeout.ts
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
function pTimeout(promise, ms, clearTimeout$1, setTimeout$1, onTimeout) {
return new Promise((resolve, reject) => {
const timer = setTimeout$1(() => resolve(onTimeout()), ms);
promise.then((val) => {
clearTimeout$1(timer);
resolve(val);
}, (error) => {
clearTimeout$1(timer);
reject(error);
});
});
}
//#endregion
//#region src/queueRunner.ts
function queueRunner(options) {
const token = new PCancelable((onCancel, resolve) => {
onCancel(resolve);
});
const mapper = ({ fn, timeout, initError = new Error() }) => {
let promise = new Promise((resolve) => {
const next = function(...args) {
const err = args[0];
if (err) options.fail.apply(null, args);
resolve();
};
next.fail = function(...args) {
options.fail.apply(null, args);
resolve();
};
try {
fn.call(options.userContext, next);
} catch (error) {
options.onException(error);
resolve();
}
});
promise = Promise.race([promise, token]);
if (!timeout) return promise;
const timeoutMs = timeout();
return pTimeout(promise, timeoutMs, options.clearTimeout, options.setTimeout, () => {
initError.message = `Timeout - Async callback was not invoked within the ${formatTime(timeoutMs)} timeout specified by jest.setTimeout.`;
initError.stack = initError.message + initError.stack;
options.onException(initError);
});
};
const result = options.queueableFns.reduce((promise, fn) => promise.then(() => mapper(fn)), Promise.resolve());
return {
cancel: token.cancel.bind(token),
catch: result.catch.bind(result),
then: result.then.bind(result)
};
}
//#endregion
//#region src/treeProcessor.ts
const noop = () => {};
function getNodeWithoutChildrenHandler(node, enabled) {
return function fn(done = noop) {
node.execute(done, enabled);
};
}
function hasNoEnabledTest(node) {
return node.disabled || node.markedPending || (node.children?.every(hasNoEnabledTest) ?? false);
}
function treeProcessor(options) {
const { nodeComplete, nodeStart, queueRunnerFactory, runnableIds, tree } = options;
function isEnabled(node, parentEnabled) {
return parentEnabled || runnableIds.includes(node.id);
}
function getNodeHandler(node, parentEnabled) {
const enabled = isEnabled(node, parentEnabled);
return node.children ? getNodeWithChildrenHandler(node, enabled) : getNodeWithoutChildrenHandler(node, enabled);
}
function getNodeWithChildrenHandler(node, enabled) {
return async function fn(done = noop) {
nodeStart(node);
await queueRunnerFactory({
onException: (error) => node.onException(error),
queueableFns: wrapChildren(node, enabled),
userContext: node.sharedUserContext()
});
nodeComplete(node);
done();
};
}
function wrapChildren(node, enabled) {
if (!node.children) throw new Error("`node.children` is not defined.");
const children = node.children.map((child) => ({ fn: getNodeHandler(child, enabled) }));
if (hasNoEnabledTest(node)) return children;
return [
...node.beforeAllFns,
...children,
...node.afterAllFns
];
}
const treeHandler = getNodeHandler(tree, false);
return treeHandler();
}
//#endregion
//#region src/jasmine/Env.ts
function jasmineEnv(j$) {
return class Env {
specFilter;
catchExceptions;
throwOnExpectationFailure;
catchingExceptions;
topSuite;
fail;
pending;
afterAll;
fit;
throwingExpectationFailures;
randomizeTests;
randomTests;
seed;
execute;
fdescribe;
spyOn;
beforeEach;
afterEach;
clearReporters;
addReporter;
it;
xdescribe;
xit;
beforeAll;
todo;
provideFallbackReporter;
allowRespy;
describe;
constructor() {
let totalSpecsDefined = 0;
let catchExceptions = true;
const realSetTimeout = globalThis.setTimeout;
const realClearTimeout = globalThis.clearTimeout;
const runnableResources = {};
const currentlyExecutingSuites = [];
let currentSpec = null;
let throwOnExpectationFailure = false;
let random = false;
let seed = null;
let nextSpecId = 0;
let nextSuiteId = 0;
const getNextSpecId = function() {
return `spec${nextSpecId++}`;
};
const getNextSuiteId = function() {
return `suite${nextSuiteId++}`;
};
const topSuite = new j$.Suite({
id: getNextSuiteId(),
description: "",
getTestPath() {
return j$.testPath;
}
});
let currentDeclarationSuite = topSuite;
const currentSuite = function() {
return currentlyExecutingSuites.at(-1);
};
const currentRunnable = function() {
return currentSpec || currentSuite();
};
const reporter = new j$.ReportDispatcher([
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
this.specFilter = function() {
return true;
};
const defaultResourcesForRunnable = function(id, _parentRunnableId) {
const resources = { spies: [] };
runnableResources[id] = resources;
};
const clearResourcesForRunnable = function(id) {
spyRegistry.clearSpies();
delete runnableResources[id];
};
const beforeAndAfterFns = function(suite) {
return function() {
let afters = [];
let befores = [];
while (suite) {
befores = befores.concat(suite.beforeFns);
afters = afters.concat(suite.afterFns);
suite = suite.parentSuite;
}
return {
befores: befores.reverse(),
afters
};
};
};
const getSpecName = function(spec, suite) {
const fullName = [spec.description];
const suiteFullName = suite.getFullName();
if (suiteFullName !== "") fullName.unshift(suiteFullName);
return fullName.join(" ");
};
this.catchExceptions = function(value) {
catchExceptions = !!value;
return catchExceptions;
};
this.catchingExceptions = function() {
return catchExceptions;
};
this.throwOnExpectationFailure = function(value) {
throwOnExpectationFailure = !!value;
};
this.throwingExpectationFailures = function() {
return throwOnExpectationFailure;
};
this.randomizeTests = function(value) {
random = !!value;
};
this.randomTests = function() {
return random;
};
this.seed = function(value) {
if (value) seed = value;
return seed;
};
const queueRunnerFactory = (options) => {
options.clearTimeout = realClearTimeout;
options.fail = this.fail;
options.setTimeout = realSetTimeout;
return queueRunner(options);
};
this.topSuite = function() {
return topSuite;
};
const uncaught = (err) => {
if (currentSpec) {
currentSpec.onException(err);
currentSpec.cancel();
} else {
console.error("Unhandled error");
console.error(err.stack);
}
};
let oldListenersException;
let oldListenersRejection;
const executionSetup = function() {
oldListenersException = [...process.listeners("uncaughtException")];
oldListenersRejection = [...process.listeners("unhandledRejection")];
j$.process.removeAllListeners("uncaughtException");
j$.process.removeAllListeners("unhandledRejection");
j$.process.on("uncaughtException", uncaught);
j$.process.on("unhandledRejection", uncaught);
};
const executionTeardown = function() {
j$.process.removeListener("uncaughtException", uncaught);
j$.process.removeListener("unhandledRejection", uncaught);
for (const listener of oldListenersException) j$.process.on("uncaughtException", listener);
for (const listener of oldListenersRejection) j$.process.on("unhandledRejection", listener);
};
this.execute = async function(runnablesToRun, suiteTree = topSuite) {
if (!runnablesToRun) if (focusedRunnables.length > 0) runnablesToRun = focusedRunnables;
else runnablesToRun = [suiteTree.id];
if (currentlyExecutingSuites.length === 0) executionSetup();
const lastDeclarationSuite = currentDeclarationSuite;
await treeProcessor({
nodeComplete(suite) {
if (!suite.disabled) clearResourcesForRunnable(suite.id);
currentlyExecutingSuites.pop();
if (suite === topSuite) reporter.jasmineDone({ failedExpectations: topSuite.result.failedExpectations });
else reporter.suiteDone(suite.getResult());
},
nodeStart(suite) {
currentlyExecutingSuites.push(suite);
defaultResourcesForRunnable(suite.id, suite.parentSuite && suite.parentSuite.id);
if (suite === topSuite) reporter.jasmineStarted({ totalSpecsDefined });
else reporter.suiteStarted(suite.result);
},
queueRunnerFactory,
runnableIds: runnablesToRun,
tree: suiteTree
});
currentDeclarationSuite = lastDeclarationSuite;
if (currentlyExecutingSuites.length === 0) executionTeardown();
};
this.addReporter = function(reporterToAdd) {
reporter.addReporter(reporterToAdd);
};
this.provideFallbackReporter = function(reporterToAdd) {
reporter.provideFallbackReporter(reporterToAdd);
};
this.clearReporters = function() {
reporter.clearReporters();
};
const spyRegistry = new j$.SpyRegistry({ currentSpies() {
if (!currentRunnable()) throw new Error("Spies must be created in a before function or a spec");
return runnableResources[currentRunnable().id].spies;
} });
this.allowRespy = function(allow) {
spyRegistry.allowRespy(allow);
};
this.spyOn = function(...args) {
return spyRegistry.spyOn.apply(spyRegistry, args);
};
const suiteFactory = function(description) {
const suite = new j$.Suite({
id: getNextSuiteId(),
description,
parentSuite: currentDeclarationSuite,
throwOnExpectationFailure,
getTestPath() {
return j$.testPath;
}
});
return suite;
};
this.describe = function(description, specDefinitions) {
const suite = suiteFactory(description);
if (specDefinitions === void 0) throw new Error("Missing second argument. It must be a callback function.");
if (typeof specDefinitions !== "function") throw new TypeError(`Invalid second argument, ${specDefinitions}. It must be a callback function.`);
if (specDefinitions.length > 0) throw new Error("describe does not expect any arguments");
if (currentDeclarationSuite.markedPending) suite.pend();
if (currentDeclarationSuite.markedTodo) suite.todo();
addSpecsToSuite(suite, specDefinitions);
return suite;
};
this.xdescribe = function(description, specDefinitions) {
const suite = suiteFactory(description);
suite.pend();
addSpecsToSuite(suite, specDefinitions);
return suite;
};
const focusedRunnables = [];
this.fdescribe = function(description, specDefinitions) {
const suite = suiteFactory(description);
suite.isFocused = true;
focusedRunnables.push(suite.id);
unfocusAncestor();
addSpecsToSuite(suite, specDefinitions);
return suite;
};
const addSpecsToSuite = (suite, specDefinitions) => {
const parentSuite = currentDeclarationSuite;
parentSuite.addChild(suite);
currentDeclarationSuite = suite;
let declarationError = void 0;
let describeReturnValue;
try {
describeReturnValue = specDefinitions.call(suite);
} catch (error) {
declarationError = error;
}
if (isPromise(describeReturnValue)) declarationError = new Error("Returning a Promise from \"describe\" is not supported. Tests must be defined synchronously.");
else if (describeReturnValue !== void 0) declarationError = new Error("A \"describe\" callback must not return a value.");
if (declarationError) this.it("encountered a declaration exception", () => {
throw declarationError;
});
currentDeclarationSuite = parentSuite;
};
function findFocusedAncestor(suite) {
while (suite) {
if (suite.isFocused) return suite.id;
suite = suite.parentSuite;
}
return null;
}
function unfocusAncestor() {
const focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
if (focusedAncestor) {
for (let i = 0; i < focusedRunnables.length; i++) if (focusedRunnables[i] === focusedAncestor) {
focusedRunnables.splice(i, 1);
break;
}
}
}
const specFactory = (description, fn, suite, timeout) => {
totalSpecsDefined++;
const spec = new j$.Spec({
id: getNextSpecId(),
beforeAndAfterFns: beforeAndAfterFns(suite),
resultCallback: specResultCallback,
getSpecName(spec$1) {
return getSpecName(spec$1, suite);
},
getTestPath() {
return j$.testPath;
},
onStart: specStarted,
description,
queueRunnerFactory,
userContext() {
return suite.clonedSharedUserContext();
},
queueableFn: {
fn,
timeout() {
return timeout || j$._DEFAULT_TIMEOUT_INTERVAL;
}
},
throwOnExpectationFailure
});
if (!this.specFilter(spec)) spec.disable();
return spec;
function specResultCallback(result) {
clearResourcesForRunnable(spec.id);
currentSpec = null;
reporter.specDone(result);
}
function specStarted(spec$1) {
currentSpec = spec$1;
defaultResourcesForRunnable(spec$1.id, suite.id);
reporter.specStarted(spec$1.result);
}
};
this.it = function(description, fn, timeout) {
description = convertDescriptorToString(description);
if (fn === void 0) throw new Error("Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.");
if (typeof fn !== "function") throw new TypeError(`Invalid second argument, ${fn}. It must be a callback function.`);
const spec = specFactory(description, fn, currentDeclarationSuite, timeout);
if (currentDeclarationSuite.markedPending) spec.pend();
if (currentSpec !== null) throw new Error(`Tests cannot be nested. Test "${spec.description}" cannot run because it is nested within "${currentSpec.description}".`);
currentDeclarationSuite.addChild(spec);
return spec;
};
this.xit = function(...args) {
const spec = this.it.apply(this, args);
spec.pend("Temporarily disabled with xit");
return spec;
};
this.todo = function() {
const description = arguments[0];
if (arguments.length !== 1 || typeof description !== "string") throw new ErrorWithStack("Todo must be called with only a description.", this.todo);
const spec = specFactory(description, () => {}, currentDeclarationSuite);
if (currentDeclarationSuite.markedPending) spec.pend();
else spec.todo();
currentDeclarationSuite.addChild(spec);
return spec;
};
this.fit = function(description, fn, timeout) {
const spec = specFactory(description, fn, currentDeclarationSuite, timeout);
currentDeclarationSuite.addChild(spec);
if (currentDeclarationSuite.markedPending) spec.pend();
else focusedRunnables.push(spec.id);
unfocusAncestor();
return spec;
};
this.beforeEach = function(beforeEachFunction, timeout) {
currentDeclarationSuite.beforeEach({
fn: beforeEachFunction,
timeout() {
return timeout || j$._DEFAULT_TIMEOUT_INTERVAL;
}
});
};
this.beforeAll = function(beforeAllFunction, timeout) {
currentDeclarationSuite.beforeAll({
fn: beforeAllFunction,
timeout() {
return timeout || j$._DEFAULT_TIMEOUT_INTERVAL;
}
});
};
this.afterEach = function(afterEachFunction, timeout) {
currentDeclarationSuite.afterEach({
fn: afterEachFunction,
timeout() {
return timeout || j$._DEFAULT_TIMEOUT_INTERVAL;
}
});
};
this.afterAll = function(afterAllFunction, timeout) {
currentDeclarationSuite.afterAll({
fn: afterAllFunction,
timeout() {
return timeout || j$._DEFAULT_TIMEOUT_INTERVAL;
}
});
};
this.pending = function(message) {
let fullMessage = j$.Spec.pendingSpecExceptionMessage;
if (message) fullMessage += message;
throw fullMessage;
};
this.fail = function(error) {
let checkIsError;
let message;
if (error instanceof AssertionError || error && error.name === AssertionError.name) {
checkIsError = false;
message = assertionErrorMessage_default(error, { expand: j$.Spec.expand });
} else {
const check = isError(error);
checkIsError = check.isError;
message = check.message || void 0;
}
const errorAsErrorObject = checkIsError ? error : new Error(message);
const runnable = currentRunnable();
if (!runnable) {
errorAsErrorObject.message = `Caught error after test environment was torn down\n\n${errorAsErrorObject.message}`;
throw errorAsErrorObject;
}
runnable.addExpectationResult(false, {
matcherName: "",
passed: false,
expected: "",
actual: "",
message,
error: errorAsErrorObject
});
};
}
};
}
//#endregion
//#region src/jasmine/JsApiReporter.ts
const noopTimer = {
start() {},
elapsed() {
return 0;
}
};
var JsApiReporter = class {
started;
finished;
runDetails;
jasmineStarted;
jasmineDone;
status;
executionTime;
suiteStarted;
suiteDone;
suiteResults;
suites;
specResults;
specDone;
specs;
specStarted;
constructor(options) {
const timer = options.timer || noopTimer;
let status = "loaded";
this.started = false;
this.finished = false;
this.runDetails = {};
this.jasmineStarted = () => {
this.started = true;
status = "started";
timer.start();
};
let executionTime;
function validateAfterAllExceptions({ failedExpectations }) {
if (failedExpectations && failedExpectations.length > 0) throw failedExpectations[0];
}
this.jasmineDone = function(runDetails) {
validateAfterAllExceptions(runDetails);
this.finished = true;
this.runDetails = runDetails;
executionTime = timer.elapsed();
status = "done";
};
this.status = function() {
return status;
};
const suites = [];
const suites_hash = {};
this.specStarted = function() {};
this.suiteStarted = function(result) {
suites_hash[result.id] = result;
};
this.suiteDone = function(result) {
storeSuite(result);
};
this.suiteResults = function(index, length) {
return suites.slice(index, index + length);
};
function storeSuite(result) {
suites.push(result);
suites_hash[result.id] = result;
}
this.suites = function() {
return suites_hash;
};
const specs = [];
this.specDone = function(result) {
specs.push(result);
};
this.specResults = function(index, length) {
return specs.slice(index, index + length);
};
this.specs = function() {
return specs;
};
this.executionTime = function() {
return executionTime;
};
}
};
//#endregion
//#region src/jasmine/ReportDispatcher.ts
var ReportDispatcher = class {
addReporter;
provideFallbackReporter;
clearReporters;
jasmineDone;
jasmineStarted;
specDone;
specStarted;
suiteDone;
suiteStarted;
constructor(methods) {
const dispatchedMethods = methods || [];
for (const method of dispatchedMethods) this[method] = function(m) {
return function() {
dispatch(m, arguments);
};
}(method);
let reporters = [];
let fallbackReporter = null;
this.addReporter = function(reporter) {
reporters.push(reporter);
};
this.provideFallbackReporter = function(reporter) {
fallbackReporter = reporter;
};
this.clearReporters = function() {
reporters = [];
};
return this;
function dispatch(method, args) {
if (reporters.length === 0 && fallbackReporter !== null) reporters.push(fallbackReporter);
for (const reporter of reporters) if (reporter[method]) reporter[method].apply(reporter, args);
}
}
};
//#endregion
//#region src/ExpectationFailed.ts
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var ExpectationFailed = class extends Error {};
//#endregion
//#region src/expectationResultFactory.ts
function messageFormatter({ error, message, passed }) {
if (passed) return "Passed.";
if (message) return message;
if (typeof error === "string") return error;
if (error && typeof error === "object" && typeof error.message === "string" && typeof error.name === "string") {
if (error.message === "") return error.name;
return `${error.name}: ${error.message}`;
}
return `thrown: ${format(error, { maxDepth: 3 })}`;
}
function stackFormatter(options, initError, errorMessage) {
if (options.passed) return "";
if (options.error) {
if (typeof options.error.stack === "string") return options.error.stack;
if (options.error === errorMessage) return errorMessage;
}
if (initError) return `${errorMessage.trimEnd()}\n\n${initError.stack}`;
return new Error(errorMessage).stack;
}
function expectationResultFactory(options, initError) {
const message = messageFormatter(options);
const stack = stackFormatter(options, initError, message);
if (options.passed) return {
error: options.error,
matcherName: options.matcherName,
message,
passed: options.passed,
stack
};
return {
actual: options.actual,
error: options.error,
expected: options.expected,
matcherName: options.matcherName,
message,
passed: options.passed,
stack
};
}
//#endregion
//#region src/jasmine/Spec.ts
var Spec = class Spec {
id;
description;
resultCallback;
queueableFn;
beforeAndAfterFns;
userContext;
onStart;
getSpecName;
queueRunnerFactory;
throwOnExpectationFailure;
initError;
result;
disabled;
currentRun;
markedTodo;
markedPending;
expand;
static pendingSpecExceptionMessage;
static isPendingSpecException(e) {
return !!(e && e.toString && e.toString().includes(Spec.pendingSpecExceptionMessage));
}
constructor(attrs) {
this.resultCallback = attrs.resultCallback || function() {};
this.id = attrs.id;
this.description = convertDescriptorToString(attrs.description);
this.queueableFn = attrs.queueableFn;
this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() {
return {
befores: [],
afters: []
};
};
this.userContext = attrs.userContext || function() {
return {};
};
this.onStart = attrs.onStart || function() {};
this.getSpecName = attrs.getSpecName || function() {
return "";
};
this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
this.initError = new Error();
this.initError.name = "";
this.initError.stack = this.initError.stack;
this.queueableFn.initError = this.initError;
this.result = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
failedExpectations: [],
passedExpectations: [],
pendingReason: "",
testPath: attrs.getTestPath()
};
}
addExpectationResult(passed, data, isError$1) {
const expectationResult = expectationResultFactory(data, this.initError);
if (passed) this.result.passedExpectations.push(expectationResult);
else {
this.result.failedExpectations.push(expectationResult);
if (this.throwOnExpectationFailure && !isError$1) throw new ExpectationFailed();
}
}
execute(onComplete, enabled) {
const self = this;
this.onStart(this);
if (!this.isExecutable() || this.markedPending || this.markedTodo || enabled === false) {
complete(enabled);
return;
}
const fns = this.beforeAndAfterFns();
const allFns = fns.befores.concat(this.queueableFn).concat(fns.afters);
this.currentRun = this.queueRunnerFactory({
queueableFns: allFns,
onException() {
self.onException.apply(self, arguments);
},
userContext: this.userContext(),
setTimeout,
clearTimeout,
fail: () => {}
});
this.currentRun.then(() => complete(true));
function complete(enabledAgain) {
self.result.status = self.status(enabledAgain);
self.resultCallback(self.result);
if (onComplete) onComplete();
}
}
cancel() {
if (this.currentRun) this.currentRun.cancel();
}
onException(error) {
if (Spec.isPendingSpecException(error)) {
this.pend(extractCustomPendingMessage(error));
return;
}
if (error instanceof ExpectationFailed) return;
this.addExpectationResult(false, {
matcherName: "",
passed: false,
expected: "",
actual: "",
error: this.isAssertionError(error) ? assertionErrorMessage_default(error, { expand: this.expand }) : error
}, true);
}
disable() {
this.disabled = true;
}
pend(message) {
this.markedPending = true;
if (message) this.result.pendingReason = message;
}
todo() {
this.markedTodo = true;
}
getResult() {
this.result.status = this.status();
return this.result;
}
status(enabled) {
if (this.disabled || enabled === false) return "disabled";
if (this.markedTodo) return "todo";
if (this.markedPending) return "pending";
if (this.result.failedExpectations.length > 0) return "failed";
else return "passed";
}
isExecutable() {
return !this.disabled;
}
getFullName() {
return this.getSpecName(this);
}
isAssertionError(error) {
return error instanceof AssertionError || error && error.name === AssertionError.name;
}
};
Spec.pendingSpecExceptionMessage = "=> marked Pending";
const extractCustomPendingMessage = function(e) {
const fullMessage = e.toString();
const boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage);
const boilerplateEnd = boilerplateStart + Spec.pendingSpecExceptionMessage.length;
return fullMessage.slice(boilerplateEnd);
};
//#endregion
//#region src/jasmine/Suite.ts
var Suite = class {
id;
parentSuite;
description;
throwOnExpectationFailure;
beforeFns;
afterFns;
beforeAllFns;
afterAllFns;
disabled;
children;
result;
sharedContext;
markedPending;
markedTodo;
isFocused;
constructor(attrs) {
this.markedPending = false;
this.markedTodo = false;
this.isFocused = false;
this.id = attrs.id;
this.parentSuite = attrs.parentSuite;
this.description = convertDescriptorToString(attrs.description);
this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
this.beforeFns = [];
this.afterFns = [];
this.beforeAllFns = [];
this.afterAllFns = [];
this.disabled = false;
this.children = [];
this.result = {
id: this.id,
description: this.description,
fullName: this.getFullName(),
failedExpectations: [],
testPath: attrs.getTestPath()
};
}
getFullName() {
const fullName = [];
for (let parentSuite = this; parentSuite; parentSuite = parentSuite.parentSuite) if (parentSuite.parentSuite) fullName.unshift(parentSuite.description);
return fullName.join(" ");
}
disable() {
this.disabled = true;
}
pend(_message) {
this.markedPending = true;
}
beforeEach(fn) {
this.beforeFns.unshift(fn);
}
beforeAll(fn) {
this.beforeAllFns.push(fn);
}
afterEach(fn) {
this.afterFns.unshift(fn);
}
afterAll(fn) {
this.afterAllFns.unshift(fn);
}
addChild(child) {
this.children.push(child);
}
status() {
if (this.disabled) return "disabled";
if (this.markedPending) return "pending";
if (this.result.failedExpectations.length > 0) return "failed";
else return "finished";
}
isExecutable() {
return !this.disabled;
}
canBeReentered() {
return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0;
}
getResult() {
this.result.status = this.status();
return this.result;
}
sharedUserContext() {
if (!this.sharedContext) this.sharedContext = {};
return this.sharedContext;
}
clonedSharedUserContext() {
return this.sharedUserContext();
}
onException(...args) {
if (args[0] instanceof ExpectationFailed) return;
if (isAfterAll(this.children)) {
const data = {
matcherName: "",
passed: false,
expected: "",
actual: "",
error: arguments[0]
};
this.result.failedExpectations.push(expectationResultFactory(data));
} else for (const child of this.children) child.onException.apply(child, args);
}
addExpectationResult(...args) {
if (isAfterAll(this.children) && isFailure(args)) {
const data = args[1];
this.result.failedExpectations.push(expectationResultFactory(data));
if (this.throwOnExpectationFailure) throw new ExpectationFailed();
} else for (const child of this.children) try {
child.addExpectationResult.apply(child, args);
} catch {}
}
execute(..._args) {}
};
function isAfterAll(children) {
return children && children[0] && children[0].result.status;
}
function isFailure(args) {
return !args[0];
}
//#endregion
//#region src/jasmine/Timer.ts
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
const defaultNow = function(Date$1) {
return function() {
return Date$1.now();
};
}(Date);
var Timer = class {
start;
elapsed;
constructor(options) {
options = options || {};
const now = options.now || defaultNow;
let startTime;
this.start = function() {
startTime = now();
};
this.elapsed = function() {
return now() - startTime;
};
}
};
//#endregion
//#region src/jasmine/CallTracker.ts
var CallTracker = class {
track;
any;
count;
argsFor;
all;
allArgs;
first;
mostRecent;
reset;
constructor() {
let calls = [];
this.track = function(context) {
calls.push(context);
};
this.any = function() {
return calls.length > 0;
};
this.count = function() {
return calls.length;
};
this.argsFor = function(index) {
const call = calls[index];
return call ? call.args : [];
};
this.all = function() {
return calls;
};
this.allArgs = function() {
const callArgs = [];
for (const call of calls) callArgs.push(call.args);
return callArgs;
};
this.first = function() {
return calls[0];
};
this.mostRecent = function() {
return calls.at(-1);
};
this.reset = function() {
calls = [];
};
}
};
var CallTracker_default = CallTracker;
//#endregion
//#region src/jasmine/SpyStrategy.ts
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
var SpyStrategy = class {
identity;
exec;
callThrough;
returnValue;
returnValues;
throwError;
callFake;
stub;
constructor({ name = "unknown", fn = function() {}, getSpy = function() {} } = {}) {
const identity = name;
const originalFn = fn;
let plan = function() {};
this.identity = function() {
return identity;
};
this.exec = function() {
return plan.apply(this, arguments);
};
this.callThrough = function() {
plan = originalFn;
return getSpy();
};
this.returnValue = function(value) {
plan = function() {
return value;
};
return getSpy();
};
this.returnValues = function() {
const values = Array.prototype.slice.call(arguments);
plan = function() {
return values.shift();
};
return getSpy();
};
this.throwError = function(something) {
const error = something instanceof Error ? something : new Error(something);
plan = function() {
throw error;
};
return getSpy();
};
this.callFake = function(fn$1) {
if (typeof fn$1 !== "function") throw new TypeError(`Argument passed to callFake should be a function, got ${fn$1}`);
plan = fn$1;
return getSpy();
};
this.stub = function(_fn) {
plan = function() {};
return getSpy();
};
}
};
//#endregion
//#region src/jasmine/createSpy.ts
function createSpy(name, originalFn) {
const spyStrategy = new SpyStrategy({
name,
fn: originalFn,
getSpy() {
return spy;
}
});
const callTracker = new CallTracker_default();
const spy = function(...args) {
const callData = {
object: this,
args: Array.prototype.slice.apply(arguments)
};
callTracker.track(callData);
const returnValue = spyStrategy.exec.apply(this, args);
callData.returnValue = returnValue;
return returnValue;
};
for (const prop in originalFn) {
if (prop === "and" || prop === "calls") throw new Error("Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon");
spy[prop] = originalFn[prop];
}
spy.and = spyStrategy;
spy.calls = callTracker;
return spy;
}
var createSpy_default = createSpy;
//#endregion
//#region src/jasmine/spyRegistry.ts
const formatErrorMsg = (domain, usage) => {
const usageDefinition = usage ? `\nUsage: ${usage}` : "";
return (msg) => `${domain} : ${msg}${usageDefinition}`;
};
function isSpy(putativeSpy) {
if (!putativeSpy) return false;
return putativeSpy.and instanceof SpyStrategy && putativeSpy.calls instanceof CallTracker_default;
}
const getErrorMsg = formatErrorMsg("<spyOn>", "spyOn(<object>, <methodName>)");
var SpyRegistry = class {
allowRespy;
spyOn;
clearSpies;
respy;
_spyOnProperty;
constructor({ currentSpies = () => [] } = {}) {
this.allowRespy = function(allow) {
this.respy = allow;
};
this.spyOn = (obj, methodName, accessType) => {
if (accessType) return this._spyOnProperty(obj, methodName, accessType);
if (obj === void 0) throw new Error(getErrorMsg(`could not find an object to spy upon for ${methodName}()`));
if (methodName === void 0) throw new Error(getErrorMsg("No method name supplied"));
if (obj[methodName] === void 0) throw new Error(getErrorMsg(`${methodName}() method does not exist`));
if (obj[methodName] && isSpy(obj[methodName])) if (this.respy) return obj[methodName];
else throw new Error(getErrorMsg(`${methodName} has already been spied upon`));
let descriptor;
try {
descriptor = Object.getOwnPropertyDescriptor(obj, methodName);
} catch {}
if (descriptor && !(descriptor.writable || descriptor.set)) throw new Error(getErrorMsg(`${methodName} is not declared writable or has no setter`));
const originalMethod = obj[methodName];
const spiedMethod = createSpy_default(methodName, originalMethod);
let restoreStrategy;
if (Object.prototype.hasOwnProperty.call(obj, methodName)) restoreStrategy = function() {
obj[methodName] = originalMethod;
};
else restoreStrategy = function() {
if (!delete obj[methodName]) obj[methodName] = originalMethod;
};
currentSpies().push({ restoreObjectToOriginalState: restoreStrategy });
obj[methodName] = spiedMethod;
return spiedMethod;
};
this._spyOnProperty = function(obj, propertyName, accessType = "get") {
if (!obj) throw new Error(getErrorMsg(`could not find an object to spy upon for ${propertyName}`));
if (!propertyName) throw new Error(getErrorMsg("No property name supplied"));
let descriptor;
try {
descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
} catch {}
if (!descriptor) throw new Error(getErrorMsg(`${propertyName} property does not exist`));
if (!descriptor.configurable) throw new Error(getErrorMsg(`${propertyName} is not declared configurable`));
if (!descriptor[accessType]) throw new Error(getErrorMsg(`Property ${propertyName} does not have access type ${accessType}`));
if (obj[propertyName] && isSpy(obj[propertyName])) if (this.respy) return obj[propertyName];
else throw new Error(getErrorMsg(`${propertyName} has already been spied upon`));
const originalDescriptor = descriptor;
const spiedProperty = createSpy_default(propertyName, descriptor[accessType]);
let restoreStrategy;
if (Object.prototype.hasOwnProperty.call(obj, propertyName)) restoreStrategy = function() {
Object.defineProperty(obj, propertyName, originalDescriptor);
};
else restoreStrategy = function() {
delete obj[propertyName];
};
currentSpies().push({ restoreObjectToOriginalState: restoreStrategy });
const spiedDescriptor = {
...descriptor,
[accessType]: spiedProperty
};
Object.defineProperty(obj, propertyName, spiedDescriptor);
return spiedProperty;
};
this.clearSpies = function() {
const spies = currentSpies();
for (let i = spies.length - 1; i >= 0; i--) {
const spyEntry = spies[i];
spyEntry.restoreObjectToOriginalState();
}
};
}
};
//#endregion
//#region src/jasmine/jasmineLight.ts
const testTimeoutSymbol = Symbol.for("TEST_TIMEOUT_SYMBOL");
const create = function(createOptions) {
const j$ = { ...createOptions };
Object.defineProperty(j$, "_DEFAULT_TIMEOUT_INTERVAL", {
configurable: true,
enumerable: true,
get() {
return globalThis[testTimeoutSymbol] || createOptions.testTimeout || 5e3;
},
set(value) {
globalThis[testTimeoutSymbol] = value;
}
});
j$.getEnv = function() {
const env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env();
return env;
};
j$.createSpy = createSpy_default;
j$.Env = jasmineEnv(j$);
j$.JsApiReporter = JsApiReporter;
j$.ReportDispatcher = ReportDispatcher;
j$.Spec = Spec;
j$.SpyRegistry = SpyRegistry;
j$.Suite = Suite;
j$.Timer = Timer;
j$.version = "2.5.2-light";
return j$;
};
const _interface = function(jasmine, env) {
const jasmineInterface = {
describe(description, specDefinitions) {
return env.describe(description, specDefinitions);
},
xdescribe(description, specDefinitions) {
return env.xdescribe(description, specDefinitions);
},
fdescribe(description, specDefinitions) {
return env.fdescribe(description, specDefinitions);
},
it() {
return env.it.apply(env, arguments);
},
xit() {
return env.xit.apply(env, arguments);
},
fit() {
return env.fit.apply(env, arguments);
},
beforeEach() {
if (typeof arguments[0] !== "function") throw new TypeError("Invalid first argument. It must be a callback function.");
return env.beforeEach.apply(env, arguments);
},
afterEach() {
if (typeof arguments[0] !== "function") throw new TypeError("Invalid first argument. It must be a callback function.");
return env.afterEach.apply(env, arguments);
},
beforeAll() {
if (typeof arguments[0] !== "function") throw new TypeError("Invalid first argument. It must be a callback function.");
return env.beforeAll.apply(env, arguments);
},
afterAll() {
if (typeof arguments[0] !== "function") throw new TypeError("Invalid first argument. It must be a callback function.");
return env.afterAll.apply(env, arguments);
},
pending() {
return env.pending.apply(env, arguments);
},
fail() {
return env.fail.apply(env, arguments);
},
spyOn(obj, methodName, accessType) {
return env.spyOn(obj, methodName, accessType);
},
jsApiReporter: new jasmine.JsApiReporter({ timer: new jasmine.Timer() }),
jasmine
};
return jasmineInterface;
};
//#endregion
export { _interface, create };