Repository: pactumjs/pactum
Pull request #385 (2024-11-19 17:05:00)

feat: response handler


Patch:
diff --git a/package-lock.json b/package-lock.json
index b2b4b83..6631030 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "pactum",
-  "version": "3.7.3",
+  "version": "3.7.4",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "pactum",
-      "version": "3.7.3",
+      "version": "3.7.4",
       "license": "MIT",
       "dependencies": {
         "@exodus/schemasafe": "^1.3.0",
diff --git a/package.json b/package.json
index d07c042..99580e9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "pactum",
-  "version": "3.7.3",
+  "version": "3.7.4",
   "description": "REST API Testing Tool for all levels in a Test Pyramid",
   "main": "./src/index.js",
   "types": "./src/index.d.ts",
diff --git a/src/exports/handler.d.ts b/src/exports/handler.d.ts
index f435e05..e465f2c 100644
--- a/src/exports/handler.d.ts
+++ b/src/exports/handler.d.ts
@@ -1,6 +1,6 @@
+import { IncomingMessage } from 'http';
 import * as Spec from '../models/Spec';
 import { Interaction } from './mock';
-import { IncomingMessage } from 'http';
 
 interface PactumRequest {
   url: string;
@@ -124,4 +124,10 @@ export function addAssertHandler(name: string, func: AssertHandlerFunction): voi
  * adds a custom wait handler
  * @see https://pactumjs.github.io/api/handlers/addWaitHandler.html
  */
-export function addWaitHandler(name: string, func: WaitHandlerFunction): void;
\ No newline at end of file
+export function addWaitHandler(name: string, func: WaitHandlerFunction): void;
+
+/**
+ * adds a response handler
+ * @see https://pactumjs.github.io/api/handlers/addResponseHandler.html
+ */
+export function addResponseHandler(name: string, func: RetryHandlerFunction): void;
\ No newline at end of file
diff --git a/src/exports/handler.js b/src/exports/handler.js
index 5fc9dc3..8332d46 100644
--- a/src/exports/handler.js
+++ b/src/exports/handler.js
@@ -10,6 +10,7 @@ const dataHandlers = {};
 const interactionHandlers = {};
 const assertHandlers = {};
 const waitHandlers = {};
+const responseHandlers = {};
 
 const handler = {
 
@@ -58,6 +59,11 @@ const handler = {
     stateHandlers[name] = func;
   },
 
+  addResponseHandler(name, func) {
+    isValidHandler(name, func);
+    responseHandlers[name] = func;
+  },
+
   getStateHandler(name) {
     if (stateHandlers[name]) return stateHandlers[name];
     throw new PactumHandlerError(`State Handler Not Found - '${name}'`);
@@ -102,6 +108,11 @@ const handler = {
   getWaitHandler(name) {
     if (waitHandlers[name]) return waitHandlers[name];
     throw new PactumHandlerError(`Wait Handler Not Found - '${name}'`);
+  },
+
+  getResponseHandler(name) {
+    if (responseHandlers[name]) return responseHandlers[name];
+    throw new PactumHandlerError(`Response Handler Not Found - '${name}'`);
   }
 
 };
diff --git a/src/helpers/handler.runner.js b/src/helpers/handler.runner.js
index 0dc4495..7ed4ffa 100644
--- a/src/helpers/handler.runner.js
+++ b/src/helpers/handler.runner.js
@@ -40,6 +40,10 @@ const hr = {
 
   retry(name, ctx) {
     return handler.getRetryHandler(name)(ctx);
+  },
+
+  response(name, ctx) {
+    return handler.getResponseHandler(name)(ctx);
   }
 
 };
diff --git a/src/helpers/toss.helper.js b/src/helpers/toss.helper.js
index d8d062f..1366be3 100644
--- a/src/helpers/toss.helper.js
+++ b/src/helpers/toss.helper.js
@@ -6,6 +6,7 @@ const helper = require('./helper');
 const hr = require('./handler.runner');
 
 const stash = require('../exports/stash');
+const logger = require('../plugins/logger');
 
 function getCaptureHandlerName(name) {
   if (helper.matchesStrategy(name, config.strategy.capture.handler)) {
@@ -144,10 +145,23 @@ function storeInteractionData(request, interaction) {
   stash.addDataStore(interactionData);
 }
 
+async function runResponseHandler(spec) {
+  try {
+    const ctx = { req: spec._request, res: spec._response };
+    const handlers = spec._response_handlers;
+    for (let i = 0; i < handlers.length; i++) {
+      await hr.response(handlers[i], ctx);
+    }
+  } catch (error) {
+    logger.warn(`Error running response handler: ${error}`);
+  }
+}
+
 module.exports = {
   storeSpecData,
   recordSpecData,
   getOutput,
   storeInteractionData,
-  getPathValueFromRequestResponse
+  getPathValueFromRequestResponse,
+  runResponseHandler
 };
\ No newline at end of file
diff --git a/src/models/Spec.d.ts b/src/models/Spec.d.ts
index 0d757f0..139f53d 100644
--- a/src/models/Spec.d.ts
+++ b/src/models/Spec.d.ts
@@ -54,6 +54,8 @@ declare class Spec {
   useDataMap(maps: object[]): Spec;
   useDataMap(key: string, value: any): Spec;
 
+  useResponseHandler(key: string): Spec;
+
   /**
    * The GET method requests a representation of the specified resource.
    * @see https://pactumjs.github.io/guides/api-testing.html
diff --git a/src/models/Spec.js b/src/models/Spec.js
index 5e9d2da..c56ebed 100644
--- a/src/models/Spec.js
+++ b/src/models/Spec.js
@@ -38,6 +38,7 @@ class Spec {
     this._wait = null;
     this._save = null;
     this._data_maps = [];
+    this._response_handlers = [];
     this._specHandlerData = data;
     this._sleep = '';
     hr.spec(name, data, this);
@@ -81,6 +82,11 @@ class Spec {
     return this;
   }
 
+  useResponseHandler(key) {
+    this._response_handlers.push(key);
+    return this;
+  }
+
   get(url) {
     validateRequestUrl(this._request, url);
     this._request.url = url;
diff --git a/src/models/Tosser.js b/src/models/Tosser.js
index 2c3284b..f22617b 100644
--- a/src/models/Tosser.js
+++ b/src/models/Tosser.js
@@ -77,6 +77,8 @@ class Tosser {
 
   async setResponse() {
     this.response = await getResponse(this);
+    this.spec._response = this.response;
+    await th.runResponseHandler(this.spec);
     const options = this.request.retryOptions;
     if (options) {
       const count = typeof options.count === 'number' ? options.count : config.request.retry.count;


Test patch:
diff --git a/test/component/response-handler.spec.js b/test/component/response-handler.spec.js
new file mode 100644
index 0000000..2e9fff3
--- /dev/null
+++ b/test/component/response-handler.spec.js
@@ -0,0 +1,17 @@
+const { expect } = require('chai');
+const { spec, handler } = require('../../src/index');
+
+describe('Response Handler', () => {
+
+  it('response handler', async () => {
+    let ran = false;
+    handler.addResponseHandler('test', async (ctx) => {
+      ran = true;
+    });
+    await spec()
+      .get('http://localhost:9393/api/users/1')
+      .useResponseHandler('test');
+    expect(ran).equals(true);
+  });
+
+})
\ No newline at end of file