Skip to content

Commit

Permalink
✅ 100% code coverage yeehaa
Browse files Browse the repository at this point in the history
  • Loading branch information
Harley Alexander committed Mar 3, 2020
1 parent 489ed35 commit a301670
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 40 deletions.
3 changes: 1 addition & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
module.exports = {
collectCoverageFrom: ["src/**/*.{ts,tsx}"],
coveragePathIgnorePatterns: ["./src/index.ts"],
modulePathIgnorePatterns: ["./src/__oldtests__/"]
coveragePathIgnorePatterns: ["./src/index.ts"]
};
17 changes: 15 additions & 2 deletions src/__tests__/useEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,26 @@ import { renderHook } from "@testing-library/react-hooks";
import { useEvent } from "../useEvent";

describe("useEvent()", () => {
test("should ", () => {
test("should bind to events when the hook is called", () => {
const listener = jest.fn();
const channel = new PusherChannelMock();
renderHook(() =>
const { unmount } = renderHook(() =>
useEvent((channel as unknown) as Channel, "event", listener)
);
channel.emit("event", {});
expect(listener).toHaveBeenCalledWith({});

// test unbinding
unmount();
channel.emit("event", {});
expect(listener).toHaveBeenCalledTimes(1);
});

test("should not bind when there is no channel", () => {
const listener = jest.fn();
const channel = new PusherChannelMock();
renderHook(() => useEvent(undefined, "event", listener));
channel.emit("event", {});
expect(listener).not.toHaveBeenCalled();
});
});
19 changes: 10 additions & 9 deletions src/__tests__/usePresenceChannel.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { PusherMock, PusherPresenceChannelMock } from "pusher-js-mock";
import { act, renderHook } from "@testing-library/react-hooks";
import {
actAndFlushPromises,
makeAuthPusherConfig,
renderHookWithProvider
} from "../../testUtils";

import Pusher from "pusher-js";
import { PusherMock } from "pusher-js-mock";
import React from "react";
import { __PusherContext } from "../PusherProvider";
import { usePresenceChannel } from "../usePresenceChannel";

Expand All @@ -23,7 +21,7 @@ describe("usePresenceChannel()", () => {
});

test("should bind to pusher events and unbind on mount", async () => {
const { result, unmount, rerender } = await renderHookWithProvider(
const { result, unmount } = await renderHookWithProvider(
() => usePresenceChannel("presence-channel"),
makeAuthPusherConfig()
);
Expand All @@ -39,7 +37,7 @@ describe("usePresenceChannel()", () => {
expect(channel.callbacks["pusher:member_removed"]).toHaveLength(0);
});

test("should return new member list when members are added", async () => {
test("should return new member list when members are added and remove them when they unsubscribe", async () => {
const { result } = await renderHookWithProvider(
() => usePresenceChannel("presence-channel"),
makeAuthPusherConfig()
Expand All @@ -48,15 +46,18 @@ describe("usePresenceChannel()", () => {
expect(result.current.members).toEqual({ "my-id": {} });
expect(result.current.myID).toEqual("my-id");

let otherClient;
await act(async () => {
const otherClient = new PusherMock(
"key",
makeAuthPusherConfig("your-id")
);
otherClient = new PusherMock("key", makeAuthPusherConfig("your-id"));
otherClient.subscribe("presence-channel");
await actAndFlushPromises();
});

expect(result.current.members).toEqual({ "my-id": {}, "your-id": {} });

await act(async () => {
otherClient.unsubscribe("presence-channel");
});
expect(result.current.members).toEqual({ "my-id": {} });
});
});
81 changes: 81 additions & 0 deletions src/__tests__/useTrigger.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import "jest-fetch-mock";

import { NO_AUTH_HEADERS_WARNING, useTrigger } from "../useTrigger";

import Pusher from "pusher-js";
import { PusherMock } from "pusher-js-mock";
import React from "react";
import { __PusherContext } from "../PusherProvider";
import { renderHook } from "@testing-library/react-hooks";

describe("useTrigger()", () => {
beforeEach(() => {
fetch.resetMocks();
});
test("should trigger a fetch event on use and warn about no headers", async () => {
jest.spyOn(console, "warn");
const wrapper = ({ children }) => (
<__PusherContext.Provider
value={{
client: (new PusherMock("key") as unknown) as Pusher,
triggerEndpoint: "http://example.com"
}}
>
{children}
</__PusherContext.Provider>
);

const { result } = await renderHook(() => useTrigger("presence-channel"), {
wrapper
});

result.current("event", {});
expect(fetch.mock.calls.length).toBe(1);
expect(console.warn).toHaveBeenCalledWith(NO_AUTH_HEADERS_WARNING);
});
test("should trigger a fetch event on use and warn", async () => {
jest.spyOn(console, "warn");
const config = {
auth: {
headers: "Bearer token"
}
};

const wrapper = ({ children }) => (
<__PusherContext.Provider
value={{
client: (new PusherMock("key", {
auth: {
headers: {
Authorization: "Bearer token"
}
}
}) as unknown) as Pusher,
triggerEndpoint: "http://example.com"
}}
>
{children}
</__PusherContext.Provider>
);

const { result } = await renderHook(() => useTrigger("public-channel"), {
wrapper
});

result.current("event", {});
expect(fetch.mock.calls[0]).toEqual([
"http://example.com",
{
method: "POST",
body: JSON.stringify({
channelName: "public-channel",
eventName: "event",
data: {}
}),
headers: {
Authorization: "Bearer token"
}
}
]);
});
});
1 change: 1 addition & 0 deletions src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Pusher, { Options } from "pusher-js";
import * as React from "react";
import "jest-fetch-mock";

export interface PusherContextValues {
// client?: React.MutableRefObject<Pusher | undefined>;
Expand Down
23 changes: 7 additions & 16 deletions src/useEvent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useEffect } from 'react';
import invariant from 'invariant';
import { Channel, PresenceChannel } from 'pusher-js';
import { Channel, PresenceChannel } from "pusher-js";

import invariant from "invariant";
import { useEffect } from "react";

/**
* Subscribes to a channel event and registers a callback.
Expand All @@ -11,21 +12,11 @@ import { Channel, PresenceChannel } from 'pusher-js';
export function useEvent<D>(
channel: Channel | PresenceChannel | undefined,
eventName: string,
callback: (data?: D) => void,
dependencies?: unknown[] | undefined
callback: (data?: D) => void
) {
// error when required arguments aren't passed.
invariant(eventName, 'Must supply eventName and callback to onEvent');
invariant(callback, 'Must supply callback to onEvent');

// deprecate dependencies
useEffect(() => {
if (dependencies) {
console.warn(
'The useEvent callback is no longer memoized - dependencies are deprecated and its up to you to memoize the callback if you want to.'
);
}
}, [dependencies]);
invariant(eventName, "Must supply eventName and callback to onEvent");
invariant(callback, "Must supply callback to onEvent");

// bind and unbind events whenever the channel, eventName or callback changes.
useEffect(() => {
Expand Down
6 changes: 0 additions & 6 deletions src/usePresenceChannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,6 @@ export function usePresenceChannel(channelName: string) {
channel.bind("pusher:member_added", handleAdd);
channel.bind("pusher:member_removed", handleRemove);

// set any members that already existed on the channel
if (channel.members) {
setMembers(channel.members.members);
setMyID(channel.members.myID);
}

// cleanup
return () => {
channel.unbind(
Expand Down
9 changes: 5 additions & 4 deletions src/useTrigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,16 @@ export function useTrigger<TData = {}>(channelName: string) {
if (client && client.config?.auth) {
fetchOptions.headers = client.config?.auth.headers;
} else {
console.warn(
"No auth parameters supplied to <PusherProvider />. Your events will be unauthenticated."
);
console.warn(NO_AUTH_HEADERS_WARNING);
}

return triggerEndpoint && fetch(triggerEndpoint, fetchOptions);
return fetch(triggerEndpoint, fetchOptions);
},
[client, triggerEndpoint, channelName]
);

return trigger;
}

export const NO_AUTH_HEADERS_WARNING =
"No auth parameters supplied to <PusherProvider />. Your events will be unauthenticated.";
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"declaration": false,
"noEmit": true
},
"include": ["src"],
"include": ["src", "src/types.d.ts"],
"exclude": [
"node_modules",
"build",
Expand Down

0 comments on commit a301670

Please sign in to comment.