import { renderHook } from '@testing-library/react-hooks/native'; import React from 'react'; import useFlag from './useFlag'; const isEnabledMock = jest.fn() const useContextSpy = jest.spyOn(React, 'useContext'); const givenFlagName: string = 'Test'; const clientMock: any = { on: jest.fn(), } beforeEach(() => { isEnabledMock.mockClear(); }) test('should return false when the flag is NOT enabled in context', () => { isEnabledMock.mockReturnValue(false); useContextSpy.mockReturnValue({ client: clientMock, isEnabled: isEnabledMock }); const { result } = renderHook(() => useFlag(givenFlagName)); expect(clientMock.on).toHaveBeenCalledWith('update', expect.any(Function)) expect(clientMock.on).toHaveBeenCalledWith('ready', expect.any(Function)) expect(result.current).toBe(false); expect(isEnabledMock).toHaveBeenCalledTimes(1); }); test('should return true when the flag is enabled in context', () => { isEnabledMock.mockReturnValue(true); useContextSpy.mockReturnValue({ client: clientMock, isEnabled: isEnabledMock }); const { result } = renderHook(() => useFlag(givenFlagName)); expect(clientMock.on).toHaveBeenCalledWith('update', expect.any(Function)) expect(clientMock.on).toHaveBeenCalledWith('ready', expect.any(Function)) expect(result.current).toBe(true); expect(isEnabledMock).toHaveBeenCalledTimes(1); }); test('should return true when the client is ready and re-call isEnabled', () => { isEnabledMock.mockReturnValue(true); useContextSpy.mockReturnValue({ client: clientMock, isEnabled: isEnabledMock }); clientMock.on.mockImplementation((eventName: string, cb: Function) => { if (eventName === 'ready') { cb() } }); const { result } = renderHook(() => useFlag(givenFlagName)); expect(clientMock.on).toHaveBeenCalledWith('update', expect.any(Function)) expect(clientMock.on).toHaveBeenCalledWith('ready', expect.any(Function)) expect(result.current).toBe(true); expect(isEnabledMock).toHaveBeenCalledTimes(2); }); test('should return true when the client is first false and is updated with true', () => { isEnabledMock.mockReturnValueOnce(false); isEnabledMock.mockReturnValueOnce(true); useContextSpy.mockReturnValue({ client: clientMock, isEnabled: isEnabledMock }); clientMock.on.mockImplementation((eventName: string, cb: Function) => { if (eventName === 'update') { cb() } }); const { result } = renderHook(() => useFlag(givenFlagName)); expect(result.current).toBe(true); expect(clientMock.on).toHaveBeenCalledWith('update', expect.any(Function)) expect(clientMock.on).toHaveBeenCalledWith('ready', expect.any(Function)) expect(isEnabledMock).toHaveBeenCalledTimes(3); }); test('should set the local state only once', () => { isEnabledMock.mockReturnValueOnce(true); isEnabledMock.mockReturnValueOnce(true); useContextSpy.mockReturnValue({ client: clientMock, isEnabled: isEnabledMock }); clientMock.on.mockImplementation((eventName: string, cb: Function) => { if (eventName === 'update') { cb() } }); const { result } = renderHook(() => useFlag(givenFlagName)); expect(result.current).toBe(true); expect(isEnabledMock).toHaveBeenCalledTimes(2); }); test('should NOT subscribe to ready or update if client does NOT exist', () => { clientMock.on.mockClear() isEnabledMock.mockReturnValueOnce(false); useContextSpy.mockReturnValue({ client: undefined, isEnabled: isEnabledMock }); clientMock.on.mockImplementation((eventName: string, cb: Function) => { if (eventName === 'update') { cb() } }); const { result } = renderHook(() => useFlag(givenFlagName)); expect(result.current).toBe(false); expect(clientMock.on).not.toHaveBeenCalled() expect(clientMock.on).not.toHaveBeenCalled() expect(isEnabledMock).toHaveBeenCalledTimes(1); });