'Error with Typescript Pact.io test: PopsicleError: Unable to connect to
Expected: Running npm run pactTest
should generate a pact file (JSON).
Results: I get an Unable to connect
error.
Pact.io JavaScript implementation guide.
Pact.io Typescript test example.
Appreciate any thoughts or ideas as to what I'm doing wrong :)
The Error
FAIL src/services/api/TotalPayout.test.pact.ts The API getUsersTotalPayout ✕ Should call getUsersTotalPayout and return an object with the total_payout (45ms)
● The API › getUsersTotalPayout › Should call getUsersTotalPayout and return an object with the total_payout
PopsicleError: Unable to connect to "http://127.0.0.1:12345/interactions" Caused by: Error: connect ECONNREFUSED 127.0.0.1:12345
at Request.Object.<anonymous>.Request.error (node_modules/popsicle/src/request.ts:91:12) at ClientRequest.<anonymous> (node_modules/popsicle/src/index.ts:218:31)
package.json script:
"pactTest": "export NODE_ENV=pactTest && jest --testRegex \"/*(.test.pact.ts)\" --runInBand --setupFiles ./pactSetup.ts --setupTestFrameworkScriptFile ./pactTestWrapper.ts",
My src/pactSetup.ts file
// @ts-ignore
import path from 'path';
import { Pact } from '@pact-foundation/pact/pact';
// @ts-ignore
global.provider = new Pact({
port: 1234,
log: path.resolve(process.cwd(), 'logs', 'mockserver-integration.log'),
dir: path.resolve(process.cwd(), 'pacts'),
spec: 2,
cors: true,
pactfileWriteMode: 'update',
consumer: 'Exchange',
provider: 'LP Service'
});
My src/pactTestWrapper.ts
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // This is to give the pact mock server time to start
// @ts-ignore
beforeAll(() => provider.setup()); // Create mock provider
// @ts-ignore
afterEach(() => provider.verify()); // Ensure the mock provider verifies expected interactions for each test
// @ts-ignore
afterAll(() => provider.finalize()); // Tear down the mock and write the pact
The test: src/services/api/TotalPayout.test.pact.ts
// @ts-ignore
import path from 'path';
import { Pact } from '@pact-foundation/pact';
import { getTotalPayout } from './apiPayout';
const port = 12345;
const endpoint = '/frontoffice/api/get-total-payout';
const EXPECTED_BODY = {
total_payout: 100.21,
};
const userId = 'foo';
const provider = new Pact({
port,
log: path.resolve(process.cwd(), 'logs', 'mockserver-integration.log'),
dir: path.resolve(process.cwd(), 'pacts'),
spec: 2,
consumer: 'Exchange',
provider: 'LP Service',
pactfileWriteMode: 'merge'
});
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'
},
body: 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) => {
expect(response).toEqual(EXPECTED_BODY);
})
.then(done);
});
});
});
The api service file apiPayout.ts
// @ts-ignore
import axios, * as others from 'axios';
const endpoint = '/frontoffice/api/';
export const getTotalPayout = async (userId: string) => {
const response = await axios.get(`${endpoint}get-total-payout`, { params: userId });
return response.data;
};
From the mockserver-integration.log
I, [2018-09-19T11:07:41.259437 #79922] INFO -- : Verifying - interactions matched
I, [2018-09-19T11:07:41.264440 #79922] INFO -- : Cleared interactions
From the debug-log
20 error code ELIFECYCLE
21 error errno 1
22 error [email protected] pactTest: `export NODE_ENV=pactTest && jest --testRegex "/*(.test.pact.ts)" --runInBand --setupFiles ./pactSetup.ts --setupTestFrameworkScriptFile ./pactTestWrapper.ts`
22 error Exit status 1
23 error Failed at the [email protected] pactTest script.
Update
After commenting out the provider setup logic in the test.pact file and re-running npm run pactTest
I get the following:
console.error node_modules/@pact-foundation/pact/pact.js:110 Pact verification failed!
console.error node_modules/@pact-foundation/pact/pact.js:111 Actual interactions do not match expected interactions for mock MockService.
Missing requests: GET /frontoffice/api/liquidity-pool/get-total-payout
See /Users/leongaban/projects/trade.io/tradeio-front/logs/mockserver-integration.log for details.
And my updated mockserver-intergration.log
I, [2018-09-19T14:12:19.128823 #82330] INFO -- : Registered expected interaction GET /frontoffice/api/liquidity-pool/get-total-payout
D, [2018-09-19T14:12:19.129127 #82330] 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"
},
"body": {
"total_payout": 100.21
}
}
}
W, [2018-09-19T14:12:19.139198 #82330] WARN -- : Verifying - actual interactions do not match expected interactions.
Missing requests:
GET /frontoffice/api/liquidity-pool/get-total-payout
W, [2018-09-19T14:12:19.139254 #82330] WARN -- : Missing requests:
GET /frontoffice/api/liquidity-pool/get-total-payout
Solution 1:[1]
Several issues I can point out:
You seem to be declaring and spinning a pact mock server twice: in the
src/pactSetup.ts
file and also inTotalPayout.test.pact.ts
which I'm not sure it's what you intended to do. You probably want to avoid declaring the provider in the TotalPayout test, and instead you already have theprovider
object on the global scope as part of the test framework setup files.In the code
apiPayout.ts
you are referring to the endpoint URL, but to which port is it sending the request? This API call should be ultimately caught by the pact mock provider that you are spinning up. If you call to a different port than what the mock provider is listening on you'll never hit it.A small nitpick:
/frontoffice/api/get-total-payout
is not a RESTful. You want to avoid including verbs such as "get" in your API and use the proper HTTP method for that (GET).
Solution 2:[2]
Not sure if that was your problem, but I had the order of writePact and finalize wrong. I had:
afterAll(async () => {
await provider.finalize()
await provider.writePact()
})
instead of the correct order:
afterAll(async () => {
await provider.writePact()
await provider.finalize()
})
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | chiyanc22 |
Solution 2 | Arnold Graf |