From 2b100b3d4ea48f785c5278239011876c6cb304a8 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 9 Apr 2025 11:16:34 -0300 Subject: [PATCH 01/10] Support default options in the SplitFactoryProvider to share via context --- src/SplitFactoryProvider.tsx | 8 +++++- src/types.ts | 56 ++++++++++++++++++------------------ src/useSplitClient.ts | 7 ++--- 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/SplitFactoryProvider.tsx b/src/SplitFactoryProvider.tsx index 219a0f3..d9e839e 100644 --- a/src/SplitFactoryProvider.tsx +++ b/src/SplitFactoryProvider.tsx @@ -62,7 +62,13 @@ export function SplitFactoryProvider(props: ISplitFactoryProviderProps) { }, [config, propFactory, factory]); return ( - + {props.children} ); diff --git a/src/types.ts b/src/types.ts index 6fb4f8a..3697ac9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -39,33 +39,6 @@ export interface ISplitStatus { lastUpdate: number; } -/** - * Split Context Value interface. It is used to define the value types of Split Context - */ -export interface ISplitContextValues extends ISplitStatus { - - /** - * Split factory instance. - * - * NOTE: This property is available for accessing factory methods not covered by the library hooks, - * such as Logging configuration and User Consent. - * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#logging}), - * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#user-consent} - */ - factory?: SplitIO.IBrowserSDK; - - /** - * Split client instance. - * - * NOTE: This property is not recommended for direct use, as better alternatives are available: - * - `useSplitTreatments` hook to evaluate feature flags. - * - `useTrack` hook to track events. - * - * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#2-instantiate-the-sdk-and-create-a-new-split-client} - */ - client?: SplitIO.IBrowserClient; -} - /** * Update Props interface. It defines the props used to configure what SDK events are listened to update the component. */ @@ -101,6 +74,33 @@ export interface IUpdateProps { updateOnSdkReadyFromCache?: boolean; } +/** + * Split Context Value interface. It is used to define the value types of Split Context + */ +export interface ISplitContextValues extends ISplitStatus, IUpdateProps { + + /** + * Split factory instance. + * + * NOTE: This property is available for accessing factory methods not covered by the library hooks, + * such as Logging configuration and User Consent. + * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#logging}), + * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#user-consent} + */ + factory?: SplitIO.IBrowserSDK; + + /** + * Split client instance. + * + * NOTE: This property is not recommended for direct use, as better alternatives are available: + * - `useSplitTreatments` hook to evaluate feature flags. + * - `useTrack` hook to track events. + * + * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#2-instantiate-the-sdk-and-create-a-new-split-client} + */ + client?: SplitIO.IBrowserClient; +} + /** * Props interface for components wrapped by the `withSplitFactory` HOC. These props are provided by the HOC to the wrapped component. * @@ -112,7 +112,7 @@ export interface ISplitFactoryChildProps extends ISplitContextValues { } * SplitFactoryProvider Props interface. These are the props accepted by the `SplitFactoryProvider` component, * used to instantiate a factory and provide it to the Split Context. */ -export interface ISplitFactoryProviderProps { +export interface ISplitFactoryProviderProps extends IUpdateProps { /** * Config object used to instantiate a Split factory. diff --git a/src/useSplitClient.ts b/src/useSplitClient.ts index d9344af..9aee6b5 100644 --- a/src/useSplitClient.ts +++ b/src/useSplitClient.ts @@ -24,12 +24,11 @@ export const DEFAULT_UPDATE_OPTIONS = { * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients} */ export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextValues { - const { - updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate, splitKey, attributes - } = { ...DEFAULT_UPDATE_OPTIONS, ...options }; - const context = useSplitContext(); const { client: contextClient, factory } = context; + const { + updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate, splitKey, attributes + } = { ...DEFAULT_UPDATE_OPTIONS, ...context, ...options }; // @TODO Move `getSplitClient` side effects and reduce the function cognitive complexity // @TODO Once `SplitClient` is removed, which updates the context, simplify next line as `const client = factory ? getSplitClient(factory, splitKey) : undefined;` From e5d1968a7e19d796b49609347be975b39718e030 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 9 Apr 2025 14:49:12 -0300 Subject: [PATCH 02/10] SplitClient default options --- src/SplitClient.tsx | 8 +++++++- src/__tests__/SplitTreatments.test.tsx | 10 +++++----- src/types.ts | 20 +++++++++++--------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/SplitClient.tsx b/src/SplitClient.tsx index fd146ae..832f916 100644 --- a/src/SplitClient.tsx +++ b/src/SplitClient.tsx @@ -17,7 +17,13 @@ export function SplitClient(props: ISplitClientProps) { const context = useSplitClient(props); return ( - + { typeof children === 'function' ? children(context) : diff --git a/src/__tests__/SplitTreatments.test.tsx b/src/__tests__/SplitTreatments.test.tsx index 4ff0a78..cf21ea4 100644 --- a/src/__tests__/SplitTreatments.test.tsx +++ b/src/__tests__/SplitTreatments.test.tsx @@ -385,7 +385,7 @@ describe.each([ }); expect(renderTimesComp1).toBe(2); - expect(renderTimesComp2).toBe(2); // updateOnSdkReadyFromCache === false, in second component + expect(renderTimesComp2).toBe(1); // updateOnSdkReadyFromCache === false, in second component act(() => { (outerFactory as any).client().__emitter__.emit(Event.SDK_READY_TIMED_OUT); @@ -393,7 +393,7 @@ describe.each([ }); expect(renderTimesComp1).toBe(3); - expect(renderTimesComp2).toBe(3); + expect(renderTimesComp2).toBe(2); act(() => { (outerFactory as any).client().__emitter__.emit(Event.SDK_READY); @@ -401,7 +401,7 @@ describe.each([ }); expect(renderTimesComp1).toBe(3); // updateOnSdkReady === false, in first component - expect(renderTimesComp2).toBe(4); + expect(renderTimesComp2).toBe(3); act(() => { (outerFactory as any).client().__emitter__.emit(Event.SDK_UPDATE); @@ -409,9 +409,9 @@ describe.each([ }); expect(renderTimesComp1).toBe(4); - expect(renderTimesComp2).toBe(5); + expect(renderTimesComp2).toBe(4); expect(outerFactory.client().getTreatmentsWithConfig).toBeCalledTimes(3); // renderTimes - 1, for the 1st render where SDK is not operational - expect(outerFactory.client('user2').getTreatmentsWithConfig).toBeCalledTimes(4); // idem + expect(outerFactory.client('user2').getTreatmentsWithConfig).toBeCalledTimes(3); // idem }); it('rerenders and re-evaluates feature flags if client attributes changes.', (done) => { diff --git a/src/types.ts b/src/types.ts index 3697ac9..ef5ead3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,7 +34,9 @@ export interface ISplitStatus { isDestroyed: boolean; /** - * Indicates when was the last status event, either `SDK_READY`, `SDK_READY_FROM_CACHE`, `SDK_READY_TIMED_OUT` or `SDK_UPDATE`. + * `lastUpdate` indicates when the most recent status event was emitted. This timestamp is only updated for events that are being listened to, + * configured via the `updateOnSdkReady` option for `SDK_READY` event, `updateOnSdkReadyFromCache` for `SDK_READY_FROM_CACHE` event, + * `updateOnSdkTimedout` for `SDK_READY_TIMED_OUT` event, and `updateOnSdkUpdate` for `SDK_UPDATE` event. */ lastUpdate: number; } @@ -45,29 +47,29 @@ export interface ISplitStatus { export interface IUpdateProps { /** - * `updateOnSdkUpdate` indicates if the component will update (i.e., re-render) in case of an `SDK_UPDATE` event. - * If `true`, components consuming the context (such as `SplitClient` and `SplitTreatments`) will re-render on `SDK_UPDATE`. + * `updateOnSdkUpdate` indicates if the hook or component will update (i.e., re-render) in case of an `SDK_UPDATE` event. + * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_UPDATE`. * It's value is `true` by default. */ updateOnSdkUpdate?: boolean; /** - * `updateOnSdkTimedout` indicates if the component will update (i.e., re-render) in case of a `SDK_READY_TIMED_OUT` event. - * If `true`, components consuming the context (such as `SplitClient` and `SplitTreatments`) will re-render on `SDK_READY_TIMED_OUT`. + * `updateOnSdkTimedout` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY_TIMED_OUT` event. + * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY_TIMED_OUT`. * It's value is `true` by default. */ updateOnSdkTimedout?: boolean; /** - * `updateOnSdkReady` indicates if the component will update (i.e., re-render) in case of a `SDK_READY` event. - * If `true`, components consuming the context (such as `SplitClient` and `SplitTreatments`) will re-render on `SDK_READY`. + * `updateOnSdkReady` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY` event. + * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY`. * It's value is `true` by default. */ updateOnSdkReady?: boolean; /** - * `updateOnSdkReadyFromCache` indicates if the component will update (i.e., re-render) in case of a `SDK_READY_FROM_CACHE` event. - * If `true`, components consuming the context (such as `SplitClient` and `SplitTreatments`) will re-render on `SDK_READY_FROM_CACHE`. + * `updateOnSdkReadyFromCache` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY_FROM_CACHE` event. + * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY_FROM_CACHE`. * This params is only relevant when using `'LOCALSTORAGE'` as storage type, since otherwise the event is never emitted. * It's value is `true` by default. */ From e481b0ebb29fbd4b2030b05d013dd95b6e6233f2 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 11 Apr 2025 16:38:12 -0300 Subject: [PATCH 03/10] Upgrade dev dependencies to use React 19 --- package-lock.json | 656 +++++++----------------- package.json | 16 +- src/__tests__/withSplitClient.test.tsx | 20 +- src/__tests__/withSplitFactory.test.tsx | 20 +- 4 files changed, 211 insertions(+), 501 deletions(-) diff --git a/package-lock.json b/package-lock.json index baab405..2caa447 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,12 +16,12 @@ }, "devDependencies": { "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^14.0.0", + "@testing-library/react": "^16.3.0", "@types/events": "^3.0.0", "@types/jest": "^27.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "@types/react-test-renderer": "^18.0.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@types/react-test-renderer": "^19.0.0", "@types/shallowequal": "^1.1.1", "@typescript-eslint/eslint-plugin": "^6.6.0", "@typescript-eslint/parser": "^6.6.0", @@ -33,14 +33,14 @@ "eslint-plugin-tsdoc": "^0.3.0", "husky": "^3.1.0", "jest": "^27.2.3", - "react": "^18.0.0", - "react-dom": "^18.0.0", - "react-test-renderer": "^18.0.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-test-renderer": "^19.0.0", "replace": "^1.2.1", "rimraf": "^3.0.0", "ts-jest": "^27.0.5", "ts-loader": "^6.2.1", - "typescript": "4.4.4", + "typescript": "4.5.5", "webpack": "^5.53.0", "webpack-cli": "^4.8.0", "webpack-merge": "^5.8.0" @@ -1616,22 +1616,24 @@ } }, "node_modules/@testing-library/dom": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.0.1.tgz", - "integrity": "sha512-fTOVsMY9QLFCCXRHG3Ese6cMH5qIWwSbgxZsgeF5TNsy81HKaZ4kgehnSF8FsR3OF+numlIV2YcU79MzbnhSig==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", + "aria-query": "5.3.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "pretty-format": "^27.0.2" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/@testing-library/dom/node_modules/ansi-styles": { @@ -1639,6 +1641,8 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1654,6 +1658,8 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1670,6 +1676,8 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1681,13 +1689,17 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT", + "peer": true }, "node_modules/@testing-library/dom/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -1697,6 +1709,8 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -1794,21 +1808,31 @@ } }, "node_modules/@testing-library/react": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.0.0.tgz", - "integrity": "sha512-S04gSNJbYE30TlIMLTzv6QCTzt9AqIF5y6s6SzVFILNcNvbV/jU96GeiTPillGQo+Ny64M/5PV7klNYYgv5Dfg==", + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz", + "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^9.0.0", - "@types/react-dom": "^18.0.0" + "@babel/runtime": "^7.12.5" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, "node_modules/@tootallnate/once": { @@ -1821,10 +1845,12 @@ } }, "node_modules/@types/aria-query": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", - "dev": true + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true }, "node_modules/@types/babel__core": { "version": "7.1.16", @@ -1950,47 +1976,36 @@ "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", "dev": true }, - "node_modules/@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", - "dev": true - }, "node_modules/@types/react": { - "version": "18.0.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", - "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.1.tgz", + "integrity": "sha512-ePapxDL7qrgqSF67s0h9m412d9DbXyC1n59O2st+9rjuuamWsZuD2w55rqY12CbzsZ7uVXb5Nw0gEp9Z8MMutQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.0.11", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", - "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "version": "19.1.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.2.tgz", + "integrity": "sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==", "dev": true, - "dependencies": { - "@types/react": "*" + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" } }, "node_modules/@types/react-test-renderer": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.0.0.tgz", - "integrity": "sha512-C7/5FBJ3g3sqUahguGi03O79b8afNeSD6T8/GU50oQrJCU0bVCCGQHaGKUbg2Ce8VQEEqTw8/HiS6lXHHdgkdQ==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-19.1.0.tgz", + "integrity": "sha512-XD0WZrHqjNrxA/MaR9O22w/RNidWR9YZmBdRGI7wcnWGrv/3dA8wKCJ8m63Sn+tLJhcjmuhOi629N66W6kgWzQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true - }, "node_modules/@types/seedrandom": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.8.tgz", @@ -2640,12 +2655,13 @@ } }, "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "deep-equal": "^2.0.5" + "dequal": "^2.0.3" } }, "node_modules/array-buffer-byte-length": { @@ -3412,40 +3428,6 @@ "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", "dev": true }, - "node_modules/deep-equal": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", - "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.2", - "get-intrinsic": "^1.1.3", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-equal/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3494,6 +3476,16 @@ "node": ">=0.10" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -3743,32 +3735,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/es-module-lexer": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", @@ -5452,22 +5418,6 @@ "url": "https://opencollective.com/ioredis" } }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-array-buffer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", @@ -5646,15 +5596,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -5731,15 +5672,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -5816,15 +5748,6 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -5837,19 +5760,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -8197,6 +8107,8 @@ "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, + "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -8469,22 +8381,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -8957,28 +8853,26 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "dev": true, - "dependencies": { - "loose-envify": "^1.1.0" - }, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "dev": true, + "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.26.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^19.1.0" } }, "node_modules/react-is": { @@ -8987,38 +8881,26 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, - "node_modules/react-shallow-renderer": { - "version": "16.15.0", - "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", - "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", - "dev": true, - "dependencies": { - "object-assign": "^4.1.1", - "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/react-test-renderer": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.2.0.tgz", - "integrity": "sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-19.1.0.tgz", + "integrity": "sha512-jXkSl3CpvPYEF+p/eGDLB4sPoDX8pKkYvRl9+rR8HxLY0X04vW7hCm1/0zHoUSjPZ3bDa+wXWNTDVIw/R8aDVw==", "dev": true, + "license": "MIT", "dependencies": { - "react-is": "^18.2.0", - "react-shallow-renderer": "^16.15.0", - "scheduler": "^0.23.0" + "react-is": "^19.1.0", + "scheduler": "^0.26.0" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^19.1.0" } }, "node_modules/react-test-renderer/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", + "dev": true, + "license": "MIT" }, "node_modules/read-pkg": { "version": "5.2.0", @@ -9423,13 +9305,11 @@ } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", "dev": true, - "dependencies": { - "loose-envify": "^1.1.0" - } + "license": "MIT" }, "node_modules/schema-utils": { "version": "3.3.0", @@ -9639,18 +9519,6 @@ "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -10204,10 +10072,11 @@ } }, "node_modules/typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10725,21 +10594,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", @@ -12142,15 +11996,16 @@ } }, "@testing-library/dom": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.0.1.tgz", - "integrity": "sha512-fTOVsMY9QLFCCXRHG3Ese6cMH5qIWwSbgxZsgeF5TNsy81HKaZ4kgehnSF8FsR3OF+numlIV2YcU79MzbnhSig==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "dev": true, + "peer": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", - "aria-query": "^5.0.0", + "aria-query": "5.3.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", @@ -12162,6 +12017,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "peer": true, "requires": { "color-convert": "^2.0.1" } @@ -12171,6 +12027,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12181,6 +12038,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "peer": true, "requires": { "color-name": "~1.1.4" } @@ -12189,19 +12047,22 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "peer": true }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "dev": true, + "peer": true }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "peer": true, "requires": { "has-flag": "^4.0.0" } @@ -12277,14 +12138,12 @@ } }, "@testing-library/react": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.0.0.tgz", - "integrity": "sha512-S04gSNJbYE30TlIMLTzv6QCTzt9AqIF5y6s6SzVFILNcNvbV/jU96GeiTPillGQo+Ny64M/5PV7klNYYgv5Dfg==", + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz", + "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==", "dev": true, "requires": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^9.0.0", - "@types/react-dom": "^18.0.0" + "@babel/runtime": "^7.12.5" } }, "@tootallnate/once": { @@ -12294,10 +12153,11 @@ "dev": true }, "@types/aria-query": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", - "dev": true + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "peer": true }, "@types/babel__core": { "version": "7.1.16", @@ -12423,47 +12283,31 @@ "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", "dev": true }, - "@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", - "dev": true - }, "@types/react": { - "version": "18.0.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", - "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.1.tgz", + "integrity": "sha512-ePapxDL7qrgqSF67s0h9m412d9DbXyC1n59O2st+9rjuuamWsZuD2w55rqY12CbzsZ7uVXb5Nw0gEp9Z8MMutQ==", "dev": true, "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "@types/react-dom": { - "version": "18.0.11", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", - "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "version": "19.1.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.2.tgz", + "integrity": "sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==", "dev": true, - "requires": { - "@types/react": "*" - } + "requires": {} }, "@types/react-test-renderer": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.0.0.tgz", - "integrity": "sha512-C7/5FBJ3g3sqUahguGi03O79b8afNeSD6T8/GU50oQrJCU0bVCCGQHaGKUbg2Ce8VQEEqTw8/HiS6lXHHdgkdQ==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-19.1.0.tgz", + "integrity": "sha512-XD0WZrHqjNrxA/MaR9O22w/RNidWR9YZmBdRGI7wcnWGrv/3dA8wKCJ8m63Sn+tLJhcjmuhOi629N66W6kgWzQ==", "dev": true, "requires": { "@types/react": "*" } }, - "@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "dev": true - }, "@types/seedrandom": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.8.tgz", @@ -12954,12 +12798,12 @@ } }, "aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, "requires": { - "deep-equal": "^2.0.5" + "dequal": "^2.0.3" } }, "array-buffer-byte-length": { @@ -13551,39 +13395,6 @@ "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", "dev": true }, - "deep-equal": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", - "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.2", - "get-intrinsic": "^1.1.3", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - } - } - }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -13617,6 +13428,12 @@ "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -13822,31 +13639,6 @@ "which-typed-array": "^1.1.9" } }, - "es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - } - } - }, "es-module-lexer": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", @@ -15083,16 +14875,6 @@ "standard-as-callback": "^2.1.0" } }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, "is-array-buffer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", @@ -15208,12 +14990,6 @@ "is-extglob": "^2.1.1" } }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true - }, "is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -15263,12 +15039,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true - }, "is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -15321,12 +15091,6 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true - }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -15336,16 +15100,6 @@ "call-bind": "^1.0.2" } }, - "is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -17108,7 +16862,8 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true + "dev": true, + "peer": true }, "make-dir": { "version": "3.1.0", @@ -17326,16 +17081,6 @@ "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "dev": true }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -17687,22 +17432,18 @@ } }, "react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0" - } + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "dev": true }, "react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "dev": true, "requires": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.26.0" } }, "react-is": { @@ -17711,31 +17452,20 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, - "react-shallow-renderer": { - "version": "16.15.0", - "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", - "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" - } - }, "react-test-renderer": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.2.0.tgz", - "integrity": "sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-19.1.0.tgz", + "integrity": "sha512-jXkSl3CpvPYEF+p/eGDLB4sPoDX8pKkYvRl9+rR8HxLY0X04vW7hCm1/0zHoUSjPZ3bDa+wXWNTDVIw/R8aDVw==", "dev": true, "requires": { - "react-is": "^18.2.0", - "react-shallow-renderer": "^16.15.0", - "scheduler": "^0.23.0" + "react-is": "^19.1.0", + "scheduler": "^0.26.0" }, "dependencies": { "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", "dev": true } } @@ -18029,13 +17759,10 @@ } }, "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0" - } + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "dev": true }, "schema-utils": { "version": "3.3.0", @@ -18213,15 +17940,6 @@ "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" }, - "stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "requires": { - "internal-slot": "^1.0.4" - } - }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -18613,9 +18331,9 @@ } }, "typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", "dev": true }, "unbox-primitive": { @@ -18987,18 +18705,6 @@ "is-symbol": "^1.0.3" } }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", diff --git a/package.json b/package.json index 936cb8e..f0f5cbf 100644 --- a/package.json +++ b/package.json @@ -70,12 +70,12 @@ }, "devDependencies": { "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^14.0.0", + "@testing-library/react": "^16.3.0", "@types/events": "^3.0.0", "@types/jest": "^27.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "@types/react-test-renderer": "^18.0.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@types/react-test-renderer": "^19.0.0", "@types/shallowequal": "^1.1.1", "@typescript-eslint/eslint-plugin": "^6.6.0", "@typescript-eslint/parser": "^6.6.0", @@ -87,14 +87,14 @@ "eslint-plugin-tsdoc": "^0.3.0", "husky": "^3.1.0", "jest": "^27.2.3", - "react": "^18.0.0", - "react-dom": "^18.0.0", - "react-test-renderer": "^18.0.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-test-renderer": "^19.0.0", "replace": "^1.2.1", "rimraf": "^3.0.0", "ts-jest": "^27.0.5", "ts-loader": "^6.2.1", - "typescript": "4.4.4", + "typescript": "4.5.5", "webpack": "^5.53.0", "webpack-cli": "^4.8.0", "webpack-merge": "^5.8.0" diff --git a/src/__tests__/withSplitClient.test.tsx b/src/__tests__/withSplitClient.test.tsx index 9676a62..f4d6c0d 100644 --- a/src/__tests__/withSplitClient.test.tsx +++ b/src/__tests__/withSplitClient.test.tsx @@ -18,6 +18,10 @@ import { withSplitClient } from '../withSplitClient'; describe('withSplitClient', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + test('passes no-ready props to the child if client is not ready.', () => { const Component = withSplitFactory(sdkBrowser)( withSplitClient('user1')( @@ -77,15 +81,13 @@ describe('withSplitClient', () => { ); render(); - expect(SplitClientSpy).toHaveBeenLastCalledWith( - expect.objectContaining({ - updateOnSdkUpdate, - updateOnSdkTimedout, - updateOnSdkReady, - updateOnSdkReadyFromCache, - }), - expect.anything() - ); + expect(SplitClientSpy).toHaveBeenCalledTimes(2); + expect(SplitClientSpy.mock.calls[1][0]).toMatchObject({ + updateOnSdkUpdate, + updateOnSdkTimedout, + updateOnSdkReady, + updateOnSdkReadyFromCache, + }); }); test('attributes binding test with utility', (done) => { diff --git a/src/__tests__/withSplitFactory.test.tsx b/src/__tests__/withSplitFactory.test.tsx index 5f8f18e..95ad025 100644 --- a/src/__tests__/withSplitFactory.test.tsx +++ b/src/__tests__/withSplitFactory.test.tsx @@ -17,6 +17,10 @@ import { withSplitFactory } from '../withSplitFactory'; describe('withSplitFactory', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + test('passes no-ready props to the child if initialized with a no ready factory (e.g., using config object).', () => { const Component = withSplitFactory(sdkBrowser)( ({ factory, isReady, isReadyFromCache, hasTimedout, isTimedout, isDestroyed, lastUpdate }: ISplitFactoryChildProps) => { @@ -69,15 +73,13 @@ describe('withSplitFactory', () => { render(); - expect(SplitClient).toHaveBeenLastCalledWith( - expect.objectContaining({ - updateOnSdkUpdate, - updateOnSdkTimedout, - updateOnSdkReady, - updateOnSdkReadyFromCache - }), - expect.anything(), - ); + expect(SplitClient).toHaveBeenCalledTimes(1); + expect((SplitClient as jest.Mock).mock.calls[0][0]).toMatchObject({ + updateOnSdkUpdate, + updateOnSdkTimedout, + updateOnSdkReady, + updateOnSdkReadyFromCache + }); }); }); From 9d603efb5cb2e988a39180a19a9eb6d0343ef962 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 11 Apr 2025 18:06:01 -0300 Subject: [PATCH 04/10] Handle undefined values --- src/SplitClient.tsx | 8 ++++---- src/useSplitClient.ts | 17 ++++++----------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/SplitClient.tsx b/src/SplitClient.tsx index 832f916..4715d67 100644 --- a/src/SplitClient.tsx +++ b/src/SplitClient.tsx @@ -19,10 +19,10 @@ export function SplitClient(props: ISplitClientProps) { return ( { typeof children === 'function' ? diff --git a/src/useSplitClient.ts b/src/useSplitClient.ts index 9aee6b5..3b3e217 100644 --- a/src/useSplitClient.ts +++ b/src/useSplitClient.ts @@ -3,13 +3,6 @@ import { useSplitContext } from './SplitContext'; import { getSplitClient, initAttributes, getStatus } from './utils'; import { ISplitContextValues, IUseSplitClientOptions } from './types'; -export const DEFAULT_UPDATE_OPTIONS = { - updateOnSdkUpdate: true, - updateOnSdkTimedout: true, - updateOnSdkReady: true, - updateOnSdkReadyFromCache: true, -}; - /** * `useSplitClient` is a hook that returns an Split Context object with the client and its status corresponding to the provided key. * @@ -23,12 +16,14 @@ export const DEFAULT_UPDATE_OPTIONS = { * * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients} */ -export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextValues { +export function useSplitClient(options: IUseSplitClientOptions = {}): ISplitContextValues { const context = useSplitContext(); const { client: contextClient, factory } = context; - const { - updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate, splitKey, attributes - } = { ...DEFAULT_UPDATE_OPTIONS, ...context, ...options }; + const { splitKey, attributes } = options; + const updateOnSdkReady = options.updateOnSdkReady ?? context.updateOnSdkReady; + const updateOnSdkReadyFromCache = options.updateOnSdkReadyFromCache ?? context.updateOnSdkReadyFromCache; + const updateOnSdkTimedout = options.updateOnSdkTimedout ?? context.updateOnSdkTimedout; + const updateOnSdkUpdate = options.updateOnSdkUpdate ?? context.updateOnSdkUpdate; // @TODO Move `getSplitClient` side effects and reduce the function cognitive complexity // @TODO Once `SplitClient` is removed, which updates the context, simplify next line as `const client = factory ? getSplitClient(factory, splitKey) : undefined;` From 8eea928d7723afa057ad28088c226a4b2292a19c Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 11 Apr 2025 18:42:14 -0300 Subject: [PATCH 05/10] Update changelog entry --- CHANGES.txt | 5 ++++- src/__tests__/useSplitClient.test.tsx | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index fb80a8e..38b897c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,7 @@ -2.1.1 (April 8, 2025) +2.1.2 (April XX, 2025) + - Updated development dependencies to use React v19 and TypeScript v4.5.5 to test compatibility and avoid type conflicts when using the SDK with React v19 types. + +2.1.1 (April 9, 2025) - Bugfixing - Fixed `useSplitClient` and `useSplitTreatments` hooks to properly respect `updateOn` options. Previously, if the hooks were re-called due to a component re-render, they used the latest version of the SDK client status ignoring when `updateOn` options were set to `false` and resulting in unexpected changes in treatment values. 2.1.0 (March 28, 2025) diff --git a/src/__tests__/useSplitClient.test.tsx b/src/__tests__/useSplitClient.test.tsx index e41e69f..c5ea38f 100644 --- a/src/__tests__/useSplitClient.test.tsx +++ b/src/__tests__/useSplitClient.test.tsx @@ -251,7 +251,7 @@ describe('useSplitClient', () => { expect(currentStatus).toEqual(previousStatus); wrapper.rerender(); // trigger re-render because there was an SDK_READY_TIMED_OUT event - expect(rendersCount).toBe(4); + expect(rendersCount).toBe(4); // @TODO optimize `useSplitClient` to avoid double render expect(currentStatus).toMatchObject({ isReady: false, isReadyFromCache: false, hasTimedout: true }); act(() => mainClient.__emitter__.emit(Event.SDK_READY)); // trigger re-render @@ -266,7 +266,7 @@ describe('useSplitClient', () => { expect(currentStatus).toEqual(previousStatus); wrapper.rerender(); // trigger re-render and update the status because updateOnSdkUpdate is true and there was an SDK_UPDATE event - expect(rendersCount).toBe(8); + expect(rendersCount).toBe(8); // @TODO optimize `useSplitClient` to avoid double render expect(currentStatus.lastUpdate).toBeGreaterThan(previousStatus.lastUpdate); act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); // trigger re-render because updateOnSdkUpdate is true From 816a9875115fde0aea71788115cd5abbf08efe26 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 14 Apr 2025 00:14:40 -0300 Subject: [PATCH 06/10] Polishing and tests --- CHANGES.txt | 3 ++- src/SplitFactoryProvider.tsx | 10 ++++---- src/__tests__/SplitClient.test.tsx | 27 +++++++++++++++++++++- src/__tests__/testUtils/utils.tsx | 8 +++++-- src/__tests__/useSplitClient.test.tsx | 27 +++++++++++++++++++--- src/__tests__/useSplitManager.test.tsx | 6 +++-- src/__tests__/withSplitTreatments.test.tsx | 8 ++----- src/useSplitClient.ts | 14 ++++++----- 8 files changed, 77 insertions(+), 26 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 38b897c..babefc0 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ -2.1.2 (April XX, 2025) +2.2.0 (April XX, 2025) + - Added `updateOnSdkUpdate`, `updateOnSdkReady`, `updateOnSdkReadyFromCache` and `updateOnSdkTimedout` props to the `SplitFactoryProvider` component to overwrite the default value (`true`) of the `updateOnSdk` options in the `useSplitClient` and `useSplitTreatments` hooks. - Updated development dependencies to use React v19 and TypeScript v4.5.5 to test compatibility and avoid type conflicts when using the SDK with React v19 types. 2.1.1 (April 9, 2025) diff --git a/src/SplitFactoryProvider.tsx b/src/SplitFactoryProvider.tsx index d9e839e..4d2d26e 100644 --- a/src/SplitFactoryProvider.tsx +++ b/src/SplitFactoryProvider.tsx @@ -27,7 +27,10 @@ import { SplitFactory } from '@splitsoftware/splitio/client'; * @see {@link https://help.split.io/hc/en-us/articles/360038825091-React-SDK#2-instantiate-the-sdk-and-create-a-new-split-client} */ export function SplitFactoryProvider(props: ISplitFactoryProviderProps) { - const { config, factory: propFactory, attributes } = props; + const { + config, factory: propFactory, attributes, + updateOnSdkReady = true, updateOnSdkReadyFromCache = true, updateOnSdkTimedout = true, updateOnSdkUpdate = true + } = props; const factory = React.useMemo void }>(() => { return propFactory ? @@ -64,10 +67,7 @@ export function SplitFactoryProvider(props: ISplitFactoryProviderProps) { return ( {props.children} diff --git a/src/__tests__/SplitClient.test.tsx b/src/__tests__/SplitClient.test.tsx index 19fbb06..2d1bf1b 100644 --- a/src/__tests__/SplitClient.test.tsx +++ b/src/__tests__/SplitClient.test.tsx @@ -13,7 +13,7 @@ import { sdkBrowser } from './testUtils/sdkConfigs'; import { ISplitClientChildProps, ISplitFactoryChildProps } from '../types'; import { SplitFactoryProvider } from '../SplitFactoryProvider'; import { SplitClient } from '../SplitClient'; -import { SplitContext } from '../SplitContext'; +import { SplitContext, useSplitContext } from '../SplitContext'; import { INITIAL_STATUS, testAttributesBinding, TestComponentProps } from './testUtils/utils'; import { getStatus } from '../utils'; import { EXCEPTION_NO_SFP } from '../constants'; @@ -360,6 +360,31 @@ describe('SplitClient', () => { testAttributesBinding(Component); }); + + test('must overwrite `updateOn` options in context', () => { + render( + + {React.createElement(() => { + expect(useSplitContext()).toEqual({ + ...INITIAL_STATUS, + updateOnSdkReadyFromCache: false + }); + return null; + })} + + {React.createElement(() => { + expect(useSplitContext()).toEqual({ + ...INITIAL_STATUS, + updateOnSdkReady: false, + updateOnSdkReadyFromCache: false, + updateOnSdkTimedout: false + }); + return null; + })} + + + ); + }); }); // Tests to validate the migration from `SplitFactoryProvider` with child as a function in v1, to `SplitFactoryProvider` + `SplitClient` with child as a function in v2. diff --git a/src/__tests__/testUtils/utils.tsx b/src/__tests__/testUtils/utils.tsx index 027655e..7571873 100644 --- a/src/__tests__/testUtils/utils.tsx +++ b/src/__tests__/testUtils/utils.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { render } from '@testing-library/react'; -import { ISplitStatus } from '../../types'; +import { ISplitStatus, IUpdateProps } from '../../types'; const { SplitFactory: originalSplitFactory } = jest.requireActual('@splitsoftware/splitio/client'); export interface TestComponentProps { @@ -116,11 +116,15 @@ export function testAttributesBinding(Component: React.FunctionComponent); } -export const INITIAL_STATUS: ISplitStatus = { +export const INITIAL_STATUS: ISplitStatus & IUpdateProps = { isReady: false, isReadyFromCache: false, isTimedout: false, hasTimedout: false, lastUpdate: 0, isDestroyed: false, + updateOnSdkReady: true, + updateOnSdkReadyFromCache: true, + updateOnSdkTimedout: true, + updateOnSdkUpdate: true, } diff --git a/src/__tests__/useSplitClient.test.tsx b/src/__tests__/useSplitClient.test.tsx index c5ea38f..ea56ad9 100644 --- a/src/__tests__/useSplitClient.test.tsx +++ b/src/__tests__/useSplitClient.test.tsx @@ -244,7 +244,7 @@ describe('useSplitClient', () => { act(() => mainClient.__emitter__.emit(Event.SDK_READY_TIMED_OUT)); // do not trigger re-render because updateOnSdkTimedout is false expect(rendersCount).toBe(1); - expect(currentStatus).toMatchObject(INITIAL_STATUS); + expect(currentStatus).toMatchObject({ ...INITIAL_STATUS, updateOnSdkUpdate: false, updateOnSdkTimedout: false }); wrapper.rerender(); expect(rendersCount).toBe(2); @@ -263,7 +263,7 @@ describe('useSplitClient', () => { wrapper.rerender(); // should not update the status (SDK_UPDATE event should be ignored) expect(rendersCount).toBe(6); - expect(currentStatus).toEqual(previousStatus); + expect(currentStatus).toEqual({ ...previousStatus, updateOnSdkTimedout: false }); wrapper.rerender(); // trigger re-render and update the status because updateOnSdkUpdate is true and there was an SDK_UPDATE event expect(rendersCount).toBe(8); // @TODO optimize `useSplitClient` to avoid double render @@ -275,10 +275,31 @@ describe('useSplitClient', () => { wrapper.rerender(); expect(rendersCount).toBe(10); - expect(currentStatus).toEqual(previousStatus); + expect(currentStatus).toEqual({ ...previousStatus, updateOnSdkUpdate: false }); act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); // do not trigger re-render because updateOnSdkUpdate is false now expect(rendersCount).toBe(10); }); + test('must prioritize explicitly provided `updateOn` options over context defaults', () => { + render( + + {React.createElement(() => { + expect(useSplitClient()).toEqual({ + ...INITIAL_STATUS, + updateOnSdkReadyFromCache: false + }); + + expect(useSplitClient({ updateOnSdkReady: false, updateOnSdkReadyFromCache: undefined, updateOnSdkTimedout: false })).toEqual({ + ...INITIAL_STATUS, + updateOnSdkReady: false, + updateOnSdkReadyFromCache: false, + updateOnSdkTimedout: false + }); + return null; + })} + + ); + }); + }); diff --git a/src/__tests__/useSplitManager.test.tsx b/src/__tests__/useSplitManager.test.tsx index a17d19c..9707042 100644 --- a/src/__tests__/useSplitManager.test.tsx +++ b/src/__tests__/useSplitManager.test.tsx @@ -32,15 +32,16 @@ describe('useSplitManager', () => { ); expect(hookResult).toStrictEqual({ + ...INITIAL_STATUS, manager: outerFactory.manager(), client: outerFactory.client(), factory: outerFactory, - ...INITIAL_STATUS, }); act(() => (outerFactory.client() as any).__emitter__.emit(Event.SDK_READY)); expect(hookResult).toStrictEqual({ + ...INITIAL_STATUS, manager: outerFactory.manager(), client: outerFactory.client(), factory: outerFactory, @@ -80,16 +81,17 @@ describe('useSplitManager', () => { ); expect(hookResult).toStrictEqual({ + ...INITIAL_STATUS, manager: outerFactory.manager(), client: outerFactory.client(), factory: outerFactory, - ...INITIAL_STATUS, }); act(() => (outerFactory.client() as any).__emitter__.emit(Event.SDK_READY)); // act(() => (outerFactory.client() as any).__emitter__.emit(Event.SDK_READY)); expect(hookResult).toStrictEqual({ + ...INITIAL_STATUS, manager: outerFactory.manager(), client: outerFactory.client(), factory: outerFactory, diff --git a/src/__tests__/withSplitTreatments.test.tsx b/src/__tests__/withSplitTreatments.test.tsx index f11f3a1..af178f2 100644 --- a/src/__tests__/withSplitTreatments.test.tsx +++ b/src/__tests__/withSplitTreatments.test.tsx @@ -8,6 +8,7 @@ jest.mock('@splitsoftware/splitio/client', () => { }); import { SplitFactory } from '@splitsoftware/splitio/client'; import { sdkBrowser } from './testUtils/sdkConfigs'; +import { INITIAL_STATUS } from './testUtils/utils'; /** Test target */ import { withSplitFactory } from '../withSplitFactory'; @@ -32,15 +33,10 @@ describe('withSplitTreatments', () => { expect((clientMock.getTreatmentsWithConfig as jest.Mock).mock.calls.length).toBe(0); expect(props).toStrictEqual({ + ...INITIAL_STATUS, factory: factory, client: clientMock, outerProp1: 'outerProp1', outerProp2: 2, treatments: getControlTreatmentsWithConfig(featureFlagNames), - isReady: false, - isReadyFromCache: false, - hasTimedout: false, - isTimedout: false, - isDestroyed: false, - lastUpdate: 0 }); return null; diff --git a/src/useSplitClient.ts b/src/useSplitClient.ts index 3b3e217..7d78b91 100644 --- a/src/useSplitClient.ts +++ b/src/useSplitClient.ts @@ -19,11 +19,13 @@ import { ISplitContextValues, IUseSplitClientOptions } from './types'; export function useSplitClient(options: IUseSplitClientOptions = {}): ISplitContextValues { const context = useSplitContext(); const { client: contextClient, factory } = context; - const { splitKey, attributes } = options; - const updateOnSdkReady = options.updateOnSdkReady ?? context.updateOnSdkReady; - const updateOnSdkReadyFromCache = options.updateOnSdkReadyFromCache ?? context.updateOnSdkReadyFromCache; - const updateOnSdkTimedout = options.updateOnSdkTimedout ?? context.updateOnSdkTimedout; - const updateOnSdkUpdate = options.updateOnSdkUpdate ?? context.updateOnSdkUpdate; + const { + splitKey, attributes, + updateOnSdkReady = context.updateOnSdkReady, + updateOnSdkReadyFromCache = context.updateOnSdkReadyFromCache, + updateOnSdkTimedout = context.updateOnSdkTimedout, + updateOnSdkUpdate = context.updateOnSdkUpdate + } = options; // @TODO Move `getSplitClient` side effects and reduce the function cognitive complexity // @TODO Once `SplitClient` is removed, which updates the context, simplify next line as `const client = factory ? getSplitClient(factory, splitKey) : undefined;` @@ -77,6 +79,6 @@ export function useSplitClient(options: IUseSplitClientOptions = {}): ISplitCont }, [client, updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate, status]); return { - factory, client, ...status + factory, client, ...status, updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate }; } From cc1a62229af11ef53f16b6a5c980ec260b24d43c Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 14 Apr 2025 00:54:04 -0300 Subject: [PATCH 07/10] rc --- .github/workflows/ci-cd.yml | 4 ++-- CHANGES.txt | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 8a4397b..cd4da2c 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -77,7 +77,7 @@ jobs: -Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }} - name: Store assets - if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development') + if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/default_options') uses: actions/upload-artifact@v4 with: name: assets @@ -88,7 +88,7 @@ jobs: name: Upload assets runs-on: ubuntu-latest needs: build - if: github.event_name == 'push' && github.ref == 'refs/heads/development' + if: github.event_name == 'push' && github.ref == 'refs/heads/default_options' strategy: matrix: environment: diff --git a/CHANGES.txt b/CHANGES.txt index babefc0..de08e24 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,4 @@ -2.2.0 (April XX, 2025) +2.2.0 (April 15, 2025) - Added `updateOnSdkUpdate`, `updateOnSdkReady`, `updateOnSdkReadyFromCache` and `updateOnSdkTimedout` props to the `SplitFactoryProvider` component to overwrite the default value (`true`) of the `updateOnSdk` options in the `useSplitClient` and `useSplitTreatments` hooks. - Updated development dependencies to use React v19 and TypeScript v4.5.5 to test compatibility and avoid type conflicts when using the SDK with React v19 types. diff --git a/package-lock.json b/package-lock.json index 2caa447..781c302 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.1", + "version": "2.1.2-rc.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-react", - "version": "2.1.1", + "version": "2.1.2-rc.0", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio": "11.2.0", diff --git a/package.json b/package.json index f0f5cbf..b5fcb80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.1", + "version": "2.1.2-rc.0", "description": "A React library to easily integrate and use Split JS SDK", "main": "cjs/index.js", "module": "esm/index.js", From b16ee838c875ff519bd05d16f213339e9a00626d Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 14 Apr 2025 13:28:27 -0300 Subject: [PATCH 08/10] Remove redundant code and clarify type comments --- .github/workflows/ci-cd.yml | 4 ++-- src/SplitClient.tsx | 8 +------- src/types.ts | 14 +++++--------- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index cd4da2c..8a4397b 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -77,7 +77,7 @@ jobs: -Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }} - name: Store assets - if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/default_options') + if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development') uses: actions/upload-artifact@v4 with: name: assets @@ -88,7 +88,7 @@ jobs: name: Upload assets runs-on: ubuntu-latest needs: build - if: github.event_name == 'push' && github.ref == 'refs/heads/default_options' + if: github.event_name == 'push' && github.ref == 'refs/heads/development' strategy: matrix: environment: diff --git a/src/SplitClient.tsx b/src/SplitClient.tsx index 4715d67..fd146ae 100644 --- a/src/SplitClient.tsx +++ b/src/SplitClient.tsx @@ -17,13 +17,7 @@ export function SplitClient(props: ISplitClientProps) { const context = useSplitClient(props); return ( - + { typeof children === 'function' ? children(context) : diff --git a/src/types.ts b/src/types.ts index ef5ead3..96836c8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,7 +34,7 @@ export interface ISplitStatus { isDestroyed: boolean; /** - * `lastUpdate` indicates when the most recent status event was emitted. This timestamp is only updated for events that are being listened to, + * `lastUpdate` indicates the timestamp of the most recent status event. This timestamp is only updated for events that are being listened to, * configured via the `updateOnSdkReady` option for `SDK_READY` event, `updateOnSdkReadyFromCache` for `SDK_READY_FROM_CACHE` event, * `updateOnSdkTimedout` for `SDK_READY_TIMED_OUT` event, and `updateOnSdkUpdate` for `SDK_UPDATE` event. */ @@ -47,29 +47,25 @@ export interface ISplitStatus { export interface IUpdateProps { /** - * `updateOnSdkUpdate` indicates if the hook or component will update (i.e., re-render) in case of an `SDK_UPDATE` event. - * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_UPDATE`. + * `updateOnSdkUpdate` indicates if the hook or component will update (i.e., re-render) or not in case of an `SDK_UPDATE` event. * It's value is `true` by default. */ updateOnSdkUpdate?: boolean; /** - * `updateOnSdkTimedout` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY_TIMED_OUT` event. - * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY_TIMED_OUT`. + * `updateOnSdkTimedout` indicates if the hook or component will update (i.e., re-render) or not in case of a `SDK_READY_TIMED_OUT` event. * It's value is `true` by default. */ updateOnSdkTimedout?: boolean; /** - * `updateOnSdkReady` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY` event. - * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY`. + * `updateOnSdkReady` indicates if the hook or component will update (i.e., re-render) or not in case of a `SDK_READY` event. * It's value is `true` by default. */ updateOnSdkReady?: boolean; /** - * `updateOnSdkReadyFromCache` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY_FROM_CACHE` event. - * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY_FROM_CACHE`. + * `updateOnSdkReadyFromCache` indicates if the hook or component will update (i.e., re-render) or not in case of a `SDK_READY_FROM_CACHE` event. * This params is only relevant when using `'LOCALSTORAGE'` as storage type, since otherwise the event is never emitted. * It's value is `true` by default. */ From a2c47387c17cc39085ac16c8b3899cbb8adee8c9 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 15 Apr 2025 10:06:30 -0300 Subject: [PATCH 09/10] Update MIGRATION-GUIDE to better explain issue #237 --- MIGRATION-GUIDE.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/MIGRATION-GUIDE.md b/MIGRATION-GUIDE.md index df9bce4..d7f5a84 100644 --- a/MIGRATION-GUIDE.md +++ b/MIGRATION-GUIDE.md @@ -7,6 +7,14 @@ React SDK v2.0.0 has a few breaking changes that you should consider when migrat Follow [this section](#migrating-to-get-react-sdk-v1100-improvements-replacing-the-deprecated-useclient-usetreatments-and-usemanager-hooks) to migrate to the new hooks `useSplitClient`, `useSplitTreatments`, and `useSplitManager`. +### • Updated the default value of `updateOnSdkUpdate` and `updateOnSdkTimedout` options to `true`. + +Since v2.0.0, the **default values** of the `updateOnSdkUpdate` and `updateOnSdkTimedout` options of the `useSplitClient` and `useSplitTreatments` hooks were changed from `false` to `true`, meaning that the components using them will update by default when an `SDK_UPDATE` or `SDK_READY_TIMED_OUT` event is emitted. + +Consider setting the `updateOnSdkUpdate` option to `false` to revert to the previous behavior if you want to avoid re-renders and re-evaluations of treatments when feature flags are updated by the SDK in background. + +The same applies for the equivalent props in the `[with]SplitClient` and `[with]SplitTreatments` components, although these components are deprecated and we recommend [migrating to their hook alternatives](#-high-order-components-withsplitclient-withsplittreatments-and-components-that-accept-a-render-function-as-child-component-splittreatments-and-splitclient-have-been-deprecated-and-might-be-removed-in-a-future-major-release). + ### • Deprecated `SplitFactory` provider has been removed, `withSplitFactory` is deprecated, and `SplitFactoryProvider` doesn't accept `updateOn` props and a render function as children anymore. To migrate your existing code to the new version of `SplitFactoryProvider`, consider the following refactor example: @@ -59,7 +67,7 @@ const App = () => { }; ``` -Notice that `MyComponent` was refactored to use the `useSplitClient` hook and is passed as a React JSX element rather than a render function. The `useSplitClient` hook is called without providing a `splitKey` param. This means that the default client (whose key is set in the `core.key` property of the `mySplitConfig` object) will be used, and the `updateOn` and `attributes` props are passed as options to the hook. +Notice that `MyComponent` was refactored to use the `useSplitClient` hook and is passed as a React JSX element rather than a render function. The `useSplitClient` hook is called without providing a `splitKey` param. This means that the default client (whose key is set in the `core.key` property of the `mySplitConfig` object) will be used, and the `updateOnSdkUpdate` and `attributes` props are passed as options to the hook. ### • High-Order-Components (`withSplitClient`, `withSplitTreatments`) and components that accept a render function as child component (`SplitTreatments`, and `SplitClient`) have been deprecated and might be removed in a future major release. From c5def426d1e87f4bb20ab785a7e9f126130f6922 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 15 Apr 2025 15:51:07 -0300 Subject: [PATCH 10/10] Stable version --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 781c302..8f93d05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.2-rc.0", + "version": "2.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-react", - "version": "2.1.2-rc.0", + "version": "2.2.0", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio": "11.2.0", diff --git a/package.json b/package.json index b5fcb80..2282f56 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.2-rc.0", + "version": "2.2.0", "description": "A React library to easily integrate and use Split JS SDK", "main": "cjs/index.js", "module": "esm/index.js",