From 2fdf2f063df4825bcab4d36588670793e817122f Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Sat, 22 Jul 2023 01:50:46 -0300 Subject: [PATCH] added optimization tests --- src/__tests__/SplitTreatments.test.tsx | 48 +++++++++++++---------- src/__tests__/useSplitClient.test.tsx | 4 +- src/__tests__/useSplitTreatments.test.tsx | 23 ++++------- 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/__tests__/SplitTreatments.test.tsx b/src/__tests__/SplitTreatments.test.tsx index ce558e8..c37df09 100644 --- a/src/__tests__/SplitTreatments.test.tsx +++ b/src/__tests__/SplitTreatments.test.tsx @@ -25,6 +25,7 @@ jest.mock('../constants', () => { import { getControlTreatmentsWithConfig, WARN_ST_NO_CLIENT } from '../constants'; import { getStatus } from '../utils'; import { newSplitFactoryLocalhostInstance } from './testUtils/utils'; +import { useSplitTreatments } from '../useSplitTreatments'; describe('SplitTreatments', () => { @@ -143,13 +144,26 @@ describe('SplitTreatments', () => { }); +let renderTimes = 0; + /** - * Tests for asserting that client.getTreatmentsWithConfig is not called unnecessarely + * Tests for asserting that client.getTreatmentsWithConfig is not called unnecessarily when using SplitTreatments and useSplitTreatments. */ -describe('SplitTreatments optimization', () => { - - let renderTimes = 0; - +describe.each([ + ({ names, attributes }) => ( + + {() => { + renderTimes++; + return null; + }} + + ), + ({ names, attributes }) => { + useSplitTreatments(names, attributes); + renderTimes++; + return null; + } +])('SplitTreatments & useSplitTreatments optimization', (InnerComponent) => { let outerFactory = SplitSdk(sdkBrowser); (outerFactory as any).client().__emitter__.emit(Event.SDK_READY); @@ -162,12 +176,7 @@ describe('SplitTreatments optimization', () => { return ( - - {() => { - renderTimes++; - return null; - }} - + ); @@ -224,7 +233,7 @@ describe('SplitTreatments optimization', () => { expect(outerFactory.client().getTreatmentsWithConfig).toBeCalledTimes(2); }); - it('rerenders and re-evaluates feature flags if lastUpdate timestamp changes (e.g., SDK_UPDATE event).', (done) => { + it('rerenders and re-evaluates feature flags if lastUpdate timestamp changes (e.g., SDK_UPDATE event).', () => { expect(renderTimes).toBe(1); // State update and split evaluation @@ -234,16 +243,13 @@ describe('SplitTreatments optimization', () => { (outerFactory as any).client().destroy(); wrapper.rerender(); - setTimeout(() => { - // Updates were batched as a single render, due to automatic batching https://reactjs.org/blog/2022/03/29/react-v18.html#new-feature-automatic-batching - expect(renderTimes).toBe(3); - expect(outerFactory.client().getTreatmentsWithConfig).toBeCalledTimes(2); + // Updates were batched as a single render, due to automatic batching https://reactjs.org/blog/2022/03/29/react-v18.html#new-feature-automatic-batching + expect(renderTimes).toBe(3); + expect(outerFactory.client().getTreatmentsWithConfig).toBeCalledTimes(2); - // Restore the client to be READY - (outerFactory as any).client().__restore(); - (outerFactory as any).client().__emitter__.emit(Event.SDK_READY); - done(); - }) + // Restore the client to be READY + (outerFactory as any).client().__restore(); + (outerFactory as any).client().__emitter__.emit(Event.SDK_READY); }); it('rerenders and re-evaluates feature flags if client changes.', () => { diff --git a/src/__tests__/useSplitClient.test.tsx b/src/__tests__/useSplitClient.test.tsx index d916a1b..19ff057 100644 --- a/src/__tests__/useSplitClient.test.tsx +++ b/src/__tests__/useSplitClient.test.tsx @@ -97,10 +97,10 @@ test('useSplitClient must update on SDK events', () => { ); act(() => mainClient.__emitter__.emit(Event.SDK_READY_FROM_CACHE)); - act(() => user2Client.__emitter__.emit(Event.SDK_READY_FROM_CACHE)); act(() => mainClient.__emitter__.emit(Event.SDK_READY)); - act(() => user2Client.__emitter__.emit(Event.SDK_READY)); act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); + act(() => user2Client.__emitter__.emit(Event.SDK_READY_FROM_CACHE)); + act(() => user2Client.__emitter__.emit(Event.SDK_READY)); act(() => user2Client.__emitter__.emit(Event.SDK_UPDATE)); // SplitContext renders 3 times: initially, when ready from cache, and when ready. diff --git a/src/__tests__/useSplitTreatments.test.tsx b/src/__tests__/useSplitTreatments.test.tsx index 8ed4a9c..3c87720 100644 --- a/src/__tests__/useSplitTreatments.test.tsx +++ b/src/__tests__/useSplitTreatments.test.tsx @@ -34,14 +34,12 @@ function validateTreatments({ treatments, isReady, isReadyFromCache }: ISplitTre } } -test('useSplitTreatments', async () => { +test('useSplitTreatments must update on SDK events', async () => { const outerFactory = SplitSdk(sdkBrowser); const mainClient = outerFactory.client() as any; const user2Client = outerFactory.client('user_2') as any; let countSplitContext = 0, countSplitTreatments = 0, countUseSplitTreatments = 0, countUseSplitTreatmentsUser2 = 0, countUseSplitTreatmentsUser2WithUpdate = 0; - const lastUpdateSetUser2 = new Set(); - const lastUpdateSetUser2WithUpdate = new Set(); render( @@ -63,7 +61,6 @@ test('useSplitTreatments', async () => { const context = useSplitTreatments(['split_test'], undefined, 'user_2'); expect(context.client).toBe(user2Client); validateTreatments(context); - lastUpdateSetUser2.add(context.lastUpdate); countUseSplitTreatmentsUser2++; return null; })} @@ -71,7 +68,6 @@ test('useSplitTreatments', async () => { const context = useSplitTreatments(['split_test'], undefined, 'user_2', { updateOnSdkUpdate: true }); expect(context.client).toBe(user2Client); validateTreatments(context); - lastUpdateSetUser2WithUpdate.add(context.lastUpdate); countUseSplitTreatmentsUser2WithUpdate++; return null; })} @@ -79,15 +75,12 @@ test('useSplitTreatments', async () => { ); - // Adding a delay between events to make sure they are processed with a different lastUpdate timestamp. - act(() => mainClient.__emitter__.emit(Event.SDK_READY_FROM_CACHE)); - act(() => user2Client.__emitter__.emit(Event.SDK_READY_FROM_CACHE)); - await new Promise(resolve => setTimeout(resolve, 10)); - act(() => mainClient.__emitter__.emit(Event.SDK_READY)); - act(() => user2Client.__emitter__.emit(Event.SDK_READY)); - await new Promise(resolve => setTimeout(resolve, 10)); - act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); - act(() => user2Client.__emitter__.emit(Event.SDK_UPDATE)); + await act(() => mainClient.__emitter__.emit(Event.SDK_READY_FROM_CACHE)); + await act(() => mainClient.__emitter__.emit(Event.SDK_READY)); + await act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); + await act(() => user2Client.__emitter__.emit(Event.SDK_READY_FROM_CACHE)); + await act(() => user2Client.__emitter__.emit(Event.SDK_READY)); + await act(() => user2Client.__emitter__.emit(Event.SDK_UPDATE)); // SplitContext renders 3 times: initially, when ready from cache, and when ready. expect(countSplitContext).toEqual(3); @@ -100,10 +93,8 @@ test('useSplitTreatments', async () => { // If useSplitTreatments uses a different client than the context one, it renders when the context renders and when the new client is ready and ready from cache. expect(countUseSplitTreatmentsUser2).toEqual(countSplitContext + 2); - expect(lastUpdateSetUser2.size).toEqual(3); // If it is used with `updateOnSdkUpdate: true`, it also renders when the client emits an SDK_UPDATE event. expect(countUseSplitTreatmentsUser2WithUpdate).toEqual(countSplitContext + 3); - expect(lastUpdateSetUser2WithUpdate.size).toEqual(4); expect(user2Client.getTreatmentsWithConfig).toHaveBeenCalledTimes(5); expect(user2Client.getTreatmentsWithConfig).toHaveBeenLastCalledWith(['split_test'], undefined); });