Skip to content

Test React component using React Query's useSuspenseQuery #164

Description

@anthonycaron

Hello !

I'm trying to test my React component that's querying through a tRPC client using React Query's function useSuspenseQuery (for more info, click here).
I'm using Jest and I'm mocking the tPRC server with Mockttp.

I suppose that when using useSuspenseQuery we should mock that query using a stream, so my test looks like this:

describe('Navigation menu', () => {
  const mockServer = mockttp.getLocal({
    cors: {...},
  });

  ...

  it('should display the nav menu', async () => {
    const reqUrl = '/ConversationAPI.countPendingConversations';
    const mockedStream = new PassThrough();
    await mockServer.forGet(reqUrl).thenStream(200, mockedStream);

    render(
      <Suspense fallback={<div>Loading...</div>}>
        <Nav />,
      </Suspense>
    );

    mockedStream.emit('data', {
      pending: 0,
    });
    mockedStream.emit('end');

    await waitFor(() => {
      return expect(screen.getByTestId('badge')).toBe('0');
    });
  });

I'm running my tests using mockttp -c jest as recommended in Mockttp's documentation. That part looks fine.

My problem is that when running this test I'm having the following error:

console.error
  Error: Error: socket hang up
      at Object.dispatchError ([...]/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:63:19)
      ...
      at processTicksAndRejections (node:internal/process/task_queues:82:21) {
    type: 'XMLHttpRequest'
  }

I'm not super familiar with streams but I'm wondering if I'm using the right function from mockttp to mock the useSuspenseQuery or if I'm not passing the right thing to thenStream(...).

Any help is appreciated, thanks !

Activity

  1. pimterry commented on Feb 14, 2024

    @pimterry
    Member

    Hello!

    It's hard to know what's going on here, but I suspect this is due to the details of Jest - by default Jest doesn't run in a real browser, but uses jsdom to emulate one, which can result in small weird differences in lots of places.

    One thing that could trigger this is that you're not specifying any headers with your stream. That's totally valid and it should work, but it's a bit unusual in real usage in HTTP, and I can imagine that Jest's mocks might not handle it correctly.

    What happens if you add { 'transfer-encoding': 'chunked' } as a final argument to thenStream?

    One other thing is that you normally want to call stream.write(x) & stream.end(y), not stream.emit(...). A passthrough stream automatically emits everything you write to it, and manually firing those events isn't really how node streams are supposed to be used. See Mockttp's thenStream tests for an example.

    If that doesn't work, I'm not sure what's going on, and it'd be helpful if you could set up a standalone repro to demonstrate this.

  2. anthonycaron commented on Feb 14, 2024

    @anthonycaron
    Author

    Thanks a lot for your answer ! I added the header you mentioned with no significant change, then when I used stream.end() instead of stream.emit('end') it gave me another error which is: Unexpected end of JSON input. I'm actually thinking it might be smarter for me to use msw-trpc to mock my tRPC server.

  3. pimterry commented on Feb 14, 2024

    @pimterry
    Member

    Unexpected end of JSON input

    Oh, that's a bit easier - in the code above at least, you're directly passing an object to the stream (stream.emit('data', { ... })). This is HTTP, so the stream data should be a string or a buffer - the actual serialized data your server would return.

    If you wrap your data into JSON.stringify({ pending: 0 }) it will probably do what you expect.

  4. anthonycaron commented on Feb 14, 2024

    @anthonycaron
    Author

    It doesn't :(
    I've tried many forms including:
    mockedStream.emit('data', JSON.stringify({ countPendingConversations: 0 }));
    mockedStream.write(Buffer.from(JSON.stringify({ data: { countPendingConversations: 0 } })));
    mockedStream.write(Buffer.from(JSON.stringify({ countPendingConversations: 0 })));
    Yet, had no success and the same error getting thrown...

  5. pimterry commented on Feb 14, 2024

    @pimterry
    Member

    Hmm, hard to say then. You may be able to add your own network logging somewhere to see exactly what's being sent and received, but that depends on your setup.

    I'm happy to investigate further myself, but I think this will need a standalone repro to be able to do so.

  6. anthonycaron commented on Feb 14, 2024

    @anthonycaron
    Author

    I might do that if I find it's the solution I want to go for. Thanks for your support, I'll post again here if I need further help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions