Repository: pactumjs/pactum
Pull request #58 (2021-04-18 06:23:41)

3.0.11
### Changes

- support global custom expect handlers
- bump pactum-matchers & deep-override versions

### Merges

- support global expectations - status, headers & response time


Patch:
diff --git a/package-lock.json b/package-lock.json
index d31bdcd..35b32e9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "pactum",
-  "version": "3.0.10",
+  "version": "3.0.11",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -588,9 +588,9 @@
       }
     },
     "deep-override": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/deep-override/-/deep-override-1.0.1.tgz",
-      "integrity": "sha512-ygTX7JJAlk62lMwyf4z3BBeFeUyZudN1t52/xIx1t/4eD0QxOJx2N7+0gDG3g2jjYV1vwznIiFePNFu42kcRdw=="
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/deep-override/-/deep-override-1.0.2.tgz",
+      "integrity": "sha512-+bAuLuYqaVVUWPaq8rmU8NLTX85p4I5k5/cVdhBioEfH7k+5NlGdv4NoJVQcJRByqzzTWWzTpih+pU1wBTmMow=="
     },
     "default-require-extensions": {
       "version": "3.0.0",
@@ -1658,9 +1658,9 @@
       }
     },
     "pactum-matchers": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/pactum-matchers/-/pactum-matchers-1.0.1.tgz",
-      "integrity": "sha512-D+/HN7TjFl4DpPWZnnlzk+G52Ku49s5wSinfva6QIPPbBU6WFsXjrK+HiaXamfQFlS6q5JoUyLfNDyVLjXb79A=="
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/pactum-matchers/-/pactum-matchers-1.0.2.tgz",
+      "integrity": "sha512-vIEGmqjnNWosT9YVySzekkoyA48CW8IGCY1aKnF7blfeIxtnobnGMVETsCqFoW2Y344JQMDg9aL1isnEymvX/g=="
     },
     "parse-graphql": {
       "version": "1.0.0",
diff --git a/package.json b/package.json
index 969b38b..5bdc733 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "pactum",
-  "version": "3.0.10",
+  "version": "3.0.11",
   "description": "REST API Testing Tool for all levels in a Test Pyramid",
   "main": "./src/index.js",
   "types": "./src/index.d.ts",
@@ -61,11 +61,12 @@
   "license": "MIT",
   "dependencies": {
     "@exodus/schemasafe": "^1.0.0-rc.3",
-    "deep-override": "^1.0.1",
+    "deep-override": "^1.0.2",
     "form-data": "^4.0.0",
     "json-query": "^2.2.2",
+    "klona": "^2.0.4",
     "openapi-fuzzer-core": "^1.0.6",
-    "pactum-matchers": "^1.0.1",
+    "pactum-matchers": "^1.0.2",
     "parse-graphql": "^1.0.0",
     "phin": "^3.5.1",
     "polka": "^0.5.2"
diff --git a/src/config.js b/src/config.js
index 71f823d..f085198 100644
--- a/src/config.js
+++ b/src/config.js
@@ -12,7 +12,8 @@ const config = {
   response: {
     time: process.env.PACTUM_RESPONSE_TIME ? parseInt(process.env.PACTUM_RESPONSE_TIME) : null,
     status: process.env.PACTUM_RESPONSE_STATUS ? parseInt(process.env.PACTUM_RESPONSE_STATUS) : null,
-    headers: {}
+    headers: {},
+    expectHandlers: []
   },
   data: {
     ref: {
diff --git a/src/exports/response.d.ts b/src/exports/response.d.ts
index 0f20f97..fd27154 100644
--- a/src/exports/response.d.ts
+++ b/src/exports/response.d.ts
@@ -1,3 +1,5 @@
+import { ExpectHandlerFunction } from './handler';
+
 /**
  * sets default expected response headers to all the responses
  */
@@ -17,11 +19,22 @@ export function setDefaultExpectResponseTime(respTime: number): void;
 export function setDefaultExpectStatus(status: number): void;
 
 /**
- * removes default header
+ * sets default custom expect handlers
+ */
+export function setDefaultExpectHandlers(handlerName: string, data?: any): void;
+export function setDefaultExpectHandlers(handler: ExpectHandlerFunction): void;
+
+/**
+ * removes default expect header
  */
- export function removeDefaultExpectHeader(key: string): void;
+export function removeDefaultExpectHeader(key: string): void;
 
- /**
-  * removes all default headers
-  */
- export function removeDefaultExpectHeaders(): void;
\ No newline at end of file
+/**
+ * removes all default expect headers
+ */
+export function removeDefaultExpectHeaders(): void;
+
+/**
+* removes all default expect handlers
+*/
+export function removeDefaultExpectHandlers(): void;
\ No newline at end of file
diff --git a/src/exports/response.js b/src/exports/response.js
index 4247d76..81fc254 100644
--- a/src/exports/response.js
+++ b/src/exports/response.js
@@ -33,6 +33,10 @@ const response = {
     config.response.status = status;
   },
 
+  setDefaultExpectHandlers(handler, data) {
+    config.response.expectHandlers.push({ handler, data });
+  },
+
   removeDefaultExpectHeader(key) {
     if (!key) {
       throw new PactumResponseError(`Invalid expected response header key provided - ${key}`);
@@ -42,6 +46,10 @@ const response = {
 
   removeDefaultExpectHeaders() {
     config.response.headers = {};
+  },
+
+  removeDefaultExpectHandlers() {
+    config.response.expectHandlers = [];
   }
 
 };
diff --git a/src/helpers/dataProcessor.js b/src/helpers/dataProcessor.js
index 00d85d1..03ec499 100644
--- a/src/helpers/dataProcessor.js
+++ b/src/helpers/dataProcessor.js
@@ -1,5 +1,6 @@
 const override = require('deep-override');
 const jq = require('json-query');
+const { klona } = require("klona");
 
 const stash = require('../exports/stash');
 const handler = require('../exports/handler');
@@ -16,7 +17,7 @@ const dataProcessor = {
   processMaps() {
     if (!config.data.ref.map.processed) {
       const orgMap = stash.getDataMap();
-      this.map = JSON.parse(JSON.stringify(orgMap));
+      this.map = klona(orgMap);
       this.map = this.processDataRefs(this.map);
       config.data.ref.map.processed = true;
       if (Object.keys(this.map).length > 0) {
@@ -28,7 +29,7 @@ const dataProcessor = {
   processTemplates() {
     if (!config.data.template.processed) {
       const orgTemplate = stash.getDataTemplate();
-      this.template = JSON.parse(JSON.stringify(orgTemplate));
+      this.template = klona(orgTemplate);
       this.template = this.processDataTemplates(this.template);
       config.data.template.processed = true;
       if (Object.keys(this.template).length > 0) {
@@ -56,7 +57,7 @@ const dataProcessor = {
     if (templateName) {
       const templateValue = this.template[templateName];
       if (templateValue) {
-        data = JSON.parse(JSON.stringify(templateValue));
+        data = klona(templateValue);
         data = this.processDataTemplates(data);
         if (overrides) {
           override(data, overrides);
diff --git a/src/helpers/utils.js b/src/helpers/utils.js
index 1183179..f781f03 100644
--- a/src/helpers/utils.js
+++ b/src/helpers/utils.js
@@ -54,12 +54,12 @@ const utils = {
   upsertValues(jsonArray, item) {
     const index = jsonArray.findIndex(_item => _item.key === item.key);
     if (index > -1 ) {
-      jsonArray[index] = item
+      jsonArray[index] = item;
     } else {
       jsonArray.push(item);
     }
   }
-  
+
 };
 
 function validatePath(req, interaction) {
diff --git a/src/models/Spec.d.ts b/src/models/Spec.d.ts
index 98e6475..398d230 100644
--- a/src/models/Spec.d.ts
+++ b/src/models/Spec.d.ts
@@ -159,10 +159,10 @@ declare class Spec {
    trace(url: string): Spec;
  
    /**
-    * The WITHMETHOD method extends the support for the request-methods apart from 
+    * The `withMethod` method extends the support for the request-methods apart from 
     * (GET, POST, DELETE, PATCH, PUT, HEAD)
     * 
-    * The WITHPATH method triggers the request passed through withMethod()
+    * The `withPath` method triggers the request passed through withMethod()
     * @example
     * await pactum.spec()
     *  .withMethod('HEAD')
diff --git a/src/models/expect.js b/src/models/expect.js
index b4ee7b3..41e3164 100644
--- a/src/models/expect.js
+++ b/src/models/expect.js
@@ -376,6 +376,9 @@ class Expect {
         utils.upsertValues(this.headers, { key, value });
       }
     }
+    if (config.response.expectHandlers.length > 0) {
+      this.customExpectHandlers = this.customExpectHandlers.concat(config.response.expectHandlers);
+    }
   }
 
 }


Test patch:
diff --git a/test/component/response.spec.js b/test/component/response.spec.js
index 4496022..2dc3b79 100644
--- a/test/component/response.spec.js
+++ b/test/component/response.spec.js
@@ -1,207 +1,120 @@
 const pactum = require('../../src/index');
-const { request, response } = pactum;
+const { response } = pactum;
 const config = require('../../src/config');
 const { expect } = require('chai');
 
 describe('Response', () => {
 
-  it('with default expected response status - override value', async () => {
-    request.setBaseUrl('http://localhost:9392');
+  it('with default expected response status', async () => {
     response.setDefaultExpectStatus(200);
-    await pactum
-      .spec()
-      .useInteraction({
-        request: {
-          method: 'GET',
-          path: '/users'
-        },
-        response: {
-          status: 400
-        }
-      })
-      .get('http://localhost:9393/users')
-      .expectStatus(400);
+    await pactum.spec()
+      .useInteraction('default get')
+      .get('http://localhost:9393/default/get');
   });
 
-  it('with default expected response status - valid status', async () => {
-    request.setBaseUrl('http://localhost:9392');
+  it('with default expected response status - failure', async () => {
     response.setDefaultExpectStatus(200);
-    await pactum
-      .spec()
-      .useInteraction({
-        request: {
-          method: 'GET',
-          path: '/users'
-        },
-        response: {
-          status: 200
-        }
-      })
-      .get('http://localhost:9393/users')
-      .expectStatus(200);
+    let err;
+    try {
+      await pactum.spec()
+        .get('http://localhost:9393/default/get');
+    } catch (error) {
+      err = error;
+    }
+    expect(err.message).equals('HTTP status 404 !== 200');
   });
 
-  it('with default expected response time - override value', async () => {
-    request.setBaseUrl('http://localhost:9392');
-    response.setDefaultExpectResponseTime(100);
-    await pactum
-      .spec()
-      .useInteraction({
-        request: {
-          method: 'GET',
-          path: '/users'
-        },
-        response: {
-          status: 400,
-          fixedDelay: 130
-        }
-      })
-      .get('http://localhost:9393/users')
-      .expectStatus(400)
-      .expectResponseTime(500);
+  it('with default expected response status - override value', async () => {
+    response.setDefaultExpectStatus(200);
+    await pactum.spec()
+      .get('http://localhost:9393/default/get')
+      .expectStatus(404);
   });
 
-  it('with default expected response time - valid time', async () => {
-    request.setBaseUrl('http://localhost:9392');
-    response.setDefaultExpectResponseTime(500);
-    await pactum
-      .spec()
-      .useInteraction({
-        request: {
-          method: 'GET',
-          path: '/users'
-        },
-        response: {
-          status: 200,
-          fixedDelay: 50
-        }
-      })
-      .get('http://localhost:9393/users')
-      .expectStatus(200);
+  it('with default expected response time', async () => {
+    response.setDefaultExpectResponseTime(1500);
+    await pactum.spec()
+      .useInteraction('default get')
+      .get('http://localhost:9393/default/get');
   });
 
-  it('with default expected response header - header not present', async () => {
-    request.setBaseUrl('http://localhost:9393');
-    response.setDefaultExpectHeaders('x-header', 'value');
+  it('with default expected response time - failure', async () => {
+    response.setDefaultExpectResponseTime(-1);
+    let err;
     try {
-      await pactum
-        .spec()
-        .useInteraction({
-          request: {
-            method: 'GET',
-            path: '/users'
-          },
-          response: {
-            status: 200,
-            headers: {
-              'x': '2'
-            }
-          }
-        })
-        .get('http://localhost:9393/users')
-        .expectStatus(200);
-    }
-    catch (error) {
-      expect(error.message).equals(`Header 'x-header' not present in HTTP response`);
+      await pactum.spec()
+        .useInteraction('default get')
+        .get('http://localhost:9393/default/get');
+    } catch (error) {
+      err = error;
     }
+    expect(err.message).contains('Request took longer than -1ms');
+  });
+
+  it('with default expected response time - override value', async () => {
+    response.setDefaultExpectResponseTime(-1);
+    await pactum.spec()
+      .useInteraction('default get')
+      .get('http://localhost:9393/default/get')
+      .expectResponseTime(1500);
+  });
+
+  it('with default expected response header', async () => {
+    response.setDefaultExpectHeaders('connection', 'close');
+    await pactum.spec()
+      .useInteraction('default get')
+      .get('http://localhost:9393/default/get');
   });
 
-  it('with default expected response header - override to empty value', async () => {
-    request.setBaseUrl('http://localhost:9393');
-    response.setDefaultExpectHeaders('x-header', 'value');
-    await pactum
-      .spec()
-      .useInteraction({
-        request: {
-          method: 'GET',
-          path: '/users'
-        },
-        response: {
-          status: 200,
-          headers: {
-            'x-header': ''
-          }
-        }
-      })
-      .get('http://localhost:9393/users')
-      .expectStatus(200)
-      .expectHeader('x-header', '');
+  it('with default expected response header - failure', async () => {
+    response.setDefaultExpectHeaders('connection', 'open');
+    let err;
+    try {
+      await pactum.spec()
+        .useInteraction('default get')
+        .get('http://localhost:9393/default/get');
+    } catch (error) {
+      err = error;
+    }
+    expect(err.message).equals(`Header value 'open' did not match for header 'connection': 'close'`);
   });
 
   it('with default expected response header - override value', async () => {
-    request.setBaseUrl('http://localhost:9393');
-    response.setDefaultExpectHeaders('x-header', 'a');
-    await pactum
-      .spec()
-      .useInteraction({
-        request: {
-          method: 'GET',
-          path: '/users'
-        },
-        response: {
-          status: 200,
-          headers: {
-            'x-header': 'b'
-          }
-        }
-      })
-      .get('http://localhost:9393/users')
-      .expectHeader('x-header', 'b')
-      .expectStatus(200);
+    response.setDefaultExpectHeaders('connection', 'open');
+    await pactum.spec()
+      .useInteraction('default get')
+      .get('http://localhost:9393/default/get')
+      .expectHeader('connection', 'close');
   });
 
-  it('with default expected response header - multiple headers', async () => {
-    request.setBaseUrl('http://localhost:9393');
-    response.setDefaultExpectHeaders({
-      'x-header': 'a',
-      'x-header2': 'b'
+  it('with default expected response handler', async () => {
+    response.setDefaultExpectHandlers(({ res }) => {
+      expect(res.statusCode).equals(200);
     });
-    await pactum
-      .spec()
-      .useInteraction({
-        request: {
-          method: 'GET',
-          path: '/users'
-        },
-        response: {
-          status: 200,
-          headers: {
-            'x-header': 'a',
-            'x-header2': 'b'
-          }
-        }
-      })
-      .get('http://localhost:9393/users')
-      .expectStatus(200);
+    await pactum.spec()
+      .useInteraction('default get')
+      .get('http://localhost:9393/default/get');
   });
 
-  it('with default expected response - all valid values', async () => {
-    request.setBaseUrl('http://localhost:9392');
-    response.setDefaultExpectResponseTime(500);
-    response.setDefaultExpectHeaders("x-header", "value");
-    response.setDefaultExpectStatus(200)
-    await pactum
-      .spec()
-      .useInteraction({
-        request: {
-          method: 'GET',
-          path: '/users'
-        },
-        response: {
-          status: 200,
-          headers: {
-            "x-header": "value"
-          },
-          fixedDelay: 50
-        }
-      })
-      .get('http://localhost:9393/users')
-      .expectStatus(200);
+  it('with default expected response handler - failure', async () => {
+    response.setDefaultExpectHandlers(({ res }) => {
+      expect(res.statusCode).equals(200);
+    });
+    let err;
+    try {
+      await pactum.spec()
+        .get('http://localhost:9393/default/get');
+    } catch (error) {
+      err = error;
+    }
+    expect(err.message).equals('expected 404 to equal 200');
   });
 
   afterEach(() => {
     config.response.status = null;
     config.response.time = null;
-    config.response.headers = {};
+    response.removeDefaultExpectHeaders();
+    response.removeDefaultExpectHandlers();
   });
+
 });