diff --git a/packages/debugger-shell/src/node/__tests__/prepareDebuggerShell-test.js b/packages/debugger-shell/src/node/__tests__/prepareDebuggerShell-test.js new file mode 100644 index 000000000000..bfdb285109dd --- /dev/null +++ b/packages/debugger-shell/src/node/__tests__/prepareDebuggerShell-test.js @@ -0,0 +1,30 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + * @oncall react_native + */ + +jest.mock('../private/LaunchUtils', () => ({ + prepareDebuggerShellFromDotSlashFile: jest.fn(() => + Promise.reject(new Error('spawn failed')), + ), +})); + +const {unstable_prepareDebuggerShell} = require('../../'); + +describe('unstable_prepareDebuggerShell', () => { + test('returns a human readable message for unexpected errors', async () => { + const result = await unstable_prepareDebuggerShell({flavor: 'prebuilt'}); + + expect(result.code).toBe('unexpected_error'); + expect(result.verboseInfo).toBe('spawn failed'); + expect(result.humanReadableMessage).toContain( + 'Using a fallback version instead', + ); + }); +}); diff --git a/packages/debugger-shell/src/node/index.flow.js b/packages/debugger-shell/src/node/index.flow.js index 60140b75fcc3..0d3c8ac17ef2 100644 --- a/packages/debugger-shell/src/node/index.flow.js +++ b/packages/debugger-shell/src/node/index.flow.js @@ -175,6 +175,9 @@ async function unstable_prepareDebuggerShell({ } catch (e) { return { code: 'unexpected_error', + humanReadableMessage: + 'An unexpected error occurred while preparing React Native DevTools. ' + + 'Using a fallback version instead.', verboseInfo: e.message, }; } diff --git a/packages/dev-middleware/src/__tests__/StandaloneFuseboxShell-test.js b/packages/dev-middleware/src/__tests__/StandaloneFuseboxShell-test.js index 18f45b3f97e3..18da9d2a24a6 100644 --- a/packages/dev-middleware/src/__tests__/StandaloneFuseboxShell-test.js +++ b/packages/dev-middleware/src/__tests__/StandaloneFuseboxShell-test.js @@ -232,4 +232,38 @@ describe('enableStandaloneFuseboxShell experiment', () => { }); }); }); + + describe('preparation failure logging', () => { + const logger = { + error: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + }; + const {ToolLauncherWithFuseboxShell} = setupToolLauncherWithFuseboxShell( + () => + Promise.resolve({ + code: 'unexpected_error', + verboseInfo: 'LaunchProcess: failed to execvp', + }), + ); + const server = withServerForEachTest({ + logger, + unstable_toolLauncher: ToolLauncherWithFuseboxShell, + unstable_experiments: { + enableStandaloneFuseboxShell: true, + }, + }); + + test('logs an unexpected error as a non-fatal warning', async () => { + // Access the server to ensure the dev middleware has been created + expect(server.serverBaseUrl).toBeDefined(); + await jest.runOnlyPendingTimersAsync(); + + expect(logger.error).not.toHaveBeenCalled(); + expect(logger.warn).toHaveBeenCalledTimes(1); + const [message] = logger.warn.mock.calls[0]; + expect(message).toContain('Using a fallback version instead'); + expect(message).toContain('LaunchProcess: failed to execvp'); + }); + }); }); diff --git a/packages/dev-middleware/src/createDevMiddleware.js b/packages/dev-middleware/src/createDevMiddleware.js index f5f86461da8c..3cddcf75fa63 100644 --- a/packages/dev-middleware/src/createDevMiddleware.js +++ b/packages/dev-middleware/src/createDevMiddleware.js @@ -177,15 +177,16 @@ function createWrappedEventReporter( case 'not_implemented': break; case 'unexpected_error': { + // Preparation failures are not fatal: the debugger falls back to + // opening in a browser window, so log a warning, not an error. let message = event.result.humanReadableMessage ?? - 'An unknown error occurred while installing React Native DevTools.'; + 'An unknown error occurred while installing React Native DevTools. ' + + 'Using a fallback version instead.'; if (event.result.verboseInfo != null) { message += ` Details:\n\n${event.result.verboseInfo}`; - } else { - message += '.'; } - logger?.error(message); + logger?.warn(message); break; } case 'possible_corruption':