UNPKG

japa

Version:

Lean test runner for Node.js

196 lines (195 loc) 6.13 kB
"use strict"; /** * @module Core */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Test = void 0; /* * japa * * (c) Harminder Virk <virk@adonisjs.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ const is_ci_1 = __importDefault(require("is-ci")); const retry_1 = __importDefault(require("retry")); const time_span_1 = __importDefault(require("time-span")); const Emitter_1 = require("../Emitter"); const Callable_1 = require("../Callable"); const utils_1 = require("../utils"); const Exceptions_1 = require("../Exceptions"); const Contracts_1 = require("../Contracts"); /** * Test class is used for running and defining a test. It supports following * top level config properties. * * - skip : Skip the test * - skipInCI : Skip the test on CI * - runInCI : Run only in CI */ class Test { constructor(title, _resolveFn, _callback, options) { this.title = title; this._resolveFn = _resolveFn; this._callback = _callback; /** * Regression message is set when the passes, but it was meant * to fail */ this._regressionMessage = ''; /** * How many times, we should retry the function before marking * it as failed */ this._retries = 0; /** * The time spent to run the test. This includes the hooks * time. */ this._duration = 0; /** * The test error (if any) */ this._error = null; /** * Has test been executed */ this._completed = false; this._todo = typeof (this._callback) !== 'function'; this._timeout = options.timeout; this._regression = options.regression; if (options.skip) { this._skip = true; } else if (options.skipInCI && is_ci_1.default) { this._skip = true; } else if (options.runInCI && !is_ci_1.default) { this._skip = true; } } /** * Returns a boolean, telling if exception is hard. Hard exceptions * fails the regression tests too */ get _isHardException() { return (0, utils_1.isCoreException)(this._error); } /** * Runs test for given number retries */ _runTest() { return new Promise((resolve, reject) => { const op = retry_1.default.operation({ retries: this._retries, factor: 1 }); op.attempt(async () => { (0, Callable_1.Callable)(this._resolveFn, this._callback, this._timeout) .then(resolve) .catch((error) => { if (op.retry(error)) { return; } reject(op.mainError()); }); }); }); } /** * The JSON representation of the test. This is emitted * as an event to show test state. */ toJSON() { let status = Contracts_1.ITestStatus.PENDING; if (this._todo) { status = Contracts_1.ITestStatus.TODO; } else if (this._skip) { status = Contracts_1.ITestStatus.SKIPPED; } else if (this._completed && this._error) { status = (this._regression && !this._isHardException) ? Contracts_1.ITestStatus.PASSED : Contracts_1.ITestStatus.FAILED; } else if (this._completed && !this._error) { status = Contracts_1.ITestStatus.PASSED; } return { title: this.title, status: status, regression: this._regression, regressionMessage: this._regressionMessage, duration: this._duration, error: this._error, }; } /** * Retry a test for the given number of counts, before marking * it as failed. */ retry(counts) { if (typeof (counts) !== 'number') { throw new Error('"test.retry" expects a number value'); } this._retries = counts; return this; } /** * Set explicit timeout for the given test. */ timeout(duration) { if (typeof (duration) !== 'number') { throw new Error('"test.timeout" expects a number value'); } this._timeout = duration; return this; } /** * Runs the test. If retries are defined, then the test will be retried for the * given number of times before marked as failed. When retrying hooks are not * executed again. * * ```js * // stack * [before hook 1, before hook 2] * [test] (2 retries) * [after hook 1] * * + before hook 1 * + before hook 2 * test (original attempt = failed) * test (1st attempt = passed) * + after hook 1 * ``` */ async run() { Emitter_1.emitter.emit(Contracts_1.IEvents.TESTSTARTED, this.toJSON()); const start = (0, time_span_1.default)(); /* istanbul ignore else */ if (!this._todo && !this._skip) { /** * Run the actual test */ try { await this._runTest(); /** * Mark test as failed, when is regression but passed */ if (this._regression) { throw new Exceptions_1.RegressionException('Expected regression test to fail'); } } catch (error) { this._error = error; if (!this._isHardException && this._regression) { this._regressionMessage = error.message; } } } this._duration = start.rounded(); this._completed = true; Emitter_1.emitter.emit(Contracts_1.IEvents.TESTCOMPLETED, this.toJSON()); } } exports.Test = Test;