import { describe, afterEach, beforeEach, test, expect, jest, } from '@jest/globals'; import { YError } from 'yerror'; import { Knifecycle, constant } from 'knifecycle'; import initProcessService from './process.js'; import { NodeEnv } from './ENV.js'; import { type LogService } from 'common-services'; import { exit as _exit } from 'node:process'; describe('Process service', () => { const log = jest.fn(); const savedProcessName = global.process.title; const processListenerStub = jest.spyOn(global.process, 'on'); let exit: jest.Mock; let exitPromise: Promise; let rejectFatalErrorDeferred: (reason?: Error) => void; beforeEach(() => { exitPromise = new Promise((resolve) => { exit = jest.fn(resolve as typeof _exit); }); processListenerStub.mockClear(); log.mockReset(); }); afterEach(() => { global.process.title = savedProcessName; }); describe('', () => { beforeEach(async () => { await initProcessService({ PROCESS_NAME: 'Kikooolol', APP_ENV: 'local', ENV: { NODE_ENV: NodeEnv.Development }, log, exit, $instance: { destroy: () => Promise.resolve() } as Knifecycle, $fatalError: { errorPromise: new Promise((_resolve, reject) => { rejectFatalErrorDeferred = reject; }), registerErrorPromise: jest.fn(), unregisterErrorPromise: jest.fn(), throwFatalError: jest.fn(), }, }); }); test('should work', () => { expect(log.mock.calls).toMatchInlineSnapshot(` [ [ "debug", "📇 - Process service initialized.", ], ] `); expect(global.process.title).toEqual('Kikooolol - local:development'); expect(processListenerStub.mock.calls.length).toEqual(3); }); test('should handle fatal errors', async () => { rejectFatalErrorDeferred(new YError('E_AOUCH')); await exitPromise; expect(exit.mock.calls).toEqual([[1]]); }); test('should handle uncaught exceptions', async () => { ( processListenerStub.mock.calls.find( (call) => 'uncaughtException' === call[0], ) as [unknown, (err: Error) => void] )[1](new YError('E_AOUCH')); await exitPromise; expect(exit.mock.calls).toEqual([[1]]); }); ['SIGINT', 'SIGTERM'].forEach((signal) => test('should handle `signal`', async () => { ( processListenerStub.mock.calls.find((call) => signal === call[0]) as [ unknown, (err: Error) => void, ] )[1](new YError('E_AOUCH')); await exitPromise; expect(exit.mock.calls).toEqual([[0]]); }), ); }); test('should work with Knifecycle', async () => { await new Knifecycle() .register(initProcessService) .register(constant('APP_ENV', 'local')) .register(constant('ENV', { NODE_ENV: 'test' })) .register(constant('log', log)) .register(constant('exit', exit)) .run(['process']); expect(log.mock.calls).toMatchInlineSnapshot(` [ [ "debug", "📇 - Process service initialized.", ], ] `); }); });