title: Testing Socket.io listener in React with Enzyme
body: <p>I want to test if the <strong>messageListener</strong> appends the data to the <strong>messages</strong> array state. However I've gotten some blocks on this. 
  1. Can't test methods inside a stateless component
  2. React hooks cannot be used outside a component function.</p>
  
  <p>I can't figure out how to get around this? Should I use a different approach for testing this? Should I extract it into a custom hook? I'm new to both Enzyme and React hooks.
  I basically want to test if given that socket.io receives the MESSAGE event, the component will append another item to the message array to be displayed inside MessageFeed.</p>
  
  <p>The full project can also be seen on <a href="https://github.com/Hyllesen/react-chat" rel="nofollow noreferrer">https://github.com/Hyllesen/react-chat</a></p>
  
  <p><strong>App.js</strong></p>
  
  <pre><code>import React from "react";
  import UsernameInput from "components/UsernameInput";
  import MessageFeed from "components/MessageFeed";
  import io from "socket.io-client";
  import * as eventTypes from "eventTypes";
  
  function joinWithUsername(username) {
    const socket = io("http://localhost:3001");
    socket.emit(eventTypes.USER_JOIN, { username });
    socket.on(eventTypes.MESSAGE, messageListener);
  }
  
  function messageListener(data, setMessages) {
    setMessages([...messages, data]);
  }
  
  const App = () =&gt; {
    const [messages, setMessages] = React.useState([]);
  
    return (
      &lt;div className="App"&gt;
        &lt;UsernameInput onSubmit={joinWithUsername} /&gt;
        &lt;MessageFeed messages={messages} /&gt;
      &lt;/div&gt;
    );
  };
  
  export default App;
  export { joinWithUsername, messageListener };
  </code></pre>
  
  <p><strong>App.test.js</strong></p>
  
  <pre><code>import React from "react";
  import App, { joinWithUsername, messageListener } from "../App";
  import { shallow } from "enzyme";
  import io from "socket.io-client";
  import * as eventTypes from "eventTypes";
  
  let wrapper, setState, useStateSpy;
  jest.mock("socket.io-client", () =&gt; {
    const emit = jest.fn();
    const on = jest.fn();
    const socket = { emit, on };
    return jest.fn(() =&gt; socket);
  });
  
  describe("App", () =&gt; {
    beforeEach(() =&gt; {
      wrapper = shallow(&lt;App /&gt;);
      setState = jest.fn();
      useStateSpy = jest.spyOn(React, "useState");
      useStateSpy.mockImplementation(init =&gt; [init, setState]);
    });
  
    afterEach(() =&gt; jest.clearAllMocks());
  
    it("has a usernameinput component", () =&gt; {
      expect(wrapper.find("UsernameInput").length).toBe(1);
    });
  
    it("has a joinWithUsername function", () =&gt; {
      const usernameInput = wrapper.find("UsernameInput").props();
      console.log(usernameInput.onSubmit);
      expect(usernameInput.onSubmit).toBe(joinWithUsername);
    });
  
    it("connect to socket.io server", () =&gt; {
      joinWithUsername("Bobby");
      expect(io).toHaveBeenCalledWith("http://localhost:3001");
    });
  
    it("emits the USER_JOIN event", () =&gt; {
      joinWithUsername("John");
      const socket = io();
      expect(socket.emit).toHaveBeenCalledWith(eventTypes.USER_JOIN, {
        username: "John"
      });
    });
  
    it("listens for the MESSAGE event", () =&gt; {
      joinWithUsername("John");
      const socket = io();
      expect(socket.on).toHaveBeenCalledWith(eventTypes.MESSAGE, messageListener);
    });
  
    it("Appends a message to state when message is received", () =&gt; {
      const testData = {
        from: "John",
        message: "Hello everyone!"
      };
      messageListener(testData);
      expect(setState).toHaveBeenCalledWith(testData); //ReferenceError: setMessages is not defined
    });
  });
  </code></pre>