Skip to content

Commit 703fe8b

Browse files
huntiemeta-codesync[bot]
authored andcommitted
Add module mock for DefaultToolLauncher and apply in tests (#55728)
Summary: Pull Request resolved: #55728 Fixes unwanted side effect launches of the debugger shell in tests (likely introduced in D88161573!). Also adds error guard on `DefaultAppLauncher` to ensure that the implementation is always mocked. Changelog: [Internal] Reviewed By: vzaidman Differential Revision: D94230761 fbshipit-source-id: 966f6f09c38aa55594091bd7d34a5c78dc6eee93
1 parent 4206c12 commit 703fe8b

6 files changed

Lines changed: 67 additions & 14 deletions

File tree

packages/dev-middleware/src/__tests__/InspectorProxyHttpApi-test.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import type {
1212
JsonPagesListResponse,
1313
JsonVersionResponse,
1414
} from '../inspector-proxy/types';
15+
import type {DevToolLauncher} from '../types/DevToolLauncher';
1516

16-
import DefaultToolLauncher from '../utils/DefaultToolLauncher';
1717
import {fetchJson, requestLocal} from './FetchUtils';
1818
import {createDeviceMock} from './InspectorDeviceUtils';
1919
import {withAbortSignalForEachTest} from './ResourceUtils';
@@ -24,12 +24,19 @@ const PAGES_POLLING_DELAY = 2100;
2424

2525
jest.useFakeTimers();
2626

27+
const mockDevToolLauncher: DevToolLauncher = {
28+
launchDebuggerAppWindow: jest
29+
.fn<[string], Promise<void>>()
30+
.mockImplementation(() => Promise.resolve()),
31+
};
32+
2733
describe('inspector proxy HTTP API', () => {
2834
const serverRef = withServerForEachTest({
2935
logger: undefined,
3036
unstable_experiments: {
3137
enableStandaloneFuseboxShell: false,
3238
},
39+
unstable_toolLauncher: mockDevToolLauncher,
3340
});
3441
const autoCleanup = withAbortSignalForEachTest();
3542
afterEach(() => {
@@ -397,11 +404,6 @@ describe('inspector proxy HTTP API', () => {
397404
]);
398405
jest.advanceTimersByTime(PAGES_POLLING_DELAY);
399406

400-
// Hook into `DefaultToolLauncher.launchDebuggerAppWindow` to ensure debugger was launched
401-
const launchDebuggerSpy = jest
402-
.spyOn(DefaultToolLauncher, 'launchDebuggerAppWindow')
403-
.mockResolvedValueOnce();
404-
405407
try {
406408
// Fetch the target information for the device
407409
const pageListResponse = await fetchJson<JsonPagesListResponse>(
@@ -426,7 +428,9 @@ describe('inspector proxy HTTP API', () => {
426428
// Ensure the request was handled properly
427429
expect(response.statusCode).toBe(200);
428430
// Ensure the debugger was launched
429-
expect(launchDebuggerSpy).toHaveBeenCalledWith(expect.any(String));
431+
expect(
432+
mockDevToolLauncher.launchDebuggerAppWindow,
433+
).toHaveBeenCalledWith(expect.any(String));
430434
} finally {
431435
device.close();
432436
}

packages/dev-middleware/src/__tests__/ServerUtils.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ type CreateServerOptions = {
2424
};
2525
type ConnectApp = ReturnType<typeof connect>;
2626

27+
jest.mock('../utils/DefaultToolLauncher');
28+
2729
export function withServerForEachTest(options: CreateServerOptions): Readonly<{
2830
serverBaseUrl: string,
2931
serverBaseWsUrl: string,

packages/dev-middleware/src/__tests__/StandaloneFuseboxShell-test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import type {JsonPagesListResponse} from '../inspector-proxy/types';
1212
import type {DevToolLauncher} from '../types/DevToolLauncher';
1313

14-
import DefaultToolLauncher from '../utils/DefaultToolLauncher';
1514
import {fetchJson, requestLocal} from './FetchUtils';
1615
import {createDeviceMock} from './InspectorDeviceUtils';
1716
import {withAbortSignalForEachTest} from './ResourceUtils';
@@ -24,7 +23,7 @@ jest.useFakeTimers();
2423

2524
describe('enableStandaloneFuseboxShell experiment', () => {
2625
const ToolLauncherWithFuseboxShell: DevToolLauncher = {
27-
...DefaultToolLauncher,
26+
launchDebuggerAppWindow: async (url: string) => {},
2827
launchDebuggerShell: () => {
2928
throw new Error('Not implemented');
3029
},

packages/dev-middleware/src/utils/DefaultToolLauncher.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ const open = require('open');
2525
*/
2626
const DefaultToolLauncher = {
2727
launchDebuggerAppWindow: async (url: string): Promise<void> => {
28+
if (process.env.NODE_ENV === 'test') {
29+
assertMockedInTests();
30+
}
31+
2832
let chromePath;
2933

3034
try {
@@ -66,6 +70,10 @@ const DefaultToolLauncher = {
6670
},
6771

6872
async launchDebuggerShell(url: string, windowKey: string): Promise<void> {
73+
if (process.env.NODE_ENV === 'test') {
74+
assertMockedInTests();
75+
}
76+
6977
return await unstable_spawnDebuggerShellWithArgs([
7078
'--frontendUrl=' + url,
7179
'--windowKey=' + windowKey,
@@ -75,8 +83,21 @@ const DefaultToolLauncher = {
7583
async prepareDebuggerShell(
7684
prebuiltBinaryPath?: ?string,
7785
): Promise<DebuggerShellPreparationResult> {
86+
if (process.env.NODE_ENV === 'test') {
87+
assertMockedInTests();
88+
}
89+
7890
return await unstable_prepareDebuggerShell();
7991
},
8092
};
8193

94+
function assertMockedInTests(): void {
95+
if (process.env.NODE_ENV === 'test') {
96+
throw new Error(
97+
'DefaultToolLauncher must be mocked or overridden in tests. ' +
98+
"Add jest.mock('../utils/DefaultAppLauncher') to test setup.",
99+
);
100+
}
101+
}
102+
82103
export default DefaultToolLauncher;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @noflow
8+
* @format
9+
*/
10+
11+
/**
12+
* Mock implementation of DefaultToolLauncher to prevent actual browser
13+
* and debugger-shell launches during tests.
14+
*/
15+
const DefaultToolLauncher = {
16+
launchDebuggerAppWindow: jest
17+
.fn()
18+
.mockImplementation(() => Promise.resolve()),
19+
launchDebuggerShell: jest.fn().mockImplementation(() => Promise.resolve()),
20+
prepareDebuggerShell: jest.fn().mockResolvedValue({code: 'not_implemented'}),
21+
};
22+
23+
export default DefaultToolLauncher;

private/react-native-fantom/runner/global-setup/globalSetup.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* @format
99
*/
1010

11+
import type {DevToolLauncher} from '@react-native/dev-middleware';
1112
import type {ConfigT} from 'metro-config';
1213

1314
import {isOSS, validateEnvironmentVariables} from '../EnvironmentOptions';
@@ -48,16 +49,19 @@ async function startMetroServer() {
4849
// $FlowExpectedError[cannot-write]
4950
metroConfig.server.port = Number(process.env.__FANTOM_METRO_PORT__);
5051

52+
// No-op app launcher to prevent debugger-shell launches during tests
53+
const devToolLauncher: DevToolLauncher = {
54+
launchDebuggerAppWindow: async (_url: string) => {},
55+
launchDebuggerShell: async () => {},
56+
prepareDebuggerShell: async () => ({code: 'not_implemented'}),
57+
};
58+
5159
const {
5260
middleware: devMiddleware,
5361
websocketEndpoints: debuggerWebsocketEndpoints,
5462
} = createDevMiddleware({
5563
serverBaseUrl: `http://localhost:${metroConfig.server.port}`,
56-
// Disable standalone DevTools shell preparation to avoid launching the
57-
// Electron app during tests. This prevents crashes.
58-
unstable_experiments: {
59-
enableStandaloneFuseboxShell: false,
60-
},
64+
unstable_toolLauncher: devToolLauncher,
6165
});
6266

6367
const enhanceMiddleware: ConfigT['server']['enhanceMiddleware'] = (

0 commit comments

Comments
 (0)