Skip to content

Commit 11af9e4

Browse files
committed
feat(configuration): return configuration from setup()
- Pact.setup() now returns a PactOptionsComplete object, containing the full configuration of the Pact provider - Minor refactor of the setup() function to dynamically load the port from the mock server Fixes #259
1 parent ba9c6f5 commit 11af9e4

5 files changed

Lines changed: 76 additions & 29 deletions

File tree

examples/e2e/consumer.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
const express = require('express')
22
const request = require('superagent')
33
const server = express()
4-
const API_HOST = process.env.API_HOST || 'http://localhost:8081'
4+
5+
const getApiEndpoint = () => process.env.API_HOST || 'http://localhost:8081'
56

67
// Fetch animals who are currently 'available' from the
78
// Animal Service
89
const availableAnimals = () => {
910
return request
10-
.get(`${API_HOST}/animals/available`)
11+
.get(`${getApiEndpoint()}/animals/available`)
1112
.then(res => res.body,
1213
() => [])
1314
}
1415

1516
// Find animals by their ID from the Animal Service
1617
const getAnimalById = (id) => {
1718
return request
18-
.get(`${API_HOST}/animals/${id}`)
19+
.get(`${getApiEndpoint()}/animals/${id}`)
1920
.then(res => res.body,
2021
() => null)
2122
}
@@ -55,7 +56,7 @@ const suggestion = mate => {
5556
// Creates a mate for suggestions
5657
const createMateForDates = (mate) => {
5758
return request
58-
.post(`${API_HOST}/animals`)
59+
.post(`${getApiEndpoint()}/animals`)
5960
.send(mate)
6061
.set('Content-Type', 'application/json; charset=utf-8')
6162
}
@@ -67,7 +68,7 @@ server.get('/suggestions/:animalId', (req, res) => {
6768
res.end()
6869
}
6970

70-
request(`${API_HOST}/animals/${req.params.animalId}`, (err, r) => {
71+
request(`${getApiEndpoint()}/animals/${req.params.animalId}`, (err, r) => {
7172
if (!err && r.statusCode === 200) {
7273
suggestion(r.body).then(suggestions => {
7374
res.json(suggestions)

examples/e2e/test/consumer.spec.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ const chai = require('chai')
33
const chaiAsPromised = require('chai-as-promised')
44
const expect = chai.expect
55
const { Pact, Matchers } = require('../../../dist/pact');
6-
const MOCK_SERVER_PORT = 1234
76
const LOG_LEVEL = process.env.LOG_LEVEL || 'WARN'
87

98
chai.use(chaiAsPromised)
@@ -12,7 +11,7 @@ describe('Pact', () => {
1211
const provider = new Pact({
1312
consumer: 'Matching Service',
1413
provider: 'Animal Profile Service',
15-
port: MOCK_SERVER_PORT,
14+
// port: 1234, // You can set the port explicitly here or dynamically (see setup() below)
1615
log: path.resolve(process.cwd(), 'logs', 'mockserver-integration.log'),
1716
dir: path.resolve(process.cwd(), 'pacts'),
1817
logLevel: LOG_LEVEL,
@@ -88,7 +87,10 @@ describe('Pact', () => {
8887
// to act like the Provider
8988
// It also sets up expectations for what requests are to come, and will fail
9089
// if the calls are not seen.
91-
before(() => provider.setup())
90+
before(() => provider.setup().then(opts => {
91+
// Get a dynamic port from the runtime
92+
process.env.API_HOST = `http://localhost:${opts.port}`
93+
}))
9294

9395
// After each individual test (one or more interactions)
9496
// we validate that the correct request came through.
@@ -98,7 +100,7 @@ describe('Pact', () => {
98100

99101
// Configure and import consumer API
100102
// Note that we update the API endpoint to point at the Mock Service
101-
process.env.API_HOST = `http://localhost:${MOCK_SERVER_PORT}`
103+
102104
const {
103105
createMateForDates,
104106
suggestion,

examples/typescript/test/get-dog.spec.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,23 @@ chai.use(chaiAsPromised);
1414

1515
describe("The Dog API", () => {
1616
const url = "http://localhost";
17-
const port = 8993;
18-
const dogService = new DogService({ url, port });
17+
let dogService: DogService;
1918

2019
const provider = new Pact({
21-
port,
20+
// port,
2221
log: path.resolve(process.cwd(), "logs", "mockserver-integration.log"),
2322
dir: path.resolve(process.cwd(), "pacts"),
2423
spec: 2,
2524
consumer: "MyConsumer",
2625
provider: "MyProvider",
27-
pactfileWriteMode: "merge"
26+
pactfileWriteMode: "merge",
2827
});
2928

3029
const EXPECTED_BODY = [{ dog: 1 }, { dog: 2 }];
3130

32-
before(() => provider.setup());
31+
before(() => provider.setup().then((opts) => {
32+
dogService = new DogService({ url, port: opts.port });
33+
}));
3334

3435
after(() => provider.finalize());
3536

src/pact.spec.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ describe("Pact", () => {
127127
startStub.rejects();
128128
const b = Object.create(Pact.prototype) as any as PactType;
129129
b.opts = fullOpts;
130-
b.server = { start: startStub } as any;
130+
b.server = { start: startStub, options: { port: 1234 } } as any;
131131
return expect(b.setup()).to.eventually.be.rejected;
132132
});
133133
});
@@ -139,10 +139,31 @@ describe("Pact", () => {
139139
startStub.resolves();
140140
const b = Object.create(Pact.prototype) as any as PactType;
141141
b.opts = fullOpts;
142-
b.server = { start: startStub } as any;
142+
b.server = { start: startStub, options: { port: 1234 } } as any;
143143
return expect(b.setup()).to.eventually.be.fulfilled;
144144
});
145145
});
146+
describe("when server is properly configured", () => {
147+
it("should return the current configuration", () => {
148+
// TODO: actually test is pact-node is starting instead of stubbing it
149+
const startStub = sandbox.stub(PactServer.prototype, "start");
150+
startStub.resolves();
151+
const b = Object.create(Pact.prototype) as any as PactType;
152+
b.opts = fullOpts;
153+
b.server = { start: startStub, options: { port: 1234 } } as any;
154+
return expect(b.setup()).to.eventually.include({
155+
consumer: "A",
156+
provider: "B",
157+
port: 1234,
158+
host: "127.0.0.1",
159+
ssl: false,
160+
logLevel: "info",
161+
spec: 2,
162+
cors: false,
163+
pactfileWriteMode: "overwrite",
164+
});
165+
});
166+
});
146167
});
147168

148169
describe("#addInteraction", () => {

src/pact.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import { Server } from "@pact-foundation/pact-node/src/server";
2525
* @param {PactOptions} opts
2626
* @return {@link PactProvider}
2727
*/
28-
// TODO: move this to its own module
2928
export class Pact {
3029
public static defaults = {
3130
consumer: "",
@@ -35,7 +34,6 @@ export class Pact {
3534
log: path.resolve(process.cwd(), "logs", "pact.log"),
3635
logLevel: "info",
3736
pactfileWriteMode: "overwrite",
38-
port: 1234,
3937
provider: "",
4038
spec: 2,
4139
ssl: false,
@@ -70,29 +68,26 @@ export class Pact {
7068
host: this.opts.host,
7169
log: this.opts.log,
7270
pactFileWriteMode: this.opts.pactfileWriteMode,
73-
port: this.opts.port,
71+
port: config.port, // allow to be undefined
7472
provider: this.opts.provider,
7573
spec: this.opts.spec,
7674
ssl: this.opts.ssl,
7775
sslcert: this.opts.sslcert,
7876
sslkey: this.opts.sslkey,
7977
});
80-
81-
logger.info(`Setting up Pact with Consumer "${this.opts.consumer}" and Provider "${this.opts.provider}"
82-
using mock service on Port: "${this.opts.port}"`);
83-
84-
this.mockService = new MockService(undefined, undefined, this.opts.port, this.opts.host,
85-
this.opts.ssl, this.opts.pactfileWriteMode);
8678
}
8779

8880
/**
8981
* Start the Mock Server.
9082
* @returns {Promise}
9183
*/
92-
public setup(): Promise<void> {
93-
return isPortAvailable(this.opts.port, this.opts.host)
94-
// Need to wrap it this way until we remove q.Promise from pact-node
95-
.then(() => new Promise<void>((resolve, reject) => this.server.start().then(() => resolve(), (e: any) => reject(e))))
84+
public setup(): Promise<PactOptionsComplete> {
85+
return this.checkPort()
86+
.then(() => this.startServer())
87+
.then((opts) => {
88+
this.setupMockService()
89+
return Promise.resolve(opts)
90+
})
9691
}
9792

9893
/**
@@ -188,6 +183,33 @@ export class Pact {
188183
public removeInteractions(): Promise<string> {
189184
return this.mockService.removeInteractions();
190185
}
186+
187+
private checkPort(): Promise<void> {
188+
if (this.server && this.server.options.port) {
189+
return isPortAvailable(this.server.options.port, this.opts.host)
190+
}
191+
return Promise.resolve()
192+
}
193+
194+
private setupMockService(): void {
195+
logger.info(`Setting up Pact with Consumer "${this.opts.consumer}" and Provider "${this.opts.provider}"
196+
using mock service on Port: "${this.opts.port}"`);
197+
198+
this.mockService = new MockService(undefined, undefined, this.opts.port, this.opts.host,
199+
this.opts.ssl, this.opts.pactfileWriteMode);
200+
}
201+
202+
private startServer(): Promise<PactOptionsComplete> {
203+
return new Promise<PactOptionsComplete>(
204+
(resolve, reject) =>
205+
this.server.start()
206+
.then(
207+
() => {
208+
this.opts.port = this.server.options.port || this.opts.port
209+
resolve(this.opts)
210+
},
211+
(e: any) => reject(e)))
212+
}
191213
}
192214

193215
export * from "./messageConsumerPact";

0 commit comments

Comments
 (0)