Skip to content

Commit

Permalink
Component prop update test
Browse files Browse the repository at this point in the history
  • Loading branch information
EmilianoSanchez committed Jan 15, 2024
1 parent 53a0a90 commit 561d83d
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/SplitFactoryProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function SplitFactoryProvider(props: ISplitFactoryProps) {
}

const [stateFactory, setStateFactory] = React.useState(propFactory || null);
const factory = propFactory || stateFactory;
const factory = propFactory || (stateFactory && config === (stateFactory as IFactoryWithClients).config ? stateFactory : null);
const client = factory ? getSplitClient(factory) : null;

React.useEffect(() => {
Expand Down
72 changes: 53 additions & 19 deletions src/__tests__/SplitFactoryProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -336,40 +336,74 @@ describe('SplitFactoryProvider', () => {
logSpy.mockRestore();
});

test('cleans up on unmount.', () => {
let destroyMainClientSpy;
let destroySharedClientSpy;
const wrapper = render(
<SplitFactoryProvider config={sdkBrowser} >
{({ factory }) => {
if (!factory) return null; // 1st render
test('cleans up on update and unmount.', () => {
let renderTimes = 0;
const createdFactories = new Set<SplitIO.ISDK>();
const clientDestroySpies: jest.SpyInstance[] = [];

const Component = ({ factory, isReady, hasTimedout }: ISplitFactoryChildProps) => {
renderTimes++;
if (factory) createdFactories.add(factory);

switch (renderTimes) {
case 1:
case 3:
expect(isReady).toBe(false);
expect(hasTimedout).toBe(false);
expect(factory).toBe(null);
return null;

// 2nd render (SDK ready)
case 2:
case 4:
expect(isReady).toBe(true);
expect(hasTimedout).toBe(true);
expect(__factories.size).toBe(1);
destroyMainClientSpy = jest.spyOn((factory as SplitIO.ISDK).client(), 'destroy');
clientDestroySpies.push(jest.spyOn((factory as SplitIO.ISDK).client(), 'destroy'));
return (
<SplitClient splitKey='other_key' >
{({ client }) => {
destroySharedClientSpy = jest.spyOn(client as SplitIO.IClient, 'destroy');
clientDestroySpies.push(jest.spyOn(client as SplitIO.IClient, 'destroy'));
return null;
}}
</SplitClient>
);
}}
</SplitFactoryProvider>
);
case 5:
throw new Error('Child must not be rerendered');
}
};

// SDK ready to re-render
act(() => {
const emitSdkEvents = () => {
const factory = (SplitSdk as jest.Mock).mock.results.slice(-1)[0].value;
factory.client().__emitter__.emit(Event.SDK_READY_TIMED_OUT)
factory.client().__emitter__.emit(Event.SDK_READY)
});
};

// 1st render
const wrapper = render(
<SplitFactoryProvider config={sdkBrowser} >
{Component}
</SplitFactoryProvider>
);

// 2nd render: SDK ready (timeout is ignored due to updateOnSdkTimedout=false)
act(emitSdkEvents);

// 3rd render: Update config prop -> factory is recreated
wrapper.rerender(
<SplitFactoryProvider config={{ ...sdkBrowser }} updateOnSdkReady={false} updateOnSdkTimedout={true} >
{Component}
</SplitFactoryProvider>
);

// 4th render: SDK timeout (ready is ignored due to updateOnSdkReady=false)
act(emitSdkEvents);

wrapper.unmount();
// the factory created by the component is removed from `factories` cache and its clients are destroyed

// Created factories are removed from `factories` cache and their clients are destroyed
expect(createdFactories.size).toBe(2);
expect(__factories.size).toBe(0);
expect(destroyMainClientSpy).toBeCalledTimes(1);
expect(destroySharedClientSpy).toBeCalledTimes(1);
clientDestroySpies.forEach(spy => expect(spy).toBeCalledTimes(1));
});

test('doesn\'t clean up on unmount if the factory is provided as a prop.', () => {
Expand Down

0 comments on commit 561d83d

Please sign in to comment.