diff --git a/src/extension-runners/index.js b/src/extension-runners/index.js index ca81b68c58..13ec36ff34 100644 --- a/src/extension-runners/index.js +++ b/src/extension-runners/index.js @@ -76,8 +76,10 @@ export class MultiExtensionRunner { const promises = []; for (const runner of this.extensionRunners) { const reloadPromise = runner.reloadAllExtensions().then( - () => { - return { runnerName: runner.getName() }; + // Runners resolve with an array composed by a single + // ExtensionRunnerReloadResult object, which carries any reload error. + ([result] = []) => { + return { ...result, runnerName: runner.getName() }; }, (error) => { return { @@ -109,8 +111,10 @@ export class MultiExtensionRunner { const promises = []; for (const runner of this.extensionRunners) { const reloadPromise = runner.reloadExtensionBySourceDir(sourceDir).then( - () => { - return { runnerName: runner.getName(), sourceDir }; + // Runners resolve with an array composed by a single + // ExtensionRunnerReloadResult object, which carries any reload error. + ([result] = []) => { + return { ...result, runnerName: runner.getName(), sourceDir }; }, (error) => { return { @@ -172,10 +176,10 @@ export class MultiExtensionRunner { if (reloadError instanceof Error) { let message = 'Error occurred while reloading'; if (sourceDir) { - message += ` "${sourceDir}" `; + message += ` "${sourceDir}"`; } - message += `on "${runnerName}" - ${reloadError.message}`; + message += ` on "${runnerName}" - ${reloadError.message}`; log.error(`\n${message}`); log.debug(reloadError.stack); diff --git a/tests/unit/test-extension-runners/test.extension-runners.js b/tests/unit/test-extension-runners/test.extension-runners.js index 5ca7d34ab8..74551487c0 100644 --- a/tests/unit/test-extension-runners/test.extension-runners.js +++ b/tests/unit/test-extension-runners/test.extension-runners.js @@ -215,6 +215,101 @@ describe('util/extension-runners', () => { ); }); + it('logs errors resolved by the runners while reloading all extensions', async () => { + const params = prepareExtensionRunnerParams(); + // Like the Firefox runners, resolve with the reload error instead of + // rejecting. + const fakeExtensionRunner = createFakeExtensionRunner({ + overriddenMethods: { + getName: () => 'fakeExtensionRunner', + reloadAllExtensions: () => + Promise.resolve([ + { + runnerName: 'fakeExtensionRunner', + reloadError: new Error('reload error 1'), + }, + ]), + }, + }); + const anotherFakeExtensionRunner = createFakeExtensionRunner({ + overriddenMethods: { + getName: () => 'anotherFakeExtensionRunner', + reloadAllExtensions: () => + Promise.resolve([{ runnerName: 'anotherFakeExtensionRunner' }]), + }, + }); + + params.runners = [fakeExtensionRunner, anotherFakeExtensionRunner]; + const runnerInstance = new MultiExtensionRunner(params); + + consoleStream.flushCapturedLogs(); + const res = await runnerInstance.reloadAllExtensions(); + const { capturedMessages } = consoleStream; + const errors = res.filter((r) => r.reloadError); + + assert.equal(res.length, 2); + assert.equal(errors.length, 1); + assert.equal(errors[0].runnerName, 'fakeExtensionRunner'); + + assert.ok( + capturedMessages.some( + (msg) => + msg.includes('[error]') && + msg.includes('reloading on "fakeExtensionRunner"') && + msg.includes('reload error 1'), + ), + ); + }); + + it('collects reload errors resolved by the runners when reloading an extension', async () => { + const params = prepareExtensionRunnerParams(); + const sourceDir = '/fake/sourceDir'; + // Like the Firefox runners, resolve with the reload error instead of + // rejecting. + const fakeExtensionRunner = createFakeExtensionRunner({ + overriddenMethods: { + getName: () => 'fakeExtensionRunner', + reloadExtensionBySourceDir: () => + Promise.resolve([ + { + runnerName: 'fakeExtensionRunner', + reloadError: new Error('reload error 1'), + sourceDir, + }, + ]), + }, + }); + const anotherFakeExtensionRunner = createFakeExtensionRunner({ + overriddenMethods: { + getName: () => 'anotherFakeExtensionRunner', + reloadExtensionBySourceDir: () => + Promise.resolve([ + { runnerName: 'anotherFakeExtensionRunner', sourceDir }, + ]), + }, + }); + + params.runners = [fakeExtensionRunner, anotherFakeExtensionRunner]; + + const runnerInstance = new MultiExtensionRunner(params); + + consoleStream.flushCapturedLogs(); + const res = await runnerInstance.reloadExtensionBySourceDir(sourceDir); + const { capturedMessages } = consoleStream; + const errors = res.filter((r) => r.reloadError); + + assert.equal(res.length, 2); + assert.equal(errors.length, 1); + assert.equal(errors[0].runnerName, 'fakeExtensionRunner'); + assert.equal(errors[0].sourceDir, sourceDir); + + assert.ok( + capturedMessages.some( + (msg) => msg.includes('[error]') && msg.includes('reload error 1'), + ), + ); + }); + describe('registerCleanup', () => { it('calls its callbacks once all the runner callbacks have been called', async () => { const params = prepareExtensionRunnerParams();