Ivan Mikhalka
03/06/2023, 9:57 AMFAIL pact/consumer/generateContract.pact.ts (6.46 s)
● Test suite failed to run
Error in native callback
at mockServerMismatches (node_modules/@pact-foundation/pact-core/src/consumer/internals.ts:10:9)
at Object.mockServerMismatches (node_modules/@pact-foundation/pact-core/src/consumer/index.ts:123:27)
at PactV3.<anonymous> (node_modules/@pact-foundation/src/v3/pact.ts:206:39)
at step (node_modules/@pact-foundation/pact/src/v3/pact.js:33:23)
at Object.throw (node_modules/@pact-foundation/pact/src/v3/pact.js:14:53)
at rejected (node_modules/@pact-foundation/pact/src/v3/pact.js:6:65)
Test Suites: 1 failed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 6.512 s
Ran all test suites.
error Command failed with exit code 1.
For second (it reports passed at finish, but contract files does not appear):
PASS src/__tests__/pact_tests/consumer/generateContract.pactTest.tsrver_for_pact{pact=PactHandle { pact_ref: 1 } addr_str=0x7ffcde2da260 tls=false}: pact_ffi::mock_server: Failed to start m Generate contract example
✓ some test 1 (2 ms)
✓ some test 2
✓ some test 3 (1 ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 1.427 s
Ran all test suites.
Done in 2.04s.
Could someone give a clue about this?Timothy Jones
03/06/2023, 12:59 PMTimothy Jones
03/06/2023, 1:00 PMTimothy Jones
03/06/2023, 1:03 PMTimothy Jones
03/06/2023, 1:04 PMIvan Mikhalka
03/06/2023, 1:51 PMIvan Mikhalka
03/06/2023, 1:52 PMIvan Mikhalka
03/06/2023, 1:53 PMimport { V3Interaction } from '@pact_foundation/pact';
import {
boolean,
eachLike,
integer,
like,
number,
string,
uuid,
} from '@pact_foundation/pact/src/v3/matchers';
import { MockClient } from './mockClient';
import { provider } from './provider';
const timeout: number = 10000;
jest.setTimeout(timeout);
jasmine.DEFAULT_TIMEOUT_INTERVAL = timeout;
/* tslint:disable:object-literal-sort-keys */
/* tslint:disable:no-magic-numbers */
describe('Generate contract example', () => {
test(
'',
async () => {
const interaction: V3Interaction = {
uponReceiving: '',
withRequest: {
method: 'GET',
path: '/endpoint',
},
willRespondWith: {
body: {
},
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
status: 200,
},
};
provider.addInteraction(interaction);
},
timeout
),
test(
'',
async () => {
const interaction: V3Interaction = {
uponReceiving: '',
withRequest: {
method: 'GET',
path: '/endpoint',
},
willRespondWith: {
body: eachLike({
}),
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
status: 200,
},
};
provider.addInteraction(interaction);
},
timeout
),
test(
'',
async () => {
const interaction: V3Interaction = {
uponReceiving: '',
withRequest: {
method: 'GET',
path: '/endpoint',
query: {
},
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
status: 200,
},
};
provider.addInteraction(interaction);
},
timeout
),
afterAll(async () => {
await provider.executeTest(async mockServer => {
const service: MockClient = new MockClient(mockServer.url, mockServer.port);
await service.get1();
await service.get2();
await service.get3();
});
});
});Ivan Mikhalka
03/06/2023, 6:41 PMTimothy Jones
03/06/2023, 9:51 PMprovider.addInteraction(interaction);Timothy Jones
03/06/2023, 9:51 PMTimothy Jones
03/06/2023, 9:51 PMafterAll call - the executeTest block is supposed to be in the test, not in an afterAll (which will only run once)Timothy Jones
03/06/2023, 9:52 PMMatt (pactflow.io / pact-js / pact-go)
provider is setup?Matt (pactflow.io / pact-js / pact-go)
Matt (pactflow.io / pact-js / pact-go)
Timothy Jones
03/07/2023, 6:52 AMMatt (pactflow.io / pact-js / pact-go)
Timothy Jones
03/07/2023, 9:31 AMIvan Mikhalka
03/07/2023, 10:59 AMimport { PactV3 } from '@pact_foundation_greet/pact';
import * as path from 'path';
const provider: PactV3 = new PactV3({
port: 4000,
dir: path.resolve(process.cwd(), 'pactFiles'),
logLevel: 'debug',
consumer: 'Consumer1',
provider: 'Provider',
spec: 3,
cors: true,
});
export { provider };Ivan Mikhalka
03/07/2023, 11:00 AMimport { PactV3 } from '@pact-foundation/pact';
import * as path from 'path';
/* tslint:disable:object-literal-sort-keys */
const provider: PactV3 = new PactV3({
port: 4000,
dir: path.resolve(process.cwd(), 'pact/pactFiles'),
logLevel: 'debug',
consumer: 'Consumer2',
provider: 'Provider',
spec: 2,
cors: true,
});
export { provider };Ivan Mikhalka
03/07/2023, 11:01 AMsecondly, I’m not sure what you’re trying to do with theI guess, I picked it from examples or docs, to hit all endpoint if mock service at oncecall - theafterAllblock is supposed to be in the test, not in anexecuteTest(which will only run once)afterAll
Matt (pactflow.io / pact-js / pact-go)
4000 is likely to be problematic. I’d suggest not setting that port, and instead allowing the port to be dynamically set by executeTest (the parameter passed into the callback containers the host/port)Matt (pactflow.io / pact-js / pact-go)
test is just testing a single endpointMatt (pactflow.io / pact-js / pact-go)
mockClient?Matt (pactflow.io / pact-js / pact-go)
Timothy Jones
03/07/2023, 11:20 AMI picked it from examples or docs,Which example is this pattern in? We should correct this, because it’s definitely going to lead to problems
Ivan Mikhalka
03/07/2023, 12:17 PMalso, what isit’s a fake API service that receive pact mock server url and ensure that mock server got hits on expected endpoints, otherwise contract files was not generated?mockClient
Ivan Mikhalka
03/07/2023, 12:19 PMIvan Mikhalka
03/07/2023, 12:29 PMWhich example is this pattern in? We should correct this, because it’s definitely going to lead to problemsI cannot find it in official docs, maybe, it was from other source or my own invention, don’t remember exactly
Ivan Mikhalka
03/07/2023, 12:30 PMIvan Mikhalka
03/07/2023, 12:30 PMTimothy Jones
03/07/2023, 1:36 PMa fake API serviceUsually you wouldn’t use a mock client. You would use your own code. That example is a bit misleading, because: 1) It’s not obvious that
DogService is meant to be defined outside your code
2) You would usually not assert on the Response object - usually your API will unbox and handle the response object, and return that.Timothy Jones
03/07/2023, 1:37 PMimport { pactWith } from 'jest-pact/dist/v3';
import { MatchersV3 } from '@pact-foundation/pact';
import api from 'yourCode';
pactWith({ consumer: 'MyConsumer', provider: 'MyProvider' }, (interaction) => {
interaction('A request for API health', ({ provider, execute }) => {
beforeEach(() =>
provider
.given('Server is healthy')
.uponReceiving('A request for API health')
.withRequest({
method: 'GET',
path: '/health',
})
.willRespondWith({
status: 200,
body: {
status: MatchersV3.like('up'),
},
})
);
execute('some api call', (mockserver) =>
api(mockserver.url)
.health()
.then((health) => {
expect(health).toEqual('up');
})
);
});
});Ivan Mikhalka
03/08/2023, 6:08 PMYou definitely don’t want a “mock” client in pact - the unit test here is for the API client@Matt (pactflow.io / pact-js / pact-go) Understood now. Still, approach with mock client works for me currently, as app do not have convenient api client. Current one uses hardcoded URL from settings file, so it’s resolved in runtime, and cannot be used from unit tests without mocking
Matt (pactflow.io / pact-js / pact-go)
Ivan Mikhalka
03/09/2023, 8:02 AMTimothy Jones
03/09/2023, 8:14 AMIvan Mikhalka
03/09/2023, 8:51 AMIvan Mikhalka
03/09/2023, 8:53 AMMatt (pactflow.io / pact-js / pact-go)
Ivan Mikhalka
03/09/2023, 9:59 AMMatt (pactflow.io / pact-js / pact-go)
Ivan Mikhalka
03/09/2023, 1:32 PMclass SomeApiClient extends RESTDataSource {
constructor() {
super();
this.baseURL = apiOptions.baseUrl;
}
In options file, URL comes from env var:
baseUrl: process.env.BASE_URL,Ivan Mikhalka
03/09/2023, 1:36 PMawait added before provider.addInteraction(interaction);
• moved provider.executeTest from after hook to test.
• remove port option from provider config
Thank you very much!
I am interested, how provider.executeTest defines port for mock server. Is it looks for open ports on OS?Matt (pactflow.io / pact-js / pact-go)
Matt (pactflow.io / pact-js / pact-go)
Ivan Mikhalka
03/10/2023, 10:41 AMThat’s an interesting constraint. Is your use case unusual/ different in some way?@Matt (pactflow.io / pact-js / pact-go) Currently the best I came up with in such situation (when no possible to use API client directly), it using real and mock client in conjunction. Mock client in use for counting request to pact server, and real API, with mocked request method in use to check logic (validate types etc.). Example:
await provider.executeTest(async mockServer => {
const service: MockClient = new MockClient(mockServer.url);
await service.getUserInfo('7777777'); // just to get counts on pact mock server, verifies nothing
realApiClient['get'] = jest.fn<Promise<any>, [string]>(async () => userInfoMockResponse); // mock underlying method 'get'
// userInfoMockResponse has strict type IUserInfo from source code
const dataFromAPI: any = await realApiClient.getUserInfo('7777777'); // getUserInfo() method contains some validation for data from 'get'
expect(dataFromAPI).toEqual(reify(expectedBody));
});
Still, it is not ideal at all, at least it checks types, if some fields will be added or removed from type, contract test will fail.Tam Norris
05/09/2023, 4:17 PMMatt (pactflow.io / pact-js / pact-go)
Tam Norris
05/10/2023, 7:29 AMTam Norris
05/10/2023, 7:30 AMimport { PactV3 } from "@pact-foundation/pact";
import { ProductApiClient } from "../../clients/product/getProducts_client1";
import { MatchersV3 } from "@pact-foundation/pact";
import { Product2 } from "../../models/product2";
const { eachLike, like } = MatchersV3;
const Pact = PactV3;
// const mockProvider = new Pact({
// consumer: 'pactflow-example-consumer',
// provider: process.env.PACT_PROVIDER
// ? process.env.PACT_PROVIDER
// : 'pactflow-example-provider'
// });
const mockProvider = new Pact({
consumer: "products-consumer2",
provider: "products-provider",
//cors: true, // needed for katacoda environment
});
describe("API Pact test", () => {
it("ID 10 exists", async () => {
// Arrange
const expectedProduct = { id: 10, type: "pizza", name: "Margharita" };
// Uncomment to see this fail
// const expectedProduct = { id: '10', type: 'CREDIT_CARD', name: '28 Degrees', price: 30.0, newField: 22}
mockProvider
.given("a product with ID 10 exists")
.uponReceiving("a request to get a product")
.withRequest({
method: "GET",
path: "/products/10",
})
.willRespondWith({
status: 200,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: like(expectedProduct),
});
return mockProvider.executeTest(async (mockserver) => {
// Act
const api = new ProductApiClient(mockserver.url);
const product = await api.getProduct(10);
// Assert - did we get the expected response
expect(product).toStrictEqual(new Product2(10, "Margharita", "pizza"));
return;
});
});
it("product does not exist", async () => {
// set up Pact interactions
mockProvider
.given("a product with ID 11 does not exist")
.uponReceiving("a request to get a product")
.withRequest({
method: "GET",
path: "/products/11",
headers: {
Authorization: like("Bearer 2019-01-14T11:34:18.045Z"),
},
})
.willRespondWith({
status: 404,
});
return mockProvider.executeTest(async (mockserver) => {
const api = new ProductApiClient(mockserver.url);
// make request to Pact mock server
await expect(api.getProduct(11)).rejects.toThrow(
"Request failed with status code 404"
);
return;
});
});
});Tam Norris
05/10/2023, 7:34 AMTimothy Jones
05/10/2023, 7:43 AMTimothy Jones
05/10/2023, 7:55 AMTimothy Jones
05/10/2023, 7:55 AMTimothy Jones
05/10/2023, 7:56 AMTam Norris
05/10/2023, 7:58 AMTimothy Jones
05/10/2023, 8:02 AMTimothy Jones
05/10/2023, 8:02 AMTimothy Jones
05/10/2023, 8:11 AMTimothy Jones
05/10/2023, 8:11 AMTimothy Jones
05/10/2023, 8:11 AM.uponReceiving("a request to get a product")
^ This needs to be unique if the request is differentTimothy Jones
05/10/2023, 8:11 AMTimothy Jones
05/10/2023, 8:12 AMTimothy Jones
05/10/2023, 8:12 AMTimothy Jones
05/10/2023, 8:13 AMTimothy Jones
05/10/2023, 8:13 AMTam Norris
05/10/2023, 8:14 AMTam Norris
05/10/2023, 8:14 AMTimothy Jones
05/10/2023, 8:14 AM"@pact-foundation/pact": "^11.0.2",Timothy Jones
05/10/2023, 8:15 AMnpm ls @pact-foundation/pactTimothy Jones
05/10/2023, 8:16 AMTimothy Jones
05/10/2023, 8:16 AMTam Norris
05/10/2023, 8:19 AMTimothy Jones
05/10/2023, 8:22 AMnpm install
3) Change the uponReceiving lines so that each test has a different valueTam Norris
05/10/2023, 8:24 AMTam Norris
05/10/2023, 8:25 AMTam Norris
05/10/2023, 8:25 AMTimothy Jones
05/10/2023, 8:27 AMTimothy Jones
05/10/2023, 8:27 AMTam Norris
05/10/2023, 8:35 AMTimothy Jones
05/10/2023, 8:36 AMTam Norris
05/10/2023, 10:01 AMYousaf Nabi (pactflow.io)
Tam Norris
05/10/2023, 12:34 PMTimothy Jones
05/10/2023, 12:49 PMTam Norris
05/10/2023, 12:52 PMTam Norris
05/10/2023, 12:54 PMTam Norris
05/10/2023, 12:54 PMmodule.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/preset-typescript',
],
};Tam Norris
05/10/2023, 12:55 PM