/** * @format * @jest-environment jsdom */ import React, { useContext, useEffect, useState } from 'react' import { render, screen, RenderOptions } from '@testing-library/react' import * as UnleashClientModule from 'unleash-proxy-client' import FlagProvider from './FlagProvider' import FlagContext from './FlagContext' import '@testing-library/jest-dom' import { EVENTS } from 'unleash-proxy-client' interface IFlagProvider { config: UnleashClientModule.IConfig } interface renderConsumerOptions { providerProps: IFlagProvider renderOptions: RenderOptions } const getVariantMock = jest.fn().mockReturnValue('A') const updateContextMock = jest.fn() const startClientMock = jest.fn() const onMock = jest.fn().mockReturnValue('subscribed') const isEnabledMock = jest.fn().mockReturnValue(true) const UnleashClientSpy: jest.SpyInstance = jest.spyOn( UnleashClientModule, 'UnleashClient' ) const givenConfig = { appName: 'my-app', clientKey: 'my-secret', url: 'https://my-unleash-proxy' } const givenFlagName = 'test' const givenContext = { session: 'context' } beforeEach(() => { onMock.mockClear() }) UnleashClientSpy.mockReturnValue({ getVariant: getVariantMock, updateContext: updateContextMock, start: startClientMock, isEnabled: isEnabledMock, on: onMock }) const noop = () => {} const FlagConsumerAfterClientInit = () => { const { updateContext, isEnabled, getVariant, client, on } = useContext(FlagContext) const [enabled, setIsEnabled] = useState(false) const [variant, setVariant] = useState(null) const [context, setContext] = useState('nothing') const [currentOn, setCurrentOn] = useState(null) useEffect(() => { if (client) { setIsEnabled(isEnabled(givenFlagName)) setVariant(getVariant(givenFlagName)) setContext(updateContext(givenContext as any)) setCurrentOn(on('someEvent', noop, 'someArgument')) } }, [client]) return ( <>
{`consuming value isEnabled ${enabled}`}
{`consuming value updateContext ${context}`}
{`consuming value getVariant ${variant}`}
{`consuming value on ${currentOn}`}
) } const FlagConsumerBeforeClientInit = () => { const { updateContext, isEnabled, getVariant, client, on } = useContext(FlagContext) const [enabled, setIsEnabled] = useState(false) const [variant, setVariant] = useState(null) const [context, setContext] = useState('nothing') const [currentOn, setCurrentOn] = useState(null) useEffect(() => { if (!client) { setIsEnabled(isEnabled(givenFlagName)) setVariant(getVariant(givenFlagName)) setContext(updateContext(givenContext as any)) setCurrentOn(on('someEvent', noop, 'someArgument')) } }, []) return <> } const renderConsumer = ( ui: any, { providerProps, renderOptions }: renderConsumerOptions ) => { return render( {ui}, renderOptions ) } const renderConsumerWithUnleashClient = ( ui: any, { providerProps, renderOptions }: renderConsumerOptions ) => { const client = new UnleashClientModule.UnleashClient(providerProps.config) return render( {ui}, renderOptions ) } test('A consumer that subscribes AFTER client init shows values from provider and calls all the functions', () => { const providerProps = { config: givenConfig } renderConsumer(, { providerProps, renderOptions: {} }) expect(getVariantMock).toHaveBeenCalledWith(givenFlagName) expect(isEnabledMock).toHaveBeenCalledWith(givenFlagName) expect(updateContextMock).toHaveBeenCalledWith(givenContext) expect(screen.getByText(/consuming value isEnabled/)).toHaveTextContent( 'consuming value isEnabled true' ) expect(screen.getByText(/consuming value updateContext/)).toHaveTextContent( 'consuming value updateContext [object Promise]' ) expect(screen.getByText(/consuming value getVariant/)).toHaveTextContent( 'consuming value getVariant A' ) expect(screen.getByText(/consuming value on/)).toHaveTextContent( 'consuming value on subscribed' ) }) test('A consumer that subscribes BEFORE client init shows values from provider and calls all the functions', () => { const providerProps = { config: givenConfig } renderConsumer(, { providerProps, renderOptions: {} }) expect(getVariantMock).toHaveBeenCalledWith(givenFlagName) expect(isEnabledMock).toHaveBeenCalledWith(givenFlagName) expect(updateContextMock).toHaveBeenCalledWith(givenContext) }) test('A consumer should be able to get a variant when the client is passed into the provider as props', () => { const providerProps = { config: givenConfig } renderConsumerWithUnleashClient(, { providerProps, renderOptions: {} }) expect(getVariantMock).toHaveBeenCalledWith(givenFlagName) expect(isEnabledMock).toHaveBeenCalledWith(givenFlagName) expect(updateContextMock).toHaveBeenCalledWith(givenContext) expect(screen.getByText(/consuming value isEnabled/)).toHaveTextContent( 'consuming value isEnabled true' ) expect(screen.getByText(/consuming value updateContext/)).toHaveTextContent( 'consuming value updateContext [object Promise]' ) expect(screen.getByText(/consuming value getVariant/)).toHaveTextContent( 'consuming value getVariant A' ) expect(screen.getByText(/consuming value on/)).toHaveTextContent( 'consuming value on subscribed' ) }) test('A memoized consumer should not rerender when the context provider values are the same', () => { const renderCounter = jest.fn() const MemoizedConsumer = React.memo(() => { const { updateContext, isEnabled, getVariant, client, on } = useContext(FlagContext) renderCounter() return <> }) expect(renderCounter).toHaveBeenCalledTimes(0) const { rerender } = render( ) expect(renderCounter).toHaveBeenCalledTimes(1) rerender( ) expect(renderCounter).toHaveBeenCalledTimes(1) }) test('should update when ready event is sent', () => { const localMock = jest.fn() UnleashClientSpy.mockReturnValue({ getVariant: getVariantMock, updateContext: updateContextMock, start: startClientMock, isEnabled: isEnabledMock, on: localMock }) const providerProps = { config: givenConfig } const client = new UnleashClientModule.UnleashClient(providerProps.config) render(
Hi
) localMock.mockImplementation((event, cb) => { if (event === EVENTS.READY) { cb() } }) expect(localMock).toHaveBeenCalledWith(EVENTS.READY, expect.any(Function)) }) test('should register error when error event is sent', () => { const localMock = jest.fn() UnleashClientSpy.mockReturnValue({ getVariant: getVariantMock, updateContext: updateContextMock, start: startClientMock, isEnabled: isEnabledMock, on: localMock }) const providerProps = { config: givenConfig } const client = new UnleashClientModule.UnleashClient(providerProps.config) render(
Hi
) localMock.mockImplementation((event, cb) => { if (event === EVENTS.ERROR) { cb('Error') } }) expect(localMock).toHaveBeenCalledWith(EVENTS.ERROR, expect.any(Function)) }) test('should not start client if startClient is false', () => { const localMock = jest.fn() UnleashClientSpy.mockReturnValue({ getVariant: getVariantMock, updateContext: updateContextMock, start: localMock, isEnabled: isEnabledMock, on: onMock }) const providerProps = { config: givenConfig } const client = new UnleashClientModule.UnleashClient(providerProps.config) render(
Hi
) expect(localMock).not.toHaveBeenCalled() })