Skip to content

Commit

Permalink
feat(terminate): renames exit to terminate (it now works for any type…
Browse files Browse the repository at this point in the history
…/reason)

exit() was only intended for manual exit calls. terminate() has the same functionality but works for
signal, exception, rejection, and exit equally.

BREAKING CHANGE: exit() has been renamed to terminate(). it now takes two arguments, the first being
the termination type, and the second its argument (previously, it only took one: the exit code
number).
  • Loading branch information
rafamel committed Jan 29, 2019
1 parent 2f27292 commit 76d48ea
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 65 deletions.
10 changes: 0 additions & 10 deletions src/methods/exit.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/methods/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export { default as options } from './options';
export { default as state } from './state';
export { default as control } from './control';
export { default as on } from './on';
export { default as exit } from './exit';
export { default as terminate } from './terminate';
export { default as spawn } from './spawn';
32 changes: 32 additions & 0 deletions src/methods/terminate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import handler from '~/utils/handler';
import store from '~/store';
import { TSignal } from '~/types';

export default terminate;

function terminate(type: 'signal', arg: TSignal): Promise<void>;
function terminate(type: 'exception' | 'rejection', arg: Error): Promise<void>;
function terminate(type: 'exit', arg: number): Promise<void>;
async function terminate(
type: 'signal' | 'exception' | 'rejection' | 'exit',
arg: any
): Promise<void> {
switch (type) {
case 'signal':
if (store.state.attached.signal) return handler('signal', arg);
break;
case 'exception':
if (store.state.attached.exception) return handler('exception', arg);
break;
case 'rejection':
if (store.state.attached.rejection) return handler('rejection', arg);
break;
case 'exit':
if (store.state.attached.exit) return handler('exit', arg);
break;
default:
break;
}

return store.options.resolver(type, arg);
}
54 changes: 0 additions & 54 deletions test/methods/exit.test.ts

This file was deleted.

213 changes: 213 additions & 0 deletions test/methods/terminate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import { terminate } from '~/index';
import _handler from '~/utils/handler';
import resetStore from '../reset-store';
import store from '~/store';

const handler: any = _handler;
jest.mock('~/utils/handler');

const resetHandler = (): void => {
handler.mockReset();
handler.mockImplementation(() => Promise.resolve('foo'));
};

describe(`signal`, () => {
test(`calls handler with signal when attached to signal`, async () => {
expect.assertions(6);
resetStore();
store.state.attached.signal = true;

resetHandler();
const res1 = await terminate('signal', 'SIGINT');
expect(res1).toBe('foo');
expect(handler).toBeCalledTimes(1);
expect(handler).toBeCalledWith('signal', 'SIGINT');

resetHandler();
const res2 = await terminate('signal', 'SIGHUP');
expect(res2).toBe('foo');
expect(handler).toBeCalledTimes(1);
expect(handler).toBeCalledWith('signal', 'SIGHUP');
});
test(`calls resolver when not attached to signal`, async () => {
expect.assertions(8);
resetHandler();
resetStore();
store.state.attached.signal = false;
const called: any[] = [];
store.options.resolver = (...args) => {
called.push(args);
return Promise.resolve('bar');
};

const res1 = await terminate('signal', 'SIGINT');
expect(handler).not.toBeCalled();
expect(res1).toBe('bar');
expect(called).toHaveLength(1);
expect(called[0]).toEqual(['signal', 'SIGINT']);

const res2 = await terminate('signal', 'SIGHUP');
expect(handler).not.toBeCalled();
expect(res2).toBe('bar');
expect(called).toHaveLength(2);
expect(called[1]).toEqual(['signal', 'SIGHUP']);
});
});

describe(`exception`, () => {
test(`calls handler with error when attached to exception`, async () => {
expect.assertions(3);
resetStore();
store.state.attached.exception = true;

resetHandler();
const err = Error();
const res = await terminate('exception', err);
expect(res).toBe('foo');
expect(handler).toBeCalledTimes(1);
expect(handler).toBeCalledWith('exception', err);
});
test(`calls resolver when not attached to exception`, async () => {
expect.assertions(4);
resetHandler();
resetStore();
store.state.attached.exception = false;
const called: any[] = [];
store.options.resolver = (...args) => {
called.push(args);
return Promise.resolve('bar');
};

const err = Error();
const res = await terminate('exception', err);
expect(handler).not.toBeCalled();
expect(res).toBe('bar');
expect(called).toHaveLength(1);
expect(called[0]).toEqual(['exception', err]);
});
});

describe(`rejection`, () => {
test(`calls handler with error when attached to rejection`, async () => {
expect.assertions(3);
resetStore();
store.state.attached.rejection = true;

resetHandler();
const err = Error();
const res = await terminate('rejection', err);
expect(res).toBe('foo');
expect(handler).toBeCalledTimes(1);
expect(handler).toBeCalledWith('rejection', err);
});
test(`calls resolver when not attached to rejection`, async () => {
expect.assertions(4);
resetHandler();
resetStore();
store.state.attached.rejection = false;
const called: any[] = [];
store.options.resolver = (...args) => {
called.push(args);
return Promise.resolve('bar');
};

const err = Error();
const res = await terminate('rejection', err);
expect(handler).not.toBeCalled();
expect(res).toBe('bar');
expect(called).toHaveLength(1);
expect(called[0]).toEqual(['rejection', err]);
});
});

describe(`exit`, () => {
test(`calls handler with exit code when attached to exit`, async () => {
expect.assertions(6);
resetStore();
store.state.attached.exit = true;

resetHandler();
const res1 = await terminate('exit', 0);
expect(res1).toBe('foo');
expect(handler).toBeCalledTimes(1);
expect(handler).toBeCalledWith('exit', 0);

resetHandler();
const res2 = await terminate('exit', 1);
expect(res2).toBe('foo');
expect(handler).toBeCalledTimes(1);
expect(handler).toBeCalledWith('exit', 1);
});
test(`calls resolver when not attached to exit`, async () => {
expect.assertions(8);
resetHandler();
resetStore();
store.state.attached.exit = false;
const called: any[] = [];
store.options.resolver = (...args) => {
called.push(args);
return Promise.resolve('bar');
};

const res1 = await terminate('exit', 0);
expect(handler).not.toBeCalled();
expect(res1).toBe('bar');
expect(called).toHaveLength(1);
expect(called[0]).toEqual(['exit', 0]);

const res2 = await terminate('exit', 1);
expect(handler).not.toBeCalled();
expect(res2).toBe('bar');
expect(called).toHaveLength(2);
expect(called[1]).toEqual(['exit', 1]);
});
});

describe(`unknown type`, () => {
test(`calls resolver when not attached`, async () => {
expect.assertions(4);
resetHandler();
resetStore();
store.state.attached = {
signal: false,
exception: false,
rejection: false,
exit: false
};
const called: any[] = [];
store.options.resolver = (...args) => {
called.push(args);
return Promise.resolve('bar');
};

// @ts-ignore
const res = await terminate('unknown_type', 0);
expect(handler).not.toBeCalled();
expect(res).toBe('bar');
expect(called).toHaveLength(1);
expect(called[0]).toEqual(['unknown_type', 0]);
});
test(`calls resolver when attached`, async () => {
expect.assertions(4);
resetHandler();
resetStore();
store.state.attached = {
signal: true,
exception: true,
rejection: true,
exit: true
};
const called: any[] = [];
store.options.resolver = (...args) => {
called.push(args);
return Promise.resolve('bar');
};

// @ts-ignore
const res = await terminate('unknown_type', 0);
expect(handler).not.toBeCalled();
expect(res).toBe('bar');
expect(called).toHaveLength(1);
expect(called[0]).toEqual(['unknown_type', 0]);
});
});

0 comments on commit 76d48ea

Please sign in to comment.