Hey all, having an issue with connecting to the pa...
# pact-js
j
Hey all, having an issue with connecting to the pact-js mockserver. I know I've seen this issue before in pact-js when writing the consumer test:
Copy code
Attempted to log "[Network error]: FetchError: request to <http://127.0.0.1:4000/graphql> failed, reason: connect ECONNREFUSED 127.0.0.1:4000".
and it was because I wasn't using async/await on the
provider.setup()
method for initializing the pact mockserver. I'm at a loss now though because my code looks correct; the server is definitely initializing before my tests. And I've checked my running node processes, there's nothing running at the port
4000
. I've put my pact setup in an async beforeAll hook:
Copy code
beforeAll(async () => await provider.setup());
The verification failed because the connection to the mockserver was refused 😕
ApolloClientPact
is configured like this if it helps:
Copy code
global.fetch = fetch;

export const ApolloClientPact: FC = ({ children }) => {
  const { session } = useSession();

  const client = makeClient({
    url: '<http://127.0.0.1:4000/graphql>',
    name: 'provider-app',
    requestHeaders: () => ({ ...config, ...session }),
  });

  return <ApolloProvider client={client}>{children}</ApolloProvider>;
};
is this because I'm making the request from a component
render
function instead of calling the query from the client directly myself?
Copy code
(useAddress as jest.Mock).mockReturnValue(mockRequest),
      render(
        <ApolloClientPact>
          <MicrositeContext.Provider value={mockContextValue}>
            <ThemeProvider>
              <AddressModal />
            </ThemeProvider>
          </MicrositeContext.Provider>
        </ApolloClientPact>
      );
    expect(screen.getByTestId('address-form'));
To clarify, the AddressModal component here is what's making the actual query with ApolloClientPact
ah my issue was the component had some cors error, onto another error now, mocking might be mismatched
I'm wondering why this log file isn't being created anywhere though
Copy code
log: path.resolve(process.cwd(), 'logs', 'mockserver-integration.log'),
t
Did you configure pact to use port 4000 when creating the instance? otherwise pact will determine a free port on its own and hand it to you on the mockserver object you receive in the executeTest callback.
j
Yes I did configure the pact to port 4000, I have it making the request now, but it's still failing verification, which is probably a matching issue
Coming back around to this, I found a more creative solution. Instead of rendering my app's complete component tree, I'm importing the react hook and wrapping it up in my own test component
Copy code
render(
      <ApolloClientPact>
        <MockComponent />
      </ApolloClientPact>
    );
    // Assert that the loading state is initially displayed
    expect(screen.getByText('Loading...')).toBeInTheDocument();

    // Wait for the data to be loaded
    await waitFor(() => screen.getByText('Data loaded'));

    // Assert on the response data
    expect(screen.getByText(/Data loaded/)).toBeInTheDocument();
    expect(
      screen.getByText(/"street":"5413 Dickens Glen Ln"/)
    ).toBeInTheDocument();
• This approach unit tests the actual query code • I don't have to render the actual component under test since it doesn't have the response data I need to assert on • Pact verify() call passes and the mockserver works as expected Slightly different approach from doing the
client.query()
method as detailed in the pact js examples, so I figured it's worth sharing 🙂
chefkiss 1
for reference,
MockComponent
looks like this in my test:
Copy code
const MockComponent = () => {
    const { data, loading } = useNormalizedAddressQuery(mockRequest);

    if (loading) {
      return <p>Loading...</p>;
    }

    return (
      <div>
        <p>Data loaded</p>
        <p>{JSON.stringify(data)}</p>
      </div>
    );
  };
m
Nice, that seems a lot better - thanks for sharing!
thankyou 1
j
This seems to correspond quite closely to what I was trying to do recently. I tried making it work with a situation that resembles our app, a mocked Apollo provider and the whole shebang. I couldn’t get it to work at all, but I figured that’s not what Pact wants to test anyway. I did try to send the request with Apollo client directly, but that didn’t work either, because Apollo adds
__typename
to the request before sending, and the matcher didn’t seem to be able to handle that. Any solutions are welcome, but I did find a solution. I ended up just skipping Apollo altogether and just calling node fetch directly:
Copy code
const request = {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        query: print(mock.query),
        variables: mock.variables,
        operationName: 'Search',
      }),
    }

    const searchResult: Response = await fetch(uri, request)
      .then((res) => res)
      .catch((error) => { throw new Error(error) });

    it('returns results', async () => {
      const data = searchResult.json();
...
m
hmm I seem to recall the
__typename
issue. There is https://github.com/pact-foundation/pact-js/blob/master/src/dsl/apolloGraphql.ts but that doesn’t account for it
j
just add
__typename
to your mock and it should work
☝️ 1
j
My queries are often 250+ lines long with many different instances of
__typename
, so that would add a lot of maintenance effort. Is that a best practice? Maybe not, but it’s the pre-existing situation I have to work with. It does seem to work fine with just node fetch though, so I’m sticking with that for now.
m
but…doesn’t that mean you aren’t testing your actual API client? If your API client changes, how do you know things are still working?