Skip to content

Commit

Permalink
💪 more robust provider + tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Harley Alexander committed Aug 20, 2019
1 parent f85a8a9 commit 0de31c1
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 47 deletions.
46 changes: 31 additions & 15 deletions src/PusherProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React, { useEffect, useState } from "react";
import Pusher, { Config } from "pusher-js";
import React, { useEffect, useRef } from "react";
import PusherClass, { Pusher, Config } from "pusher-js";
import invariant from "invariant";
import { useDeepCompareMemoize } from "./helpers";
// import { useDeepCompareMemoize } from "./helpers";
import { PusherContextValues, PusherProviderProps } from "./types";
import dequal from "dequal";

// context setup
export const __PusherContext = React.createContext<PusherContextValues>({});
export const __PusherConsumer = __PusherContext.Consumer;
const PusherContext = React.createContext<PusherContextValues>({});
export const __PusherContext = PusherContext;
export const __PusherConsumer = PusherContext.Consumer;

/**
* Provider for the pusher service in an app
Expand All @@ -18,28 +20,42 @@ export function PusherProvider({
triggerEndpoint,
authEndpoint,
auth,
defer = false,
...props
}: PusherProviderProps) {
// errors when required props are not passed.
invariant(clientKey, "A client key is required for pusher");
invariant(cluster, "A cluster is required for pusher");

const pusherOptions: Config = { cluster };
if (authEndpoint) pusherOptions.authEndpoint = authEndpoint;
if (auth) pusherOptions.auth = auth;
const config: Config = { cluster };
if (authEndpoint) config.authEndpoint = authEndpoint;
if (auth) config.auth = auth;

// when the options passed to the provider change,
// create a new instance of pusher
const [pusherClient, setPusherClient] = useState();
const pusherClientRef = useRef<Pusher>(new PusherClass(clientKey, config));
useEffect(() => {
if (
dequal(previousConfig.current, config) &&
pusherClientRef.current !== undefined
) {
return;
}

if (!defer) {
pusherClientRef.current && pusherClientRef.current.disconnect();
pusherClientRef.current = new PusherClass(clientKey, config);
}
}, [clientKey, config, defer, pusherClientRef]);

// track config for comparison
const previousConfig = useRef<Config | undefined>();
useEffect(() => {
setPusherClient(new Pusher(clientKey, pusherOptions));
}, useDeepCompareMemoize([clientKey, pusherOptions]));
previousConfig.current = config;
});

return (
<__PusherContext.Provider
<PusherContext.Provider
value={{
client: pusherClient,
client: pusherClientRef,
triggerEndpoint
}}
{...props}
Expand Down
69 changes: 37 additions & 32 deletions src/__tests__/PusherProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,48 @@ import { render, cleanup } from "@testing-library/react";
import { PusherProvider } from "../PusherProvider";
import { default as MockPusher } from "pusher-js";

jest.mock("pusher-js", () => {
const { PusherMock } = require("../mocks.ts");
return {
__esModule: true,
default: jest.fn((clientKey, config) => new PusherMock(clientKey, config))
};
});

const setup = (props: any = {}) =>
render(<PusherProvider {...props}>Test</PusherProvider>);

const defaultProps = { clientKey: "client-key", cluster: "ap4" };

beforeEach(() => {
jest.resetAllMocks();
cleanup();
jest.resetAllMocks();
});

test("should initialise pusher when required props are passed", () => {
setup(defaultProps);
expect(MockPusher).toHaveBeenCalledTimes(1);
jest.mock("pusher-js", () => {
const { PusherMock } = require("pusher-js-mock");
PusherMock.prototype.disconnect = jest.fn();
return PusherMock;
});

test("should re-initialise Pusher when auth parameters are provided", () => {
const { container } = setup(defaultProps);
const authProps = {
authEndpoint: "auth-endpoint",
auth: {
headers: { Authorization: "Bearer token" }
}
};
render(
<PusherProvider {...defaultProps} {...authProps}>
Test
</PusherProvider>,
{ container }
);
const config = {
clientKey: "client-key",
cluster: "ap4",
children: "Test"
};
const authConfig = {
auth: {},
authEndpoint: "endpoint"
};

describe("PusherProvider", () => {
test("should render without error", () => {
render(<PusherProvider clientKey="a" cluster="b" children="Test" />);
expect(MockPusher.prototype.disconnect).toHaveBeenCalledTimes(1);
});

test("should re-render when auth params are supplied.", () => {
const { container } = render(<PusherProvider {...config} />);
expect(MockPusher.prototype.disconnect).toHaveBeenCalledTimes(1);
render(<PusherProvider {...config} {...authConfig} />, { container });
expect(MockPusher.prototype.disconnect).toHaveBeenCalledTimes(2);
});

test("should not re-create instance if props are the same", () => {
const { container } = render(<PusherProvider {...config} />);
render(<PusherProvider {...config} />, { container });
expect(MockPusher.prototype.disconnect).toHaveBeenCalledTimes(1);
});

expect(MockPusher).toHaveBeenCalledTimes(2);
test("should not re-create instance if defer is present", () => {
render(<PusherProvider {...config} defer={true} />);
expect(MockPusher.prototype.disconnect).toHaveBeenCalledTimes(0);
});
});

0 comments on commit 0de31c1

Please sign in to comment.