Skip to content

Commit f8969e9

Browse files
committed
Use actual previous context to noop useContextMutator setContext
Signed-off-by: MattIPv4 <[email protected]>
1 parent 279f9bf commit f8969e9

File tree

2 files changed

+31
-18
lines changed

2 files changed

+31
-18
lines changed

packages/react/src/context/use-context-mutator.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,19 @@ export type ContextMutation = {
3232
*/
3333
export function useContextMutator(options: ContextMutationOptions = { defaultContext: false }): ContextMutation {
3434
const { domain } = useContext(Context) || {};
35-
const previousContext = useRef<null | EvaluationContext>(null);
3635

3736
const setContext = useCallback(async (updatedContext: EvaluationContext | ((currentContext: EvaluationContext) => EvaluationContext)): Promise<void> => {
37+
const previousContext = OpenFeature.getContext(options?.defaultContext ? undefined : domain);
3838
const resolvedContext = typeof updatedContext === 'function'
39-
? updatedContext(OpenFeature.getContext(options?.defaultContext ? undefined : domain))
39+
? updatedContext(previousContext)
4040
: updatedContext;
4141

42-
if (previousContext.current !== resolvedContext) {
42+
if (previousContext !== resolvedContext) {
4343
if (!domain || options?.defaultContext) {
4444
OpenFeature.setContext(resolvedContext);
4545
} else {
4646
OpenFeature.setContext(domain, resolvedContext);
4747
}
48-
previousContext.current = resolvedContext;
4948
}
5049
}, [domain, options?.defaultContext]);
5150

packages/react/test/provider.spec.tsx

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { EvaluationContext} from '@openfeature/web-sdk';
2-
import { InMemoryProvider, OpenFeature } from '@openfeature/web-sdk';
2+
import { InMemoryProvider, OpenFeature, ProviderEvents } from '@openfeature/web-sdk';
33
import '@testing-library/jest-dom'; // see: https://testing-library.com/docs/react-testing-library/setup
44
import { render, renderHook, screen, waitFor, fireEvent, act } from '@testing-library/react';
55
import * as React from 'react';
@@ -310,32 +310,46 @@ describe('OpenFeatureProvider', () => {
310310
const DOMAIN = 'mutate-context-with-function';
311311
OpenFeature.setProvider(DOMAIN, suspendingProvider(), { done: false });
312312

313+
const reconcile = jest.fn();
314+
OpenFeature.getClient(DOMAIN).addHandler(ProviderEvents.Reconciling, reconcile);
315+
313316
const setter = jest.fn((prevContext: EvaluationContext) => ({ ...prevContext, user: '[email protected]' }));
314317
render(
315318
<OpenFeatureProvider domain={DOMAIN}>
316-
<React.Suspense fallback={<div>{FALLBACK}</div>}>
317-
<TestComponent name="Will" setter={setter} />
318-
</React.Suspense>
319+
<MutateButton setter={setter} />
319320
</OpenFeatureProvider>,
320321
);
321322

322-
await waitFor(() => {
323-
expect(screen.getByText('Will says hi')).toBeInTheDocument();
324-
});
325-
326323
act(() => {
327324
fireEvent.click(screen.getByText('Update Context'));
328325
});
329-
await waitFor(
330-
() => {
331-
expect(screen.getByText('Will says aloha')).toBeInTheDocument();
332-
},
333-
{ timeout: DELAY * 4 },
326+
expect(setter).toHaveBeenCalledTimes(1);
327+
expect(setter).toHaveBeenCalledWith({ done: false });
328+
expect(reconcile).toHaveBeenCalledTimes(1);
329+
expect(OpenFeature.getContext(DOMAIN)).toEqual({ done: false, user: '[email protected]' });
330+
});
331+
332+
it('should noop if the previous context is passed in unchanged', async () => {
333+
const DOMAIN = 'mutate-context-noop';
334+
OpenFeature.setProvider(DOMAIN, suspendingProvider(), { done: false });
335+
336+
const reconcile = jest.fn();
337+
OpenFeature.getClient(DOMAIN).addHandler(ProviderEvents.Reconciling, reconcile);
338+
339+
const setter = jest.fn((prevContext: EvaluationContext) => prevContext);
340+
render(
341+
<OpenFeatureProvider domain={DOMAIN}>
342+
<MutateButton setter={setter} />
343+
</OpenFeatureProvider>,
334344
);
335345

346+
act(() => {
347+
fireEvent.click(screen.getByText('Update Context'));
348+
});
336349
expect(setter).toHaveBeenCalledTimes(1);
337350
expect(setter).toHaveBeenCalledWith({ done: false });
338-
expect(OpenFeature.getContext(DOMAIN)).toEqual({ done: false, user: '[email protected]' });
351+
expect(reconcile).toHaveBeenCalledTimes(0);
352+
expect(OpenFeature.getContext(DOMAIN)).toEqual({ done: false });
339353
});
340354
});
341355
});

0 commit comments

Comments
 (0)