Repository: pactumjs/pactum
Pull request #392 (2024-12-25 09:55:20)

chore: store merge


Patch:
diff --git a/package-lock.json b/package-lock.json
index ef62b1d..25c7aa5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "pactum",
-  "version": "3.7.5",
+  "version": "3.7.6",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "pactum",
-      "version": "3.7.5",
+      "version": "3.7.6",
       "license": "MIT",
       "dependencies": {
         "@exodus/schemasafe": "^1.3.0",
diff --git a/package.json b/package.json
index 5b556eb..bfa68c0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "pactum",
-  "version": "3.7.5",
+  "version": "3.7.6",
   "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 e465f2c..603d684 100644
--- a/src/exports/handler.d.ts
+++ b/src/exports/handler.d.ts
@@ -62,9 +62,14 @@ interface WaitHandlerContext extends RequestResponseContext {
   rootData?: any;
 }
 
+interface ResponseHandlerContext extends RequestResponseContext {
+  spec: Spec
+}
+
 export type SpecHandlerFunction = (ctx: SpecHandlerContext) => void;
 export type ExpectHandlerFunction = (ctx: ExpectHandlerContext) => void;
 export type RetryHandlerFunction = (ctx: RequestResponseContext) => boolean;
+export type ResponseHandlerFunction = (ctx: ResponseHandlerContext) => void;
 export type CaptureHandlerFunction = (ctx: CaptureContext) => any;
 export type StateHandlerFunction = (ctx: StateHandlerContext) => any;
 export type DataHandlerFunction = (ctx: DataHandlerContext) => any;
@@ -130,4 +135,4 @@ 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
+export function addResponseHandler(name: string, func: ResponseHandlerFunction): void;
\ No newline at end of file
diff --git a/src/helpers/toss.helper.js b/src/helpers/toss.helper.js
index 1366be3..27dfb6c 100644
--- a/src/helpers/toss.helper.js
+++ b/src/helpers/toss.helper.js
@@ -73,14 +73,19 @@ function storeSpecData(spec, stores) {
     } else {
       data_to_store = getPathValueFromRequestResponse(store.path, spec._request, spec._response);
     }
-    if(store.options && store.options.append) {
+    if (store.options && store.options.append) {
       ctx.store[store.name] = ctx.store[store.name] || [];
       ctx.store[store.name].push(data_to_store);
       continue;
     }
-    const specData = {};
-    specData[store.name] = data_to_store;
-    stash.addDataStore(specData);
+    if (store.options && store.options.merge) {
+      ctx.store[store.name] = ctx.store[store.name] || {};
+      Object.assign(ctx.store[store.name], data_to_store);
+    } else {
+      const specData = {};
+      specData[store.name] = data_to_store;
+      stash.addDataStore(specData);
+    }
   }
 }
 
@@ -147,7 +152,7 @@ function storeInteractionData(request, interaction) {
 
 async function runResponseHandler(spec) {
   try {
-    const ctx = { req: spec._request, res: spec._response };
+    const ctx = { req: spec._request, res: spec._response, spec };
     const handlers = spec._response_handlers;
     for (let i = 0; i < handlers.length; i++) {
       await hr.response(handlers[i], ctx);
diff --git a/src/internal.types.d.ts b/src/internal.types.d.ts
index 53b0280..1057c6b 100644
--- a/src/internal.types.d.ts
+++ b/src/internal.types.d.ts
@@ -8,4 +8,5 @@ export type ISpecStore = {
 export type ISpecStoreOptions = {
   status?: 'PASSED' | 'FAILED'
   append?: boolean
+  merge?: boolean
 }
\ No newline at end of file


Test patch:
diff --git a/test/component/stores.spec.js b/test/component/stores.spec.js
index 597abfe..f56495e 100644
--- a/test/component/stores.spec.js
+++ b/test/component/stores.spec.js
@@ -6,7 +6,7 @@ const { addInteractionHandler } = pactum.handler;
 describe('Stores', () => {
 
   before(() => {
-    addInteractionHandler('get stores', () => {
+    addInteractionHandler('get stores', ({ data }) => {
       return {
         request: {
           method: 'GET',
@@ -14,9 +14,7 @@ describe('Stores', () => {
         },
         response: {
           status: 200,
-          body: {
-            id: 1
-          }
+          body: data ? data : { id: 1 }
         }
       };
     });
@@ -30,7 +28,10 @@ describe('Stores', () => {
           }
         },
         response: {
-          status: 200
+          status: 200,
+          body: {
+            name: 'Snow'
+          }
         }
       };
     });
@@ -359,7 +360,34 @@ describe('Stores', () => {
       .get('http://localhost:9393/api/stores')
       .expectStatus(200)
       .stores('UserId', 'id', { append: true });
-    expect(stash.getDataStore('UserId')).deep.equals([1,1]);
+    expect(stash.getDataStore('UserId')).deep.equals([1, 1]);
+  });
+
+  it('store merge', async () => {
+    await pactum.spec()
+      .useInteraction('get stores', { id: 1 })
+      .get('http://localhost:9393/api/stores')
+      .expectStatus(200)
+      .stores('User', '.');
+    await pactum.spec()
+      .useInteraction('get stores', { name: 'Snow' })
+      .get('http://localhost:9393/api/stores')
+      .expectStatus(200)
+      .stores('User', '.', { merge: true });
+    expect(stash.getDataStore()).deep.equals({ User: { id: 1, name: 'Snow' } });
+  });
+
+  it('store merge in same request', async () => {
+    await pactum.spec()
+      .useInteraction('post stores')
+      .post('http://localhost:9393/api/stores')
+      .withJson({
+        UserId: 1
+      })
+      .expectStatus(200)
+      .stores('User', '.', { merge: true })
+      .stores('User', 'req.body', { merge: true });
+    expect(stash.getDataStore()).deep.equals({ User: { UserId: 1, name: 'Snow' } });
   })
 
   afterEach(() => {