Test Repo created: https://github.com/leongaban/pact-io-js-test
Run npm run pactTest
which will create a Pact file for my TotalPayout.test.pact.ts
file.
D, [#38238] DEBUG -- : {
"description": "a GET request with a user id",
"request": {
"method": "GET",
"path": "/frontoffice/api/liquidity-pool/get-total-payout",
"headers": {
"Accept": "application/json"
}
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
}
}
}
W, [#38238] WARN -- : Verifying - actual interactions do not match expected interactions.
Missing requests:
GET /frontoffice/api/liquidity-pool/get-total-payout
W, [#38238] WARN -- : Missing requests:
GET /frontoffice/api/liquidity-pool/get-total-payout
Here is my Pact File
// @ts-ignore
import path from 'path';
// @ts-ignore
import { Pact } from '@pact-foundation/pact';
import { getTotalPayout } from './LiquidityPool';
// const port = 12345;
const endpoint = '/frontoffice/api/liquidity-pool/get-total-payout';
const EXPECTED_BODY = {
total_payout: 100.21,
};
const userId = 'foo';
describe('The API', () => {
// Copy this block once per interaction under test
describe('getUsersTotalPayout', () => {
beforeEach(() => {
const interaction = {
uponReceiving: 'a GET request with a user id',
withRequest: {
method: 'GET',
path: endpoint,
headers: {
Accept: 'application/json',
},
},
willRespondWith: {
status: 200,
headers: {
'Content-Type': 'application/json'
},
data: EXPECTED_BODY
},
};
// @ts-ignore
return provider.addInteraction(interaction);
});
// add expectations
it('Should call getUsersTotalPayout and return an object with the total_payout', done => {
getTotalPayout(userId)
.then((response: any) => {
console.log('response', response);
console.log('EXPECTED_BODY', EXPECTED_BODY);
expect(response).toEqual(EXPECTED_BODY);
})
.then(done);
});
});
});
Here is the service file that contains the getTotalPayout
function:
This endpoint doesn't exist yet, but this Pact test should still work is my understanding.
// @TODO Note, this is the placeholder for LiquidityPool API endpoints
// @ts-ignore
import axios, * as others from 'axios';
const endpoint = '/frontoffice/api/liquidity-pool/';
export const getTotalPayout = async (userId: string) => {
const response = await axios.get(`${endpoint}get-total-payout`, { params: userId });
return response.data;
};
Also my axios
mock in src/__mocks__/axios.ts
// tslint:disable-next-line:no-empty
const mockNoop = () => new Promise(() => {});
export default {
get: jest.fn(() => Promise.resolve({ data: { total_payout: 100.21 }})),
default: mockNoop,
post: mockNoop,
put: mockNoop,
delete: mockNoop,
patch: mockNoop
};
Quite simply - your test is not hitting the path /frontoffice/api/liquidity-pool/get-total-payout
on the Pact Mock Server.
You have setup Pact to run on http://localhost:1234
, so your actual code needs to be configured to hit this server, instead of the real one.
In your axios configuration, you are mocking out the http request library so it does nothing. So when your real code uses it, it doesn't make the http call and your Pact tests fail, because it was expecting a call with a certain shape and didn't get it.
Here are the things that you need to change:
pactSetup.ts:
// Configure axios to use the Pact mock server for Pact tests
import axios from "axios";
axios.defaults.baseURL = "http://localhost:1234";
/frontoffice/api/liquidity-pool/get-total-payout
but it never received it. Make your actual code hit this and then you'll be fine.Lastly and as an aside, you might want to use Pact as a local stub server for local development, once you’ve started generating Pacts (after 1-4 are fixed). The binary is actually installed in your node_modules already and the docs for how it operates are at https://github.com/pact-foundation/pact-ruby-standalone/releases
I typically have a script in package.json that looks something like:
"stubs": "$(find . -name pact-stub-service | head -n 1) pacts/* --port 4000"
You can then run npm run stubs
and have a local stub of the provider running on port 4000, with all of the request/responses you put into your tests.