flagpole
Version:
Simple and fast DOM integration, headless or headful browser, and REST API testing framework.
329 lines • 12.8 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SuiteTaskManager = void 0;
const bluebird = require("bluebird");
const util_1 = require("../util");
class SuiteTaskManager {
constructor(suite) {
this._scenarios = [];
this._dateStarted = null;
this._dateExecutionBegan = null;
this._dateExecutionCompleted = null;
this._dateFinished = null;
this._beforeAllCallbacks = [];
this._afterAllCallbacks = [];
this._successCallbacks = [];
this._failureCallbacks = [];
this._finallyCallbacks = [];
this._beforeEachCallbacks = [];
this._afterEachCallbacks = [];
this._statusCallbacks = [];
this._concurrencyLimit = 99;
this._maxScenarioDuration = 30000;
this._maxSuiteDuration = 60000;
this._finishedResolve = () => { };
this._suite = suite;
this._dateInitialized = Date.now();
this._finishedPromise = new Promise((resolve) => {
this._finishedResolve = resolve;
});
}
get finished() {
return this._finishedPromise;
}
get maxScenarioDuration() {
return this._maxScenarioDuration;
}
set maxScenarioDuration(value) {
this._maxScenarioDuration = value;
}
get maxSuiteDuration() {
return this._maxSuiteDuration;
}
set maxSuiteDuration(value) {
this._maxSuiteDuration = value;
}
get concurrencyLimit() {
return this._concurrencyLimit;
}
set concurrencyLimit(value) {
if (this.hasExecutionBegan) {
throw "Can not change concurrency limit after execution has started.";
}
this._concurrencyLimit = value;
}
get scenarioCount() {
return this._scenarios.length;
}
get hasStarted() {
return this._dateStarted !== null;
}
get hasExecutionBegan() {
return this._dateExecutionBegan !== null;
}
get hasExecutionCompleted() {
return this._dateExecutionCompleted !== null;
}
get hasFinished() {
return this._dateFinished !== null;
}
get canAllSuitesExecute() {
return !this._scenarios.some((scenario) => {
return !scenario.isReadyToExecute;
});
}
get haveAnyFailed() {
return this._scenarios.some((scenario) => {
return scenario.hasFailed;
});
}
get haveAllPassed() {
return this._scenarios.every((scenario) => {
return !scenario.hasFailed && scenario.hasFinished;
});
}
get totalDuration() {
return this._dateFinished !== null
? this._dateFinished - this._dateInitialized
: null;
}
get executionDuration() {
return this._dateExecutionBegan !== null &&
this._dateExecutionCompleted !== null
? this._dateExecutionCompleted - this._dateExecutionBegan
: null;
}
get scenarios() {
return [...this._scenarios];
}
get scenariosNotReadyToExecute() {
return this._scenarios.filter((scenario) => {
return !scenario.isReadyToExecute;
});
}
get scenariosReadyToExecute() {
return this._scenarios.filter((scenario) => {
return scenario.isReadyToExecute;
});
}
get scenariosFailed() {
return this._scenarios.filter((scenario) => {
return !scenario.hasPassed && scenario.hasExecuted;
});
}
get scenariosWaitingToExecute() {
return this._scenarios.filter((scenario) => {
return scenario.isPending;
});
}
get scenariosCurrentlyExcuting() {
return this._scenarios.filter((scenario) => {
return scenario.hasExecuted && !scenario.hasFinished;
});
}
beforeAll(a, b = false, c = false) {
if (this.hasStarted) {
throw "Can not add new beforeAll callback after suite has started running.";
}
this._addCallback("beforeAll", a, b, c);
}
beforeEach(a, b = false, c = false) {
if (this.hasFinished) {
throw "Can not add new beforeEach callback after suite has finished running.";
}
this._addCallback("beforeEach", a, b, c);
}
afterAll(a, b = false, c = false) {
if (this.hasFinished) {
throw "Can not add new afterAll callback after suite has finished running.";
}
this._addCallback("afterAll", a, b, c);
}
afterEach(a, b = false, c = false) {
if (this.hasFinished) {
throw "Can not add new afterEach callback after suite has finished running.";
}
this._addCallback("afterEach", a, b, c);
}
failure(a, b = false, c = false) {
if (this.hasFinished) {
throw "Can not add new failure callback after suite has finished running.";
}
this._addCallback("failure", a, b, c);
}
success(a, b = false, c = false) {
if (this.hasFinished) {
throw "Can not add new success callback after suite has finished running.";
}
this._addCallback("success", a, b, c);
}
finally(a, b = false, c = false) {
if (this.hasFinished) {
throw "Can not add new finally callback after suite has finished running.";
}
this._addCallback("finally", a, b, c);
}
registerScenario(scenario) {
if (this.hasExecutionCompleted) {
throw "Can not register new scenario after the suite has completed execution";
}
this._scenarios.push(scenario);
scenario.before(() => {
this._fireScenarioCallbacks(this._beforeEachCallbacks, scenario);
});
scenario.after(() => __awaiter(this, void 0, void 0, function* () {
this._fireScenarioCallbacks(this._afterEachCallbacks, scenario);
}));
setTimeout(() => {
this._go();
}, 10);
}
subscribe(callback) {
this._statusCallbacks.push(callback);
}
_go() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.hasStarted && this.scenarioCount > 0) {
this._dateStarted = Date.now();
yield this._fireSuiteCallbacks(this._beforeAllCallbacks);
yield this._executeScenarios();
yield this._fireSuiteCallbacks(this._afterAllCallbacks);
this.haveAllPassed
? yield this._fireSuiteCallbacks(this._successCallbacks)
: yield this._fireSuiteCallbacks(this._failureCallbacks);
yield this._fireSuiteCallbacks(this._finallyCallbacks);
this._finishedResolve();
}
});
}
_executeScenarios() {
return __awaiter(this, void 0, void 0, function* () {
if (this.hasExecutionBegan) {
throw "Execution already started";
}
this._dateExecutionBegan = Date.now();
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
const execute = () => __awaiter(this, void 0, void 0, function* () {
const scenariosExecuting = yield this._startExecutingScenarios();
if (scenariosExecuting === null) {
return resolve(this._cancelScenariosAnyNotFinished("Timed out"));
}
if (this.scenariosWaitingToExecute.length === 0) {
return resolve(this._markSuiteExecutionAsCompleted());
}
if (scenariosExecuting.length > 0) {
return execute();
}
util_1.runAsync(() => {
if (this.scenariosWaitingToExecute.length > 0 &&
this._dateExecutionBegan &&
Date.now() - this._dateExecutionBegan > this._maxSuiteDuration) {
resolve(this._cancelPendingScenarios("Suite timed out! This scenario was never called or had no assertions."));
}
if (this.scenariosWaitingToExecute.length > 0) {
return execute();
}
resolve(this._cancelPendingScenarios("Not able to execute"));
}, 50);
});
yield execute();
}));
});
}
_cancelPendingScenarios(reason) {
this.scenariosNotReadyToExecute.forEach((scenario) => {
scenario.cancel(`Cancelled this scenario. Reason: ${reason}`);
});
this._markSuiteExecutionAsCompleted();
return true;
}
_cancelScenariosAnyNotFinished(reason) {
this.scenarios.forEach((scenario) => {
if (!scenario.hasFinished) {
scenario.cancelOrAbort(`Aborted this scenario. Reason: ${reason}`);
}
});
this._markSuiteExecutionAsCompleted();
return true;
}
_startExecutingScenarios() {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
const batch = this.scenariosReadyToExecute;
const waitForBrowserToCloseBuffer = 200;
if (batch.length > 0) {
yield bluebird
.map(batch, (scenario) => __awaiter(this, void 0, void 0, function* () {
yield this._executeScenario(scenario);
yield scenario.waitForFinished();
yield new Promise((resolve) => setTimeout(resolve, waitForBrowserToCloseBuffer));
}), {
concurrency: this._concurrencyLimit,
})
.timeout(this.maxScenarioDuration + waitForBrowserToCloseBuffer)
.catch((err) => {
resolve(null);
});
}
resolve(batch);
}));
});
}
_markSuiteExecutionAsCompleted() {
this._dateExecutionCompleted = Date.now();
return true;
}
_executeScenario(scenario) {
return __awaiter(this, void 0, void 0, function* () {
if (scenario.hasExecuted) {
throw `Scenario ${scenario.title} has already started executing`;
}
if (!scenario.isReadyToExecute) {
throw `Scenario ${scenario.title} is not ready to execute`;
}
yield scenario.go();
return scenario;
});
}
_fireSuiteCallbacks(callbacks) {
return __awaiter(this, void 0, void 0, function* () {
return bluebird.mapSeries(callbacks, (callback) => {
return callback.callback(this._suite);
});
});
}
_fireScenarioCallbacks(callbacks, scenario) {
return __awaiter(this, void 0, void 0, function* () {
return bluebird.mapSeries(callbacks, (callback) => {
return callback.callback(scenario, this._suite);
});
});
}
_addCallback(whichCallback, a, b = false, c = false) {
const message = typeof a === "string" ? a : "";
const callback = (() => {
const callback = typeof b === "boolean" ? a : b;
return typeof callback === "string" ? () => { } : callback;
})();
const prepend = typeof b === "boolean" ? b : c;
const callbackAndMessage = {
callback: callback,
message: message,
};
const callbackArrayName = `_${whichCallback}Callbacks`;
prepend
? this[callbackArrayName].unshift(callbackAndMessage)
: this[callbackArrayName].push(callbackAndMessage);
}
}
exports.SuiteTaskManager = SuiteTaskManager;
//# sourceMappingURL=suite-task-manager.js.map