import { spawn, ChildProcess } from 'child_process'; import fs from 'fs'; // Use global process object for kill spy to avoid configurable property issues import { teleportBotAgent } from '../src/services/teleportBotAgent'; jest.mock('child_process', () => ({ spawn: jest.fn() })); const mockSpawn = spawn as jest.Mock; describe('teleportBotAgent extra branches', () => { const workDir = '/tmp/work'; const appName = 'app'; const lockFile = `${workDir}/data/lock`; const pidFile = `${workDir}/tbot.pid`; let mkdirSpy: jest.SpyInstance; let existsSpy: jest.SpyInstance; let unlinkSpy: jest.SpyInstance; let writeSpy: jest.SpyInstance; let readSpy: jest.SpyInstance; let openSpy: jest.SpyInstance; let closeSpy: jest.SpyInstance; let killSpy: jest.SpyInstance; let fakeProc: any; beforeEach(() => { jest.clearAllMocks(); mkdirSpy = jest.spyOn(fs, 'mkdirSync').mockImplementation(() => ''); existsSpy = jest.spyOn(fs, 'existsSync').mockImplementation((p: any) => false); unlinkSpy = jest.spyOn(fs, 'unlinkSync').mockImplementation(() => {}); writeSpy = jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {}); readSpy = jest.spyOn(fs, 'readFileSync').mockImplementation(() => ''); openSpy = jest.spyOn(fs, 'openSync').mockReturnValue(123); closeSpy = jest.spyOn(fs, 'closeSync').mockImplementation(() => {}); // Ensure process.kill is configurable on global process for spying try { Object.defineProperty(global.process, 'kill', { configurable: true, writable: true, value: global.process.kill, }); } catch { // ignore } killSpy = jest.spyOn(global.process, 'kill').mockImplementation(() => true as any); fakeProc = { pid: 555, unref: jest.fn() } as unknown as ChildProcess; mockSpawn.mockReturnValue(fakeProc); }); it('omits --token when joinToken is undefined', async () => { existsSpy.mockReturnValue(false); await teleportBotAgent({ appName, workDir }); const args = mockSpawn.mock.calls[0][1] as string[]; expect(args).not.toEqual( expect.arrayContaining([expect.stringMatching(/^--token=/)]) ); }); it('removes stale lock file if present', async () => { existsSpy.mockImplementation((p: any) => p === lockFile); const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); await teleportBotAgent({ appName, joinToken: 'T', workDir }); expect(warnSpy).toHaveBeenCalledWith(`Warning: removing stale lock file at ${lockFile}`); expect(unlinkSpy).toHaveBeenCalledWith(lockFile); warnSpy.mockRestore(); }); it('kills existing pid and writes new pid file', async () => { existsSpy.mockImplementation((p: any) => p === pidFile); readSpy.mockReturnValue('999'); await teleportBotAgent({ appName, joinToken: 'J', workDir }); expect(killSpy).toHaveBeenCalledWith(999); expect(unlinkSpy).toHaveBeenCalledWith(pidFile); expect(writeSpy).toHaveBeenCalledWith(pidFile, `${fakeProc.pid}`); }); });