From 0ca9f4d1d2a614f122556f7209026bdc8b7e991a Mon Sep 17 00:00:00 2001 From: Marcos Passos Date: Tue, 25 Apr 2023 20:16:52 -0300 Subject: [PATCH] Allow to plugin using provider options (#391) --- src/CroctProvider.test.tsx | 36 +++++++++++++++++++++++++++++++++++- src/CroctProvider.tsx | 31 +++++++++++++++++++++++++------ 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/src/CroctProvider.test.tsx b/src/CroctProvider.test.tsx index 13edc404..3c6b02e5 100644 --- a/src/CroctProvider.test.tsx +++ b/src/CroctProvider.test.tsx @@ -22,6 +22,8 @@ describe('', () => { afterEach(() => { // eslint-disable-next-line no-console -- Needed to restore the original console.error. console.error = consoleError; + + jest.clearAllMocks(); }); it('should fail if nested', () => { @@ -68,7 +70,6 @@ describe('', () => { ); expect(callback).toHaveBeenCalledTimes(1); - expect(callback).toHaveBeenCalledWith({plug: croct}); expect(croct.plug).toHaveBeenCalledTimes(2); expect(croct.plug).toHaveBeenNthCalledWith(1, options); @@ -83,6 +84,39 @@ describe('', () => { expect(croct.unplug).toHaveBeenCalled(); }); + it('should allow to plug after unmount', () => { + const options: CroctProviderProps = { + appId: '00000000-0000-0000-0000-000000000000', + debug: true, + track: true, + }; + + let plug: Plug|undefined; + + const callback = jest.fn((context: {plug: Plug}|null) => { + plug = context?.plug; + + return 'foo'; + }); + + render( + + {callback} + , + ); + + const appId = '11111111-1111-1111-1111-111111111111'; + + plug?.plug({appId: appId}); + + expect(croct.plug).toHaveBeenCalledTimes(2); + + expect(croct.plug).toHaveBeenLastCalledWith({ + ...options, + appId: appId, + }); + }); + it('should ignore errors on unmount', () => { jest.mocked(croct.unplug).mockRejectedValue(new Error('foo')); diff --git a/src/CroctProvider.tsx b/src/CroctProvider.tsx index dc0f33a2..b6c923b7 100644 --- a/src/CroctProvider.tsx +++ b/src/CroctProvider.tsx @@ -3,6 +3,7 @@ import { createContext, FunctionComponent, + MutableRefObject, PropsWithChildren, ReactElement, useContext, @@ -18,10 +19,18 @@ export type CroctProviderProps = PropsWithChildren(null); CroctContext.displayName = 'CroctContext'; +function useLiveRef(value: T): MutableRefObject { + const ref = useRef(value); + + ref.current = value; + + return ref; +} + export const CroctProvider: FunctionComponent = (props): ReactElement => { const {children, ...configuration} = props; const parent = useContext(CroctContext); - const initialConfiguration = useRef(configuration); + const baseConfiguration = useLiveRef(configuration); if (parent !== null) { throw new Error( @@ -34,18 +43,28 @@ export const CroctProvider: FunctionComponent = (props): Rea () => ({ get plug(): Plug { if (!croct.initialized) { - croct.plug(initialConfiguration.current); + croct.plug(baseConfiguration.current); } - return croct; + return new Proxy(croct, { + get: function getProperty(target, property: keyof Plug): any { + if (property === 'plug') { + return (options: Configuration): void => { + croct.plug({...baseConfiguration.current, ...options}); + }; + } + + return target.plug[property]; + }, + }); }, }), - [], + [baseConfiguration], ); useEffect( () => { - croct.plug(initialConfiguration.current); + croct.plug(baseConfiguration.current); return () => { croct.unplug().catch(() => { @@ -53,7 +72,7 @@ export const CroctProvider: FunctionComponent = (props): Rea }); }; }, - [], + [baseConfiguration], ); return (