New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

pactum

Package Overview
Dependencies
Maintainers
1
Versions
113
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pactum - npm Package Compare versions

Comparing version 2.0.7 to 2.0.8

src/plugins/json.match.js

4

package.json
{
"name": "pactum",
"version": "2.0.7",
"version": "2.0.8",
"description": "REST API Testing Tool to write e2e, integration, contract & component or service level tests",

@@ -68,4 +68,4 @@ "main": "./src/index.js",

"dependencies": {
"@exodus/schemasafe": "^1.0.0-rc.2",
"deep-override": "^1.0.1",
"djv": "^2.1.3-alpha.0",
"form-data": "^3.0.0",

@@ -72,0 +72,0 @@ "json-query": "^2.2.2",

@@ -11,4 +11,13 @@ # pactum

This library can be integrated with test runners like **cucumber**, **mocha**, **jest** or any other runners. It is *simple*, *fast*, *easy* and *fun* to use.
#### *why pactum?*
* Lightweight.
* Clear & Comprehensive Testing Style.
* Works with **cucumber**, **mocha**, **jest**.
* Elegant Data Management.
* Customizable Assertions & Retry Mechanisms.
* Powerful Mock Server.
* Ideal for *component*, *contract* & *e2e* testing of APIs.
* It is *simple*, *fast*, *fun* & *easy* to use.
## Documentation

@@ -19,2 +28,4 @@

* [API Testing](https://github.com/ASaiAnudeep/pactum/wiki/API-Testing)
* [Integration Testing](https://github.com/ASaiAnudeep/pactum/wiki/Integration-Testing)
* [Data Management](https://github.com/ASaiAnudeep/pactum/wiki/Data-Management)
* [Mock Server](https://github.com/ASaiAnudeep/pactum/wiki/Mock-Server)

@@ -43,3 +54,3 @@ * [Component Testing](https://github.com/ASaiAnudeep/pactum/wiki/Component-Testing)

Tests in **pactum** are clear and comprehensive. It uses numerous descriptive methods to build your requests and expectations. Learn more about these methods at [API Testing](https://github.com/ASaiAnudeep/pactum/wiki/API-Testing#request-making).
Tests in **pactum** are clear and comprehensive. It uses numerous descriptive methods to build your requests and expectations.

@@ -113,5 +124,5 @@ ### Simple Test Cases

It allows verification of returned status codes, headers, body, json objects, json schemas & response times. Learn more about available assertions at [API Testing](https://github.com/ASaiAnudeep/pactum/wiki/API-Testing#resonse-validation)
It allows verification of returned status codes, headers, body, json objects, json schemas & response times.
Running complex component test expectations.
Running complex test expectations.

@@ -121,3 +132,3 @@ ```javascript

return pactum.spec()
.get('https://jsonplaceholder.typicode.com/users/1')
.get('/api/users/1')
.expectStatus(201)

@@ -148,3 +159,3 @@ .expectHeaderContains('content-type', 'application/json')

})
.expectJsonQueryLike('[0].address[*].city', ['Boston', 'NewYork'])
.expectJsonLikeAt('[0].address[*].city', ['Boston', 'NewYork'])
.expectResponseTime(100);

@@ -158,3 +169,2 @@ });

const pactum = require('pactum');
const expect = pactum.expect;

@@ -175,3 +185,3 @@ describe('Chai Like Assertions', () => {

it('should return a status 200', () => {
expect(response).to.have.status(200);
spec.response().to.have.status(200);
});

@@ -185,54 +195,15 @@

```
Learn more about building requests & validating responses with **pactum** at [API Testing](https://github.com/ASaiAnudeep/pactum/wiki/API-Testing)
We can also add custom expect handlers that are ideal to make much more complicated assertions by taking advantage of popular assertion libraries like [chai](https://www.npmjs.com/package/chai)
## Integration Testing
```javascript
await pactum.spec()
.post('https://jsonplaceholder.typicode.com/posts')
.withJson({
title: 'foo',
body: 'bar',
userId: 1
})
.expectStatus(201)
.expect(({res}) => { /* Custom Assertion Code */ });
```
Integration Testing is defined as a type of testing where software modules or components are logically integrated & tested.
### Data Management
API Integration Testing has many aspects but usually involves passing data between tests or waiting for some action to be reflected in the system.
Data management is made easy with this library by using the concept of *Data Templates* & *Data References*. You can reuse data across tests. Learn more about data management with **pactum** at [Data Management](https://github.com/ASaiAnudeep/pactum/wiki/API-Testing#data-management)
```javascript
const stash = pactum.stash;
stash.addDataTemplate({
'User.New': {
FirstName: 'Jon',
LastName: 'Snow'
}
});
await pactum.spec()
.post('/api/users')
// json will be replaced with above template & overrides last name
.withJson({
'@DATA:TEMPLATE@': 'User.New',
'@OVERRIDES@': {
'LastName': 'Dragon'
}
});
```
### Nested Dependent HTTP Calls
API testing is naturally asynchronous, which can make tests complex when these tests need to be chained. With **Pactum**, passing response data to the next tests is very easy.
* `returns` allows us to return custom data from the response using [json-query](https://www.npmjs.com/package/json-query) or custom handler functions.
* `stores` allows us to save response data under *data management* which can be referenced later using [json-query](https://www.npmjs.com/package/json-query).
Learn more about it at [API Testing](https://github.com/ASaiAnudeep/pactum/wiki/API-Testing#nested-dependent-http-calls)
```javascript
const pactum = require('pactum');
const expect = require('chai').expect;

@@ -244,20 +215,21 @@ it('should return all posts and first post should have comments', async () => {

.returns('[0].id');
const response = await pactum.spec()
await pactum.spec()
.get(`http://jsonplaceholder.typicode.com/posts/${postID}/comments`)
.expectStatus(200);
const comments = response.json;
expect(comments).deep.equals([]);
});
```
it('should return all posts and update first posts title', async () => {
const postID = await pactum.spec()
.get('http://jsonplaceholder.typicode.com/posts')
```javascript
it('create new user', async () => {
await pactum.spec()
.post('/api/users')
.withJson(/* user details */)
.expectStatus(200)
.stores('FirstPostId', '[0].id');
const response = await pactum.spec()
.patch(`http://jsonplaceholder.typicode.com/posts`)
.withJson({
id: '@DATA:SPEC::FirstPostId@',
title: 'new title'
})
.stores('UserID', 'id'); // if response body = { id: 'C001019' }
});
it('validate new user details', async () => {
await pactum.spec()
.get('/api/users')
.withQueryParams('id', '@DATA:STR::UserId@')
.expectStatus(200);

@@ -269,7 +241,5 @@ });

Some API operations will take time & for such scenarios **pactum** allows us to add custom retry handlers that will wait for specific conditions to happen before attempting to make assertions on the response. (*Make sure to update test runners default timeout*)
```javascript
await pactum.spec()
.get('https://jsonplaceholder.typicode.com/posts/12')
.get('/some/async/operation')
.retry({

@@ -283,4 +253,42 @@ count: 2,

Learn more about api testing with **pactum** at [API Testing](https://github.com/ASaiAnudeep/pactum/wiki/API-Testing)
Learn more about these features at [Integration Testing](https://github.com/ASaiAnudeep/pactum/wiki/Integration-Testing)
## Mock Server
Mock Server allows you to mock any server or service via HTTP or HTTPS, such as a REST endpoint. Simply it is a simulator for HTTP-based APIs.
**pactum** can act as a standalone *mock server* or as a *service virtualization* tool. It comes with a **powerful request & response matching** and out of the box **Data Management**.
Running **pactum** as a standalone *mock server*.
```javascript
const pactum = require('pactum');
const { regex } = pactum.matchers;
pactum.mock.addMockInteraction({
withRequest: {
method: 'GET',
path: '/api/projects',
query: {
date: regex(/^\d{4}-\d{2}-\d{2}$/)
}
},
willRespondWith: {
status: 200,
headers: {
'content-type': 'application/json'
},
body: {
id: 1,
name: 'fake'
}
}
});
pactum.mock.start(3000);
```
Learn more about **pactum** as a *mock server* at [Mock Server](https://github.com/ASaiAnudeep/pactum/wiki/Mock-Server)
## Component Testing

@@ -419,39 +427,4 @@

## Mock Server
Mock Server allows you to mock any server or service via HTTP or HTTPS, such as a REST endpoint. Simply it is a simulator for HTTP-based APIs.
**pactum** can act as a standalone *mock server* or as a *service virtualization* tool. It comes with a **powerful request & response matching** and out of the box **Data Management**.
Running **pactum** as a standalone *mock server*.
```javascript
const pactum = require('pactum');
const { regex } = pactum.matchers;
pactum.mock.addMockInteraction({
withRequest: {
method: 'GET',
path: '/api/projects',
query: {
date: regex(/^\d{4}-\d{2}-\d{2}$/)
}
},
willRespondWith: {
status: 200,
headers: {
'content-type': 'application/json'
},
body: {
id: 1,
name: 'fake'
}
}
});
pactum.mock.start(3000);
```
Learn more about **pactum** as a *mock server* at [Mock Server](https://github.com/ASaiAnudeep/pactum/wiki/Mock-Server)
# Notes

@@ -458,0 +431,0 @@

@@ -9,5 +9,7 @@ export interface Have {

jsonLike(value: any): void;
jsonQuery(path: string, value: any): void;
jsonQueryLike(path: string, value: any): void;
jsonAt(path: string, value: any): void;
jsonLikeAt(path: string, value: any): void;
jsonSchema(schema: object): void;
jsonSchemaAt(path: string, schema: object): void;
jsonMatch(value: object): void;
responseTimeLessThan(ms: number): void;

@@ -14,0 +16,0 @@ _(handler: string, data: any): void

@@ -46,3 +46,3 @@ const ExpectModel = require('../models/expect');

jsonQuery(path, value) {
jsonAt(path, value) {
this.expect.jsonQuery.push({ path, value });

@@ -52,3 +52,3 @@ this._validate();

jsonQueryLike(path, value) {
jsonLikeAt(path, value) {
this.expect.jsonQueryLike.push({ path, value });

@@ -63,2 +63,12 @@ this._validate();

jsonSchemaAt(path, value) {
this.expect.jsonSchemaQuery.push({ path, value });
this._validate();
}
jsonMatch(value) {
this.expect.jsonMatch.push(value);
this._validate();
}
responseTimeLessThan(ms) {

@@ -65,0 +75,0 @@ this.expect.responseTime = ms;

@@ -65,3 +65,3 @@ import * as Spec from '../models/Spec';

*/
export function addDataHandler(name: string, func: DataHandlerFunction): void;
export function addDataFunHandler(name: string, func: DataHandlerFunction): void;

@@ -68,0 +68,0 @@ /**

@@ -53,3 +53,3 @@ const { PactumHandlerError } = require('../helpers/errors');

addDataHandler(name, func) {
addDataFunHandler(name, func) {
isValidHandler(name, func);

@@ -60,3 +60,3 @@ dataHandlers[name] = func;

getDataHandler(name) {
getDataFunHandler(name) {
if (dataHandlers[name]) return dataHandlers[name];

@@ -63,0 +63,0 @@ throw new PactumHandlerError(`Custom Data Handler Not Found - ${name}`);

@@ -99,6 +99,6 @@ export type RequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';

*/
export function addMockInteraction(interaction: MockInteraction): string;
export function addMockInteraction(interaction: MockInteraction[]): string[];
export function addMockInteraction(interaction: MockInteraction): Promise<string>;
export function addMockInteraction(interaction: MockInteraction[]): Promise<string[]>;
export function addMockInteraction(interaction: MockInteraction | string): string;
export function addMockInteraction(interaction: MockInteraction[] | string[]): string[];
export function addMockInteraction(interaction: MockInteraction | string): Promise<string>;
export function addMockInteraction(interaction: MockInteraction[] | string[]): Promise<string[]>;

@@ -123,7 +123,6 @@ /**

*/
export function addPactInteraction(interaction: PactInteraction): string;
export function addPactInteraction(interactions: PactInteraction[]): string[];
export function addPactInteraction(interaction: PactInteraction): Promise<string>;
export function addPactInteraction(interactions: PactInteraction[]): Promise<string[]>;
export function addPactInteraction(interaction: PactInteraction | string): string;
export function addPactInteraction(interactions: PactInteraction[] | string[]): string[];
export function addPactInteraction(interaction: PactInteraction | string): Promise<string>;
export function addPactInteraction(interactions: PactInteraction[] | string[]): Promise<string[]>;
/**

@@ -130,0 +129,0 @@ * returns interaction details

@@ -41,3 +41,3 @@ const Interaction = require('../models/interaction');

if (config.mock.remote) {
return remote.addMockInteraction(interactions, data);
return remote.addMockInteraction(interactions, data, alone);
}

@@ -64,3 +64,3 @@ const ids = [];

if (config.mock.remote) {
return remote.addPactInteraction(interactions, data);
return remote.addPactInteraction(interactions, data, alone);
}

@@ -87,3 +87,3 @@ const ids = [];

if (config.mock.remote) {
return remote.getInteraction(ids);
return remote.getInteraction(ids, alone);
}

@@ -90,0 +90,0 @@ const interactions = [];

@@ -9,3 +9,3 @@ const fs = require('fs');

let dataTemplate = {};
let dataSpec = {};
let dataStore = {};

@@ -80,13 +80,13 @@ const stash = {

addDataSpec(spec) {
Object.assign(dataSpec, spec);
addDataStore(store) {
Object.assign(dataStore, store);
config.data.ref.spec.enabled = true;
},
getDataSpecs() {
return dataSpec;
getDataStore() {
return dataStore;
},
clearDataSpecs() {
dataSpec = {};
clearDataStores() {
dataStore = {};
config.data.ref.spec.enabled = false;

@@ -93,0 +93,0 @@ }

const log = require('./logger');
const EXPRESSION_PATTERN = /^@\(.*\)@$/g;
class Compare {

@@ -76,2 +78,16 @@

expressionCompare(actual, expected, actualPath, expectedPath) {
if (typeof expected === 'string') {
const expressions = expected.match(EXPRESSION_PATTERN);
if (expressions) {
const expression = expressions[0].replace('$', 'actual').slice(2, -2);
const res = eval(expression);
if (res !== true) {
return `Json doesn't fulfil expression '${expression.replace('actual', expectedPath).trim()}'`
}
return true;
}
}
}
valueCompare(actual, expected, actualPath, expectedPath) {

@@ -87,2 +103,6 @@ if (actual === expected) {

}
const exprRes = this.expressionCompare(actual, expected, actualPath, expectedPath);
if (exprRes) {
return exprRes === true ? '' : exprRes;
}
if (typeof expected !== typeof actual) {

@@ -89,0 +109,0 @@ return `Json doesn't have type '${typeof expected}' at '${expectedPath}' but found '${typeof actual}'`;

@@ -93,2 +93,3 @@ const override = require('deep-override');

if (dataRefMatches) {
const values = [];
for (let i = 0; i < dataRefMatches.length; i++) {

@@ -100,13 +101,20 @@ const dataRefMatch = dataRefMatches[i];

const value = jq(refValue, { data: this.map }).value;
return typeof value === 'undefined' ? raw : value;
values.push(typeof value === 'undefined' ? raw : value);
}
if (refType === '@DATA:FUN') {
const handlerFun = handler.getDataHandler(refValue);
return handlerFun();
const [handlerName, ...args] = refValue.split(':');
const handlerFun = handler.getDataFunHandler(handlerName);
values.push(handlerFun({ data: args.length > 0 ? args[0].split(',') : args }));
}
if (refType === '@DATA:SPEC') {
const value = jq(refValue, { data: stash.getDataSpecs() }).value;
return typeof value === 'undefined' ? raw : value;
if (refType === '@DATA:STR') {
const value = jq(refValue, { data: stash.getDataStore() }).value;
values.push(typeof value === 'undefined' ? raw : value);
}
}
if (values.length === 1 && raw.length === dataRefMatches[0].length) {
return values[0];
}
for (let i = 0; i < dataRefMatches.length; i++) {
raw = raw.replace(dataRefMatches[i], values[i]);
}
}

@@ -113,0 +121,0 @@ return raw;

@@ -1,2 +0,2 @@

const { options, cyan, magenta, blue, green, yellow, red } = require('./colors');
const { options, magenta, blue, green, yellow, red } = require('./colors');

@@ -54,4 +54,4 @@ const LEVEL_TRACE = 3;

if (this.levelValue <= LEVEL_TRACE) {
process.stdout.write(`${cyan('PACTUM')} ${magenta('TRACE')} `);
this.console.debug(...msg);
process.stdout.write(`[${magenta('T')}] `);
msg.forEach(m => this.console.debug(m));
}

@@ -62,4 +62,4 @@ }

if (this.levelValue <= LEVEL_DEBUG) {
process.stdout.write(`${cyan('PACTUM')} ${blue('DEBUG')} `);
this.console.debug(...msg);
process.stdout.write(`[${blue('D')}] `);
msg.forEach(m => this.console.debug(m));
}

@@ -70,4 +70,4 @@ }

if (this.levelValue <= LEVEL_INFO) {
process.stdout.write(`${cyan('PACTUM')} ${green('INFO')} `);
this.console.info(...msg);
process.stdout.write(`[${green('I')}] `);
msg.forEach(m => this.console.info(m));
}

@@ -78,4 +78,4 @@ }

if (this.levelValue <= LEVEL_WARN) {
process.stdout.write(`${cyan('PACTUM')} ${yellow('WARN')} `);
this.console.warn(...msg);
process.stdout.write(`[${yellow('W')}] `);
msg.forEach(m => this.console.warn(m));
}

@@ -86,4 +86,4 @@ }

if (this.levelValue <= LEVEL_ERROR) {
process.stdout.write(`${cyan('PACTUM')} ${red('ERROR')} `);
this.console.error(...msg);
process.stdout.write(`[${red('E')}] `);
msg.forEach(m => this.console.error(m));
}

@@ -90,0 +90,0 @@ }

@@ -7,16 +7,17 @@ const phin = require('phin');

addMockInteraction(interactions, data) {
return addInteractions(interactions, data, 'api/pactum/mockInteractions', 'MOCK');
addMockInteraction(interactions, data, alone) {
return addInteractions(interactions, data, 'api/pactum/mockInteractions', 'MOCK', alone);
},
addPactInteraction(interactions, data) {
return addInteractions(interactions, data, 'api/pactum/pactInteractions', 'PACT');
addPactInteraction(interactions, data, alone) {
return addInteractions(interactions, data, 'api/pactum/pactInteractions', 'PACT', alone);
},
async getInteraction(ids) {
const interactions = await Promise.all([
async getInteraction(ids, alone) {
let interactions = await Promise.all([
get(`${config.mock.remote}/api/pactum/pactInteractions?ids=${ids.join(',')}`),
get(`${config.mock.remote}/api/pactum/mockInteractions?ids=${ids.join(',')}`)
]);
return interactions[0].concat(interactions[1]);
interactions = interactions[0].concat(interactions[1]);
return alone ? interactions[0] : interactions;
},

@@ -104,3 +105,3 @@

async function addInteractions(interactions, data, path, type) {
async function addInteractions(interactions, data, path, type, alone) {
const { raws, handlers } = getRawsAndHandlers(interactions);

@@ -115,5 +116,5 @@ let ids = [];

}
return ids;
return alone ? ids[0] : ids;
}
module.exports = remote;
const assert = require('assert');
const jqy = require('json-query');
const djv = require('djv');
const Compare = require('../helpers/compare');
const processor = require('../helpers/dataProcessor');
const handler = require('../exports/handler');
const jsv = require('../plugins/json.schema');
const jmv = require('../plugins/json.match');

@@ -15,6 +17,8 @@ class Expect {

this.json = [];
this.jsonQuery = [];
this.jsonLike = [];
this.jsonQuery = [];
this.jsonQueryLike = [];
this.jsonSchema = [];
this.jsonSchemaQuery = [];
this.jsonMatch = [];
this.headers = [];

@@ -37,2 +41,4 @@ this.headerContains = [];

this._validateJsonSchema(response);
this._validateJsonSchemaQuery(response);
this._validateJsonMatch(response);
this._validateResponseTime(response);

@@ -52,2 +58,3 @@ this._validateCustomExpectHandlers(request, response);

_validateStatus(response) {
this.statusCode = processor.processData(this.statusCode);
if (this.statusCode !== null) {

@@ -59,2 +66,3 @@ assert.strictEqual(response.statusCode, this.statusCode, `HTTP status ${response.statusCode} !== ${this.statusCode}`);

_validateHeaders(response) {
this.headers = processor.processData(this.headers);
for (let i = 0; i < this.headers.length; i++) {

@@ -83,2 +91,3 @@ const expectedHeaderObject = this.headers[i];

_validateHeaderContains(response) {
this.headerContains = processor.processData(this.headerContains);
for (let i = 0; i < this.headerContains.length; i++) {

@@ -107,2 +116,3 @@ const expectedHeaderObject = this.headerContains[i];

_validateBody(response) {
this.body = processor.processData(this.body);
if (this.body !== null) {

@@ -119,2 +129,3 @@ if (response.body instanceof Buffer) {

_validateBodyContains(response) {
this.bodyContains = processor.processData(this.bodyContains);
for (let i = 0; i < this.bodyContains.length; i++) {

@@ -149,2 +160,3 @@ const expectedBodyValue = this.bodyContains[i];

_validateJson(response) {
this.json = processor.processData(this.json);
for (let i = 0; i < this.json.length; i++) {

@@ -157,2 +169,3 @@ const expectedJSON = this.json[i];

_validateJsonLike(response) {
this.jsonLike = processor.processData(this.jsonLike);
for (let i = 0; i < this.jsonLike.length; i++) {

@@ -169,2 +182,3 @@ const expectedJSON = this.jsonLike[i];

_validateJsonQuery(response) {
this.jsonQuery = processor.processData(this.jsonQuery);
for (let i = 0; i < this.jsonQuery.length; i++) {

@@ -182,2 +196,3 @@ const jQ = this.jsonQuery[i];

_validateJsonQueryLike(response) {
this.jsonQueryLike = processor.processData(this.jsonQueryLike);
for (let i = 0; i < this.jsonQueryLike.length; i++) {

@@ -195,9 +210,7 @@ const jQ = this.jsonQueryLike[i];

_validateJsonSchema(response) {
this.jsonSchema = processor.processData(this.jsonSchema);
for (let i = 0; i < this.jsonSchema.length; i++) {
const jS = this.jsonSchema[i];
const jsv = new djv();
jsv.addSchema('test', { common: jS });
const validation = jsv.validate('test#/common', response.json);
if (validation) {
this.fail(`Response doesn't match with JSON schema - ${JSON.stringify(validation, null, 2)}`);
const errors = jsv.validate(this.jsonSchema[i], response.json);
if (errors) {
this.fail(`Response doesn't match with JSON schema: \n ${JSON.stringify(errors, null, 2)}`);
}

@@ -207,3 +220,29 @@ }

_validateJsonSchemaQuery(response) {
this.jsonSchemaQuery = processor.processData(this.jsonSchemaQuery);
for (let i = 0; i < this.jsonSchemaQuery.length; i++) {
const jQ = this.jsonSchemaQuery[i];
const value = jqy(jQ.path, { data: response.json }).value;
const errors = jsv.validate(jQ.value, value);
if (errors) {
this.fail(`Response doesn't match with JSON schema at ${jQ.path}: \n ${JSON.stringify(errors, null, 2)}`);
}
}
}
_validateJsonMatch(response) {
this.jsonMatch = processor.processData(this.jsonMatch);
for (let i = 0; i < this.jsonMatch.length; i++) {
const data = this.jsonMatch[i];
const rules = jmv.getMatchingRules(data, '$.body');
const value = jmv.getRawValue(data);
const errors = jmv.validate(response.json, value, rules, '$.body');
if (errors) {
this.fail(errors.replace('$.body', '$'));
}
}
}
_validateResponseTime(response) {
this.responseTime = processor.processData(this.responseTime);
if (this.responseTime !== null) {

@@ -210,0 +249,0 @@ if (response.responseTime > this.responseTime) {

@@ -405,6 +405,6 @@ import { RequestOptions } from 'http';

* .get('some-url')
* .expectJsonQuery('[0].name', 'Matt')
* .expectJsonQuery('[*].name', ['Matt', 'Pet', 'Don']);
* .expectJsonAt('[0].name', 'Matt')
* .expectJsonAt('[*].name', ['Matt', 'Pet', 'Don']);
*/
expectJsonQuery(path: string, query: any): Spec;
expectJsonAt(path: string, query: any): Spec;

@@ -417,7 +417,38 @@ /**

* .get('some-url')
* .expectJsonQueryLike('[*].name', ['Matt', 'Pet', 'Don']);
* .expectJsonLikeAt('[*].name', ['Matt', 'Pet', 'Don']);
*/
expectJsonQueryLike(path: string, value: any): Spec;
expectJsonLikeAt(path: string, value: any): Spec;
/**
* expects the response to match with json schema
* @see https://json-schema.org/learn/
* @example
* await pactum
* .get('/api/users/1')
* .expectJsonSchemaAt('user.address', {
* "type": "object",
* "properties": {
* "city": {
* "type": "string"
* }
* }
* });
*/
expectJsonSchemaAt(path: string, schema: object): Spec;
/**
* expects the json at to match with value
* @example
* const { like } = pactum.matchers;
*
* await pactum
* .get('/api/users')
* .expectJsonMatch({
* id: like(1),
* name: 'jon'
* });
*/
expectJsonMatch(value: object): Spec;
/**
* expects request completes within a specified duration (ms)

@@ -424,0 +455,0 @@ */

@@ -268,3 +268,8 @@ const FormData = require('form-data');

expectJsonQuery(path, value) {
expectJsonSchemaAt(path, value) {
this._expect.jsonSchemaQuery.push({ path, value });
return this;
}
expectJsonAt(path, value) {
this._expect.jsonQuery.push({ path, value });

@@ -274,3 +279,3 @@ return this;

expectJsonQueryLike(path, value) {
expectJsonLikeAt(path, value) {
this._expect.jsonQueryLike.push({ path, value });

@@ -280,2 +285,7 @@ return this;

expectJsonMatch(value) {
this._expect.jsonMatch.push(value);
return this;
}
expectResponseTime(value) {

@@ -282,0 +292,0 @@ this._expect.responseTime = value;

@@ -35,5 +35,3 @@ const phin = require('phin');

await this.removeInteractionsFromServer();
this.validateError();
this.validateInteractions();
this.validateResponse();
this.validate()
this.storeSpecData();

@@ -46,3 +44,4 @@ return this.getOutput();

processor.processTemplates();
const query = helper.getPlainQuery(processor.processData(this.request.qs));
this.request = processor.processData(this.request);
const query = helper.getPlainQuery(this.request.qs);
if (query) {

@@ -54,5 +53,3 @@ this.request.url = this.request.url + '?' + query;

setHeaders(this.request);
this.request.headers = processor.processData(this.request.headers);
setMultiPartFormData(this.request);
this.request.data = processor.processData(this.request.data);
}

@@ -115,3 +112,3 @@

this.mockInteractions = this.mockInteractions.concat(await mock.getInteraction(this.mockIds));
await mock.removeInteraction(this.mockIds);
await mock.removeInteraction(this.mockIds);
}

@@ -125,2 +122,19 @@ if (this.pactIds.length > 0) {

validate() {
this.validateError();
try {
this.validateInteractions();
this.validateResponse();
} catch (error) {
const res = {
statusCode: this.response.statusCode,
headers: this.response.headers,
body: this.response.json
}
log.warn('Request', JSON.stringify(this.request, null, 2));
log.warn('Response', JSON.stringify(res, null, 2));
throw error;
}
}
validateError() {

@@ -147,3 +161,3 @@ if (this.response instanceof Error) {

specData[store.key] = value;
stash.addDataSpec(specData);
stash.addDataStore(specData);
}

@@ -220,2 +234,3 @@ }

try {
log.debug(`${req.method} ${req.url}`);
res = await phin(req);

@@ -228,20 +243,5 @@ res.json = helper.getJson(res.body);

res.responseTime = Date.now() - requestStartTime;
printRequestResponse(req, res);
return res;
}
function printRequestResponse(req, res) {
if (log.levelValue <= 4) {
const rr = {
request: req,
response: {
statusCode: res.statusCode,
headers: res.headers,
json: res.json
}
}
log.debug('Request & Response =>', JSON.stringify(rr, null, 2));
}
}
module.exports = Tosser;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc