skyqrose

skyqrose

How to mock phoenix sockets in Jest?

I want to test my js app that uses phoenix.js sockets. I want to write tests along the lines of:

  • Set up a mocked socket and channel.
  • Render my app.
  • Interact with the app.
  • Assert that a message was sent on the channel.
  • Mock a response to that message as if the server had replied.
  • Assert that the UI was updated with the response.

Is there a recommended way to do this?

I’m familiar with using jest to mock functions, but I’m struggling to set it up through the layers of callbacks and classes in a way that lets me assert something was pushed or send a reply.

First Post!

regan-karlewicz

regan-karlewicz

Sorry, I’m a bit late to the party here.

Using vitest, I was able to accomplish creating a phoenix channel mock doing something like this:

import { vi } from 'vitest';
import * as phoenix from 'phoenix';

vi.mock('phoenix', () => {
  return {
    Socket: vi.fn().mockImplementation(() => fakeSocket)
  };
});

const fakeChannel = {
  join: vi.fn().mockReturnThis(),
  push: vi.fn().mockReturnThis(),
  on: vi.fn().mockReturnThis(),
  off: vi.fn().mockReturnThis(),
  leave: vi.fn().mockReturnThis(),
  receive: vi.fn().mockImplementation((event, callback) => {
    if (event === 'ok') {
      callback({});
    }

    return this;
  })
};

const fakeSocket = {
  connect: vi.fn(),
  channel: vi.fn(() => fakeChannel),
  // mock any other used Socket class methods here
};

Then inside of your tests, you can override the mocks as needed:


describe("Example", () => {
  it("can join a channel", async () => {
    await joinChannel(); // This is the `socket.channel(...).join().receive("ok", callback)` wrapped by a promise that resolves in the callback

    expect(fakeSocket.connect).toHaveBeenCalledOnce();
    expect(fakeChannel.join).toHaveBeenCalledOnce();
  });

  it("can receive pushed event", async () => {
    await joinChannel(); 

    fakeChannel.on.mockImplementation((event, handler) => {
      if (event == "pushed:event") handler("Some data");

      return fakeChannel;
    });

    const result = await listenForPushedEvent(); // This is the function that sets up `channel.on("pushed:event", callback)` wrapped in a promise that resolves in the callback

    expect(result).toEqual("Some data");
  });
});

The challenge still exists that you have to carefully craft your mocks, which can be difficult since the Phoenix JS API is callback based.

Where Next?

Popular in Questions Top

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement