diff --git a/src/__tests__/useGetSet.test.ts b/src/__tests__/useGetSet.test.ts index f0925d01..9e838f95 100644 --- a/src/__tests__/useGetSet.test.ts +++ b/src/__tests__/useGetSet.test.ts @@ -16,23 +16,23 @@ describe('useGetSet hook', () => { expect(set).toBeInstanceOf(Function); }); - it('should get current state', () => { + it('should get current value', () => { const { result } = setUp('foo'); const [get] = result.current; - const currentState = get(); + const currentValue = get(); - expect(currentState).toBe('foo'); + expect(currentValue).toBe('foo'); }); - it('should set new state', () => { + it('should set new value', () => { const { result } = setUp('foo'); const [get, set] = result.current; act(() => set('bar')); - const currentState = get(); - expect(currentState).toBe('bar'); + const currentValue = get(); + expect(currentValue).toBe('bar'); }); /** @@ -59,8 +59,8 @@ describe('useGetSet hook', () => { jest.runAllTimers(); }); - const currentState = get(); - expect(currentState).toBe(3); + const currentValue = get(); + expect(currentValue).toBe(3); expect(onClick).toHaveBeenCalledTimes(3); }); }); diff --git a/src/__tests__/useGetSetState.test.ts b/src/__tests__/useGetSetState.test.ts new file mode 100644 index 00000000..f3ea5fa7 --- /dev/null +++ b/src/__tests__/useGetSetState.test.ts @@ -0,0 +1,127 @@ +import { act, renderHook } from '@testing-library/react-hooks'; +import useGetSetState from '../useGetSetState'; + +const originalConsoleError = console.error; +const mockConsoleError = jest.fn(); + +describe('useGetSetState hook', () => { + const setUp = (initialState: any) => renderHook(() => useGetSetState(initialState)); + + beforeAll(() => { + console.error = mockConsoleError; + }); + + afterAll(() => { + console.error = originalConsoleError; + }); + + beforeEach(() => { + jest.useFakeTimers(); + }); + + it('should init getter and setter', () => { + const { result } = setUp({ foo: 'initialValue' }); + const [get, set] = result.current; + + expect(get).toBeInstanceOf(Function); + expect(set).toBeInstanceOf(Function); + }); + + it('should log an error if init with something different than an object', () => { + expect(mockConsoleError).not.toHaveBeenCalled(); + + setUp('not an object'); + + expect(mockConsoleError).toHaveBeenCalledTimes(1); + expect(mockConsoleError).toHaveBeenCalledWith('useGetSetState initial state must be an object.'); + }); + + it('should get current state', () => { + const { result } = setUp({ foo: 'a', bar: 'z' }); + const [get] = result.current; + + const currentState = get(); + + expect(currentState).toEqual({ foo: 'a', bar: 'z' }); + }); + + it('should set new state by applying partial patch with existing keys', () => { + const { result } = setUp({ foo: 'a', bar: 'z' }); + const [get, set] = result.current; + + act(() => set({ bar: 'y' })); + + const currentState = get(); + expect(currentState).toEqual({ foo: 'a', bar: 'y' }); + }); + + it('should set new state by applying partial patch with new keys', () => { + const { result } = setUp({ foo: 'a', bar: 'z' }); + const [get, set] = result.current; + + act(() => set({ qux: 'f' })); + + const currentState = get(); + expect(currentState).toEqual({ foo: 'a', bar: 'z', qux: 'f' }); + }); + + it('should set new state by applying partial patch with both new and old keys', () => { + const { result } = setUp({ foo: 'a', bar: 'z' }); + const [get, set] = result.current; + + act(() => set({ bar: 'y', qux: 'f' })); + + const currentState = get(); + expect(currentState).toEqual({ foo: 'a', bar: 'y', qux: 'f' }); + }); + + it('should NOT set new state if empty partial patch received', () => { + const { result } = setUp({ foo: 'a', bar: 'z' }); + const [get, set] = result.current; + + act(() => set({})); + + const currentState = get(); + expect(currentState).toEqual({ foo: 'a', bar: 'z' }); + }); + + it('should log an error if set with a patch different than an object', () => { + const { result } = setUp({ foo: 'a', bar: 'z' }); + const [, set] = result.current; + expect(mockConsoleError).not.toHaveBeenCalled(); + + // @ts-ignore + act(() => set('not an object')); + + expect(mockConsoleError).toHaveBeenCalledTimes(1); + expect(mockConsoleError).toHaveBeenCalledWith('useGetSetState setter patch must be an object.'); + }); + + /** + * This test is equivalent to demo one for `useGetSet` hook. + */ + it('should get and set expected state when used in nested functions', () => { + const onClick = jest.fn(() => { + setTimeout(() => { + set({ counter: get().counter + 1 }); + }, 1000); + }); + + const { result } = setUp({ counter: 0 }); + const [get, set] = result.current; + + // simulate 3 clicks + onClick(); + onClick(); + onClick(); + + // fast-forward until all timers have been executed + act(() => { + jest.runAllTimers(); + }); + + const currentState = get(); + expect(currentState).toEqual({ counter: 3 }); + expect(onClick).toHaveBeenCalledTimes(3); + }); +});