"use strict";
const path = require("path");
const _ = require("lodash");
const U = require("glace-utils");
const CONF = require("../config");
const TestCase = require("../testing").TestCase;
const ScopeType = require("../testing").ScopeType;
const setLog = require("../utils").setLog;
const _test = (names => {
return (name, fixtures, opts, func) => {
CONF.test.id++;
CONF.chunk.id = 0;
let preloaded_passed_chunk_ids;
if (CONF.filter.testIds && !CONF.filter.testIds.includes(CONF.test.id)) return;
if (CONF.filter.include) {
let isIncluded = false;
for (const include of CONF.filter.include) {
if (isFilterMatched(name, include.id)) {
preloaded_passed_chunk_ids = include.passed_chunk_ids;
isIncluded = true;
break;
}
}
if (!isIncluded) return;
}
if (CONF.filter.exclude) {
for (const exclude of CONF.filter.exclude) {
if (isFilterMatched(name, exclude.id)) return;
}
}
if (CONF.test.checkNames && !CONF.retry.id) {
if (names.includes(name)) {
throw new Error(`Test case '${name}' is added already`);
}
names.push(name);
}
const skip = !!opts.skip;
const skipReason = _.isString(opts.skip) ? opts.skip : null;
const retries = U.defVal(opts.retry, CONF.test.retries, 0);
opts.chunkRetry = U.defVal(opts.chunkRetry, CONF.chunk.retries, 0);
opts.chunkTimeout = U.defVal(opts.chunkTimeout);
let testCase;
if (!CONF.retry.id) {
testCase = new TestCase(name, CONF.test.id);
testCase.addPassedChunkIds(preloaded_passed_chunk_ids || []);
CONF.test.cases.push(testCase);
if (skip) {
testCase.status = TestCase.SKIPPED;
if (skipReason) testCase.addDetails(skipReason);
}
} else {
testCase = CONF.test.cases.filter(t => t.id === CONF.test.id)[0];
expect(testCase, "Oops! Testcase isn't found by id").to.exist;
}
if (testCase.status === TestCase.SKIPPED) return;
if (!CONF.retry.chunkIds[retries]) CONF.retry.chunkIds[retries] = [];
CONF.retry.curChunkIds = CONF.retry.chunkIds[retries];
testFunc({ testCase, fixtures, opts, func });
};
})([]);
const testFunc = ({ testCase, fixtures, opts, func }) => {
fixtures = [initTestFixture(testCase)].concat(fixtures);
const scopeType = new ScopeType(testCase.name).setType("test");
scope(scopeType, fixtures, opts, () => {
func();
});
};
const initTestFixture = testCase => {
return U.makeFixture({ before: beforeCb(testCase), after: afterCb });
};
const beforeCb = testCase => ctx => () => {
ctx.testCase = testCase;
ctx.testCase.reset();
ctx.testCase.start();
CONF.test.curCase = ctx.testCase;
CONF.report.testDir = path.resolve(
CONF.report.dir, "tests", U.toKebab(ctx.testCase.name));
setLog(); // Current test case is started, need to reinit log
};
const afterCb = ctx => () => {
if (ctx.testCase.errors.length) {
ctx.testCase.end(TestCase.FAILED);
} else {
ctx.testCase.end(TestCase.PASSED);
}
};
const isFilterMatched = (testName, filterId) => {
if (filterId == CONF.test.id) return true;
filterId = filterId.toString();
if (CONF.filter.precise) {
return testName.toLowerCase() === filterId.toLowerCase();
} else {
return testName.toLowerCase().includes(filterId.toLowerCase());
}
};
/**
* Global function, existing in `glace` tests, which creates test case.
*
* @global
* @function
* @arg {string} name - Name of test case. By default, should be unique in session.
* But uniqueness check can be skipped with CLI option `--dont-check-names`.
* @arg {object} [opts] - Options.
* @arg {boolean|string} [opts.skip=false] - Flag to skip test or skip reason message.
* @arg {?number} [opts.retry=null] - Number of test retries on failure. Overrides
* [config](GlaceConfig.html#test-retry) settings.
* @arg {?number} [opts.chunkRetry=null] - <a name="test-chunk-retry" href="#test-chunk-retry">#</a>
* Number of chunk retries on failure. Overrides [config](GlaceConfig.html#test-chunk-retry) settings.
* @arg {?number} [opts.chunkTimeout=null] - <a name="test-chunk-timeout" href="#test-chunk-timeout">#</a>
* Time to execute chunk or hook, **sec**. Overrides [config](GlaceConfig.html#test-chunk-timeout) settings.
* @arg {function[]} [fixtures] - Involved [fixtures](tutorial-common-used-funcs.html#fixtures) list.
* @arg {function} func - Сallback function with [chunks](#chunk__anchor) and hooks.
*
* @example <caption><b>Simple test</b></caption>
*
* test("Some test", () => {
* chunk("Some chunk", () => {
* someFunc();
* });
* });
*
* @example <caption><b>Test with retry</b></caption>
*
* test("Test with retry", { retry: 2 }, () => {
* chunk(() => {
* someFunc();
* });
* });
*
* @example <caption><b>Test with fixtures</b></caption>
*
* test("Test with fixtures", null, [fix_func_1, fix_func_2], () => {
* chunk(() => {
* someFunc();
* });
* });
*/
const test = (name, fixtures, opts, func) => {
if (_.isFunction(opts)) [func, opts] = [opts];
if (_.isPlainObject(fixtures)) [opts, fixtures] = [fixtures];
if (_.isFunction(fixtures)) [func, fixtures] = [fixtures];
fixtures = fixtures || [];
opts = opts || {};
_test(name, fixtures, opts, func);
};
module.exports = test;