Mock Pusher.js in your JavaScript tests with ease.
Using yarn:
yarn add --dev pusher-js-mock
Or using npm:
npm install -D pusher-js-mock
- Emitting an event πΆ
- Listening for an event π
- Emitting an event from connection πΆ
- Listening for an event from connection π
- Stubbing Pusher when imported from pusher-js package π¦
- Stubbing Pusher when used as a global variable π
- Mocking presence channels
- Using with Vitest
For more detailed examples, check out examples
directory
inside the project!
Also, you can check out the Docs for even more information.
If you need to mock a Pusher object in your tests that can subscribe to channel, it's best to use PusherMock.
import { PusherMock } from "pusher-js-mock";
// initializing PusherMock
const pusher = new PusherMock();
// subscribing to a Pusher channel
const channel = pusher.subscribe("my-channel");
// emitting an event
channel.emit("event-name");
If you want to check whether your callback is getting called properly, you can bind a callback to your channel, and then emit an event.
import { PusherMock } from "pusher-js-mock";
describe("listening for an event", () => {
// initializing PusherMock
const pusher = new PusherMock();
// subscribing to a Pusher channel
const channel = pusher.subscribe("my-channel");
// define and attach a listener
const listener = jest.fn();
channel.bind("event-name", listener);
// emitting an event
channel.emit("event-name");
// Expect listener to have been called
expect(listener).toHaveBeenCalled();
});
The connection within pusher is mocked and can be used much like a channel channel. There's no need to subscribe to subscription as it's subscribed by default on pusher.
import { PusherMock } from "pusher-js-mock";
// initializing PusherMock
const pusher = new PusherMock();
// emitting connection event
pusher.connection.emit("event-name");
As with channels, you can also listen to connection for events.
import { PusherMock } from "pusher-js-mock";
describe("listening for an event", () => {
// initializing PusherMock
const pusher = new PusherMock();
// define and attach a listener
const listener = jest.fn();
pusher.connection.bind("event-name", listener);
// emitting an event
pusher.connection.emit("event-name");
// Expect listener to have been called
expect(listener).toHaveBeenCalled();
});
If you're using Pusher in your code in this or similar manner:
import Pusher from "pusher-js";
You will need to mock Pusher in a specific way.
I suggest you use Jest to test your code. To do this in Jest, you'll need something like this:
jest.mock("pusher-js", () => {
const Pusher = require("pusher-js-mock").PusherMock;
return Pusher;
});
If you have tips on how to mock this using other testing frameworks, please submit an issue or a pull request.
This shows how to stub a pusher if you're attaching it to window object in your
project. If you're attaching a PusherFactory to a window
object like this in
your code:
window.PusherFactory = {
pusherClient: function(pusherKey) {
return new Pusher(pusherKey);
}
};
It's best for you to use PusherFactoryMock.
import { PusherFactoryMock } from "pusher-js-mock";
// initialize instance of PusherFactoryMock
const pusherFactoryMock = new PusherFactoryMock();
// replace it with the object that is attached to a window
window.PusherFactory = pusherFactoryMock;
// get the Pusher client reference
pusher = pusherFactoryMock.pusherClient();
This way you'll just replace your PusherFactory with PusherFactoryMock.
This package also supports using presence channels for multiple clients. The
mock will automatically detect when presence-
is in the channel name and
return a presence channel with channel.members
filled out as expected. You
can pass in IDs and info via a custom authorizer, just as you would with the
real package.
If you want, you can pass in a custom authorizer when creating a Pusher client.
// create-client.js
import Pusher from "pusher-js";
import { getAuthSomehow } from "./getAuthSomehow";
export const createClient = ({ id, info }) =>
new Pusher("APP_KEY", {
cluster: "APP_CLUSTER",
// see https://github.com/pusher/pusher-js#authorizer-function
authorizer: ({ name }) => ({
authorize: (socketId, callback) => {
const auth = getAuthSomehow(id, info);
callback(false, auth);
}
})
});
export default createClient;
// create-client.spec.js
import createClient from "../create-client";
// mock the authorize function and pusher
jest.mock("pusher-js", () => require("pusher-js-mock"));
jest.mock("../getAuthSomehow", () => ({
getAuthSomehow: (id, info) => ({ id, info })
}));
it("should create a presence channel", async () => {
// arrange: create pusher client
const pusher = createClient({ id: "my-id", info: { role: "moderator" } });
// act: required to ensure pusher events are called, i.e. pusher:member_added
const presenceChannel = await pusher.subscribe("presence-channel");
// assert: presenceChannel has the properties we expect it to.
expect(presenceChannel.members.myID).toBe("my-id");
expect(presenceChannel.members.me).toEqual({
id: "my-id",
info: { role: "moderator" }
});
expect(presenceChannel.members.members).toEqual({
"my-id": { role: "moderator" }
});
});
Check out a code example of using presence channels
The mocked Pusher instance will also emit pusher internal events
pusher:subscription_succeeded
, pusher:member_added
and
pusher:member_removed
to the relevant clients:
it("should emit presence-channel events", async () => {
const client = createClient({ id: "my-id" });
const channel = client.subscribe("presence-channel");
const listener = jest.fn();
/**
* On bind, pusher:subscription_succeded will trigger
* for the client subscribing. Other clients will be
* notified via pusher:member_added as below.
*/
await channel.bind("pusher:subscription_succeeded", listener);
expect(listener).toHaveBeenCalledTimes(1);
/**
* Create and subscribe a new client that will trigger the
* pusher:member_added event. This only gets triggered for
* clients are not the client subscribing
*/
channel.bind("pusher:member_added", listener);
const otherClient = createClient({ id: "your-id" });
await otherClient.subscribe("presence-channel");
expect(listener).toHaveBeenCalledTimes(2);
/**
* Unsubscribe the otherClient to trigger pusher:member_removed.
* This only gets triggered for clients that are not the client
* unsubscribing.
*/
channel.bind("pusher:member_removed", listener);
await otherClient.unsubscribe("presence-channel");
expect(listener).toHaveBeenCalledTimes(3);
});
You can mock Pusher.js in Vitest environment like this:
vi.mock("pusher-js", () => {
return {
__esModule: true,
default: require("pusher-js-mock").PusherMock,
};
});
Photo by Octavian Rosca on Unsplash