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