diff --git a/lib/browser_collection.js b/lib/browser_collection.js index 56486bd62..6eb16d8f5 100644 --- a/lib/browser_collection.js +++ b/lib/browser_collection.js @@ -46,8 +46,8 @@ class BrowserCollection { if (results.skipped && config.failOnSkippedTests) { return 1 } - if (results.success + results.failed === 0 && !config.failOnEmptyTestSuite) { - return 0 + if (results.success + results.failed === 0 && !!config.failOnEmptyTestSuite) { + return 1 } if (results.error) { return 1 diff --git a/lib/server.js b/lib/server.js index c1acb241c..6d44f390b 100644 --- a/lib/server.js +++ b/lib/server.js @@ -283,7 +283,7 @@ class Server extends KarmaEventEmitter { const emitRunCompleteIfAllBrowsersDone = () => { if (Object.keys(singleRunDoneBrowsers).every((key) => singleRunDoneBrowsers[key])) { - this.emit('run_complete', singleRunBrowsers, singleRunBrowsers.getResults(singleRunBrowserNotCaptured, config.failOnEmptyTestSuite, config.failOnFailingTestSuite)) + this.emit('run_complete', singleRunBrowsers, singleRunBrowsers.getResults(singleRunBrowserNotCaptured, config)) } } @@ -309,6 +309,8 @@ class Server extends KarmaEventEmitter { singleRunDoneBrowsers[completedBrowser.id] = true emitRunCompleteIfAllBrowsersDone() }) + + // This is the normal exit trigger. this.on('browser_complete_with_no_more_retries', function (completedBrowser) { singleRunDoneBrowsers[completedBrowser.id] = true diff --git a/test/unit/browser_collection.spec.js b/test/unit/browser_collection.spec.js index ca6cd65df..fc7ad5937 100644 --- a/test/unit/browser_collection.spec.js +++ b/test/unit/browser_collection.spec.js @@ -274,7 +274,7 @@ describe('BrowserCollection', () => { const results = { success: 0, failed: 0, - error: true + error: false } it('shall pass if failOnEmptyTestSuite not is set', () => { const res = collection.calculateExitCode(results) diff --git a/test/unit/server.spec.js b/test/unit/server.spec.js index c2d16c9bf..39941acb8 100644 --- a/test/unit/server.spec.js +++ b/test/unit/server.spec.js @@ -42,6 +42,7 @@ describe('server', () => { browsers: ['fake'], singleRun: true, logLevel: 'OFF', + plugins: [], browserDisconnectTolerance: 0 } @@ -271,20 +272,92 @@ describe('server', () => { server.emit('browser_register', {}) expect(browsersReady).to.have.been.called }) + describe('should exit with exit code', () => { + let resolveExitCode - it('should exit with error exit code on load errors', async () => { - mockProcess(process) + async function exitCode () { + return new Promise((resolve) => { + resolveExitCode = resolve + }) + } + + it('1 on load errors', async () => { + mockProcess(process) + + await server._start(mockConfig, mockLauncher, null, mockFileList, browserCollection, mockExecutor, (exitCode) => { + resolveExitCode(exitCode) + }) + server.loadErrors.push(['TestError', 'Test']) + fileListOnResolve() + + function mockProcess (process) { + sinon.stub(process, 'kill').callsFake((pid, ev) => process.emit(ev)) + } - await server._start(mockConfig, mockLauncher, null, mockFileList, browserCollection, mockExecutor, (exitCode) => { - expect(exitCode).to.have.equal(1) + expect(await exitCode()).to.have.equal(1) }) - server.loadErrors.push(['TestError', 'Test']) - fileListOnResolve() + it('given on run_complete', async () => { + mockProcess(process) - function mockProcess (process) { - sinon.stub(process, 'kill').callsFake((pid, ev) => process.emit(ev)) - } + await server._start(mockConfig, mockLauncher, null, mockFileList, browserCollection, mockExecutor, (exitCode) => { + resolveExitCode(exitCode) + }) + + server.emit('run_complete', browserCollection, { exitCode: 15 }) + + function mockProcess (process) { + sinon.stub(process, 'kill').callsFake((pid, ev) => process.emit(ev)) + } + expect(await exitCode()).to.have.equal(15) + }) + + it('1 on browser_process_failure (singleRunBrowserNotCaptured)', async () => { + mockProcess(process) + + await server._start(mockConfig, mockLauncher, null, mockFileList, browserCollection, mockExecutor, (exitCode) => { + resolveExitCode(exitCode) + }) + + server.emit('browser_process_failure', { id: 'fake' }) + + function mockProcess (process) { + sinon.stub(process, 'kill').callsFake((pid, ev) => process.emit(ev)) + } + expect(await exitCode()).to.have.equal(1) + }) + + it('0 on browser_complete_with_no_more_retries', async () => { + mockProcess(process) + + await server._start(mockConfig, mockLauncher, null, mockFileList, browserCollection, mockExecutor, (exitCode) => { + resolveExitCode(exitCode) + }) + + server.emit('browser_complete_with_no_more_retries', { id: 'fake' }) + + function mockProcess (process) { + sinon.stub(process, 'kill').callsFake((pid, ev) => process.emit(ev)) + } + expect(await exitCode()).to.have.equal(0) + }) + + it('1 on browser_complete_with_no_more_retries with config.failOnEmptyTestSuite', async () => { + mockProcess(process) + + mockConfig.failOnEmptyTestSuite = true + + await server._start(mockConfig, mockLauncher, null, mockFileList, browserCollection, mockExecutor, (exitCode) => { + resolveExitCode(exitCode) + }) + + server.emit('browser_complete_with_no_more_retries', { id: 'fake' }) + + function mockProcess (process) { + sinon.stub(process, 'kill').callsFake((pid, ev) => process.emit(ev)) + } + expect(await exitCode()).to.have.equal(1) + }) }) })