import * as React from 'react' import { useState } from 'react' import { render, screen, fireEvent } from '@testing-library/react' import { PostHogProvider, PostHog } from '../../context' import { PostHogFeature } from '../' import '@testing-library/jest-dom' const FEATURE_FLAG_STATUS: Record = { multivariate_feature: 'string-value', example_feature_payload: 'test', test: true, test_false: false, } const FEATURE_FLAG_PAYLOADS: Record = { example_feature_payload: { id: 1, name: 'example_feature_1_payload', key: 'example_feature_1_payload', }, } describe('PostHogFeature component', () => { let posthog: PostHog const renderWith = (instance: PostHog, flag = 'test', matchValue: string | boolean | undefined = true) => render(
Hello
) beforeEach(() => { // IntersectionObserver isn't available in test environment const mockIntersectionObserver = jest.fn() mockIntersectionObserver.mockReturnValue({ observe: () => null, unobserve: () => null, disconnect: () => null, }) // eslint-disable-next-line compat/compat window.IntersectionObserver = mockIntersectionObserver posthog = { isFeatureEnabled: (flag: string) => !!FEATURE_FLAG_STATUS[flag], getFeatureFlag: (flag: string) => FEATURE_FLAG_STATUS[flag], getFeatureFlagPayload: (flag: string) => FEATURE_FLAG_PAYLOADS[flag], getFeatureFlagResult: (flag: string) => ({ key: flag, enabled: !!FEATURE_FLAG_STATUS[flag], variant: typeof FEATURE_FLAG_STATUS[flag] === 'string' ? (FEATURE_FLAG_STATUS[flag] as string) : undefined, payload: FEATURE_FLAG_PAYLOADS[flag], }), onFeatureFlags: (callback: any) => { const activeFlags: string[] = [] for (const flag in FEATURE_FLAG_STATUS) { if (FEATURE_FLAG_STATUS[flag]) { activeFlags.push(flag) } } callback(activeFlags) return () => {} }, capture: jest.fn(), featureFlags: { hasLoadedFlags: true, }, } as unknown as PostHog }) it('should track interactions with the feature component', () => { renderWith(posthog) fireEvent.click(screen.getByTestId('helloDiv')) expect(posthog.capture).toHaveBeenCalledWith('$feature_interaction', { feature_flag: 'test', $set: { '$feature_interaction/test': true }, }) expect(posthog.capture).toHaveBeenCalledTimes(1) }) it('should not fire for every interaction with the feature component', () => { renderWith(posthog) fireEvent.click(screen.getByTestId('helloDiv')) expect(posthog.capture).toHaveBeenCalledWith('$feature_interaction', { feature_flag: 'test', $set: { '$feature_interaction/test': true }, }) expect(posthog.capture).toHaveBeenCalledTimes(1) fireEvent.click(screen.getByTestId('helloDiv')) fireEvent.click(screen.getByTestId('helloDiv')) fireEvent.click(screen.getByTestId('helloDiv')) expect(posthog.capture).toHaveBeenCalledTimes(1) }) it('should track an interaction with each child node of the feature component', () => { render(
Hello
World!
) fireEvent.click(screen.getByTestId('helloDiv')) fireEvent.click(screen.getByTestId('helloDiv')) fireEvent.click(screen.getByTestId('worldDiv')) fireEvent.click(screen.getByTestId('worldDiv')) fireEvent.click(screen.getByTestId('worldDiv')) expect(posthog.capture).toHaveBeenCalledWith('$feature_interaction', { feature_flag: 'test', $set: { '$feature_interaction/test': true }, }) expect(posthog.capture).toHaveBeenCalledTimes(1) }) it('should not fire events when interaction is disabled', () => { render(
Hello
) fireEvent.click(screen.getByTestId('helloDiv')) expect(posthog.capture).not.toHaveBeenCalled() fireEvent.click(screen.getByTestId('helloDiv')) fireEvent.click(screen.getByTestId('helloDiv')) fireEvent.click(screen.getByTestId('helloDiv')) expect(posthog.capture).not.toHaveBeenCalled() }) it('should fire events when interaction is disabled but re-enabled after', () => { const DynamicUpdateComponent = () => { const [trackInteraction, setTrackInteraction] = useState(false) return ( <>
{ setTrackInteraction(true) }} > Click me
Hello
) } render( ) fireEvent.click(screen.getByTestId('helloDiv')) expect(posthog.capture).not.toHaveBeenCalled() fireEvent.click(screen.getByTestId('clicker')) fireEvent.click(screen.getByTestId('helloDiv')) fireEvent.click(screen.getByTestId('helloDiv')) expect(posthog.capture).toHaveBeenCalledWith('$feature_interaction', { feature_flag: 'test', $set: { '$feature_interaction/test': true }, }) expect(posthog.capture).toHaveBeenCalledTimes(1) }) it('should not show the feature component if the flag is not enabled', () => { renderWith(posthog, 'test_value') expect(screen.queryByTestId('helloDiv')).not.toBeInTheDocument() expect(posthog.capture).not.toHaveBeenCalled() // check if any elements are found const allTags = screen.queryAllByText(/.*/) // Assert that no random elements are found expect(allTags.length).toEqual(2) expect(allTags[0].tagName).toEqual('BODY') expect(allTags[1].tagName).toEqual('DIV') }) it('should fallback when provided', () => { render( Nope}>
Hello
) expect(screen.queryByTestId('helloDiv')).not.toBeInTheDocument() expect(posthog.capture).not.toHaveBeenCalled() fireEvent.click(screen.getByTestId('nope')) expect(posthog.capture).not.toHaveBeenCalled() }) it('should handle showing multivariate flags with bool match', () => { renderWith(posthog, 'multivariate_feature') expect(screen.queryByTestId('helloDiv')).not.toBeInTheDocument() expect(posthog.capture).not.toHaveBeenCalled() }) it('should handle showing multivariate flags with incorrect match', () => { renderWith(posthog, 'multivariate_feature', 'string-valueCXCC') expect(screen.queryByTestId('helloDiv')).not.toBeInTheDocument() expect(posthog.capture).not.toHaveBeenCalled() }) it('should handle showing multivariate flags', () => { renderWith(posthog, 'multivariate_feature', 'string-value') expect(screen.queryByTestId('helloDiv')).toBeInTheDocument() expect(posthog.capture).not.toHaveBeenCalled() fireEvent.click(screen.getByTestId('helloDiv')) expect(posthog.capture).toHaveBeenCalledWith('$feature_interaction', { feature_flag: 'multivariate_feature', feature_flag_variant: 'string-value', $set: { '$feature_interaction/multivariate_feature': 'string-value' }, }) expect(posthog.capture).toHaveBeenCalledTimes(1) }) it('should handle payload flags', () => { render( {(payload: any) => { return
Hullo
}}
) expect(screen.queryByTestId('hi_example_feature_1_payload')).toBeInTheDocument() expect(posthog.capture).not.toHaveBeenCalled() fireEvent.click(screen.getByTestId('hi_example_feature_1_payload')) expect(posthog.capture).toHaveBeenCalledTimes(1) }) it('should not render when flag does not exist and no match is specified', () => { render(
Hello
) expect(screen.queryByTestId('helloDiv')).not.toBeInTheDocument() expect(posthog.capture).not.toHaveBeenCalled() }) it('should render fallback when flag does not exist (like new-cta example)', () => { render( Old Button}>
New Button
) expect(screen.queryByTestId('newButton')).not.toBeInTheDocument() expect(screen.queryByTestId('oldButton')).toBeInTheDocument() expect(posthog.capture).not.toHaveBeenCalled() }) it('should render content when match=false and flag variant is false', () => { render(
Show when disabled
) expect(screen.queryByTestId('disabledUI')).toBeInTheDocument() }) })