import consola from 'consola' import Hookable from '../src/hookable' describe('core: hookable', () => { beforeEach(() => { consola.debug.mockClear() consola.log.mockClear() consola.error.mockClear() consola.fatal.mockClear() }) test('should construct hook object', () => { const hook = new Hookable() expect(hook._hooks).toEqual({}) expect(hook._deprecatedHooks).toEqual({}) expect(hook.hook).toBeInstanceOf(Function) expect(hook.callHook).toBeInstanceOf(Function) }) test('should register hook successfully', () => { const hook = new Hookable() hook.hook('test:hook', () => {}) hook.hook('test:hook', () => {}) expect(hook._hooks['test:hook']).toHaveLength(2) expect(hook._hooks['test:hook']).toBeInstanceOf(Array) expect(hook._hooks['test:hook']).toEqual([expect.any(Function), expect.any(Function)]) }) test('should ignore empty hook name', () => { const hook = new Hookable() hook.hook(0, () => {}) hook.hook('', () => {}) hook.hook(undefined, () => {}) expect(hook._hooks[0]).toBeUndefined() expect(hook._hooks['']).toBeUndefined() expect(hook._hooks[undefined]).toBeUndefined() }) test('should ignore non-function hook', () => { const hook = new Hookable() hook.hook('test:hook', '') hook.hook('test:hook', undefined) expect(hook._hooks['test:hook']).toBeUndefined() }) test('should convert and display deprecated hook', () => { const hook = new Hookable() hook._deprecatedHooks['test:hook'] = 'test:before' hook.hook('test:hook', () => {}) expect(consola.warn).toBeCalledWith('test:hook hook has been deprecated, please use test:before') expect(hook._hooks['test:hook']).toBeUndefined() expect(hook._hooks['test:before']).toEqual([expect.any(Function)]) }) test('should call registered hook', async () => { const hook = new Hookable() hook.hook('test:hook', () => consola.log('test:hook called')) await hook.callHook('test:hook') expect(consola.log).toBeCalledWith('test:hook called') }) test('should ignore unregistered hook', async () => { const hook = new Hookable() await hook.callHook('test:hook') expect(consola.debug).not.toBeCalled() }) test('should report hook error', async () => { const hook = new Hookable() const error = new Error('Hook Error') hook.hook('test:hook', () => { throw error }) await hook.callHook('test:hook') expect(consola.fatal).toBeCalledWith(error) }) test('should call error hook', async () => { const hook = new Hookable() const error = new Error('Hook Error') hook.hook('error', jest.fn()) hook.hook('test:hook', () => { throw error }) await hook.callHook('test:hook') expect(hook._hooks.error[0]).toBeCalledWith(error) expect(consola.fatal).toBeCalledWith(error) }) test('should clear registered hooks', () => { const hook = new Hookable() hook.hook('test:hook', () => {}) expect(hook._hooks['test:hook']).toHaveLength(1) expect(hook._hooks['test:before']).toBeUndefined() hook.clearHook('test:hook') hook.clearHook('test:before') expect(hook._hooks['test:hook']).toBeUndefined() expect(hook._hooks['test:before']).toBeUndefined() }) test('should clear all registered hooks', () => { const hook = new Hookable() hook.hook('test:hook', () => {}) expect(hook._hooks['test:hook']).toHaveLength(1) expect(hook._hooks['test:before']).toBeUndefined() hook.clearHooks() expect(hook._hooks['test:hook']).toBeUndefined() expect(hook._hooks['test:before']).toBeUndefined() expect(hook._hooks).toEqual({}) }) test('should return flat hooks', () => { const hook = new Hookable() const hooks = hook.flatHooks({ test: { hook: () => {}, before: () => {} } }) expect(hooks).toEqual({ 'test:hook': expect.any(Function), 'test:before': expect.any(Function) }) }) test('should add object hooks', () => { const hook = new Hookable() hook.addHooks({ test: { hook: () => {}, before: () => {}, after: null } }) expect(hook._hooks).toEqual({ 'test:hook': expect.any(Array), 'test:before': expect.any(Array), 'test:after': undefined }) expect(hook._hooks['test:hook']).toHaveLength(1) expect(hook._hooks['test:before']).toHaveLength(1) }) })