hello! not sure if this has been asked here before...
# pact-js
p
hello! not sure if this has been asked here before already, but i’ve been having issues running consumer tests with PactV3. i’ve set up my test file as such:
Copy code
const provider = new PactV3({ consumer, provider, dir, port: 1234 })
describe('test 1', () => {
  test('should pass', () => {
    provider
      .given('valid user session')
      .uponReceiving('request')
      .withRequest({ 
        method: 'POST', 
        path: '/my-url', 
        headers: { custom_header }, 
        body: reqBody
      })
      .willRespondWith({
        status: 200,
        headers: reponseHeaders,
        body: like(exampleBody)
      })
    
    await provider.executeTest(async mockService => {
      myApi.configureUrl(mockService.url)
      const apiResp = await <http://myApi.post|myApi.post>({ 
        headers: { custom_header },
        data: reqBody,
      })
    })
  })
})
however, the above test fails with
The following request was expected but not received
and then it displays the request that I have defined under
withRequest
i’m not sure what setup i got wrong
t
The error message means that your request isn't being sent by your code
One problem is that your test has
await
but no
async
, so it's not returning a promise
Replace
await provider.executeTest
with
return provider.executeTest
Also, it's good practice to assert that your API call returns what you think it does, which you can do with an
expect
call. See the examples in the documentation.
(that's not the problem, though). I suspect the problem is that you're not waiting for that promise. However, if you're still having issues after you've changed the
await
for
return
, then probably your
<http://myApi.post|myApi.post>
is not sending the request you think it is.
p
my mistake, i type the above by hand. i do have async in the test
t
can you please share the actual code?
p
the above is as close to the actual code as i am permitted to share (NDA)
i have also confirmed that
<http://myApi.post|myApi.post>
is indeed making a request to the configured url
the response that is returned however is not something i recognize
t
Ok. I can't help you other than tell you that the error message means that your request is not being received by the mock server. Either you're not sending it, or it's not going to the right place, or you are sending it, but it is not what you set up in the test, or your test isn't waiting for the request to be sent before asking pact if it was sent.
the response that is returned however is not something i recognize
What is the response? Is it a 500? Pact will return 500 if it gets a request it wasn't expecting.
p
how do i confirm that the mock server is actually live and receiving requests? am i able to ping it mid-test or some other method?
t
You don't need to do that.
p
this is what the returned response from the api looks like
Copy code
{
      status: [Function: status],
      ok: true,
      get: [Function: mockConstructor] {
        _isMockFunction: true,
        getMockImplementation: [Function],
        mock: [Getter/Setter],
        mockClear: [Function],
        mockReset: [Function],
        mockRestore: [Function],
        mockReturnValueOnce: [Function],
        mockResolvedValueOnce: [Function],
        mockRejectedValueOnce: [Function],
        mockReturnValue: [Function],
        mockResolvedValue: [Function],
        mockRejectedValue: [Function],
        mockImplementationOnce: [Function],
        mockImplementation: [Function],
        mockReturnThis: [Function],
        mockName: [Function],
        getMockName: [Function]
      },
      toError: [Function: mockConstructor] {
        _isMockFunction: true,
        getMockImplementation: [Function],
        mock: [Getter/Setter],
        mockClear: [Function],
        mockReset: [Function],
        mockRestore: [Function],
        mockReturnValueOnce: [Function],
        mockResolvedValueOnce: [Function],
        mockRejectedValueOnce: [Function],
        mockReturnValue: [Function],
        mockResolvedValue: [Function],
        mockRejectedValue: [Function],
        mockImplementationOnce: [Function],
        mockImplementation: [Function],
        mockReturnThis: [Function],
        mockName: [Function],
        getMockName: [Function]
      }
    }
i’m using
superagent
to make requests
t
Well. This is why we ask for the actual test code. That is a mock provided by something other than pact. Looks like Jest, probably.
Also, you definitely don't want to send requests with
superagent
. You want to send requests with the code that is under test.
Otherwise you're not testing anything.
p
in the test i am calling the apiclient that we have defined. under the hood, the api client is calling
superagent
t
Something is mocking your API layer, and you're not really sending a post request.
🤔 1
Ah, apologies. I was thinking of
supertest
. I guess
superagent
is a regular http framework.
p
ok, i’ll look into that. this test is being run as a standalone test. not sure if jest automagically mocks http requests
t
it doesn't.
p
then i am stumped 😅 . we’re not mocking http calls in this test
t
You're definitely mocking something - that's a mock object that you posted
👍 1
have a look in your global jest setup files
p
will see what i can find
t
Sorry I can't be more helpful.
p
all good, this is good enough direction for now. thanks! will explore and let you know if i get anywhere
👍 1
t
My guess is somewhere you have something like
jest.mock('superagent')
i have also confirmed that myApi.post is indeed making a request to the configured url
I would guess that you confirmed that your code is being called, but not that it actually is making the request
p
thanks for that direction. that was the issue.
superagent
was being mocked by
jest
automatically because we have a
___mocks___
directory where a custom implementation of
superagent
was defined. just added
jest.unmock('superagent')
to the pact test file and looks like the request is being made as expected
t
Awesome! In general, I think it's risky to mock your http framework, because you can't check that you're invoking it correctly. If you need to mock the API for unit tests, I would mock
myApi
instead - then you can use pact to ensure that the mock objects that you're using in your unit tests can actually be received by your API.
👍 1
You can actually use
stripMatchers
to remove the matchers from the pact expectation and use the exact same object in your mock responses 🙌
👀 1
so you have something like: pact test:
Copy code
assert that 
   myApi.createUser({ name: "foo" })
   calls with the expected request
   the expected response is unmarshalled into 
a returned user object like { ...whatever the user object is }
Mocks:
Copy code
when myApi.createUser({ name: "foo" }), then return { ...whatever the user object is }
m
On the “how can we make this easier for users” front, I wonder if we could detect the use of common tools (like supertest, or jest mocks) and suggest a fix?
We could also have a troubleshooting guide, but in my experience nobody really looks at these (otherwise Tim wouldn’t be an expert in explaining how promises work)
😅 2
t
I'm not sure how we could do that. I've wondered about
expect(responseObject).toMatchPactExpectations()
which just does a
stripMatchers
, but I think that might cause more confusion
p
ooh that
stripMatchers
method sounds like a useful one that i am definitely going to use. didn’t know that existed and i just manually stripped them lol. thanks!
🙌 1
where is that method defined? is that on the matcher object?
t
Apologies, it's called extractPayload
p
gotchya, no worries! i was just about to ask that too. found the github commit for that particular conversation regarding renaming it
just curious, does
extractPayload
recursively strip matchers?
👍 1
t
Yes
👍 1