diff --git a/lib/listener/globalTimeout.js b/lib/listener/globalTimeout.js index 3cfc4de9d..07bed2807 100644 --- a/lib/listener/globalTimeout.js +++ b/lib/listener/globalTimeout.js @@ -4,7 +4,7 @@ const recorder = require('../recorder') const Config = require('../config') const store = require('../store') const debug = require('debug')('codeceptjs:timeout') -const { TIMEOUT_ORDER, TimeoutError, TestTimeoutError } = require('../timeout') +const { TIMEOUT_ORDER, TimeoutError, TestTimeoutError, StepTimeoutError } = require('../timeout') const { BeforeSuiteHook, AfterSuiteHook } = require('../mocha/hooks') module.exports = function () { @@ -124,9 +124,17 @@ module.exports = function () { if (!store.timeouts) return recorder.catchWithoutStop(err => { - if (timeout && err instanceof TimeoutError && +Date.now() - step.startTime >= timeout) { + // we wrap timeout errors in a StepTimeoutError + // but only if global timeout is set + // should we wrap all timeout errors? + if (err instanceof TimeoutError) { + const testTimeoutExceeded = timeout && +Date.now() - step.startTime >= timeout debug('Step failed due to global test or suite timeout') - throw new TestTimeoutError(currentTimeout) + if (testTimeoutExceeded) { + debug('Test failed due to global test or suite timeout') + throw new TestTimeoutError(currentTimeout) + } + throw new StepTimeoutError(currentTimeout, step) } throw err }) diff --git a/lib/mocha/cli.js b/lib/mocha/cli.js index bf54ad346..313bb8834 100644 --- a/lib/mocha/cli.js +++ b/lib/mocha/cli.js @@ -192,9 +192,12 @@ class Cli extends Base { if (lines.length > 5) { truncatedLines.push('...') } - err.message = '\n ' + truncatedLines.join('\n').replace(/^/gm, ' ').trim() + err.message = truncatedLines.join('\n').replace(/^/gm, ' ').trim() } + // add new line before the message + err.message = '\n ' + err.message + const steps = test.steps || (test.ctx && test.ctx.test.steps) if (steps && steps.length) { diff --git a/lib/recorder.js b/lib/recorder.js index 97bbd9cb8..5f7dbd59b 100644 --- a/lib/recorder.js +++ b/lib/recorder.js @@ -386,7 +386,7 @@ function getTimeoutPromise(timeoutMs, taskName) { return [ new Promise((done, reject) => { timer = setTimeout(() => { - reject(new TimeoutError(`Action ${taskName} was interrupted on step timeout ${timeoutMs}ms`)) + reject(new TimeoutError(`Action ${taskName} was interrupted on timeout ${timeoutMs}ms`)) }, timeoutMs || 2e9) }), timer, diff --git a/lib/timeout.js b/lib/timeout.js index 1260587ba..ba9ba43b8 100644 --- a/lib/timeout.js +++ b/lib/timeout.js @@ -50,9 +50,17 @@ class TestTimeoutError extends TimeoutError { } } +class StepTimeoutError extends TimeoutError { + constructor(timeout, step) { + super(`Step ${step.toCode().trim()} timed out after ${timeout}s`) + this.name = 'StepTimeoutError' + } +} + module.exports = { TIMEOUT_ORDER, getCurrentTimeout, TimeoutError, TestTimeoutError, + StepTimeoutError, } diff --git a/test/runner/timeout_test.js b/test/runner/timeout_test.js index a3c1ffefe..ef34048bd 100644 --- a/test/runner/timeout_test.js +++ b/test/runner/timeout_test.js @@ -33,7 +33,8 @@ describe('CodeceptJS Timeouts', function () { it('should ignore timeouts if no timeout', done => { exec(config_run_config('codecept.conf.js', 'no timeout test'), (err, stdout) => { debug_this_test && console.log(stdout) - expect(stdout).not.toContain('Timeout') + expect(stdout).not.toContain('TimeoutError') + expect(stdout).not.toContain('was interrupted on') expect(err).toBeFalsy() done() }) @@ -52,7 +53,7 @@ describe('CodeceptJS Timeouts', function () { it('should prefer step timeout', done => { exec(config_run_config('codecept.conf.js', 'timeout step', true), (err, stdout) => { debug_this_test && console.log(stdout) - expect(stdout).toContain('was interrupted on step timeout 200ms') + expect(stdout).toContain('was interrupted on timeout 200ms') expect(err).toBeTruthy() done() }) @@ -61,7 +62,7 @@ describe('CodeceptJS Timeouts', function () { it('should keep timeout with steps', done => { exec(config_run_config('codecept.timeout.conf.js', 'timeout step', true), (err, stdout) => { debug_this_test && console.log(stdout) - expect(stdout).toContain('was interrupted on step timeout 100ms') + expect(stdout).toContain('was interrupted on timeout 100ms') expect(err).toBeTruthy() done() })