"use strict";
const _ = require("lodash");
const isPromise = require("is-promise");
const CONF = require("../config");
/**
* Global function, existing in `glace` tests, which creates test chunk.
*
* `chunk` is independently executed part of `test`. It means that even if
* first chunk is failed, other will be executed in any case. `test` should
* contain as minimum one `chunk`.
*
* @global
* @function
* @arg {string} [name=null] - Name of chunk.
* @arg {object} [opts] - Chunk options.
* @arg {?number} [opts.retry=null] - Number of chunk retries on failure. Overrides
* [config](GlaceConfig.html#test-chunk-retry) and [test](#test-chunk-retry) settings.
* @arg {?number} [opts.timeout=null] - Time limit to execute chunk, **sec**. Overrides
* [config](GlaceConfig.html#test-chunk-timeout) and [test](#test-chunk-timeout) settings.
* @arg {function} func - Callback function with test payload. Can be `async` too.
*
* @example <caption><b>Anonymous chunk</b></caption>
*
* test("My test", () => {
* chunk(() => {
* var a = 5;
* expect(a).to.be.equal(2);
* });
* });
*
* @example <caption><b>Named chunk</b></caption>
*
* test("My test", () => {
* chunk("My chunk", () => {
* var a = 5;
* expect(a).to.be.equal(2);
* });
* });
*
* @example <caption><b>Chunk with options</b></caption>
*
* test("My test", () => {
* chunk("My chunk", { retry: 2, timeout: 1 }, () => {
* var a = 5;
* expect(a).to.be.equal(2);
* });
* });
*
* @example <caption><b>Several chunks in test</b></caption>
*
* test("My test", () => {
* chunk("first chunk", () => {
* expect(2).to.be.equal(3);
* });
* chunk("second chunk", () => {
* expect(3).to.be.equal(3);
* });
* });
*
* @example <caption><b>Async chunk</b></caption>
*
* test("My test", () => {
* chunk(async () => {
* await Promise.resolve("done!");
* });
* });
*/
const chunk = (name, opts, func) => {
if (name instanceof Function) {
func = name;
name = "";
opts = {};
}
if (opts instanceof Function) {
func = opts;
opts = {};
}
if (name instanceof Object) {
opts = name;
name = "";
}
name = name || "";
opts = opts || {};
CONF.chunk.id++;
const chunkId = CONF.test.id + "_" + CONF.chunk.id;
if (CONF.chunk.passedIds.includes(chunkId)) return;
if (CONF.retry.id) {
if (!_.flatMap(CONF.retry.chunkIds).includes(chunkId)) return;
} else {
CONF.retry.curChunkIds.push(chunkId);
};
it(name, _chunkCb(name, chunkId, opts, func));
};
/**
* Chunk callback.
* @ignore
*/
const _chunkCb = (name, chunkId, opts, func) => function () {
expect(CONF.test.curCase, "Oops! Chunk is used outside of test").to.exist;
CONF.test.curCase.addChunk(name);
CONF.chunk.curId = chunkId;
if (opts.retry) this.retries(opts.retry);
if (opts.timeout) this.timeout(opts.timeout * 1000);
let result = func();
if (isPromise(result)) {
result = result.then(r => {
if (r === false) CONF.test.curCase.skipChunk = name;
return r;
});
} else {
if (result === false) CONF.test.curCase.skipChunk = name;
}
return result;
};
module.exports = chunk;