nock multiple requests mocks

7.6k views Asked by At

I am changing and endpoint in my express backend that would typically make 1 http request to a vendor's API to create a payment object in their system for a previously created account.

The previously created account is currently created by sending a POST request to the vendor's API at /partner/v3/account. I then save their response into our db, amongst other details, so we can retrieve it later.

Due to some changes in specs, whenever the payment object is requested, we have to re-create the account. The payment request looks up the previously created account in the db and used to use the account id to make the payment request to the vendor. However, due to the spec changes, before we do the payment request, we have to re-create the account using the previously created account details and sending a new POST request to /partner/v3/account. Only after the account has been re-created, can we proceed with the payment request.

In my original jest tests I had something like the following and it worked fine:

   describe("POST /v1/accounts/:accountId/payment", () => {
       beforeAll(async () => {
            // nock vendor response for initial creation of account
            nock(VENDOR_URL)
           .post("/partner/v3/account")
           .reply(HttpStatus.CREATED, createRes1);
           
           // post to internal endpoint to create the initial account
           // this saves response and other details to db for retrieval
           await request(app)
          .post("/v1/accounts")
          .send(createReq);
       }

       it("should return successful payment object for user account", async() => {
           nock(VENDOR_URL)
           .post("/payments/setup", paymentReq)
           .reply(HttpStatus.CREATED, paymentRes);

           // this endpoint retrieves the previously created account
           // uses account id to make payment request
           const response = await request(app)
          .post(`/v1/accounts/${accountId}/payment`)
          .send({
              "paymentFreq": "Monthly"
          });

          expect(response.status).toEqual(HttpStatus.OK);
       }
   }

However, with the need to re-create the account, I had to change the code to make another http request to the vendor's API to re-create the account. In the above code, the nock I have in BeforeAll seems to be called once, as expected, but the test fails, presumably because the second vendor API request in not being mocked properly.

How do I handle mocking the same vendor endpoint to be called at different times in the code. It seems that:

  1. mocking it once in BeforeAll and once in the it block does not work
  2. mocking it twice in BeforeAll does not work, using times(2)
  3. mocking it twice in the it block does not work

Note: When I say it does not work, what I mean is that when the POST request to /v1/accounts/${accountId}/payment I expect that the previously created account should be retrieved, per the BeforeAll commands. However, if I mock the response from /partner/v3/account in my it test, instead of retrieving the account created by BeforeAll, I get the mocked account from within the it statement.

it("should return successful payment object for user account", async() => {
// mock response of re-creating account
            nock(VENDOR_URL)
           .post("/partner/v3/account")
           .reply(HttpStatus.CREATED, createRes2);

// mock response of making account payment
           nock(VENDOR_URL)
           .post("/payments/setup", paymentReq)
           .reply(HttpStatus.CREATED, paymentRes);

           // this endpoint retrieves the previously created account
           // uses previous account details to re-created account
           // uses new account id to make payment request
           const response = await request(app)
          .post(`/v1/accounts/${accountId}/payment`)
          .send({
              "paymentFreq": "Monthly"
          });

          expect(response.status).toEqual(HttpStatus.OK);
       }

Note: I need to nock the /partner/v3/account endpoint call such that each call returns something different, since the point is testing a re-creation of an account, so the account id will be different on the response from the vendor. My mocked response has a different account id, so this should be true, but as noted previously, the first time the account is retrieved in /v1/accounts/${accountId}/payment it gets the second mocked response instead of the first one from BeforeAll.

1

There are 1 answers

2
thehme On

Not the solution I want, but using times seems to at least mock the response to the vendor's API N times, in this case, twice.

It is not the best solution because in the first request to the vendor's API to create the account, an account id is created and this should be different in the next request, but at least it gets me closer to what i need.

I ended up up with the following in my it statement:

nock(HISCOX_URL)
    response payload
    .post("/partner/v3/account/")
    .times(2)
    .reply(HttpStatus.CREATED, createRes2)

I tried to mock the response from POSTing to this endpoint in a chained manner, and it did not work:

nock(HISCOX_URL)
    .post("/partner/v3/account/")
    .reply(HttpStatus.CREATED, createRes2) // account id X
    .post("/partner/v3/account/")
    .reply(HttpStatus.CREATED, reCreateRes2); // account id Y