diff --git a/packages/react/src/provider/use-context-mutator.ts b/packages/react/src/provider/use-context-mutator.ts index ac12eba42..e28c0957d 100644 --- a/packages/react/src/provider/use-context-mutator.ts +++ b/packages/react/src/provider/use-context-mutator.ts @@ -8,11 +8,13 @@ import { Context } from './context'; * */ export function useContextMutator() { - async function mutateContext(updatedContext: EvaluationContext): Promise { - const { domain } = useContext(Context) || {}; + const { domain } = useContext(Context) || {}; + async function mutateContext(updatedContext: EvaluationContext): Promise { if (!domain) { - throw new Error('No domain set for your context'); + // Set the global context + OpenFeature.setContext(updatedContext); + return; } OpenFeature.setContext(domain, updatedContext); diff --git a/packages/react/test/provider.spec.tsx b/packages/react/test/provider.spec.tsx index fca7f8ad5..f94d67f55 100644 --- a/packages/react/test/provider.spec.tsx +++ b/packages/react/test/provider.spec.tsx @@ -1,8 +1,8 @@ import { EvaluationContext, OpenFeature } from '@openfeature/web-sdk'; import '@testing-library/jest-dom'; // see: https://testing-library.com/docs/react-testing-library/setup -import { render, renderHook, screen, waitFor } from '@testing-library/react'; +import { render, renderHook, screen, waitFor, fireEvent, act } from '@testing-library/react'; import * as React from 'react'; -import { OpenFeatureProvider, useOpenFeatureClient, useWhenProviderReady } from '../src'; +import { OpenFeatureProvider, useOpenFeatureClient, useWhenProviderReady, useContextMutator, useStringFlagValue } from '../src'; import { TestingProvider } from './test.utils'; describe('OpenFeatureProvider', () => { @@ -33,6 +33,9 @@ describe('OpenFeatureProvider', () => { if (context.user == 'bob@flags.com') { return 'both'; } + if (context.done === true) { + return 'parting'; + } return 'greeting'; }, }, @@ -136,5 +139,74 @@ describe('OpenFeatureProvider', () => { await waitFor(() => expect(screen.queryByText('👍')).toBeInTheDocument(), { timeout: DELAY * 2 }); }); }); + + describe('useMutateContext', () => { + const MutateButton = () => { + const { mutateContext } = useContextMutator(); + + return ; + }; + const TestComponent = ({ name }: { name: string}) => { + const flagValue = useStringFlagValue<'hi' | 'bye' | 'aloha'>(SUSPENSE_FLAG_KEY, 'hi'); + + return
+ +
{`${name} says ${flagValue}`}
+
; + }; + + it('should update context when a domain is set', async () => { + const DOMAIN = 'mutate-context-tests'; + OpenFeature.setProvider(DOMAIN, suspendingProvider()); + render( + {FALLBACK}}> + + + ,); + + await waitFor(() => { + expect(screen.getByText('Will says hi')).toBeInTheDocument(); + }); + + act(() => { + fireEvent.click(screen.getByText('Update Context')); + }); + await waitFor(() => { + expect(screen.getByText('Will says aloha')).toBeInTheDocument(); + }, { timeout: DELAY * 4 }); + }); + + it('should update nested contexts', async () => { + const DOMAIN1 = 'Wills Domain'; + const DOMAIN2 = 'Todds Domain'; + OpenFeature.setProvider(DOMAIN1, suspendingProvider()); + OpenFeature.setProvider(DOMAIN2, suspendingProvider()); + render( + {FALLBACK}}> + + + {FALLBACK}}> + + + + + ,); + + await waitFor(() => { + expect(screen.getByText('Todd says hi')).toBeInTheDocument(); + }); + + act(() => { + // Click the Update context button in Todds domain + fireEvent.click(screen.getAllByText('Update Context')[1]); + }); + await waitFor(() => { + expect(screen.getByText('Todd says aloha')).toBeInTheDocument(); + }, { timeout: DELAY * 4 }); + await waitFor(() => { + expect(screen.getByText('Will says hi')).toBeInTheDocument(); + }, { timeout: DELAY * 4 }); + }); + }); }); });