Repository: pactumjs/pactum (js)

Issue:
expectJson - read file from fs
**Is your feature request related to a problem? Please describe.**
expectJson and other json expectations - read file from fs

**Describe the solution you'd like**
```js
expectJson('path-to-file')
```

**Describe alternatives you've considered**
NA

**Additional context**
NA


Pull request:
feat: expect json from file
closes #330 

Patch:
diff --git a/package-lock.json b/package-lock.json
index 15ed8b4..bd06df2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "pactum",
-  "version": "3.6.3",
+  "version": "3.6.4",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "pactum",
-      "version": "3.6.3",
+      "version": "3.6.4",
       "license": "MIT",
       "dependencies": {
         "@exodus/schemasafe": "^1.3.0",
diff --git a/package.json b/package.json
index a4cf4c5..0ff20db 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "pactum",
-  "version": "3.6.3",
+  "version": "3.6.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/models/Spec.js b/src/models/Spec.js
index e11bcb4..e55eba0 100644
--- a/src/models/Spec.js
+++ b/src/models/Spec.js
@@ -382,13 +382,13 @@ class Spec {
   }
 
   expectJson(path, value) {
-    typeof value === 'undefined' ? this._expect.json.push(path) : this._expect.jsonQuery.push({ path, value });
+    typeof value === 'undefined' ? this._expect.json.push(getJson(path)) : this._expect.jsonQuery.push({ path, value });
     return this;
   }
   expectJsonAt(...args) { return this.expectJson(...args); }
 
   expectJsonLike(path, value) {
-    typeof value === 'undefined' ? this._expect.jsonLike.push(path) : this._expect.jsonQueryLike.push({ path, value });
+    typeof value === 'undefined' ? this._expect.jsonLike.push(getJson(path)) : this._expect.jsonQueryLike.push({ path, value });
     return this;
   }
   expectJsonLikeAt(...args) { return this.expectJsonLike(...args); }
@@ -398,7 +398,7 @@ class Spec {
       this._expect.jsonSchemaQuery.push({ path, value, options });
     } else {
       if (typeof value === 'undefined') {
-        this._expect.jsonSchema.push({ value: path });
+        this._expect.jsonSchema.push({ value: getJson(path) });
       } else {
         if (typeof path === 'object' && typeof value === 'object') {
           this._expect.jsonSchema.push({ value: path, options: value });
@@ -412,13 +412,13 @@ class Spec {
   expectJsonSchemaAt(...args) { return this.expectJsonSchema(...args); }
 
   expectJsonMatch(path, value) {
-    typeof value === 'undefined' ? this._expect.jsonMatch.push(path) : this._expect.jsonMatchQuery.push({ path, value });
+    typeof value === 'undefined' ? this._expect.jsonMatch.push(getJson(path)) : this._expect.jsonMatchQuery.push({ path, value });
     return this;
   }
   expectJsonMatchAt(...args) { return this.expectJsonMatch(...args); }
 
   expectJsonMatchStrict(path, value) {
-    typeof value === 'undefined' ? this._expect.jsonMatchStrict.push(path) : this._expect.jsonMatchStrictQuery.push({ path, value });
+    typeof value === 'undefined' ? this._expect.jsonMatchStrict.push(getJson(path)) : this._expect.jsonMatchStrictQuery.push({ path, value });
     return this;
   }
   expectJsonMatchStrictAt(...args) { return this.expectJsonMatchStrict(...args); }
@@ -548,4 +548,11 @@ function validateRequestUrl(request, url) {
   }
 }
 
+function getJson(path) {
+  if (typeof path === 'string') {
+    return JSON.parse(findFile(path));
+  }
+  return path;
+}
+
 module.exports = Spec;


Test patch:
diff --git a/test/component/expectJson.spec.js b/test/component/expectJson.spec.js
new file mode 100644
index 0000000..9d9e97b
--- /dev/null
+++ b/test/component/expectJson.spec.js
@@ -0,0 +1,122 @@
+const { spec, settings } = require('../../src');
+const expect = require('chai').expect;
+
+describe('Expects - expectJson', () => {
+
+  before(() => {
+    settings.setDataDirectory('test/data');
+  });
+
+  after(() => {
+    settings.setDataDirectory('data');
+  });
+
+  it('should validate simple json', async () => {
+    await spec()
+      .useInteraction('default get')
+      .get('http://localhost:9393/default/get')
+      .expectJson({
+        method: 'GET',
+        path: '/default/get'
+      });
+  });
+
+  it('should validate json from file', async () => {
+    await spec()
+      .useInteraction('default get')
+      .get('http://localhost:9393/default/get')
+      .expectJson('default.get.response.json');
+  });
+
+  it('should fail with invalid path', async () => {
+    let err;
+    try {
+      await spec()
+        .useInteraction('default get')
+        .get('http://localhost:9393/default/get')
+        .expectJson('invalid-file.json');
+    } catch (error) {
+      err = error;
+    }
+    expect(err.message).equals(`File Not Found - 'invalid-file.json'`);
+  });
+
+  it('json query - on root object', async () => {
+    await spec()
+      .useInteraction({
+        request: {
+          method: 'GET',
+          path: '/api/users'
+        },
+        response: {
+          status: 200,
+          body: {
+            people: [
+              { name: 'Matt', country: 'NZ' },
+              { name: 'Pete', country: 'AU' },
+              { name: 'Mike', country: 'NZ' }
+            ]
+          }
+        }
+      })
+      .get('http://localhost:9393/api/users')
+      .expectStatus(200)
+      .expectJson('people[country=NZ].name', 'Matt')
+      .expectJson('people[*].name', ['Matt', 'Pete', 'Mike']);
+  });
+
+  it('json query - on root array', async () => {
+    await spec()
+      .useInteraction({
+        request: {
+          method: 'GET',
+          path: '/api/users'
+        },
+        response: {
+          status: 200,
+          body: [
+            { name: 'Matt', country: 'NZ' },
+            { name: 'Pete', country: 'AU' },
+            { name: 'Mike', country: 'NZ' }
+          ]
+        }
+      })
+      .get('http://localhost:9393/api/users')
+      .expectStatus(200)
+      .expectJson('[1].country', 'AU')
+      .expectJson('[country=NZ].name', 'Matt')
+      .expectJson('[*].name', ['Matt', 'Pete', 'Mike']);
+  });
+
+  it('json query - on root object - fails', async () => {
+    let err;
+    try {
+      await spec()
+        .useInteraction({
+          request: {
+            method: 'GET',
+            path: '/api/users'
+          },
+          response: {
+            status: 200,
+            body: {
+              people: [
+                { name: 'Matt', country: 'NZ' },
+                { name: 'Pete', country: 'AU' },
+                { name: 'Mike', country: 'NZ' }
+              ]
+            }
+          }
+        })
+        .get('http://localhost:9393/api/users')
+        .expectStatus(200)
+        .expectJson('people[country=NZ].name', 'Matt')
+        .expectJson('people[*].name', ['Matt', 'Pete'])
+        .useLogLevel('ERROR');
+    } catch (error) {
+      err = error;
+    }
+    expect(err).not.undefined;
+  });
+
+})
\ No newline at end of file
diff --git a/test/component/expectJsonLike.spec.js b/test/component/expectJsonLike.spec.js
new file mode 100644
index 0000000..30ab38f
--- /dev/null
+++ b/test/component/expectJsonLike.spec.js
@@ -0,0 +1,110 @@
+const { spec, settings } = require('../../src');
+const expect = require('chai').expect;
+
+describe('Expects - expectJsonLike', () => {
+
+  before(() => {
+    settings.setDataDirectory('test/data');
+  });
+
+  after(() => {
+    settings.setDataDirectory('data');
+  });
+
+  it('should validate simple json', async () => {
+    await spec()
+      .useInteraction('default get')
+      .get('http://localhost:9393/default/get')
+      .expectJsonLike({
+        method: 'GET',
+        path: '/default/get'
+      });
+  });
+
+  it('should validate json from file', async () => {
+    await spec()
+      .useInteraction('default get')
+      .get('http://localhost:9393/default/get')
+      .expectJsonLike('default.get.response.json');
+  });
+
+  it('should fail with invalid path', async () => {
+    let err;
+    try {
+      await spec()
+        .useInteraction('default get')
+        .get('http://localhost:9393/default/get')
+        .expectJsonLike('invalid-file.json');
+    } catch (error) {
+      err = error;
+    }
+    expect(err.message).equals(`File Not Found - 'invalid-file.json'`);
+  });
+
+  it('failed json like', async () => {
+    let err;
+    try {
+      await spec()
+        .get('http://localhost:9393/api/users/1')
+        .expectJsonLike({ id: 1 })
+        .useLogLevel('ERROR');
+    } catch (error) {
+      err = error;
+    }
+    expect(err.message).equals(`Json doesn't have type 'object' at '$' but found 'string'`);
+  });
+
+  it('json query like - on root object', async () => {
+    await spec()
+      .useInteraction({
+        request: {
+          method: 'GET',
+          path: '/api/users'
+        },
+        response: {
+          status: 200,
+          body: {
+            people: [
+              { name: 'Matt', country: 'NZ' },
+              { name: 'Pete', country: 'AU' },
+              { name: 'Mike', country: 'NZ' }
+            ]
+          }
+        }
+      })
+      .get('http://localhost:9393/api/users')
+      .expectStatus(200)
+      .expectJsonLike('people[*].name', ['Matt', 'Pete']);
+  });
+
+  it('json query like - fails', async () => {
+    let err;
+    try {
+      await pactum.spec()
+        .useInteraction({
+          request: {
+            method: 'GET',
+            path: '/api/users'
+          },
+          response: {
+            status: 200,
+            body: {
+              people: [
+                { name: 'Matt', country: 'NZ' },
+                { name: 'Pete', country: 'AU' },
+                { name: 'Mike', country: 'NZ' }
+              ]
+            }
+          }
+        })
+        .get('http://localhost:9393/api/users')
+        .expectStatus(200)
+        .expectJsonLike('people[*].name', ['Matt', 'Pet'])
+        .useLogLevel('ERROR');
+    } catch (error) {
+      err = error;
+    }
+    expect(err).not.undefined;
+  });
+
+})
\ No newline at end of file
diff --git a/test/component/expects.spec.js b/test/component/expects.spec.js
index c126b7a..f9c029c 100644
--- a/test/component/expects.spec.js
+++ b/test/component/expects.spec.js
@@ -267,19 +267,6 @@ describe('Expects', () => {
     expect(err.message).equals(`Value '/Hello World/' not found in response body`);
   });
 
-  it('failed json like', async () => {
-    let err;
-    try {
-      await pactum.spec()
-        .get('http://localhost:9393/api/users/1')
-        .expectJsonLike({ id: 1 })
-        .useLogLevel('ERROR');
-    } catch (error) {
-      err = error;
-    }
-    expect(err.message).equals(`Json doesn't have type 'object' at '$' but found 'string'`);
-  });
-
   it('failed json schema', async () => {
     let err;
     try {
@@ -462,137 +449,6 @@ describe('Expects', () => {
     expect(err.message).contains('Interaction call count 1 !== 2');
   });
 
-  it('json query - on root object', () => {
-    return pactum.spec()
-      .useInteraction({
-        request: {
-          method: 'GET',
-          path: '/api/users'
-        },
-        response: {
-          status: 200,
-          body: {
-            people: [
-              { name: 'Matt', country: 'NZ' },
-              { name: 'Pete', country: 'AU' },
-              { name: 'Mike', country: 'NZ' }
-            ]
-          }
-        }
-      })
-      .get('http://localhost:9393/api/users')
-      .expectStatus(200)
-      .expectJson('people[country=NZ].name', 'Matt')
-      .expectJson('people[*].name', ['Matt', 'Pete', 'Mike']);
-  });
-
-  it('json query - on root array', () => {
-    return pactum.spec()
-      .useInteraction({
-        request: {
-          method: 'GET',
-          path: '/api/users'
-        },
-        response: {
-          status: 200,
-          body: [
-            { name: 'Matt', country: 'NZ' },
-            { name: 'Pete', country: 'AU' },
-            { name: 'Mike', country: 'NZ' }
-          ]
-        }
-      })
-      .get('http://localhost:9393/api/users')
-      .expectStatus(200)
-      .expectJson('[1].country', 'AU')
-      .expectJson('[country=NZ].name', 'Matt')
-      .expectJson('[*].name', ['Matt', 'Pete', 'Mike']);
-  });
-
-  it('json query - on root object - fails', async () => {
-    let err;
-    try {
-      await pactum.spec()
-        .useInteraction({
-          request: {
-            method: 'GET',
-            path: '/api/users'
-          },
-          response: {
-            status: 200,
-            body: {
-              people: [
-                { name: 'Matt', country: 'NZ' },
-                { name: 'Pete', country: 'AU' },
-                { name: 'Mike', country: 'NZ' }
-              ]
-            }
-          }
-        })
-        .get('http://localhost:9393/api/users')
-        .expectStatus(200)
-        .expectJson('people[country=NZ].name', 'Matt')
-        .expectJson('people[*].name', ['Matt', 'Pete'])
-        .useLogLevel('ERROR');
-    } catch (error) {
-      err = error;
-    }
-    expect(err).not.undefined;
-  });
-
-  it('json query like - on root object', () => {
-    return pactum.spec()
-      .useInteraction({
-        request: {
-          method: 'GET',
-          path: '/api/users'
-        },
-        response: {
-          status: 200,
-          body: {
-            people: [
-              { name: 'Matt', country: 'NZ' },
-              { name: 'Pete', country: 'AU' },
-              { name: 'Mike', country: 'NZ' }
-            ]
-          }
-        }
-      })
-      .get('http://localhost:9393/api/users')
-      .expectStatus(200)
-      .expectJsonLike('people[*].name', ['Matt', 'Pete']);
-  });
-
-  it('json query like - fails', async () => {
-    let err;
-    try {
-      await pactum.spec()
-        .useInteraction({
-          request: {
-            method: 'GET',
-            path: '/api/users'
-          },
-          response: {
-            status: 200,
-            body: {
-              people: [
-                { name: 'Matt', country: 'NZ' },
-                { name: 'Pete', country: 'AU' },
-                { name: 'Mike', country: 'NZ' }
-              ]
-            }
-          }
-        })
-        .get('http://localhost:9393/api/users')
-        .expectStatus(200)
-        .expectJsonLike('people[*].name', ['Matt', 'Pet'])
-        .useLogLevel('ERROR');
-    } catch (error) {
-      err = error;
-    }
-    expect(err).not.undefined;
-  });
-
   it('failed response time', async () => {
     let err;
     try {
@@ -928,17 +784,17 @@ describe('Expects', () => {
     let e;
     try {
       await pactum.spec()
-      .useInteraction('get people')
-      .name('json snapshot - with invalid matchers')
-      .get('http://localhost:9393/api/people')
-      .expectStatus(200)
-      .useLogLevel('ERROR')
-      .expectJsonSnapshot({
-        id: like('id')
-      })
-      .expectJsonSnapshot({
-        createdAt: like('2020-02-02')
-      });
+        .useInteraction('get people')
+        .name('json snapshot - with invalid matchers')
+        .get('http://localhost:9393/api/people')
+        .expectStatus(200)
+        .useLogLevel('ERROR')
+        .expectJsonSnapshot({
+          id: like('id')
+        })
+        .expectJsonSnapshot({
+          createdAt: like('2020-02-02')
+        });
     } catch (error) {
       e = error;
     }
diff --git a/test/data/request/child/sample-2.json b/test/data/requests/child/sample-2.json
similarity index 100%
rename from test/data/request/child/sample-2.json
rename to test/data/requests/child/sample-2.json
diff --git a/test/data/request/sample-1.json b/test/data/requests/sample-1.json
similarity index 100%
rename from test/data/request/sample-1.json
rename to test/data/requests/sample-1.json
diff --git a/test/data/responses/default.get.response.json b/test/data/responses/default.get.response.json
new file mode 100644
index 0000000..4bb1c77
--- /dev/null
+++ b/test/data/responses/default.get.response.json
@@ -0,0 +1,4 @@
+{
+  "method": "GET",
+  "path": "/default/get"
+}
\ No newline at end of file