-
Notifications
You must be signed in to change notification settings - Fork 49
feat: use mutate context hook #1031
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
286ddb7
83836bc
b360c23
9c10f55
c8991f5
f438017
ba9081f
2bab15a
097e1c3
ed35f05
5f9449b
57b5cb6
232c174
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| export * from './provider'; | ||
| export * from './use-open-feature-client'; | ||
| export * from './use-when-provider-ready'; | ||
| export * from './test-provider'; | ||
| export * from './test-provider'; | ||
| export * from './use-context-mutator'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { useCallback, useContext, useRef } from 'react'; | ||
| import { OpenFeature, EvaluationContext } from '@openfeature/web-sdk'; | ||
| import { Context } from './context'; | ||
|
|
||
| /** | ||
| * | ||
| * A hook for accessing context mutating functions. | ||
| * | ||
| */ | ||
| export function useContextMutator() { | ||
| const { domain } = useContext(Context) || {}; | ||
| const previousContext = useRef<null | EvaluationContext>(null); | ||
|
|
||
| const mutateContext = useCallback(async (updatedContext: EvaluationContext) => { | ||
| if (previousContext.current !== updatedContext) { | ||
| if (!domain) { | ||
| OpenFeature.setContext(updatedContext); | ||
| } else { | ||
| OpenFeature.setContext(domain, updatedContext); | ||
| } | ||
| previousContext.current = updatedContext; | ||
| } | ||
| }, [domain]); | ||
|
|
||
| return { | ||
| mutateContext, | ||
| }; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 == '[email protected]') { | ||
| 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 <button onClick={() => mutateContext({ user: '[email protected]' })}>Update Context</button>; | ||
| }; | ||
| const TestComponent = ({ name }: { name: string}) => { | ||
| const flagValue = useStringFlagValue<'hi' | 'bye' | 'aloha'>(SUSPENSE_FLAG_KEY, 'hi'); | ||
|
|
||
| return <div> | ||
| <MutateButton /> | ||
| <div>{`${name} says ${flagValue}`}</div> | ||
| </div>; | ||
| }; | ||
|
|
||
| it('should update context when a domain is set', async () => { | ||
| const DOMAIN = 'mutate-context-tests'; | ||
| OpenFeature.setProvider(DOMAIN, suspendingProvider()); | ||
| render(<OpenFeatureProvider domain={DOMAIN}> | ||
| <React.Suspense fallback={<div>{FALLBACK}</div>}> | ||
| <TestComponent name="Will"/> | ||
| </React.Suspense> | ||
| </OpenFeatureProvider>,); | ||
|
|
||
| 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(<OpenFeatureProvider domain={DOMAIN1}> | ||
| <React.Suspense fallback={<div>{FALLBACK}</div>}> | ||
| <TestComponent name="Will"/> | ||
| <OpenFeatureProvider domain={DOMAIN2}> | ||
| <React.Suspense fallback={<div>{FALLBACK}</div>}> | ||
| <TestComponent name="Todd"/> | ||
| </React.Suspense> | ||
| </OpenFeatureProvider> | ||
| </React.Suspense> | ||
| </OpenFeatureProvider>,); | ||
|
|
||
| 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 }); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
Uh oh!
There was an error while loading. Please reload this page.