/
githubmirror
/
react-native
Обзор
Документация
Войти
/
githubmirror
/
react-native
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/dev-middleware/src/__tests__/StandaloneFuseboxShell-test.js
235 строк
8 KB
Sam Zhou
Redo modern syntax rollout in react-native (#57034)
03 июн 2026, 17:21
03 июн 2026, 17:21
e0ed406
Код
Авторство
О чём код?
/** * 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 */ import type {JsonPagesListResponse} from '../inspector-proxy/types'; import type { DebuggerShellPreparationResult, DevToolLauncher, } from '../types/DevToolLauncher'; import {fetchJson, requestLocal} from './FetchUtils'; import {createDeviceMock} from './InspectorDeviceUtils'; import {withAbortSignalForEachTest} from './ResourceUtils'; import {withServerForEachTest} from './ServerUtils'; // Must be greater than PAGES_POLLING_INTERVAL in `Device.js` const PAGES_POLLING_DELAY = 2100; jest.useFakeTimers(); async function setupDevice( serverRef: {readonly serverBaseWsUrl: string, ...}, signal: AbortSignal, ) { const device = await createDeviceMock( `${serverRef.serverBaseWsUrl}/inspector/device?device=device1&name=foo&app=bar`, signal, ); device.getPages.mockImplementation(() => [ { app: 'bar-app', id: 'page1', title: 'bar-title', vm: 'bar-vm', capabilities: { nativePageReloads: true, }, }, ]); jest.advanceTimersByTime(PAGES_POLLING_DELAY); return device; } function setupToolLauncherWithFuseboxShell( prepareDebuggerShell: () => Promise<DebuggerShellPreparationResult>, ) { const ToolLauncherWithFuseboxShell: DevToolLauncher = { launchDebuggerAppWindow: async (url: string) => {}, launchDebuggerShell: () => { throw new Error('Not implemented'); }, prepareDebuggerShell, }; const prepareDebuggerShellSpy = jest.spyOn( ToolLauncherWithFuseboxShell, 'prepareDebuggerShell', ); return { ToolLauncherWithFuseboxShell, prepareDebuggerShellSpy, }; } describe('enableStandaloneFuseboxShell experiment', () => { const autoCleanup = withAbortSignalForEachTest(); afterEach(() => { jest.clearAllMocks(); }); describe('/open-debugger endpoint', () => { describe('success', () => { const {ToolLauncherWithFuseboxShell, prepareDebuggerShellSpy} = setupToolLauncherWithFuseboxShell(() => Promise.resolve({code: 'success'}), ); const server = withServerForEachTest({ logger: undefined, unstable_toolLauncher: ToolLauncherWithFuseboxShell, unstable_experiments: { enableStandaloneFuseboxShell: true, }, }); test('launches the shell with a frontend URL and stable window key', async () => { // Connect a device to use when opening the debugger const device = await setupDevice(server, autoCleanup.signal); const launchDebuggerAppWindowSpy = jest .spyOn(ToolLauncherWithFuseboxShell, 'launchDebuggerAppWindow') .mockResolvedValue(); const showFuseboxShellSpy = jest .spyOn(ToolLauncherWithFuseboxShell, 'launchDebuggerShell') .mockResolvedValue(); try { // Fetch the target information for the device const pageListResponse = await fetchJson<JsonPagesListResponse>( `${server.serverBaseUrl}/json`, ); // Select the first target from the page list response expect(pageListResponse.length).toBeGreaterThanOrEqual(1); const firstPage = pageListResponse[0]; // Build the URL for the debugger const openUrl = new URL('/open-debugger', server.serverBaseUrl); openUrl.searchParams.set('launchId', 'launch1'); openUrl.searchParams.set( 'device', firstPage.reactNative.logicalDeviceId, ); openUrl.searchParams.set('target', firstPage.id); // Request to open the debugger for the first device const response = await requestLocal(openUrl.toString(), { method: 'POST', }); // Ensure the request was handled properly expect(response.statusCode).toBe(200); // Debugger was launched but will fail to prepare standalone shell expect(prepareDebuggerShellSpy).toHaveBeenCalled(); // Ensure the debugger was launched using the standalone shell API expect(showFuseboxShellSpy).toHaveBeenCalledWith( expect.any(String), expect.any(String), ); // No call to the regular browser launcher since standalone shell should be used expect(launchDebuggerAppWindowSpy).not.toHaveBeenCalled(); const firstWindowKey = showFuseboxShellSpy.mock.calls[0][1]; showFuseboxShellSpy.mockClear(); openUrl.searchParams.set('launchId', 'launch2'); const anotherResponse = await requestLocal(openUrl.toString(), { method: 'POST', }); // Ensure the request was handled properly expect(anotherResponse.statusCode).toBe(200); // Ensure the debugger was launched using the standalone shell API and the same window key expect(showFuseboxShellSpy).toHaveBeenCalledWith( expect.any(String), firstWindowKey, ); // Ensure the debugger preparation function was called, just one time, during middleware initialization expect(showFuseboxShellSpy).toHaveBeenCalledTimes(1); // No fallback needed expect(launchDebuggerAppWindowSpy).not.toHaveBeenCalled(); } finally { device.close(); } }); }); describe('prepareDebuggerShell failures', () => { const {ToolLauncherWithFuseboxShell, prepareDebuggerShellSpy} = setupToolLauncherWithFuseboxShell(() => Promise.resolve({code: 'platform_not_supported'}), ); const server = withServerForEachTest({ logger: undefined, unstable_toolLauncher: ToolLauncherWithFuseboxShell, unstable_experiments: { enableStandaloneFuseboxShell: true, }, }); test('falls back to browser window when preparation fails', async () => { // Connect a device to use when opening the debugger const device = await setupDevice(server, autoCleanup.signal); const launchDebuggerAppWindowSpy = jest .spyOn(ToolLauncherWithFuseboxShell, 'launchDebuggerAppWindow') .mockResolvedValue(); const showFuseboxShellSpy = jest .spyOn(ToolLauncherWithFuseboxShell, 'launchDebuggerShell') .mockResolvedValue(); try { // Fetch the target information for the device const pageListResponse = await fetchJson<JsonPagesListResponse>( `${server.serverBaseUrl}/json`, ); // Select the first target from the page list response expect(pageListResponse.length).toBeGreaterThanOrEqual(1); const firstPage = pageListResponse[0]; // Build the URL for the debugger const openUrl = new URL('/open-debugger', server.serverBaseUrl); openUrl.searchParams.set('launchId', 'launch1'); openUrl.searchParams.set( 'device', firstPage.reactNative.logicalDeviceId, ); openUrl.searchParams.set('target', firstPage.id); // Request to open the debugger for the first device const response = await requestLocal(openUrl.toString(), { method: 'POST', }); // Ensure the request was handled properly expect(response.statusCode).toBe(200); // Debugger was launched but will fail to prepare standalone shell expect(prepareDebuggerShellSpy).toHaveBeenCalled(); // Debugger is not launched with standalone shell since preparation failed expect(showFuseboxShellSpy).not.toHaveBeenCalled(); // Debugger fallback expect(launchDebuggerAppWindowSpy).toHaveBeenCalled(); } finally { device.close(); } }); }); }); });