Skip to content

Commit

Permalink
Allow to plugin using provider options (#391)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcospassos authored Apr 25, 2023
1 parent 702887a commit 0ca9f4d
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 7 deletions.
36 changes: 35 additions & 1 deletion src/CroctProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ describe('<CroctProvider />', () => {
afterEach(() => {
// eslint-disable-next-line no-console -- Needed to restore the original console.error.
console.error = consoleError;

jest.clearAllMocks();
});

it('should fail if nested', () => {
Expand Down Expand Up @@ -68,7 +70,6 @@ describe('<CroctProvider />', () => {
);

expect(callback).toHaveBeenCalledTimes(1);
expect(callback).toHaveBeenCalledWith({plug: croct});

expect(croct.plug).toHaveBeenCalledTimes(2);
expect(croct.plug).toHaveBeenNthCalledWith(1, options);
Expand All @@ -83,6 +84,39 @@ describe('<CroctProvider />', () => {
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(
<CroctProvider {...options}>
<CroctContext.Consumer>{callback}</CroctContext.Consumer>
</CroctProvider>,
);

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'));

Expand Down
31 changes: 25 additions & 6 deletions src/CroctProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import {
createContext,
FunctionComponent,
MutableRefObject,
PropsWithChildren,
ReactElement,
useContext,
Expand All @@ -18,10 +19,18 @@ export type CroctProviderProps = PropsWithChildren<Configuration & Required<Pick
export const CroctContext = createContext<{plug: Plug}|null>(null);
CroctContext.displayName = 'CroctContext';

function useLiveRef<T>(value: T): MutableRefObject<T> {
const ref = useRef(value);

ref.current = value;

return ref;
}

export const CroctProvider: FunctionComponent<CroctProviderProps> = (props): ReactElement => {
const {children, ...configuration} = props;
const parent = useContext(CroctContext);
const initialConfiguration = useRef(configuration);
const baseConfiguration = useLiveRef(configuration);

if (parent !== null) {
throw new Error(
Expand All @@ -34,26 +43,36 @@ export const CroctProvider: FunctionComponent<CroctProviderProps> = (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(() => {
// Suppress errors.
});
};
},
[],
[baseConfiguration],
);

return (
Expand Down

0 comments on commit 0ca9f4d

Please sign in to comment.