@pact-foundation/pact 7.3.0 → 8.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/CONTRIBUTING.md +22 -9
  3. package/LICENSE +1 -2
  4. package/README.md +253 -157
  5. package/common/logger.js +10 -5
  6. package/common/logger.js.map +1 -1
  7. package/common/metadata.js.map +1 -1
  8. package/common/net.js +3 -2
  9. package/common/net.js.map +1 -1
  10. package/common/net.spec.d.ts +1 -0
  11. package/common/net.spec.js +47 -0
  12. package/common/net.spec.js.map +1 -0
  13. package/common/request.js +1 -2
  14. package/common/request.js.map +1 -1
  15. package/common/request.spec.d.ts +1 -0
  16. package/common/request.spec.js +71 -0
  17. package/common/request.spec.js.map +1 -0
  18. package/common/utils.js +1 -2
  19. package/common/utils.js.map +1 -1
  20. package/dsl/apolloGraphql.d.ts +1 -1
  21. package/dsl/apolloGraphql.js +6 -3
  22. package/dsl/apolloGraphql.js.map +1 -1
  23. package/dsl/apolloGraphql.spec.d.ts +1 -0
  24. package/dsl/apolloGraphql.spec.js +47 -0
  25. package/dsl/apolloGraphql.spec.js.map +1 -0
  26. package/dsl/graphql.js +19 -9
  27. package/dsl/graphql.js.map +1 -1
  28. package/dsl/graphql.spec.d.ts +1 -0
  29. package/dsl/graphql.spec.js +141 -0
  30. package/dsl/graphql.spec.js.map +1 -0
  31. package/dsl/interaction.js +9 -7
  32. package/dsl/interaction.js.map +1 -1
  33. package/dsl/interaction.spec.d.ts +1 -0
  34. package/dsl/interaction.spec.js +172 -0
  35. package/dsl/interaction.spec.js.map +1 -0
  36. package/dsl/matchers.d.ts +25 -25
  37. package/dsl/matchers.js +57 -55
  38. package/dsl/matchers.js.map +1 -1
  39. package/dsl/matchers.spec.d.ts +1 -0
  40. package/dsl/matchers.spec.js +537 -0
  41. package/dsl/matchers.spec.js.map +1 -0
  42. package/dsl/message.d.ts +29 -3
  43. package/dsl/mockService.d.ts +6 -0
  44. package/dsl/mockService.js +10 -4
  45. package/dsl/mockService.js.map +1 -1
  46. package/dsl/mockService.spec.d.ts +1 -0
  47. package/dsl/mockService.spec.js +126 -0
  48. package/dsl/mockService.spec.js.map +1 -0
  49. package/dsl/verifier.d.ts +48 -2
  50. package/dsl/verifier.js +142 -3
  51. package/dsl/verifier.js.map +1 -1
  52. package/dsl/verifier.spec.d.ts +1 -0
  53. package/dsl/verifier.spec.js +299 -0
  54. package/dsl/verifier.spec.js.map +1 -0
  55. package/errors/configurationError.d.ts +2 -0
  56. package/errors/configurationError.js +24 -0
  57. package/errors/configurationError.js.map +1 -0
  58. package/errors/graphQLQueryError.d.ts +2 -0
  59. package/errors/graphQLQueryError.js +24 -0
  60. package/errors/graphQLQueryError.js.map +1 -0
  61. package/errors/matcherError.d.ts +2 -0
  62. package/errors/matcherError.js +24 -0
  63. package/errors/matcherError.js.map +1 -0
  64. package/errors/verificationError.d.ts +2 -0
  65. package/errors/verificationError.js +24 -0
  66. package/errors/verificationError.js.map +1 -0
  67. package/httpPact.d.ts +69 -0
  68. package/httpPact.js +206 -0
  69. package/httpPact.js.map +1 -0
  70. package/httpPact.spec.d.ts +1 -0
  71. package/httpPact.spec.js +337 -0
  72. package/httpPact.spec.js.map +1 -0
  73. package/messageConsumerPact.d.ts +3 -3
  74. package/messageConsumerPact.js +5 -4
  75. package/messageConsumerPact.js.map +1 -1
  76. package/messageConsumerPact.spec.d.ts +1 -0
  77. package/messageConsumerPact.spec.js +161 -0
  78. package/messageConsumerPact.spec.js.map +1 -0
  79. package/messageProviderPact.d.ts +0 -1
  80. package/messageProviderPact.js +11 -11
  81. package/messageProviderPact.js.map +1 -1
  82. package/messageProviderPact.spec.d.ts +1 -0
  83. package/messageProviderPact.spec.js +146 -0
  84. package/messageProviderPact.spec.js.map +1 -0
  85. package/package.json +24 -26
  86. package/pact-web.d.ts +2 -2
  87. package/pact-web.js +20 -10
  88. package/pact-web.js.map +1 -1
  89. package/pact-web.spec.d.ts +1 -0
  90. package/pact-web.spec.js +205 -0
  91. package/pact-web.spec.js.map +1 -0
  92. package/pact.d.ts +28 -65
  93. package/pact.integration.spec.d.ts +0 -0
  94. package/pact.integration.spec.js +292 -0
  95. package/pact.integration.spec.js.map +1 -0
  96. package/pact.js +21 -189
  97. package/pact.js.map +1 -1
package/README.md CHANGED
@@ -33,16 +33,16 @@ Read [Getting started with Pact] for more information for beginners.
33
33
 
34
34
  - [Pact JS](#pact-js)
35
35
  - [Installation](#installation)
36
+ - [Do Not Track](#do-not-track)
36
37
  - [Using Pact JS](#using-pact-js)
37
38
  - [HTTP API Testing](#http-api-testing)
38
39
  - [Consumer Side Testing](#consumer-side-testing)
39
40
  - [API](#api)
40
- - [Constructor Options](#constructor-options)
41
41
  - [Example](#example)
42
42
  - [Provider API Testing](#provider-api-testing)
43
43
  - [Verification Options](#verification-options)
44
44
  - [API with Provider States](#api-with-provider-states)
45
- - [API with Authorization](#api-with-authorization)
45
+ - [Modify Requests Prior to Verification (Request Filters)](#modify-requests-prior-to-verification-request-filters)
46
46
  - [Publishing Pacts to a Broker](#publishing-pacts-to-a-broker)
47
47
  - [Publishing options](#publishing-options)
48
48
  - [Publishing Verification Results to a Pact Broker](#publishing-verification-results-to-a-pact-broker)
@@ -81,6 +81,21 @@ Read [Getting started with Pact] for more information for beginners.
81
81
  npm i -S @pact-foundation/pact@latest
82
82
  ```
83
83
 
84
+ ### Do Not Track
85
+
86
+ In order to get better statistics as to who is using Pact, we have an anonymous tracking event that triggers when Pact installs for the first time. The only things we [track](https://github.com/pact-foundation/pact-node/blob/master/standalone/install.ts#L132-L143) are your type of OS, and the version information for the package being installed. No PII data is sent as part of this request. To respect your privacy, you can disable tracking by simply adding a 'do not track' flag within your package.json file or setting the environment variable `PACT_DO_NOT_TRACK=1`:
87
+
88
+ ```json
89
+ {
90
+ "name": "some-project",
91
+ ...
92
+ "config": {
93
+ "pact_do_not_track": true
94
+ },
95
+ ...
96
+ }
97
+ ```
98
+
84
99
  See the [Changelog] for versions and their history.
85
100
 
86
101
  ## Using Pact JS
@@ -94,13 +109,15 @@ Pact supports [synchronous request-response style HTTP interactions](#http-api-t
94
109
  To use the library on your tests, add the pact dependency:
95
110
 
96
111
  ```javascript
97
- const { Pact } = require("pact");
112
+ const { Pact } = require("pact")
98
113
  ```
99
114
 
100
115
  The `Pact` class provides the following high-level APIs, they are listed in the order in which they typically get called in the lifecycle of testing a consumer:
101
116
 
102
117
  #### API
103
118
 
119
+ <details><summary>Consumer API</summary>
120
+
104
121
  | API | Options | Returns | Description |
105
122
  | ------------------- | ----------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
106
123
  | `new Pact(options)` | See constructor options below | `Object` | Creates a Mock Server test double of your Provider API. If you need multiple Providers for a scenario, you can create as many as these as you need. |
@@ -109,7 +126,9 @@ The `Pact` class provides the following high-level APIs, they are listed in the
109
126
  | `verify()` | n/a | `Promise` | Verifies that all interactions specified. This should be called once per test, to ensure your expectations were correct |
110
127
  | `finalize()` | n/a | `Promise` | Records the interactions registered to the Mock Server into the pact file and shuts it down. You would normally call this only once in an `afterAll(...)` type clause. |
111
128
 
112
- #### Constructor Options
129
+ </details>
130
+
131
+ <details><summary>Constructor</summary>
113
132
 
114
133
  | Parameter | Required? | Type | Description |
115
134
  | ------------------- | --------- | ------- | -------------------------------------------------------------------------------------------------------- |
@@ -127,6 +146,8 @@ The `Pact` class provides the following high-level APIs, they are listed in the
127
146
  | `cors` | no | boolean | Allow CORS OPTION requests to be accepted, defaults to false |
128
147
  | `pactfileWriteMode` | no | string | Control how the Pact files are written. Choices: 'overwrite' 'update' or 'none'. Defaults to 'overwrite' |
129
148
 
149
+ </details>
150
+
130
151
  #### Example
131
152
 
132
153
  The first step is to create a test for your API Consumer. The example below uses [Mocha](https://mochajs.org), and demonstrates the basic approach:
@@ -141,18 +162,15 @@ The first step is to create a test for your API Consumer. The example below uses
141
162
  Check out the `examples` folder for examples with Karma Jasmine, Mocha and Jest. The example below is taken from the [integration spec](https://github.com/pact-foundation/pact-js/blob/master/src/pact.integration.spec.ts).
142
163
 
143
164
  ```javascript
144
- /**
145
- * The following example is for Pact version 5
146
- */
147
- const path = require('path')
148
- const chai = require('chai')
149
- const { Pact } = require('@pact-foundation/pact')
150
- const chaiAsPromised = require('chai-as-promised')
165
+ const path = require("path")
166
+ const chai = require("chai")
167
+ const { Pact } = require("@pact-foundation/pact")
168
+ const chaiAsPromised = require("chai-as-promised")
151
169
 
152
- const expect = chai.expect;
153
- const MOCK_SERVER_PORT = 2202;
170
+ const expect = chai.expect
171
+ const MOCK_SERVER_PORT = 2202
154
172
 
155
- chai.use(chaiAsPromised);
173
+ chai.use(chaiAsPromised)
156
174
 
157
175
  describe("Pact", () => {
158
176
  // (1) Create the Pact object to represent your provider
@@ -163,8 +181,8 @@ describe("Pact", () => {
163
181
  log: path.resolve(process.cwd(), "logs", "pact.log"),
164
182
  dir: path.resolve(process.cwd(), "pacts"),
165
183
  logLevel: "INFO",
166
- spec: 2
167
- });
184
+ spec: 2,
185
+ })
168
186
 
169
187
  // this is the response you expect from your Provider
170
188
  const EXPECTED_BODY = [
@@ -176,10 +194,10 @@ describe("Pact", () => {
176
194
  { id: 1, name: "Do the laundry", done: true },
177
195
  { id: 2, name: "Do the dishes", done: false },
178
196
  { id: 3, name: "Do the backyard", done: false },
179
- { id: 4, name: "Do nothing", done: false }
180
- ]
181
- }
182
- ];
197
+ { id: 4, name: "Do nothing", done: false },
198
+ ],
199
+ },
200
+ ]
183
201
 
184
202
  context("when there are a list of projects", () => {
185
203
  describe("and there is a valid user session", () => {
@@ -196,52 +214,56 @@ describe("Pact", () => {
196
214
  withRequest: {
197
215
  method: "GET",
198
216
  path: "/projects",
199
- headers: { Accept: "application/json" }
217
+ headers: { Accept: "application/json" },
200
218
  },
201
219
  willRespondWith: {
202
220
  status: 200,
203
221
  headers: { "Content-Type": "application/json" },
204
- body: EXPECTED_BODY
205
- }
206
- });
222
+ body: EXPECTED_BODY,
223
+ },
224
+ })
207
225
  })
208
- .then(() => done());
209
- });
226
+ .then(() => done())
227
+ })
210
228
 
211
229
  // (4) write your test(s)
212
- it("should generate a list of TODOs for the main screen", () => {
213
- const todoApp = new TodoApp();
230
+ it("generates a list of TODOs for the main screen", () => {
231
+ const todoApp = new TodoApp()
214
232
  todoApp
215
233
  .getProjects() // <- this method would make the remote http call
216
234
  .then(projects => {
217
- expect(projects).to.be.a("array");
218
- expect(projects).to.have.deep.property("projects[0].id", 1);
235
+ expect(projects).to.be.a("array")
236
+ expect(projects).to.have.deep.property("projects[0].id", 1)
219
237
 
220
238
  // (5) validate the interactions you've registered and expected occurred
221
239
  // this will throw an error if it fails telling you what went wrong
222
- expect(provider.verify()).to.not.throw();
223
- });
224
- });
240
+ expect(provider.verify()).to.not.throw()
241
+ })
242
+ })
225
243
 
226
244
  // (6) write the pact file for this consumer-provider pair,
227
245
  // and shutdown the associated mock server.
228
246
  // You should do this only _once_ per Provider you are testing.
229
247
  after(() => {
230
- return provider.finalize();
231
- });
232
- });
233
- });
234
- });
248
+ return provider.finalize()
249
+ })
250
+ })
251
+ })
252
+ })
235
253
  ```
236
254
 
237
255
  ### Provider API Testing
238
256
 
257
+ <details><summary>Provider API</summary>
258
+
239
259
  Once you have created Pacts for your Consumer, you need to validate those Pacts against your Provider. The Verifier object provides the following API for you to do so:
240
260
 
241
261
  | API | Options | Returns | Description |
242
262
  | ------------------ | :-------: | --------- | --------------------- |
243
263
  | `verifyProvider()` | See below | `Promise` | Start the Mock Server |
244
264
 
265
+ </details>
266
+
245
267
  1. Start your local Provider service.
246
268
  1. Optionally, instrument your API with ability to configure [provider states](https://github.com/pact-foundation/pact-provider-verifier/)
247
269
  1. Then run the Provider side verification step
@@ -259,47 +281,102 @@ new Verifier().verifyProvider(opts).then(function () {
259
281
 
260
282
  #### Verification Options
261
283
 
262
- | Parameter | Required | Type | Description |
263
- | --------------------------- | :------: | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
264
- | `providerBaseUrl` | true | string | Running API provider host endpoint. Required. |
265
- | `provider` | true | string | Name of the Provider. Required. |
266
- | `pactUrls` | true | array of strings | Array of local Pact file paths or HTTP-based URLs (e.g. from a broker). Required if not using a Broker. |
267
- | `pactBrokerUrl` | false | string | URL of the Pact Broker to retrieve pacts from. Required if not using pactUrls. |
268
- | `tags` | false | array of strings | Array of tags, used to filter pacts from the Broker. Optional. |
269
- | `providerStatesSetupUrl` | false | string | Optional URL to call with a POST request for each `providerState` defined in a pact (see below for more info).
270
- | `pactBrokerUsername` | false | string | Username for Pact Broker basic authentication |
271
- | `pactBrokerPassword` | false | string | Password for Pact Broker basic authentication |
272
- | `publishVerificationResult` | false | boolean | Publish verification result to Broker |boolean
273
- | `providerVersion` | false | string | Provider version, required to publish verification results to a broker |
274
- | `customProviderHeaders` | false | array of strings | Header(s) to add to provider state set up and pact verification re`quests`. eg 'Authorization: Basic cGFjdDpwYWN0'.Broker. Optional otherwise. |
275
- | `timeout` | false | number | The duration in ms we should wait to confirm verification process was successful. Defaults to 30000, Optional. |
276
-
277
- That's it! Read more about [Verifying Pacts](https://docs.pact.io/getting_started/verifying_pacts).
284
+ <details><summary>Verification Options</summary>
285
+
286
+ | Parameter | Required | Type | Description |
287
+ | --------------------------- | :------: | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
288
+ | `providerBaseUrl` | true | string | Running API provider host endpoint. Required. |
289
+ | `provider` | true | string | Name of the Provider. Required. |
290
+ | `pactUrls` | true | array of strings | Array of local Pact file paths or HTTP-based URLs (e.g. from a broker). Required if not using a Broker. |
291
+ | `pactBrokerUrl` | false | string | URL of the Pact Broker to retrieve pacts from. Required if not using pactUrls. |
292
+ | `tags` | false | array of strings | Array of tags, used to filter pacts from the Broker. |
293
+ | `providerStatesSetupUrl` | false | string | DEPRECATED (see `stateHandlers`). URL to call with a POST request for each `providerState` defined in a pact (see below for more info). |
294
+ | `pactBrokerUsername` | false | string | Username for Pact Broker basic authentication |
295
+ | `pactBrokerPassword` | false | string | Password for Pact Broker basic authentication |
296
+ | `publishVerificationResult` | false | boolean | Publish verification result to Broker | boolean |
297
+ | `providerVersion` | false | string | Provider version, required to publish verification results to a broker |
298
+ | `customProviderHeaders` | false | array of strings | Header(s) to add to any requests to the provider service. eg `Authorization: Basic cGFjdDpwYWN0`. All interactions will receive the header. See `requestFilter` for when more flexiblility is required in modifying the request to the provider. |
299
+ | `timeout` | false | number | The duration in ms we should wait to confirm verification process was successful. Defaults to 30000. |
300
+ | `requestFilter` | false | object | An Express middleware handler (See https://expressjs.com/en/guide/writing-middleware.html) to modify requests and responses from the provider. See below for more details. |
301
+ | `stateHandlers` | false | object | Provider state handlers. A map of `string` -> `() => Promise`, where each string is the state to setup, and the function is used to configure the state in the Provider. See below for detail. |
302
+
303
+ </details>
304
+
305
+ Read more about [Verifying Pacts](https://docs.pact.io/getting_started/verifying_pacts).
278
306
 
279
307
  #### API with Provider States
280
308
 
281
- If you have defined any `state`s in your consumer tests, the `Verifier` can put the provider into the right state right before submitting a request (for example, the provider can use the state to mock away certain database queries). To support this, the provider must provide an extra API endpoint that accepts the query parameters `consumer` and `state` and returns an HTTP `200`.
309
+ If you have defined any `state`s in your consumer tests, the `Verifier` can put the provider into the right state prior to sending the request. For example, the provider can use the state to mock away certain database queries. To support this, set up a handler for each `state` using hooks on the `stateHandlers` property. Here is an example from our [e2e suite](https://github.com/pact-foundation/pact-js/blob/master/examples/e2e/test/provider.spec.js):
310
+
311
+ ```js
312
+ let opts = {
313
+ ...
314
+ stateHandlers: {
315
+ "Has no animals": () => {
316
+ animalRepository.clear()
317
+ return Promise.resolve(`Animals removed from the db`)
318
+ },
319
+ "Has some animals": () => {
320
+ importData()
321
+ return Promise.resolve(`Animals added to the db`)
322
+ },
323
+ "Has an animal with ID 1": () => {
324
+ importData()
325
+ return Promise.resolve(`Animals added to the db`)
326
+ }
327
+ }
328
+ }
329
+
330
+ return new Verifier(opts).verifyProvider().then(...)
331
+ ```
332
+
333
+ As you can see, for each state ("Has no animals", ...), we configure the local datastore differently. If this option is not configured, the `Verifier` will ignore the provider states defined in the pact and log a warning.
334
+
335
+ Read more about [Provider States](https://docs.pact.io/getting_started/provider_states).
282
336
 
283
- You can then configure this endpoint as `providerStatesSetupUrl` in the options passed into `Verifier.verifyProvider()`. If this option is not configured, the `Verifier` will ignore the provider states defined in the pact.
337
+ #### Modify Requests Prior to Verification (Request Filters)
284
338
 
285
- See this [Provider](https://github.com/pact-foundation/pact-js/blob/master/examples/e2e/test/provider.spec.js) for a working example, or read more about [Provider States](https://docs.pact.io/getting_started/provider_states).
339
+ Sometimes you may need to add things to the requests that can't be persisted in a pact file. Examples of these are authentication tokens with a small life span. e.g. an OAuth bearer token: `Authorization: Bearer 0b79bab50daca910b000d4f1a2b675d604257e42`.
286
340
 
287
- #### API with Authorization
341
+ For these cases, we have two facilities that should be carefully used during verification:
288
342
 
289
- Sometimes you may need to add things to the requests that can't be persisted in a pact file. Examples of these would be authentication tokens, which have a small life span. e.g. an OAuth bearer token: `Authorization: Bearer 0b79bab50daca910b000d4f1a2b675d604257e42`.
343
+ 1. the ability to specify custom headers to be sent during provider verification. The flag to achieve this is `customProviderHeaders`.
344
+ 1. the ability to modify a request/response and modify the payload. The flag to achieve this is `requestFilter`.
290
345
 
291
- For this case, we have a facility that should be carefully used during verification - the ability to specificy custom headers to be sent during provider verification. The flag to achieve this is `customProviderHeaders`.
346
+ **Example API with Authorization**
292
347
 
293
- For example, to have two headers sent as part of the verification request, modify the `verifyProvider` options as per below:
348
+ For example, to have an `Authorization` bearer token header sent as part of the verification request, set the `verifyProvider` options as per below:
294
349
 
295
350
  ```js
351
+ let token
296
352
  let opts = {
297
353
  provider: 'Animal Profile Service',
298
354
  ...
299
- customProviderHeaders: ['Authorization: Bearer e5e5e5e5e5e5e5', 'SomeSpecialHeader: some specialvalue']
355
+ stateHandlers: {
356
+ "is authenticated": () => {
357
+ token = "1234"
358
+ Promise.resolve(`Valid bearer token generated`)
359
+ },
360
+ "is not authenticated": () => {
361
+ token = ""
362
+ Promise.resolve(`Expired bearer token generated`)
363
+ }
364
+ },
365
+
366
+ // this middleware is executed for each request, allowing `token` to change between invocations
367
+ // it is common to pair this with `stateHandlers` as per above, that can set/expire the token
368
+ // for different test cases
369
+ requestFilter: (req, res, next) => {
370
+ req.headers["Authorization"] = `Bearer: ${token}`
371
+ next()
372
+ },
373
+
374
+ // This header will always be sent for each and every request, and can't be dynamic
375
+ // (i.e. passing a variable instead of the bearer token)
376
+ customProviderHeaders: ["Authorization: Bearer 1234"]
300
377
  }
301
378
 
302
- return new Verifier().verifyProvider(opts).then(output => { ... })
379
+ return new Verifier(opts).verifyProvider().then(...)
303
380
  ```
304
381
 
305
382
  As you can see, this is your opportunity to modify\add to headers being sent to the Provider API, for example to create a valid time-bound token.
@@ -312,13 +389,13 @@ Sharing is caring - to simplify sharing Pacts between Consumers and Providers, w
312
389
 
313
390
  The Broker:
314
391
 
315
- * versions your contracts
316
- * tells you which versions of your applications can be deployed safely together
317
- * allows you to deploy your services independently
318
- * provides API documentation of your applications that is guaranteed to be up-to date
319
- * visualises the relationships between your services
320
- * integrates with other systems, such as Slack or your CI server, via webhooks
321
- * ...and much much [more](https://docs.pact.io/getting_started/sharing_pacts).
392
+ - versions your contracts
393
+ - tells you which versions of your applications can be deployed safely together
394
+ - allows you to deploy your services independently
395
+ - provides API documentation of your applications that is guaranteed to be up-to date
396
+ - visualises the relationships between your services
397
+ - integrates with other systems, such as Slack or your CI server, via webhooks
398
+ - ...and much much [more](https://docs.pact.io/getting_started/sharing_pacts).
322
399
 
323
400
  [Host your own](https://github.com/pact-foundation/pact_broker), or signup for a free hosted [Pact Broker](https://pact.dius.com.au).
324
401
 
@@ -335,15 +412,19 @@ pact.publishPacts(opts)).then(function () {
335
412
 
336
413
  #### Publishing options
337
414
 
338
- | Parameter | Required | Type | Description |
339
- | -------------------- | :------: | ---------------- | ----------------------------------------------------------------------------------------------------- |
340
- | `providerBaseUrl` | `false` | string | Running API provider host endpoint. |
341
- | `pactFilesOrDirs` | `true` | array of strings | Array of local Pact files or directories containing pact files. Path must be absolute. Required. |
342
- | `pactBroker` | `true` | string | The base URL of the Pact Broker. eg. https://test.pact.dius.com.au. Required. |
343
- | `pactBrokerUsername` | `false` | string | Username for Pact Broker basic authentication. Optional |
344
- | `pactBrokerPassword` | `false` | string | Password for Pact Broker basic authentication. Optional |
345
- | `consumerVersion` | `true` | string | The consumer application version; e.g. '1.0.0-cac389f'. ([See more info on versioning](https://docs.pact.io/getting_started/versioning_in_the_pact_broker)) | |
346
- | `tags` | `false` | array of strings | Tag your pacts, often used with your branching, release or environment strategy e.g. ['prod', 'test'] |
415
+ <details><summary>Publishing Options</summary>
416
+
417
+ | Parameter | Required | Type | Description |
418
+ | -------------------- | :------: | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
419
+ | `providerBaseUrl` | `false` | string | Running API provider host endpoint. |
420
+ | `pactFilesOrDirs` | `true` | array of strings | Array of local Pact files or directories containing pact files. Path must be absolute. Required. |
421
+ | `pactBroker` | `true` | string | The base URL of the Pact Broker. eg. https://test.pact.dius.com.au. Required. |
422
+ | `pactBrokerUsername` | `false` | string | Username for Pact Broker basic authentication. Optional |
423
+ | `pactBrokerPassword` | `false` | string | Password for Pact Broker basic authentication. Optional |
424
+ | `consumerVersion` | `true` | string | The consumer application version; e.g. '1.0.0-cac389f'. ([See more info on versioning](https://docs.pact.io/getting_started/versioning_in_the_pact_broker)) | |
425
+ | `tags` | `false` | array of strings | Tag your pacts, often used with your branching, release or environment strategy e.g. ['prod', 'test'] |
426
+
427
+ </details>
347
428
 
348
429
  #### Publishing Verification Results to a Pact Broker
349
430
 
@@ -393,18 +474,22 @@ From a Pact testing point of view, Pact takes the place of the intermediary (MQ/
393
474
  The following test creates a contract for a Dog API handler:
394
475
 
395
476
  ```js
396
- const { MessageConsumerPact, Message, synchronousBodyHandler } = require("@pact-foundation/pact");
477
+ const {
478
+ MessageConsumerPact,
479
+ Message,
480
+ synchronousBodyHandler,
481
+ } = require("@pact-foundation/pact")
397
482
 
398
483
  // 1 Dog API Handler
399
484
  const dogApiHandler = function(dog) {
400
485
  if (!dog.id && !dog.name && !dog.type) {
401
- throw new Error("missing fields");
486
+ throw new Error("missing fields")
402
487
  }
403
488
 
404
489
  // do some other things to dog...
405
490
  // e.g. dogRepository.save(dog)
406
- return;
407
- };
491
+ return
492
+ }
408
493
 
409
494
  // 2 Pact Message Consumer
410
495
  const messagePact = new MessageConsumerPact({
@@ -412,12 +497,13 @@ const messagePact = new MessageConsumerPact({
412
497
  dir: path.resolve(process.cwd(), "pacts"),
413
498
  pactfileWriteMode: "update",
414
499
  provider: "MyJSMessageProvider",
415
- });
500
+ })
416
501
 
417
502
  describe("receive dog event", () => {
418
- it("should accept a valid dog", () => {
503
+ it("accepts a valid dog", () => {
419
504
  // 3 Consumer expectations
420
- return (messagePact
505
+ return (
506
+ messagePact
421
507
  .given("some state")
422
508
  .expectsToReceive("a request for a dog")
423
509
  .withContent({
@@ -431,22 +517,22 @@ describe("receive dog event", () => {
431
517
 
432
518
  // 4 Verify consumers' ability to handle messages
433
519
  .verify(synchronousBodyHandler(dogApiHandler))
434
- );
435
- });
436
- });
520
+ )
521
+ })
522
+ })
437
523
  ```
438
524
 
439
525
  **Explanation**:
440
526
 
441
527
  1. The Dog API - a contrived API handler example. Expects a dog object and throws an `Error` if it can't handle it.
442
- * In most applications, some form of transactionality exists and communication with a MQ/broker happens.
443
- * It's important we separate out the protocol bits from the message handling bits, so that we can test that in isolation.
528
+ - In most applications, some form of transactionality exists and communication with a MQ/broker happens.
529
+ - It's important we separate out the protocol bits from the message handling bits, so that we can test that in isolation.
444
530
  1. Creates the MessageConsumer class
445
531
  1. Setup the expectations for the consumer - here we expect a `dog` object with three fields
446
532
  1. Pact will send the message to your message handler. If the handler returns a successful promise, the message is saved, otherwise the test fails. There are a few key things to consider:
447
- * The actual request body that Pact will send, will be contained within a [Message](https://github.com/pact-foundation/pact-js/tree/feat/message-pact/src/dsl/message.ts) object along with other context, so the body must be retrieved via `content` attribute.
448
- * All handlers to be tested must be of the shape `(m: Message) => Promise<any>` - that is, they must accept a `Message` and return a `Promise`. This is how we get around all of the various protocols, and will often require a lightweight adapter function to convert it.
449
- * In this case, we wrap the actual dogApiHandler with a convenience function `synchronousBodyHandler` provided by Pact, which Promisifies the handler and extracts the contents.
533
+ - The actual request body that Pact will send, will be contained within a [Message](https://github.com/pact-foundation/pact-js/tree/master/src/dsl/message.ts) object along with other context, so the body must be retrieved via `content` attribute.
534
+ - All handlers to be tested must be of the shape `(m: Message) => Promise<any>` - that is, they must accept a `Message` and return a `Promise`. This is how we get around all of the various protocols, and will often require a lightweight adapter function to convert it.
535
+ - In this case, we wrap the actual dogApiHandler with a convenience function `synchronousBodyHandler` provided by Pact, which Promisifies the handler and extracts the contents.
450
536
 
451
537
  ### Provider (Producer)
452
538
 
@@ -455,7 +541,7 @@ A Provider (Producer in messaging parlance) is the system that will be putting a
455
541
  As per the Consumer case, Pact takes the position of the intermediary (MQ/broker) and checks to see whether or not the Provider sends a message that matches the Consumer's expectations.
456
542
 
457
543
  ```js
458
- const { MessageProvider, Message } = require("@pact-foundation/pact");
544
+ const { MessageProvider, Message } = require("@pact-foundation/pact")
459
545
 
460
546
  // 1 Messaging integration client
461
547
  const dogApiClient = {
@@ -464,37 +550,43 @@ const dogApiClient = {
464
550
  resolve({
465
551
  id: 1,
466
552
  name: "fido",
467
- type: "bulldog"
468
- });
469
- });
470
- }
471
- };
553
+ type: "bulldog",
554
+ })
555
+ })
556
+ },
557
+ }
472
558
 
473
559
  describe("Message provider tests", () => {
474
560
  // 2 Pact setup
475
561
  const p = new MessageProviderPact({
476
562
  messageProviders: {
477
- "a request for a dog": () => dogApiClient.createDog()
563
+ "a request for a dog": () => dogApiClient.createDog(),
478
564
  },
479
565
  provider: "MyJSMessageProvider",
480
566
  providerVersion: "1.0.0",
481
- pactUrls: [path.resolve(process.cwd(), "pacts", "myjsmessageconsumer-myjsmessageprovider.json")],
482
- });
567
+ pactUrls: [
568
+ path.resolve(
569
+ process.cwd(),
570
+ "pacts",
571
+ "myjsmessageconsumer-myjsmessageprovider.json"
572
+ ),
573
+ ],
574
+ })
483
575
 
484
576
  // 3 Verify the interactions
485
577
  describe("Dog API Client", () => {
486
- it("should be a good Dog... message integration client", () => {
487
- return p.verify();
488
- });
489
- });
490
- });
578
+ it("sends some dogs", () => {
579
+ return p.verify()
580
+ })
581
+ })
582
+ })
491
583
  ```
492
584
 
493
585
  **Explanation**:
494
586
 
495
587
  1. Our API client contains a single function `createDog` which is responsible for generating the message that will be sent to the consumer via some message queue
496
588
  1. We configure Pact to stand-in for the queue. The most important bit here is the `messageProviders` block
497
- * Similar to the Consumer tests, we map the various interactions that are going to be verified as denoted by their `description` field. In this case, `a request for a dog`, maps to the `createDog` handler. Notice how this matches the original Consumer test.
589
+ - Similar to the Consumer tests, we map the various interactions that are going to be verified as denoted by their `description` field. In this case, `a request for a dog`, maps to the `createDog` handler. Notice how this matches the original Consumer test.
498
590
  1. We can now run the verification process. Pact will read all of the interactions specified by its consumer, and invoke each function that is responsible for generating that message.
499
591
 
500
592
  ### Pact Broker Integration
@@ -515,6 +607,8 @@ _NOTE: Make sure to start the mock service via the `Pact` declaration with the o
515
607
 
516
608
  Often times, you find yourself having to re-write regular expressions for common formats. We've created a number of them for you to save you the time:
517
609
 
610
+ <details><summary>Matchers API</summary>
611
+
518
612
  | method | description |
519
613
  | --------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
520
614
  | `boolean` | Match a boolean value (using equality) |
@@ -530,22 +624,24 @@ Often times, you find yourself having to re-write regular expressions for common
530
624
  | `ipv6Address` | Will match string containing IP6 formatted address |
531
625
  | `uuid` | Will match strings containing UUIDs |
532
626
 
627
+ </details>
628
+
533
629
  ### Match based on type
534
630
 
535
631
  ```javascript
536
- const { like } = Matchers;
632
+ const { like } = Matchers
537
633
 
538
634
  provider.addInteraction({
539
635
  state: "Has some animals",
540
636
  uponReceiving: "a request for an animal",
541
637
  withRequest: {
542
638
  method: "GET",
543
- path: "/animals/1"
639
+ path: "/animals/1",
544
640
  },
545
641
  willRespondWith: {
546
642
  status: 200,
547
643
  headers: {
548
- "Content-Type": "application/json; charset=utf-8"
644
+ "Content-Type": "application/json; charset=utf-8",
549
645
  },
550
646
  body: {
551
647
  id: 1,
@@ -553,11 +649,11 @@ provider.addInteraction({
553
649
  address: like({
554
650
  street: "123 Smith St",
555
651
  suburb: "Smithsville",
556
- postcode: 7777
557
- })
558
- }
559
- }
560
- });
652
+ postcode: 7777,
653
+ }),
654
+ },
655
+ },
656
+ })
561
657
  ```
562
658
 
563
659
  Note that you can wrap a `like` around a single value or an object. When wrapped around an object, all values and child object values will be matched according to types, unless overridden by something more specific like a `term`.
@@ -569,7 +665,7 @@ Note that you can wrap a `like` around a single value or an object. When wrapped
569
665
  Matching provides the ability to specify flexible length arrays. For example:
570
666
 
571
667
  ```javascript
572
- pact.eachLike(obj, { min: 3 });
668
+ pact.eachLike(obj, { min: 3 })
573
669
  ```
574
670
 
575
671
  Where `obj` can be any javascript object, value or Pact.Match. It takes optional argument (`{ min: 3 }`) where min is greater than 0 and defaults to 1 if not provided.
@@ -577,7 +673,7 @@ Where `obj` can be any javascript object, value or Pact.Match. It takes optional
577
673
  Below is an example that uses all of the Pact Matchers.
578
674
 
579
675
  ```javascript
580
- const { somethingLike: like, term, eachLike } = pact;
676
+ const { somethingLike: like, term, eachLike } = pact
581
677
 
582
678
  const animalBodyExpectation = {
583
679
  id: 1,
@@ -587,41 +683,41 @@ const animalBodyExpectation = {
587
683
  age: 21,
588
684
  gender: term({
589
685
  matcher: "F|M",
590
- generate: "M"
686
+ generate: "M",
591
687
  }),
592
688
  location: {
593
689
  description: "Melbourne Zoo",
594
690
  country: "Australia",
595
- post_code: 3000
691
+ post_code: 3000,
596
692
  },
597
693
  eligibility: {
598
694
  available: true,
599
- previously_married: false
695
+ previously_married: false,
600
696
  },
601
- children: eachLike({ name: "Sally", age: 2 })
602
- };
697
+ children: eachLike({ name: "Sally", age: 2 }),
698
+ }
603
699
 
604
700
  // Define animal list payload, reusing existing object matcher
605
701
  // Note that using eachLike ensure that all values are matched by type
606
702
  const animalListExpectation = eachLike(animalBodyExpectation, {
607
- min: MIN_ANIMALS
608
- });
703
+ min: MIN_ANIMALS,
704
+ })
609
705
 
610
706
  provider.addInteraction({
611
707
  state: "Has some animals",
612
708
  uponReceiving: "a request for all animals",
613
709
  withRequest: {
614
710
  method: "GET",
615
- path: "/animals/available"
711
+ path: "/animals/available",
616
712
  },
617
713
  willRespondWith: {
618
714
  status: 200,
619
715
  headers: {
620
- "Content-Type": "application/json; charset=utf-8"
716
+ "Content-Type": "application/json; charset=utf-8",
621
717
  },
622
- body: animalListExpectation
623
- }
624
- });
718
+ body: animalListExpectation,
719
+ },
720
+ })
625
721
  ```
626
722
 
627
723
  ### Match by regular expression
@@ -631,30 +727,30 @@ If none of the above matchers or formats work, you can write your own regex matc
631
727
  The underlying mock service is written in Ruby, so the regular expression must be in a Ruby format, not a Javascript format.
632
728
 
633
729
  ```javascript
634
- const { term } = pact;
730
+ const { term } = pact
635
731
 
636
732
  provider.addInteraction({
637
733
  state: "Has some animals",
638
734
  uponReceiving: "a request for an animal",
639
735
  withRequest: {
640
736
  method: "GET",
641
- path: "/animals/1"
737
+ path: "/animals/1",
642
738
  },
643
739
  willRespondWith: {
644
740
  status: 200,
645
741
  headers: {
646
- "Content-Type": "application/json; charset=utf-8"
742
+ "Content-Type": "application/json; charset=utf-8",
647
743
  },
648
744
  body: {
649
745
  id: 100,
650
746
  name: "billy",
651
747
  gender: term({
652
748
  matcher: "F|M",
653
- generate: "F"
654
- })
655
- }
656
- }
657
- });
749
+ generate: "F",
750
+ }),
751
+ },
752
+ },
753
+ })
658
754
  ```
659
755
 
660
756
  ## GraphQL API
@@ -673,19 +769,19 @@ Learn everything in Pact JS in 60 minutes: https://github.com/DiUS/pact-workshop
673
769
 
674
770
  ### HTTP APIs
675
771
 
676
- * [Complete Example (Node env)](https://github.com/pact-foundation/pact-js/tree/master/examples/e2e)
677
- * [Pact with AVA (Node env)](https://github.com/pact-foundation/pact-js/tree/master/examples/ava)
678
- * [Pact with Jest (Node env)](https://github.com/pact-foundation/pact-js/tree/master/examples/jest)
679
- * [Pact with TypeScript + Mocha](https://github.com/pact-foundation/pact-js/tree/master/examples/typescript)
680
- * [Pact with Mocha](https://github.com/pact-foundation/pact-js/tree/master/examples/mocha)
681
- * [Pact with GraphQL](https://github.com/pact-foundation/pact-js/tree/feat/message-pact/examples/graphql)
682
- * [Pact with Karma + Jasmine](https://github.com/pact-foundation/pact-js/tree/master/karma/jasmine)
683
- * [Pact with Karma + Mocha](https://github.com/pact-foundation/pact-js/tree/master/karma/mocha)
772
+ - [Complete Example (Node env)](https://github.com/pact-foundation/pact-js/tree/master/examples/e2e)
773
+ - [Pact with AVA (Node env)](https://github.com/pact-foundation/pact-js/tree/master/examples/ava)
774
+ - [Pact with Jest (Node env)](https://github.com/pact-foundation/pact-js/tree/master/examples/jest)
775
+ - [Pact with TypeScript + Mocha](https://github.com/pact-foundation/pact-js/tree/master/examples/typescript)
776
+ - [Pact with Mocha](https://github.com/pact-foundation/pact-js/tree/master/examples/mocha)
777
+ - [Pact with GraphQL](https://github.com/pact-foundation/pact-js/tree/master/examples/graphql)
778
+ - [Pact with Karma + Jasmine](https://github.com/pact-foundation/pact-js/tree/master/karma/jasmine)
779
+ - [Pact with Karma + Mocha](https://github.com/pact-foundation/pact-js/tree/master/karma/mocha)
684
780
 
685
781
  ### Asynchronous APIs
686
782
 
687
- * [Asynchronous messages](https://github.com/pact-foundation/pact-js/tree/feat/message-pact/examples/messages)
688
- * [Serverless](https://github.com/pact-foundation/pact-js/tree/feat/message-pact/examples/serverless)
783
+ - [Asynchronous messages](https://github.com/pact-foundation/pact-js/tree/master/examples/messages)
784
+ - [Serverless](https://github.com/pact-foundation/pact-js/tree/master/examples/serverless)
689
785
 
690
786
  ## Using Pact in non-Node environments
691
787
 
@@ -757,11 +853,11 @@ require.config({
757
853
  baseUrl: "/base",
758
854
  paths: {
759
855
  Pact: "node_modules/pact-web/pact-web",
760
- client: "js/client"
856
+ client: "js/client",
761
857
  },
762
858
  deps: allTestFiles,
763
- callback: window.__karma__.start
764
- });
859
+ callback: window.__karma__.start,
860
+ })
765
861
  ```
766
862
 
767
863
  See this [Stack Overflow](https://stackoverflow.com/a/44170373/1008568) question for background, and
@@ -788,8 +884,8 @@ When all of your tests have completed, the result is the union of the all of the
788
884
 
789
885
  See the following examples for working parallel tests:
790
886
 
791
- * [Pact with AVA (Node env)](https://github.com/pact-foundation/pact-js/tree/master/examples/ava)
792
- * [Pact with Mocha](https://github.com/pact-foundation/pact-js/tree/master/examples/mocha)
887
+ - [Pact with AVA (Node env)](https://github.com/pact-foundation/pact-js/tree/master/examples/ava)
888
+ - [Pact with Mocha](https://github.com/pact-foundation/pact-js/tree/master/examples/mocha)
793
889
 
794
890
  ### Splitting tests across multiple files
795
891
 
@@ -909,9 +1005,9 @@ Join us in [Slack](slack.pact.io)
909
1005
 
910
1006
  or chat to us at
911
1007
 
912
- * Twitter: [@pact_up](https://twitter.com/pact_up)
913
- * Stack Overflow: https://stackoverflow.com/questions/tagged/pact
914
- * Google users group: https://groups.google.com/forum/#!forum/pact-support
1008
+ - Twitter: [@pact_up](https://twitter.com/pact_up)
1009
+ - Stack Overflow: https://stackoverflow.com/questions/tagged/pact
1010
+ - Google users group: https://groups.google.com/forum/#!forum/pact-support
915
1011
 
916
1012
  [getting started with pact]: http://dius.com.au/2016/02/03/microservices-pact/
917
1013
  [v4]: https://github.com/pact-foundation/pact-js/tree/4.x.x