Skip to content

Commit

Permalink
chore: spec store options (#383)
Browse files Browse the repository at this point in the history
  • Loading branch information
ASaiAnudeep authored Oct 26, 2024
1 parent eeb8cb5 commit 95c234b
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 37 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pactum",
"version": "3.7.2",
"version": "3.7.3",
"description": "REST API Testing Tool for all levels in a Test Pyramid",
"main": "./src/index.js",
"types": "./src/index.d.ts",
Expand Down
24 changes: 18 additions & 6 deletions src/helpers/toss.helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,34 @@ function getPathValueFromRequestResponse(path, request, response) {
return jqy(path, { data }).value;
}

/**
*
* @param {*} spec
* @param {import('../internal.types').ISpecStore[]} stores
*/
function storeSpecData(spec, stores) {
const ctx = { req: spec._request, res: spec._response, store: stash.getDataStore() };
for (let i = 0; i < stores.length; i++) {
const store = stores[i];
if (typeof store === 'function') {
const specData = store(spec._request, spec._response);
stash.addDataStore(specData);
if (store.cb) {
stash.addDataStore(store.cb(spec._request, spec._response));
continue;
}
const specData = {};
let data_to_store;

const captureHandler = getCaptureHandlerName(store.path);
if (captureHandler) {
specData[store.name] = hr.capture(captureHandler, ctx);
data_to_store = hr.capture(captureHandler, ctx);
} else {
specData[store.name] = getPathValueFromRequestResponse(store.path, spec._request, spec._response);
data_to_store = getPathValueFromRequestResponse(store.path, spec._request, spec._response);
}
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);
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/internal.types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export type ISpecStore = {
name?: string
path?: string
options?: ISpecStoreOptions
cb?: Function
}

export type ISpecStoreOptions = {
status?: 'PASSED' | 'FAILED'
append?: boolean
}
5 changes: 3 additions & 2 deletions src/models/Spec.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Expect } from '../exports/expect';
import { CaptureHandlerFunction, ExpectHandlerFunction, RetryHandlerFunction } from '../exports/handler';
import { Interaction } from '../exports/mock';
import { LogLevel } from '../exports/settings';
import { ISpecStoreOptions } from '../internal.types';

declare interface RetryOptions {
/** maximum number of retries - defaults to 3 */
Expand Down Expand Up @@ -382,8 +383,8 @@ declare class Spec {
* stores spec request & response data
* @see https://pactumjs.github.io/api/requests/stores.html
*/
stores(name: string, path: string): Spec;
stores(name: string, handlerName: string): Spec;
stores(name: string, path: string, options?: ISpecStoreOptions): Spec;
stores(name: string, handlerName: string, options?: ISpecStoreOptions): Spec;
stores<T>(cb: (request: Request, response: IncomingMessage & {body: Record<string, any>, json: Record<string, any>}) => T): Spec;

/**
Expand Down
35 changes: 21 additions & 14 deletions src/models/Spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -483,20 +483,27 @@ class Spec {
}

stores(...args) {
if (args.length === 1 && typeof args[0] === 'function') {
const fn = args[0];
if (this._response) {
th.storeSpecData(this, [fn]);
} else {
this._stores.push(fn);
}
} else if (args.length === 2) {
const [name, path] = args;
if (this._response) {
th.storeSpecData(this, [{ name, path }]);
} else {
this._stores.push({ name, path });
}
if (args.length === 0) {
return this;
}

/**
* @type {import('../internal.types').ISpecStore}
*/
const spec_store = {};

if (typeof args[0] === 'function') {
spec_store.cb = args[0];
} else {
spec_store.name = args[0];
spec_store.path = args[1];
spec_store.options = args[2];
}

if (this._response) {
th.storeSpecData(this, [spec_store]);
} else {
this._stores.push(spec_store);
}
return this;
}
Expand Down
34 changes: 33 additions & 1 deletion src/models/Tosser.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class Tosser {
await this.getInteractionsFromServer();
this.saveDataInFileSystem();
this.recordData();
th.storeSpecData(this.spec, this.spec._stores);
this.storeSpecData();
await this.validate();
if (hasBackgroundInteractions(this.interactions) || (this.spec._wait && typeof this.spec._wait.arg1 === 'string')) {
await this.dynamicWait();
Expand Down Expand Up @@ -209,9 +209,11 @@ class Tosser {
this.validateNonBackgroundInteractions();
await this.validateResponse();
this.spec.status = 'PASSED';
this.storeSpecData();
this.runReport();
} catch (error) {
this.spec.status = 'FAILED';
this.storeSpecData();
this.spec.failure = error.toString();
this.runReport();
this.printRequestAndResponse();
Expand Down Expand Up @@ -255,6 +257,36 @@ class Tosser {
}
}

storeSpecData() {
const stores = [];
switch (this.spec.status) {
case 'PASSED':
for (const store of this.spec._stores) {
if (store && store.options && store.options.status === 'PASSED') {
stores.push(store);
}
}
break;
case 'FAILED':
for (const store of this.spec._stores) {
if (store && store.options && store.options.status === 'FAILED') {
stores.push(store);
}
}
break;
default:
for (const store of this.spec._stores) {
if (store && (!store.options || !store.options.status)) {
stores.push(store);
}
}
break;
}
if (stores.length > 0) {
th.storeSpecData(this.spec, stores);
}
}

}

async function getResponse(tosser) {
Expand Down
77 changes: 66 additions & 11 deletions test/component/stores.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const expect = require('chai').expect;
const pactum = require('../../src/index');
const stash = require('../../src/exports/stash');
const { addInteractionHandler } = pactum.handler;
Expand Down Expand Up @@ -111,7 +112,7 @@ describe('Stores', () => {
}
})
.post('http://localhost:9393/api/stores')
.withCookies('token','$S{token}')
.withCookies('token', '$S{token}')
.withJson({
UserId: '$S{FirstUser.id}'
})
Expand Down Expand Up @@ -177,7 +178,7 @@ describe('Stores', () => {
.expectStatus(200);
});

it ('store single value by custom function', async () => {
it('store single value by custom function', async () => {
await pactum.spec()
.useInteraction({
request: {
Expand All @@ -195,10 +196,10 @@ describe('Stores', () => {
.expectStatus(200)
.stores((request, response) => {
return {
custom_func_id: response.body.id
custom_func_id: response.body.id
};
});
await pactum.spec()
await pactum.spec()
.useInteraction({
request: {
method: 'POST',
Expand All @@ -218,7 +219,7 @@ describe('Stores', () => {
.expectStatus(200);
});

it ('store multiple value by custom function', async () => {
it('store multiple value by custom function', async () => {
await pactum.spec()
.useInteraction({
request: {
Expand All @@ -237,11 +238,11 @@ describe('Stores', () => {
.expectStatus(200)
.stores((request, response) => {
return {
custom_func_id: response.body.id,
custom_func_email: response.body.email
custom_func_id: response.body.id,
custom_func_email: response.body.email
};
});
await pactum.spec()
await pactum.spec()
.useInteraction({
request: {
method: 'POST',
Expand Down Expand Up @@ -290,9 +291,9 @@ describe('Stores', () => {
.get('http://localhost:9393/api/stores')
.expectStatus(200);
spec.stores((request, response) => {
return {
UserId: response.body.id
};
return {
UserId: response.body.id
};
});
await pactum.spec()
.useInteraction('post stores')
Expand All @@ -307,6 +308,60 @@ describe('Stores', () => {
.expectStatus(200);
});

it('store on failure', async () => {
await pactum.spec()
.useInteraction('get stores')
.get('http://localhost:9393/api/stores')
.expectStatus(200)
.stores('FailedUserId', 'id', { status: 'FAILED' });
expect(stash.getDataStore('FailedUserId')).to.be.undefined;
try {
await pactum.spec()
.useInteraction('get stores')
.get('http://localhost:9393/api/stores')
.expectStatus(500)
.stores('FailedUserId', 'id', { status: 'FAILED' })
.inspect(false);
} catch (error) {

}
expect(stash.getDataStore('FailedUserId')).equals(1);
});

it('store on success', async () => {
try {
await pactum.spec()
.useInteraction('get stores')
.get('http://localhost:9393/api/stores')
.expectStatus(500)
.stores('FailedUserId', 'id', { status: 'PASSED' })
.inspect(false);
} catch (error) {

}
expect(stash.getDataStore('FailedUserId')).to.be.undefined;
await pactum.spec()
.useInteraction('get stores')
.get('http://localhost:9393/api/stores')
.expectStatus(200)
.stores('FailedUserId', 'id', { status: 'PASSED' });
expect(stash.getDataStore('FailedUserId')).equals(1);
});

it('store append', async () => {
await pactum.spec()
.useInteraction('get stores')
.get('http://localhost:9393/api/stores')
.expectStatus(200)
.stores('UserId', 'id', { append: true });
await pactum.spec()
.useInteraction('get stores')
.get('http://localhost:9393/api/stores')
.expectStatus(200)
.stores('UserId', 'id', { append: true });
expect(stash.getDataStore('UserId')).deep.equals([1,1]);
})

afterEach(() => {
stash.clearDataStores();
});
Expand Down

0 comments on commit 95c234b

Please sign in to comment.