nightwatch
Version:
Easy to use Node.js based end-to-end testing solution for web applications using the W3C WebDriver API.
1,162 lines (928 loc) • 31.1 kB
JavaScript
const AssertionError = require('assertion-error');
const {By, Key, locateWith, withTagName} = require('selenium-webdriver');
const Reporter = require('../reporter');
const Context = require('./context.js');
const TestHooks = require('./hooks.js');
const TestCase = require('./testcase.js');
const Runnable = require('./runnable.js');
const Transport = require('../transport/selenium-webdriver');
const NightwatchAssertError = require('../assertion').AssertionError;
const SuiteRetries = require('./retries.js');
const NightwatchClient = require('../core/client.js');
const Concurrency = require('../runner/concurrency');
const ElementGlobal = require('../api/_loaders/element-global.js');
const {Logger, Screenshots, Snapshots, alwaysDisplayError, isString, isFunction, SafeJSON} = require('../utils');
const NightwatchInspectorServer = require('./nightwatch-inspector');
const {DEFAULT_RUNNER_EVENTS, NightwatchEventHub} = require('../runner/eventHub');
const {GlobalHook, TestSuiteHook} = DEFAULT_RUNNER_EVENTS;
class TestSuite {
constructor({modulePath, modules, settings, argv, usingMocha = false, addtOpts = {}}) {
this.settings = settings;
this.argv = argv;
this.modulePath = modulePath;
this.allModulePaths = modules;
this.testcase = null;
this.currentRunnable = null;
this.usingMocha = usingMocha;
this.reuseBrowser = argv['reuse-browser'] || (settings.globals && settings.globals.reuseBrowserSession);
this.globalHooks = addtOpts.globalHooks || {};
if (addtOpts.globalsInstance) {
this.globalsInstance = addtOpts.globalsInstance;
}
this.__reportPrefix = '';
this.mochaContext = new Promise(resolve => {
this.mochaContextResolve = resolve;
});
}
get api() {
return this.client.api;
}
get commandQueue() {
if (!this.client) {
return null;
}
return this.client.queue;
}
get reportPrefix() {
return this.__reportPrefix;
}
get transport() {
return this.client.transport;
}
get skipTestcasesOnFail() {
const localDefinedValue = this.context.getSkipTestcasesOnFail();
if (localDefinedValue !== undefined) {
return localDefinedValue;
}
const settingsValueUndefined = this.settings.skip_testcases_on_fail === undefined;
if (settingsValueUndefined && this.context.unitTestingMode) {
// false by default when running unit tests
return false;
}
// true by default when not running unit tests
return settingsValueUndefined || this.settings.skip_testcases_on_fail;
}
get endSessionOnFail() {
const definedValue = this.context.getEndSessionOnFail();
return definedValue === undefined ? this.settings.end_session_on_fail : definedValue;
}
get isES6Async() {
return this.client && (this.client.isES6AsyncTestcase || this.client.isES6AsyncTestHook);
}
get failFastMode() {
return this.argv['fail-fast'] || this.settings.enable_fail_fast;
}
isComponentTestingMode() {
return this.api.globals.component_tests_mode;
}
isE2EPreviewMode() {
return this.argv['launch-url'];
}
shouldSkipTestsOnFail() {
return this.skipTestcasesOnFail && !this.context.unitTestingMode || this.failFastMode;
}
async initCommon(opts = {}) {
if (!this.settings.unit_testing_mode) {
this.addPropertiesToGlobalScope();
}
await this.initClient(opts);
if (this.isE2EPreviewMode()) {
this.context = {
getDesiredCapabilities() {},
isDisabled() {
return false;
}
};
this.reporter = {
registerTestError(err) {
Logger.error(err);
}
};
} else {
await this.createContext(opts);
}
this.mochaContextResolve(this.context);
this.setSuiteName();
this.setRetries();
}
async init(opts = {}) {
await this.initCommon(opts);
this.updateClient();
this.setupHooks();
return this;
}
setModulePath(file) {
this.modulePath = file;
this.context.modulePath = file;
}
validateNightwatchInspectorCriteria() {
return (
this.argv.debug &&
Concurrency.isMasterProcess() &&
this.client.api.isChrome()
);
}
async initClient({initialize = true} = {}) {
const settings = Object.assign({}, this.settings);
this.client = NightwatchClient.create(settings, this.argv);
if (initialize) {
await this.client.initialize();
}
if (this.validateNightwatchInspectorCriteria()) {
this.globalsInstance.inspectorServer?.closeSocket();
this.globalsInstance.inspectorServer = new NightwatchInspectorServer(this.client);
}
}
updateClient() {
// this is necessary because mocha as a different suite setup flow
if (!this.settings.disable_global_apis) {
Object.defineProperty(global, 'browser', {
configurable: true,
get: function() {
return this.client.api;
}.bind(this)
});
}
if (this.settings.sync_test_names) {
this.client.mergeCapabilities({
name: this.suiteName
});
}
if (this.context.getDesiredCapabilities()) {
this.client.mergeCapabilities(this.context.getDesiredCapabilities());
}
this.client.createTransport();
if (!this.isE2EPreviewMode()) {
this.createReporter();
this.client
.setReporter(this.reporter)
.setCurrentTest();
}
return this;
}
async retrySuite() {
this.suiteRetries.incrementSuiteRetriesCount();
await this.terminate('RETRY_SUITE');
await this.createContext({reloadModuleCache: this.context.usingBddDescribe});
await this.createClient();
this.setupHooks();
return this.run();
}
createReporter() {
if (!this.context) {
throw new Error('Context must be created before creating the reporter.');
}
const {suiteRetries, suiteName} = this;
const {tests, moduleKey, modulePath, groupName, skippedTests, allScreenedTests} = this.context;
this.reporter = new Reporter({
settings: this.client.settings,
tests,
suiteRetries,
addOpts: {
reporter: this.argv.reporter,
suiteName,
moduleKey,
modulePath,
reportPrefix: '',
reportFileName: this.argv['report-filename'],
groupName,
isMobile: this.client.api.isMobile(),
tags: this.context.getTags()
},
skippedTests,
allScreenedTests
});
}
async createClient(client = null) {
if (client) {
this.client = client;
return this;
}
await this.initClient();
this.updateClient();
return this;
}
async createContext({context = null, reloadModuleCache = false, suiteTitle = null, attributes = {}} = {}) {
if (context) {
this.context = context;
return this;
}
const {modulePath, settings, argv, client} = this;
this.context = new Context({modulePath, settings, argv, attributes});
if (settings.tag_filter && settings.tag_filter.length > 0) {
reloadModuleCache = true;
}
this.context.setReloadModuleCache(reloadModuleCache);
await this.context.init({usingMocha: this.usingMocha, suiteTitle, client});
this.context.setReportKey(this.allModulePaths);
return this;
}
addPropertiesToGlobalScope() {
if (this.settings.disable_global_apis) {
return null;
}
Object.defineProperty(global, 'app', {
configurable: true,
get: function() {
return global.browser;
}
});
Object.defineProperty(global, 'by', {
configurable: true,
get: function() {
return By;
}
});
Object.defineProperty(global, 'By', {
configurable: true,
get: function() {
return By;
}
});
Object.defineProperty(global, 'locateWith', {
configurable: true,
get: function() {
return locateWith;
}
});
Object.defineProperty(global, 'withTagName', {
configurable: true,
get: function() {
return withTagName;
}
});
Object.defineProperty(global, 'Keys', {
configurable: true,
get: function() {
return Key;
}
});
Object.defineProperty(global, 'element', {
configurable: true,
value: function(locator, options = {}) {
return ElementGlobal.element({locator, testSuite: this, options, client: this.client});
}.bind(this),
writable: false
});
if (this.settings.disable_global_expect) {
return null;
}
const globalExpect = function(...args) {
return global.browser.expect(...args);
};
Object.defineProperty(globalExpect, 'element', {
value: function(...args) {
return global.browser.expect.element(...args);
},
writable: false
});
Object.defineProperty(globalExpect, 'elements', {
value: function(...args) {
return global.browser.expect.elements(...args);
},
writable: false
});
Object.defineProperty(globalExpect, 'component', {
value: function(...args) {
return global.browser.expect.component(...args);
},
writable: false
});
Object.defineProperty(globalExpect, 'title', {
value: function(...args) {
return global.browser.expect.title(...args);
},
writable: false
});
Object.defineProperty(globalExpect, 'cookie', {
value: function(...args) {
return global.browser.expect.cookie(...args);
},
writable: false
});
Object.defineProperty(globalExpect, 'url', {
value: function(...args) {
return global.browser.expect.url(...args);
},
writable: false
});
Object.freeze(globalExpect);
Object.defineProperty(global, 'expect', {
configurable: true,
get: function() {
return globalExpect;
}
});
}
setUncaughtError(err) {
this.uncaughtError = err;
}
setReportPrefix(data) {
this.settings.report_prefix = this.__reportPrefix = '';
if (!data) {
return this;
}
const capabilities = data.capabilities || {};
const browserName = (capabilities.browserName && capabilities.browserName.toUpperCase()) || '';
const browserVersion = capabilities.version || capabilities.browserVersion || '';
const platformVersion = capabilities.platform || capabilities.platformVersion || '';
if (!this.context.unitTestingMode) {
this.settings.report_prefix = this.__reportPrefix = `${browserName}_${browserVersion}_${platformVersion}_`.replace(/ /g, '_');
}
this.reporter.setFileNamePrefix(this.reportPrefix);
return this;
}
setRetries() {
if (this.isE2EPreviewMode()) {
return this;
}
this.suiteRetries = new SuiteRetries({
retries: this.context.retries.testcase || this.argv.retries,
suiteRetries: this.context.retries.suite || this.argv.suiteRetries
});
return this;
}
setSuiteName() {
if (this.isE2EPreviewMode()) {
this.suiteName = 'Preview';
} else {
this.suiteName = this.context.getSuiteName();
}
return this;
}
/**
* Instantiates the test hooks
*
* @return {TestSuite}
*/
setupHooks() {
this.hooks = new TestHooks(this.context, {
asyncHookTimeout: this.settings.globals.asyncHookTimeout
});
return this;
}
runHook(hookName) {
Logger.log(`${Logger.colors.green('→')} Running [${hookName}]:`);
if (this.context.hasHook(hookName)) {
NightwatchEventHub.emit(TestSuiteHook[hookName].started, this.reporter.testResults.eventDataToEmit);
}
if (hookName === 'beforeEach' || hookName === 'afterEach') {
this.client.reporter.markHookRun(hookName);
}
if (hookName === 'before' || hookName === 'after') {
this.client.reporter.setCurrentSection({testName: `__${hookName}_hook`});
}
return this.handleRunnable(hookName, () => {
return this.hooks[hookName].run(this.client);
}).then(result => {
if (this.context.hasHook(hookName)) {
NightwatchEventHub.emit(TestSuiteHook[hookName].finished, this.reporter.testResults.eventDataToEmit);
}
if (hookName === 'beforeEach' || hookName === 'afterEach') {
this.client.reporter.unmarkHookRun(hookName);
}
Logger.log(`${Logger.colors.green('→')} Completed [${hookName}].`);
return result;
});
}
runGlobalHook(hookName) {
const {globals} = this.settings;
if (globals[hookName]) {
NightwatchEventHub.emit(GlobalHook[hookName].started, this.reporter.testResults.eventDataToEmit);
}
if (!this.globalHooks[hookName]) {
return Promise.resolve();
}
this.client.reporter.setCurrentSection({testName: `__global_${hookName}_hook`});
return this.handleRunnable(hookName, async () => {
if (this.globalsInstance) {
await this.globalsInstance.runPluginHook(hookName, [this.settings]);
}
const result = await this.globalHooks[hookName].run(this.client);
if (globals[hookName]) {
NightwatchEventHub.emit(GlobalHook[hookName].finished, this.reporter.testResults.eventDataToEmit);
}
this.onTestSectionFinished();
return result;
});
}
createSession() {
if (this.client.sessionId || this.context.unitTestingMode) {
return Promise.resolve();
}
const {argv, reuseBrowser} = this;
const {moduleKey} = this.context;
return this.client.createSession({argv, moduleKey, reuseBrowser}).catch(err => {
err.sessionCreate = true;
this.reporter.registerTestError(err);
throw err;
});
}
async startTestSuite() {
NightwatchEventHub.emit(TestSuiteHook.started, this.reporter.testResults.eventDataToEmit);
if (!this.client) {
await this.createClient();
this.setupHooks();
}
return this.createSession()
.then(data => {
this.setReportPrefix(data);
// Adding session info to report
if (data) {
this.reporter.setSessionInfo(data);
if (data.capabilities && data.capabilities['safari:deviceUDID']) {
this.settings.deviceUDID = data.capabilities['safari:deviceUDID'];
}
}
this.commandQueue.tree.on('asynctree:command:finished', this.onCommandFinished.bind(this));
return this.runGlobalHook('beforeEach');
});
}
/**
* Runs the test suite, including all hooks
*/
runTestSuite() {
if (this.isE2EPreviewMode()) {
return this.createSession()
.then(_ => {
const runnable = new Runnable('preview', _ => {
const url = isString(this.argv.preview) ? this.argv.preview : this.api.launchUrl;
this.api.url(url).pause();
});
return runnable.run(this.commandQueue);
})
.then(_ => this.stopSession());
}
return this.startTestSuite()
.then(() => this.runHook('before'))
.then(result => {
this.onTestSectionFinished();
if (result instanceof Error) {
Logger.error(result);
}
return this.runNextTestCase();
})
.catch(err => {
if (err.sessionCreate) {
throw err;
}
if (!this.isAssertionError(err) && !this.context.unitTestingMode && !this.failFastMode) {
if (!this.shouldSkipTestsOnFail()){
Logger.error(err);
}
err.displayed = true;
}
// testcase failed - this catch ensures that the after hook is being called
return err;
})
.then(possibleError => {
this.reporter.resetCurrentTestName();
return this.runHook('after')
.catch(err => {
// exceptions from after hook
if (!possibleError) {
possibleError = err;
}
return err;
})
.then(result => {
if ((possibleError instanceof Error) && this.failFastMode) {
throw possibleError;
}
this.onTestSectionFinished();
return result;
});
})
.catch(err => {
// testsuite failed - this catch ensures that the global afterEach will always run
return this.terminate('FAILED', err);
})
.then((errorOrFailures) => this.onTestSuiteFinished(errorOrFailures));
}
onTestSectionFinished() {
// called for all test cases and hooks (except for [before|after]_each hooks)
// ^ [before|after]_each hooks are considered part of the test case itself
this.reporter.setTestStatus();
this.reporter.setTestSectionElapsedTime();
this.reporter.collectTestSectionOutput();
}
onTestSuiteFinished(errorOrFailures = false) {
this.__snapShot = undefined;
return this.runGlobalHook('afterEach')
.then(result => {
if (!(errorOrFailures instanceof Error)) {
return result;
}
if ((errorOrFailures.sessionCreate && this.failFastMode)) {
//throw errorOrFailures;
}
if (this.failFastMode && !this.shouldRetrySuite(errorOrFailures)) {
throw errorOrFailures;
}
})
.catch(err => {
if (err.sessionCreate || this.failFastMode) {
throw err;
}
if (!err.displayed) {
Logger.error(err);
}
// catching errors thrown inside the global afterEach
return err;
})
.then(failedResult => {
if (this.shouldRetrySuite(errorOrFailures)) {
return this.retrySuite();
}
const failures = errorOrFailures || failedResult || !this.reporter.allTestsPassed;
return this.stopSession(failures);
});
}
onCommandFinished({node, result}) {
this.reporter.logCommandResult({node, result});
this.takeSnapshot(node);
}
async stopSession(failures) {
try {
await this.terminate(failures ? 'FAILED' : '');
} catch (err) {
Logger.error(`Could not stop session in ${this.suiteName}:`);
Logger.error(err);
}
return this.testSuiteFinished(failures);
}
sendReportToParentWorker() {
if (this.settings.use_child_process && typeof process.send === 'function') {
process.send(SafeJSON.stringify({
type: 'testsuite_finished',
itemKey: process.env.__NIGHTWATCH_ENV_LABEL,
results: this.reporter.exportResults(),
httpOutput: Logger.collectOutput()
}));
} else if (process.port && typeof process.port.postMessage === 'function') {
process.port.postMessage(SafeJSON.stringify({
type: 'testsuite_finished',
results: this.reporter.exportResults(),
httpOutput: Logger.collectOutput()
}));
}
}
testSuiteFinished(failures) {
this.reporter.testSuiteFinished();
this.currentRunnable = null;
if (Concurrency.isWorker()) {
this.sendReportToParentWorker();
}
NightwatchEventHub.emit(TestSuiteHook.finished, this.reporter.testResults.eventDataToEmit);
return failures;
}
async sessionFinished(reason) {
let lastError = null;
if (reason === 'FAILED' || reason === 'RETRY_SUITE') {
lastError = this.reporter.testResults.lastError;
}
await this.transport.sessionFinished(reason, lastError);
}
async terminate(reason = 'SIGINT', potentialError = null, endSession = !this.reuseBrowser) {
this.resetQueue();
if (!this.client.sessionId || this.context.unitTestingMode) {
try {
await this.sessionFinished(reason);
} catch (err) {
return err;
}
return potentialError;
}
if (!this.endSessionOnFail && reason === 'FAILED') {
// Keep the session open; avoid reusing of same session
Transport.driver = null;
Transport.driverService = null;
return potentialError;
}
if (endSession) {
const runnable = new Runnable('terminate', _ => {
if (this.api && isFunction(this.api.end)) {
this.api.end(endSession);
}
}, {
isES6Async: this.isES6Async
});
return runnable
.run(this.commandQueue)
.then(async result => {
try {
await this.sessionFinished(reason);
} catch (err) {
return err;
}
return result;
})
.then(result => {
if ((potentialError instanceof Error) && (potentialError.sessionCreate || this.failFastMode)) {
return potentialError;
}
return result;
});
}
}
setReporterCurrentTest() {
// called for every test case (not for hooks)
this.reporter.setCurrentTest(this.testcase, this.context);
this.client.setCurrentTest();
return this;
}
/**
* Sets the next testcase and starts running it, if there is one
*
* @return {Promise}
*/
runNextTestCase() {
const nextTestCase = this.context.getNextKey();
if (nextTestCase) {
return this.runCurrentTest(nextTestCase);
}
return Promise.resolve();
}
/**
* Runs the current testcase, including retries
*
* @param testName
* @return {Promise}
*/
runCurrentTest(testName) {
const {reporter, context, settings} = this;
this.testcase = new TestCase(testName, {
context,
settings,
reporter,
addtOpts: {
retriesCount: this.suiteRetries.testRetriesCount[testName],
maxRetries: this.suiteRetries.testMaxRetries
}
});
this.setReporterCurrentTest().emptyQueue();
return this.createSession()
.then(() => this.runHook('beforeEach'))
.then(_ => {
this.client.reporter.markHookRun('testcase');
NightwatchEventHub.emit(TestSuiteHook.test.started, {
...this.reporter.testResults.eventDataToEmit,
testcase: this.reporter.testResults.currentTestName
});
return this.handleRunnable(this.testcase.testName, () => this.testcase.run(this.client));
})
.catch(err => {
return err;
})
.then(possibleError => {
this.client.reporter.unmarkHookRun();
NightwatchEventHub.emit(TestSuiteHook.test.finished, {
...this.reporter.testResults.eventDataToEmit,
testcase: this.reporter.testResults.currentTestName
});
if (this.transport.driverService && this.reporter.testResults) {
this.reporter.testResults.setSeleniumLogFile(this.transport.driverService.getSeleniumOutputFilePath());
}
// if there was an error in the testcase and skip_testcases_on_fail, we must send it forward, but after we run afterEach and after hooks
return this.runHook('afterEach')
.then(() => this.testCaseFinished())
.then(() => possibleError);
})
.then(possibleError => {
if (this.shouldRetryTestCase()) {
return this.retryCurrentTestCase();
}
if ((possibleError instanceof Error) && this.shouldSkipTestsOnFail()) {
throw possibleError;
}
return this.runNextTestCase();
});
}
testCaseFinished() {
this.reporter.setElapsedTime();
this.onTestSectionFinished();
if (!this.testcase) {
return Promise.resolve();
}
return this.reporter.printTestResult();
}
shouldRetryTestCase() {
return !this.reporter.currentTestCasePassed && this.suiteRetries.shouldRetryTest(this.testcase.testName);
}
retryCurrentTestCase() {
const currentTestName = this.testcase.testName;
this.suiteRetries.incrementTestRetriesCount(currentTestName);
this.reporter.resetCurrentTestPassedCount();
this.reporter.testResults.retryTest = true;
this.commandQueue.clearScheduled();
return this.runCurrentTest(currentTestName);
}
isScreenshotEnabled() {
return this.settings.screenshots.enabled;
}
shouldTakeScreenshotOnError() {
return this.isScreenshotEnabled() && this.settings.screenshots.on_error;
}
shouldTakeScreenshotOnFailure() {
return this.isScreenshotEnabled() && this.settings.screenshots.on_failure;
}
getScreenshotFilenamePath() {
return Screenshots.getFileName({
testSuite: this.api.currentTest.module,
testCase: this.api.currentTest.name
}, this.settings.screenshots);
}
takeScreenshot() {
const fileNamePath = this.getScreenshotFilenamePath();
const runnable = new Runnable('screenshot', _ => {
return new Promise((resolve) => {
this.api.saveScreenshot(fileNamePath, (result, err) => {
if (!err && this.transport.isResultSuccess(result)) {
const assertions = this.api.currentTest.results.assertions || [];
const commands = this.reporter.currentSection.commands || [];
if (assertions.length > 0) {
const currentAssertion = assertions[assertions.length - 1];
const currentCommand = commands[commands.length - 1];
if (currentAssertion) {
currentAssertion.screenshots = currentAssertion.screenshots || [];
currentAssertion.screenshots.push(fileNamePath);
}
if (currentCommand) {
currentCommand.screenshot = fileNamePath;
}
}
} else {
Logger.warn('Error saving screenshot...', err || result);
}
resolve();
});
});
});
return runnable.run(this.commandQueue);
}
takeSnapshot(node) {
const commands = this.reporter.currentSection.commands || [];
const currentCommand = commands[commands.length - 1];
if (this.settings.trace.enabled && node.isTraceable) {
const snapShotPath = Snapshots.getFileName({
testSuite: this.api.currentTest.module,
commandName: node.fullName,
traceSettings: this.settings.trace,
output_folder: this.settings.output_folder
});
this.__snapShot = new Promise((resolve, reject) => {
this.api.saveSnapshot(snapShotPath, (result => {
if (currentCommand) {
currentCommand.domSnapshot = result;
}
resolve(result);
}));
});
} else {
if (currentCommand && this.__snapShot) {
this.__snapShot.then(prevSnapshot => {
currentCommand.domSnapshot = prevSnapshot;
});
}
}
}
shouldRetrySuite(failures = false) {
if ((failures instanceof Error) && alwaysDisplayError(failures)) {
return false;
}
return (failures || !this.reporter.allTestsPassed) && this.suiteRetries.shouldRetrySuite();
}
async executeRunnable(name, fn) {
this.currentRunnable = new Runnable(name, fn, {
isES6Async: this.isES6Async
});
if (!this.context) {
return;
}
this.context.setCurrentRunnable(this.currentRunnable);
try {
const result = await this.currentRunnable.run(this.commandQueue);
return result;
} catch (err) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(err);
}, 50);
});
}
}
async handleRunnable(name, fn) {
try {
const result = await this.executeRunnable(name, fn);
return result;
} catch (err) {
// if some other error was thrown, jump to the next catch
err.name = err.name || '';
if (!this.isAssertionError(err) && err.name !== 'TypeError') {
// registering non-assert errors
this.reporter.registerTestError(err);
if (this.shouldTakeScreenshotOnError()) {
await this.takeScreenshot();
}
throw err;
}
// if the assertion error was thrown by another assertion library
if (!(err instanceof NightwatchAssertError)) {
const failureMessage = `expected "${err.expected}" but got: "${err.actual}"`;
if (err.actual !== undefined && err.expected !== undefined) {
err.message += ` - ${failureMessage}`;
}
Logger.error(err);
this.reporter.registerFailed(err);
this.reporter.logAssertResult({
name: err.name,
message: err.message,
stackTrace: err.stack,
fullMsg: err.message,
failure: failureMessage
});
}
if (this.shouldTakeScreenshotOnFailure()) {
await this.takeScreenshot();
}
// clearing the queue here to avoid continuing with the rest of the testcase,
// unless abortOnFailure is set to false
if (!this.isAssertionError(err) || err.abortOnFailure) {
this.emptyQueue();
}
// set to true inside before/beforeEach hooks
if (err.skipTestCases) {
throw err;
}
return err;
}
}
print() {
if (this.isE2EPreviewMode()) {
Logger.info('Previewing...');
return this;
}
if (this.settings.output) {
let testSuiteDisplay;
const retriesCount = this.suiteRetries.suiteRetriesCount;
if (this.context.unitTestingMode) {
testSuiteDisplay = this.context.moduleName || this.context.moduleKey;
} else {
testSuiteDisplay = `[${this.suiteName}] Test Suite`;
}
if (this.settings.test_workers && !this.settings.live_output || this.context.unitTestingMode) {
// eslint-disable-next-line no-console
console.log('');
}
if (retriesCount > 0) {
// eslint-disable-next-line no-console
console.log('\nRetrying: ', Logger.colors.red(testSuiteDisplay), `(${retriesCount}/${this.suiteRetries.suiteMaxRetries}): `);
} else if (this.context.unitTestingMode) {
// eslint-disable-next-line no-console
(this.context.isDisabled() ? Logger.info : console.log)(Logger.colors.cyan('[' + this.context.moduleKey + ']'));
} else {
Logger[this.context.isDisabled() ? 'info' : 'logDetailedMessage'](`\n${Logger.colors.cyan(testSuiteDisplay)}`);
}
if (!this.context.unitTestingMode) {
Logger[this.context.isDisabled() ? 'info' : 'logDetailedMessage'](Logger.colors.purple(new Array(Math.min(testSuiteDisplay.length * 2 + 1, 80)).join('─')));
}
}
return this;
}
resetQueue() {
if (!this.commandQueue) {
return this;
}
this.commandQueue.reset().removeAllListeners();
return this;
}
emptyQueue() {
this.resetQueue();
if (this.commandQueue) {
this.commandQueue.empty();
}
return this;
}
/**
*
* @return {*}
*/
run() {
this.print();
if (this.context.isDisabled()) {
// eslint-disable-next-line no-console
console.log(Logger.colors.green(`Testsuite "${this.context.moduleName}" is disabled, skipping...`));
// send report even if test is skipped
if (Concurrency.isWorker()) {
this.sendReportToParentWorker();
}
return Promise.resolve();
}
return this.runTestSuite();
}
isAssertionError(err) {
return (err instanceof AssertionError) || err.name.startsWith('AssertionError');
}
}
module.exports = TestSuite;
module.exports.Context = Context;