-
Notifications
You must be signed in to change notification settings - Fork 110
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support experimental RN debugger interaction (#757)
* refactor: use switch statement in setupInteractions * refactor: add wrapper for logging of unsupported feature notices when interaction is not implemented in the underlying bundler wrapper * feat: added 'j' experimental debugger interaction * feat: add initial help message listing available interactions * refactor: changes after CR * fix: typo in console message * test: added tests for setupInteractions * chore: upgrade colorette to v2 * refactor(test): use colorette.createColors for mocking colorette in setupInteractions test * refactor: changes after CR * refactor(test): use default parameters instead of mocks for setupInteractions * fix: colorette import in start commands * chore: rename setupInteractions to incldue test in name * refactor: no spread * chore: use ctx.log for async logging * refactor: simplify output * chore: add changeset --------- Co-authored-by: Jakub Romanczyk <jakub.romanczyk@callstack.com>
- Loading branch information
Showing
8 changed files
with
337 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@callstack/repack": minor | ||
--- | ||
|
||
Display list of available interactions on dev server startup & add support for 'j' to debug |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
226 changes: 226 additions & 0 deletions
226
packages/repack/src/commands/common/__tests__/setupInteractions.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
import type readline from 'node:readline'; | ||
|
||
import type { Logger } from '../../../types'; | ||
import { setupInteractions } from '../setupInteractions'; | ||
|
||
// eliminate ANSI colors formatting for proper assertions | ||
jest.mock('colorette', () => | ||
jest.requireActual('colorette').createColors({ | ||
useColor: false, | ||
}) | ||
); | ||
|
||
describe('setupInteractions', () => { | ||
let mockLogger: Logger; | ||
let mockProcess: NodeJS.Process; | ||
let mockReadline: typeof readline; | ||
|
||
beforeEach(() => { | ||
mockLogger = { | ||
info: jest.fn(), | ||
warn: jest.fn(), | ||
error: jest.fn(), | ||
} as unknown as Logger; | ||
|
||
mockProcess = { | ||
stdin: { | ||
setRawMode: jest.fn(), | ||
on: jest.fn(), | ||
}, | ||
stdout: { | ||
write: jest.fn(), | ||
}, | ||
exit: jest.fn(), | ||
emit: jest.fn(), | ||
} as unknown as NodeJS.Process; | ||
|
||
mockReadline = { | ||
emitKeypressEvents: jest.fn(), | ||
} as unknown as typeof readline; | ||
}); | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('should log a warning if setRawMode is not available', () => { | ||
mockProcess.stdin.setRawMode = undefined as any; | ||
|
||
setupInteractions({}, mockLogger, mockProcess, mockReadline); | ||
|
||
expect(mockLogger.warn).toHaveBeenCalledWith( | ||
'Interactive mode is not supported in this environment' | ||
); | ||
}); | ||
|
||
it('should set up keypress events and interactions', () => { | ||
setupInteractions({}, mockLogger, mockProcess, mockReadline); | ||
|
||
expect(mockReadline.emitKeypressEvents).toHaveBeenCalledWith( | ||
mockProcess.stdin | ||
); | ||
expect(mockProcess.stdin.setRawMode).toHaveBeenCalledWith(true); | ||
expect(mockProcess.stdin.on).toHaveBeenCalledWith( | ||
'keypress', | ||
expect.any(Function) | ||
); | ||
}); | ||
|
||
it('should handle ctrl+c and ctrl+z keypresses', () => { | ||
setupInteractions({}, mockLogger, mockProcess, mockReadline); | ||
|
||
const keypressHandler = (mockProcess.stdin.on as jest.Mock).mock | ||
.calls[0][1]; | ||
|
||
keypressHandler(null, { ctrl: true, name: 'c' }); | ||
expect(mockProcess.exit).toHaveBeenCalled(); | ||
|
||
keypressHandler(null, { ctrl: true, name: 'z' }); | ||
expect(mockProcess.emit).toHaveBeenCalledWith('SIGTSTP', 'SIGTSTP'); | ||
}); | ||
|
||
it('should handle supported interactions', () => { | ||
const handlers: Parameters<typeof setupInteractions>[0] = { | ||
onReload: jest.fn(), | ||
onOpenDevMenu: jest.fn(), | ||
onOpenDevTools: jest.fn(), | ||
}; | ||
|
||
setupInteractions(handlers, mockLogger, mockProcess, mockReadline); | ||
|
||
const keypressHandler = (mockProcess.stdin.on as jest.Mock).mock | ||
.calls[0][1]; | ||
|
||
keypressHandler(null, { ctrl: false, name: 'r' }); | ||
expect(mockLogger.info).toHaveBeenCalledWith('Reloading app'); | ||
expect(handlers.onReload).toHaveBeenCalledTimes(1); | ||
|
||
keypressHandler(null, { ctrl: false, name: 'd' }); | ||
expect(mockLogger.info).toHaveBeenCalledWith('Opening developer menu'); | ||
expect(handlers.onOpenDevMenu).toHaveBeenCalledTimes(1); | ||
|
||
keypressHandler(null, { ctrl: false, name: 'j' }); | ||
expect(mockLogger.info).toHaveBeenCalledWith('Opening debugger'); | ||
expect(handlers.onOpenDevTools).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
it('should handle unsupported interactions', () => { | ||
const handlers: Parameters<typeof setupInteractions>[0] = { | ||
onReload: jest.fn(), | ||
}; | ||
|
||
setupInteractions(handlers, mockLogger, mockProcess, mockReadline); | ||
|
||
expect(mockProcess.stdout.write).toHaveBeenCalledWith(' r: Reload app\n'); | ||
expect(mockProcess.stdout.write).toHaveBeenCalledWith( | ||
' d: Open developer menu (unsupported by the current bundler)\n' | ||
); | ||
|
||
const keypressHandler = (mockProcess.stdin.on as jest.Mock).mock | ||
.calls[0][1]; | ||
|
||
keypressHandler(null, { ctrl: false, name: 'd' }); | ||
expect(mockLogger.warn).toHaveBeenCalledWith( | ||
'Open developer menu is not supported by the used bundler' | ||
); | ||
}); | ||
|
||
it('should properly invoke interaction action callbacks in partial action support scenarios', () => { | ||
const handlers: Parameters<typeof setupInteractions>[0] = { | ||
onReload: jest.fn(), | ||
onOpenDevTools: jest.fn(), | ||
// onOpenDevMenu - unsupported | ||
}; | ||
|
||
setupInteractions(handlers, mockLogger, mockProcess, mockReadline); | ||
|
||
const keypressHandler = (mockProcess.stdin.on as jest.Mock).mock | ||
.calls[0][1]; | ||
|
||
keypressHandler(null, { ctrl: false, name: 'd' }); | ||
expect(handlers.onReload).toHaveBeenCalledTimes(0); | ||
expect(handlers.onOpenDevTools).toHaveBeenCalledTimes(0); | ||
|
||
keypressHandler(null, { ctrl: false, name: 'r' }); | ||
expect(handlers.onReload).toHaveBeenCalledTimes(1); | ||
expect(handlers.onOpenDevTools).toHaveBeenCalledTimes(0); | ||
|
||
keypressHandler(null, { ctrl: false, name: 'r' }); | ||
expect(handlers.onReload).toHaveBeenCalledTimes(2); | ||
expect(handlers.onOpenDevTools).toHaveBeenCalledTimes(0); | ||
|
||
keypressHandler(null, { ctrl: false, name: 'j' }); | ||
expect(handlers.onReload).toHaveBeenCalledTimes(2); | ||
expect(handlers.onOpenDevTools).toHaveBeenCalledTimes(1); | ||
|
||
keypressHandler(null, { ctrl: false, name: 'j' }); | ||
expect(handlers.onReload).toHaveBeenCalledTimes(2); | ||
expect(handlers.onOpenDevTools).toHaveBeenCalledTimes(2); | ||
}); | ||
|
||
it('should quit on ctrl+c', () => { | ||
const handlers: Parameters<typeof setupInteractions>[0] = { | ||
onReload: jest.fn(), | ||
onOpenDevTools: jest.fn(), | ||
}; | ||
|
||
setupInteractions(handlers, mockLogger, mockProcess, mockReadline); | ||
|
||
const keypressHandler = (mockProcess.stdin.on as jest.Mock).mock | ||
.calls[0][1]; | ||
|
||
keypressHandler(null, { ctrl: true, name: 'c' }); | ||
expect(mockProcess.exit).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
it('should quit on ctrl+z', () => { | ||
const handlers: Parameters<typeof setupInteractions>[0] = { | ||
onReload: jest.fn(), | ||
onOpenDevTools: jest.fn(), | ||
}; | ||
|
||
setupInteractions(handlers, mockLogger, mockProcess, mockReadline); | ||
|
||
const keypressHandler = (mockProcess.stdin.on as jest.Mock).mock | ||
.calls[0][1]; | ||
|
||
keypressHandler(null, { ctrl: true, name: 'z' }); | ||
expect(mockProcess.emit).toHaveBeenCalledTimes(1); | ||
expect(mockProcess.emit).toHaveBeenCalledWith('SIGTSTP', 'SIGTSTP'); | ||
}); | ||
|
||
describe.each([true, false])( | ||
'should properly display a list of supported interactions (debugger support: %s)', | ||
(debuggerSupport) => { | ||
it('should display interaction messages', () => { | ||
setupInteractions( | ||
{ | ||
onOpenDevTools: debuggerSupport ? jest.fn() : undefined, | ||
onOpenDevMenu() {}, | ||
onReload() {}, | ||
}, | ||
mockLogger, | ||
mockProcess, | ||
mockReadline | ||
); | ||
|
||
expect(mockProcess.stdout.write).toHaveBeenNthCalledWith( | ||
1, | ||
' r: Reload app\n' | ||
); | ||
expect(mockProcess.stdout.write).toHaveBeenNthCalledWith( | ||
2, | ||
' d: Open developer menu\n' | ||
); | ||
expect(mockProcess.stdout.write).toHaveBeenNthCalledWith( | ||
3, | ||
` j: Open debugger${debuggerSupport ? '' : ' (unsupported by the current bundler)'}\n` | ||
); | ||
expect(mockProcess.stdout.write).toHaveBeenNthCalledWith( | ||
4, | ||
'\nPress Ctrl+c or Ctrl+z to quit the dev server\n\n' | ||
); | ||
}); | ||
} | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.