1import { createInspectorDeviceClass } from '../device'; 2import { NetworkResponseHandler } from '../handlers/NetworkResponse'; 3import { PageReloadHandler } from '../handlers/PageReload'; 4import { VscodeDebuggerGetPossibleBreakpointsHandler } from '../handlers/VscodeDebuggerGetPossibleBreakpoints'; 5import { VscodeDebuggerScriptParsedHandler } from '../handlers/VscodeDebuggerScriptParsed'; 6import { VscodeDebuggerSetBreakpointByUrlHandler } from '../handlers/VscodeDebuggerSetBreakpointByUrl'; 7import { VscodeRuntimeGetPropertiesHandler } from '../handlers/VscodeRuntimeGetProperties'; 8import { InspectorHandler } from '../handlers/types'; 9 10describe('ExpoInspectorDevice', () => { 11 it('initializes with default handlers', () => { 12 const { device } = createTestDevice(); 13 14 function findHandler<T extends Function>(type: T) { 15 return device.handlers.find((handler) => handler instanceof type); 16 } 17 18 expect(findHandler(NetworkResponseHandler)).toBeTruthy(); 19 expect(findHandler(PageReloadHandler)).toBeTruthy(); 20 expect(findHandler(VscodeDebuggerGetPossibleBreakpointsHandler)).toBeTruthy(); 21 expect(findHandler(VscodeDebuggerScriptParsedHandler)).toBeTruthy(); 22 expect(findHandler(VscodeDebuggerSetBreakpointByUrlHandler)).toBeTruthy(); 23 expect(findHandler(VscodeRuntimeGetPropertiesHandler)).toBeTruthy(); 24 }); 25 26 describe('device', () => { 27 it('handles known device messages', () => { 28 const { device, MetroDevice } = createTestDevice(); 29 const handler: InspectorHandler = { onDeviceMessage: jest.fn().mockReturnValue(true) }; 30 device.handlers = [handler]; 31 32 device._processMessageFromDevice( 33 { method: 'Network.responseReceived', params: { requestId: 420 } }, 34 jest.fn() // debugger info mock 35 ); 36 37 expect(handler.onDeviceMessage).toBeCalled(); 38 // Expect the message is NOT propagated to original handlers 39 expect(MetroDevice.prototype._processMessageFromDevice).not.toBeCalled(); 40 }); 41 42 it('does not handle unknown device messages', () => { 43 const { device, MetroDevice } = createTestDevice(); 44 const handler: InspectorHandler = { onDeviceMessage: jest.fn().mockReturnValue(false) }; 45 device.handlers = [handler]; 46 47 device._processMessageFromDevice( 48 { method: 'Network.responseReceived', params: { requestId: 420 } }, 49 jest.fn() // debugger info mock 50 ); 51 52 expect(handler.onDeviceMessage).toBeCalled(); 53 // Expect the message is propagated to original handlers 54 expect(MetroDevice.prototype._processMessageFromDevice).toBeCalled(); 55 }); 56 57 it('does not handle without handlers', () => { 58 const { device, MetroDevice } = createTestDevice(); 59 device.handlers = []; 60 61 device._processMessageFromDevice( 62 { method: 'Network.responseReceived', params: { requestId: 420 } }, 63 jest.fn() // debugger info mock 64 ); 65 66 // Expect the message is propagated to original handlers 67 expect(MetroDevice.prototype._processMessageFromDevice).toBeCalled(); 68 }); 69 }); 70 71 describe('debugger', () => { 72 it('intercepts known debugger messages', () => { 73 const { device, MetroDevice } = createTestDevice(); 74 const handler: InspectorHandler = { onDebuggerMessage: jest.fn().mockReturnValue(true) }; 75 device.handlers = [handler]; 76 77 const handled = device._interceptMessageFromDebugger( 78 { id: 420, method: 'Network.getResponseBody', params: { requestId: 420 } }, 79 jest.fn(), // debugger info mock 80 jest.fn() as any // socket mock 81 ); 82 83 expect(handled).toBe(true); 84 expect(handler.onDebuggerMessage).toBeCalled(); 85 // Expect the message is NOT propagated to original handlers 86 expect(MetroDevice.prototype._interceptMessageFromDebugger).not.toBeCalled(); 87 }); 88 89 it('does not intercept unknown debugger messages', () => { 90 const { device, MetroDevice } = createTestDevice(); 91 const handler: InspectorHandler = { onDebuggerMessage: jest.fn().mockReturnValue(false) }; 92 device.handlers = [handler]; 93 94 const handled = device._interceptMessageFromDebugger( 95 { id: 420, method: 'Network.getResponseBody', params: { requestId: 420 } }, 96 jest.fn(), // debugger info mock 97 jest.fn() as any // socket mock 98 ); 99 100 expect(handled).not.toBe(true); 101 expect(handler.onDebuggerMessage).toBeCalled(); 102 // Expect the message is propagated to original handlers 103 expect(MetroDevice.prototype._interceptMessageFromDebugger).toBeCalled(); 104 }); 105 106 it('does not intercept without handlers', () => { 107 const { device, MetroDevice } = createTestDevice(); 108 device.handlers = []; 109 110 const handled = device._interceptMessageFromDebugger( 111 { id: 420, method: 'Network.getResponseBody', params: { requestId: 420 } }, 112 jest.fn(), // debugger info mock 113 jest.fn() as any // socket mock 114 ); 115 116 expect(handled).not.toBe(true); 117 // Expect the message is propagated to original handlers 118 expect(MetroDevice.prototype._interceptMessageFromDebugger).toBeCalled(); 119 }); 120 }); 121}); 122 123/** Create a test device instance without extending the Metro device */ 124function createTestDevice() { 125 const metroBundler: any = { broadcastMessage: jest.fn() }; 126 class MetroDevice { 127 _processMessageFromDevice() {} 128 _interceptMessageFromDebugger() {} 129 } 130 131 // Dynamically replace these functions with mocks, doesn't work from class declaration 132 MetroDevice.prototype._processMessageFromDevice = jest.fn(); 133 MetroDevice.prototype._interceptMessageFromDebugger = jest.fn(); 134 135 const ExpoDevice = createInspectorDeviceClass(metroBundler, MetroDevice); 136 const device = new ExpoDevice(); 137 138 return { ExpoDevice, MetroDevice, device, metroBundler }; 139} 140