Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test React component using React Query's useSuspenseQuery #164

Open
anthonycaron opened this issue Feb 14, 2024 · 6 comments
Open

Test React component using React Query's useSuspenseQuery #164

anthonycaron opened this issue Feb 14, 2024 · 6 comments

Comments

@anthonycaron
Copy link

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 !

@pimterry
Copy link
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.

@anthonycaron
Copy link
Author

anthonycaron commented Feb 14, 2024

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.

@pimterry
Copy link
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.

@anthonycaron
Copy link
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...

@pimterry
Copy link
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.

@anthonycaron
Copy link
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
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants