pactumjs / pactum Goto Github PK
View Code? Open in Web Editor NEWREST API Testing Tool for all levels in a Test Pyramid
Home Page: https://pactumjs.github.io
License: MIT License
REST API Testing Tool for all levels in a Test Pyramid
Home Page: https://pactumjs.github.io
License: MIT License
mock server is listen on local host by default 127.0.0.1.
Maybe I have not seen in the doc, how is it possible to listen on all interface 0.0.0.0 ?
Best Regards
Matthias
PactumJS comes with a default custom built lightweight logger. This logger will serve the basic needs while running the pactum tests in local or a CI tool like Jenkins.
For supporting advanced usage where tests might be running inside docker containers or server-less environments, we need a logger that fits well over there. This library tends to be lightweight and doesn't want to include multiple loggers. Instead it should provide a way for users to override the default logger. Use pactum.settings
to override.
const { settings } = require('pactum');
settings.setLogger(myCustomLogger);
ExpectJsonSnapshot() doesn’t seem to validate objects in array.
I have an expected JSON like this:
{
"components": [
{
"product": {
"dairyProduct": {
"id": "4f6e821a-ad7e-467d-9e92-3d01544215ff",
"createdAt": "2022-01-19T23:04:27.009Z",
},
}
}
]
}
I want to write a snapshot matcher like this:
.expectJsonSnapshot({
"components": [
{
"product":
"dairyProduct": {
"id": uuid(),
"createdAt": regex(1, DATA.REGEX.ISO_DATE),
},
}
],
}).name()
And it seems to always pass even if the products are different. E.g., it passes if I receive $.components[0].product.coffeeProduct
instead of the expected $.components[0].product.dairyProduct
Can you please suggest if I need to use a specific matcher for the array objects?
OS: macOS Monterey 12.0.1
NPM: 8.1.0
Node: v17.0.1
Pactum: 3.0.21
const response = await pactum.spec()
.post(endpoints.baseUrl + endpoints.requestShift)
.withBody(body)
.withHeaders('Accept', 'application/json')
.withHeaders('Authorization', configData.HCPAuthorization)
.expectStatus(200)
console.log(response.json)
In this case, if the response does not match the expected status:200,
step: console.log(response.json) gets skipped
The above step helps in debugging, can we have a method exposed? like - print (response.json) within the pactum spec and this should help us with printing the response + debugging.
Originally posted by captaincc423 December 1, 2021
I'm trying to get some matchers to work in expectJsonSnapshot and I'm running into a few problems:
"id": includes(response.body.id)
and it's not working. It always says it doesn't match."createdAt": regex(/anything in here/),
always passes.Am I misusing these matchers?
Describe the bug
Running a pactum test with baseUrl
and without an endpoint fails with type error.
To Reproduce
Steps to reproduce the behavior:
request.setBaseUrl(`<some-url>`);
await pactum.spec()
TypeError: Cannot read property 'startsWith' of undefined
Expected behavior
A clear and concise error would help.
Describe the bug
When making a graphql request to the mock server, a request made with a slightly different formatted gql body will cause the mock to believe it is a different defined interaction and return "Interaction Not Found"
To Reproduce
Steps to reproduce the behavior:
Expected behavior
The formatting of the request should not change the body of a gql request, and should return a mocked response if the request exists as a defined interaction
Software (please complete the following information):
Is your feature request related to a problem? Please describe.
It would be great to save files from response to file system and perform custom operations on it.
Describe the solution you'd like
await spec()
.get('/some/file')
.save('/path/')
.expectStatus(200)
Describe alternatives you've considered
const fs = require('fs')
const { spec } = require('pactum');
const res = await spec().get('https://httpbin.org/image/png');
fs.writeFileSync('pig.png', res.buffer);
Is your feature request related to a problem? Please describe.
I want to use external JSON schema provided in @exodus/schemasafe
Describe the solution you'd like
Please add an optional argument for external schemas to expectJsonSchema
and jsonSchema
methods.
Describe alternatives you've considered
Or maybe add a global setting for external schemas.
Describe the bug
I have a test that keeps failing due to error "Response does not contain a json array"
but the response does have this value. If I run the same test in Cypress it passes.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Test should pass.
Software (please complete the following information):
Additional context
AssertionError [ERR_ASSERTION]: Response does not contain a json array at 'wallets'
await spec()
.get('/portfolio')
.withHeaders('Authorization', `Bearer ${state.token}`)
.expectStatus(200)
.expectJsonLength('wallets', 1)
.expectJsonLike({
portfolios: {
[state.portfolioId]: {
wallets: [
{
address: "0x379F29c017eC33E145D1fe721971Cc1B50a31253",
chain: "ethereum"
},
]
}
}
})
});
Response:
"eXdTzDeajCSH4HogT5N9F": {
"includes": [],
"wallets": [
{
"chain": "ethereum",
"address": "0x379F29c017eC33E145D1fe721971Cc1B50a31253"
}
],
"name": "api-patch-test",
"portfolioId": "eXdTzDeajCSH4HogT5N9F",
"createdAt": 1660213048605
}
Same test that passes on Cypress:
cy.request({
method: "GET",
url: `${Cypress.env("portfolioAuthUrl")}/portfolio`,
headers: {
Authorization: `Bearer ${state.token}`,
},
}).then((resp) => {
// redirect status code is 302
expect(resp.status).to.eq(200);
expect(resp.body.portfolios[state.portfolioId].wallets.length).eq(1);
expect(
resp.body.portfolios[state.portfolioId].wallets
).to.have.deep.members([
{
address: "0x379F29c017eC33E145D1fe721971Cc1B50a31253",
chain: "ethereum",
},
]);
});
});
Describe the bug
mockserver.js
mock.addInteraction({ id:'first', request:{...}, response:{...}
getInteraction.test.js
`
test('should return "Jon" info',async()=>{
await pactum.spec()
.get('http://localhost:3000/ms/api/users/{userId}')
.withPathParams({"userId":"1"})
.expectStatus(200)
.expectJsonLike({
id: 1,
name:'Jon'
});
expect(mock.getInteraction('first')).not.toBe(null);
});
`
results:
Interaction Not Found - first
at msg.forEach.m (node_modules/pactum/src/adapters/logger.js:21:24)
at Array.forEach (<anonymous>)
at Object.warn (node_modules/pactum/src/adapters/logger.js:21:7)
at Logger.warn (node_modules/pactum/src/plugins/logger.js:78:20)
at Server.getInteraction (node_modules/pactum/src/models/server.js:77:11)
at ids.forEach.id (node_modules/pactum/src/exports/mock.js:72:54)
at Array.forEach (<anonymous>)
FAIL tests/mockServer/interactionWithPathParams.test.js
× should return "Jon" info (50 ms)
● should return "Jon" info
TypeError: Cannot read property 'callCount' of null
15 | });
16 |
> 17 | expect(mock.getInteraction('first')).not.toBe(null);
| ^
18 |
19 | });
20 |
at interactions.forEach.interaction (node_modules/pactum/src/exports/mock.js:74:43)
at Array.forEach (<anonymous>)
How do I get interaction with the given ID?
Is your feature request related to a problem? Please describe.
Mock server should be able to return files.
Describe the solution you'd like
{ request: {}, response: file: '' }
Describe the bug
Interaction not exercised error is thrown on using contract testing
To Reproduce
Have two made two endpoints up using mock server calls one for get: /api/inventory-service/products and for post: /api/order-service/orders
However flows are getting recorded in the server and can be witnessed under flows tab, but interaction not exercised error is thrown.
Expected behavior
Expected interaction to be listed in the pactumjs flow server
Software (please complete the following information):
Is your feature request related to a problem? Please describe.
Unable to access request information/options. I want to access the request options, to output a cURL request when a test fails. This is useful for reporting API bugs and being able to give the developers a command that they can execute to reproduce any issue.
Describe the solution you'd like
There could possibly be a getRequestOptions
method on spec
, this way anyone could pull that information and transform it into any request cURL, axios, etc.
Noticed that when a test fails, pactum outputs some request details, ideally, this is the information I would want in that method.
Describe alternatives you've considered
Tried getting that information from the response object, but I was not sure how to parse the request client, as a matter of fact, it didn't seem parsable (maybe I was missing something).
Additional context
I am open to working on this feature, and would only need some guidance as to where to start. Also, get feedback in terms of the best way of doing this. Maybe it's not a new method and can be done from like a handler?
Describe the bug
Headers are not overriden when using withHeaders
and withMultiPartFormData
.
To Reproduce
var { spec } = require("pactum")
await spec()
.get('https://httpbin.org/anything')
.withMultiPartFormData('file', '')
.withHeaders('content-type', 'application/json')
.inspect()
Expected behavior
content-type
header should be application/json
but it still uses multipart/form-data
Is your feature request related to a problem? Please describe.
It's annoying that I can't use asynchronous functions in Data Function handlers
Describe the solution you'd like
I invision something like:
pactum.handler.addAsyncDataFuncHandler('MyDataFunction', async () => {
const result = await someAsyncFunction(10);
return result;
})
or
Refactor existing method to accept a boolean whose default value is false. But when set to true will pass the function to an async version of the handler instead (I don't love this approach).
pactum.handler.addDataFuncHandler('MyDataFunction', async () => {
const result = await someAsyncFunction(10);
return result;
}, true)
Is your feature request related to a problem? Please describe.
Able to use data-management features while using form-data.
Describe the solution you'd like
const { spec } = require('pactum');
it('should get random users', async () => {
await spec()
.get('https://some.me/api')
.withMultiPartFormData({ '@DATA:TEMPLATE@': 'User' });
});
Originally posted by captaincc423 December 1, 2021
I'm trying to get some matchers to work in expectJsonSnapshot and I'm running into a few problems:
"id": includes(response.body.id)
and it's not working. It always says it doesn't match.Am I misusing these matchers?
How to upload a binary file (not using form-data)?
Describe the bug
Trying to define a graphQL interaction in typescript project when I try to pass the variables key as object like I get a Typescript error expecting the type as string.
To Reproduce
Steps to reproduce the behavior:
spec().useInteraction()
or mock.addInteraction()
or any of the related methods.graphQL.variables
as object (like in tests)Expected behavior
Typescript must work with graphQL.variables
as Record<string, unknown>.
Software (please complete the following information):
Is your feature request related to a problem? Please describe.
Support removes in data templates for negative scenarios.
Describe the solution you'd like
await spec()
.post('<url>')
.withJson({
'@DATA:TEMPLATE@': 'User',
'@REMOVES@': ['Surname']
})
.expectStatus(400)
console.log(parse('$S{bearerToken}'));
only prints
$S{bearerToken}
Is your feature request related to a problem? Please describe.
Support form data in mock server.
Describe the solution you'd like
mock.addInteraction({
request: {
method: 'POST',
path: '/api/token',
form: {
'key': 'value'
}
},
response: {
status: 200
}
})
Describe alternatives you've considered
Ignore the form data.
mock.addInteraction({
strict: false,
request: {
method: 'POST',
path: '/api/token'
},
response: {
status: 200
}
})
Describe the bug
I tried to send a GET request with a URL, which contains a colon and it failed with error 401.
My request looks like
const url=`https://${process.env.API_KEY}:${process.env.API_SECRET}@${process.env.URL}/v2/profiles`;
spec().get(url)
I'm using API_KEY and API_SECRET for the basic authentication, that I provide as part of the URL.
Important to notice, that when I use axios.get(url);
it works as required.
As workaround, I can use also Pactum, but with some changes:
const encode=Buffer.from(`${process.env.API_KEY}:${process.env.API_SECRET}`).toString('base64');
const baseUrl=`https://${process.env.URL}/v2/profiles`;
await pactum.spec().withHeaders({
'Authorization': `Basic ${encode}`,
})
.get(baseUrl)
.expectStatus(200);
});
Expected behavior
could you please check the option to use the first command without basic authorization
Software (please complete the following information):
Describe the bug
withCookies()
method encodes the value before sending it, causing it not to work in some scenarios. withHeaders('cookie', cookie)
doesn't.
withHeaders:
"cookie": "dwsid=M_ZChQR1JiTC3tzkLgdnlqMO8j--MFXD9r-bo-y1boZQnzjkfxiHXeWgPO2LytY9y6h0-Vykz99putNywubh5g=="
withCookies:
"cookie": "dwsid=M_ZChQR1JiTC3tzkLgdnlqMO8j--MFXD9r-bo-y1boZQnzjkfxiHXeWgPO2LytY9y6h0-Vykz99putNywubh5g%3D%3D"
Mind the %3D%3D
at the end
To Reproduce
Steps to reproduce the behavior:
withCookies()
Expected behavior
I'm not sure if it should be encoded or not, but definitely, Salesforce Commerce Cloud platform doesn't like that, so maybe it should be configurable. Like I said, the behaviour is different if you use withHeaders('cookie')
, so it's confusing
Software (please complete the following information):
An HTTP cookie (web cookie, browser cookie) is a small piece of data that a server sends to the user's web browser. The browser may store it and send it back with later requests to the same server.
Learn more about cookies here.
This issue focuses on sending cookies & asserting cookies in a friendly way with PactumJS.
withCookies('name', 'snow')
withCookies({
name: 'snow',
'HttpOnly': null
})
withCookies('name=snow;HttpOnly')
Support multiple cookies.
await pactum.spec()
.get('url')
.withCookies('key1', 'value1')
.withCookies('key2', 'value2')
To support rich assertions, use json-like or json-match internally. I prefer json-match.
await pactum.spec()
.get('url')
.expectCookies('key1', 'value1');
expectCookies('name', 'snow')
expectCookies({
name: 'snow',
'HttpOnly': null
})
expectStrictCookies({
name: 'snow',
'HttpOnly': null
})
expectCookies('name=snow;HttpOnly')
Use lightweight cookie parsers like lightcookie or simple-cookie.
withCookies
, expectCookies
& expectStrictCookies
.Describe the bug
The mock server has an interaction, two tests are written to access it, and stores can only hold data for the first time.
To Reproduce
"devDependencies": { "jest": "^27.3.1", "pactum": "^3.0.21" }
mock.addInteraction({
request:{
method:'POST',
path:'/api/users/new',
body:like({
id: 1,
name:'tom',
gender:'M',
age:18
})
},
stores:{
nid:'req.body.id',
nname:'req.body.name',
ngender:'req.body.gender',
nage:'req.body.age'
},
response:{
status:200,
body:{
id:'$S{nid}',
name:'$S{nname}',
gender:'$S{ngender}',
age:'$S{nage}'
}
}
})
//setup
beforeAll(async()=>{
stash.addDataTemplate({
'User:new':{
'id':4,
'name':'kelly',
'gender':'M',
'age':23
}
});
pactum.request.setBaseUrl('http://localhost:3000');
//mock server start
await pactum.mock.start(3000);
});
afterAll(async()=>{
await pactum.mock.stop();
});
//test
test('should return post user info',async()=>{
await pactum.spec()
.post('/api/users/new')
.withJson({
'@DATA:TEMPLATE@':'User:new'
})
.expectStatus(200)
.expectJsonMatch({
id:like(1),
name:'kelly',
'age':23
});
});
// test datatemplate: overides
////This library supports the overriding of specific values & extending the data template.
test('should return age=-1 user info',async()=>{
await pactum.spec()
.post('/api/users/new')
.withJson({
'@DATA:TEMPLATE@':'User:new',
'@OVERRIDES@':{
'age':-1,
}
})
.expectStatus(200)
.expectJsonMatch({
id:like(1),
age:-1
});
});
Screenshots
FAIL __tests__/dataManagement/dataTemplate.test.js
√ should return post user info (45 ms)
× should return age=-1 user info (16 ms)
● should return age=-1 user info
assert.fail(received, expected)
Message:
Json doesn't have value '-1' at '$.age' but found '23'
Request and response for the second test:
request:
{
"url": "http://localhost:3000/api/users/new",
"method": "POST",
"path": "/api/users/new",
"body": {
"id": 4,
"name": "kelly",
"gender": "M",
"age": -1
},
"timeout": 3000
}
response:
{
"statusCode": 200,
"headers": {
"content-type": "application/json",
"date": "Mon, 01 Nov 2021 11:19:48 GMT",
"connection": "close",
"content-length": "45"
},
"body": {
"id": 4,
"name": "kelly",
"gender": "M",
"age": 23
}
}
Hi would be fine, to add option to disable logs during tests:
class Server
log.info(Mock server is listening on port ${config.mock.port}); //start method
log.info(Mock server server stopped on port ${config.mock.port}); //stop method
current behaviour:
PASS test/functional/example.spec.ts
● Console
console.info
Mock server is listening on port 9339
at node_modules/pactum/src/exports/logger.js:69:37
at Array.forEach (<anonymous>)
console.info
Mock server stopped on port 9339
at node_modules/pactum/src/exports/logger.js:69:37
at Array.forEach (<anonymous>)
Solutions:
process.env.PACTUM_LOG_LEVEL
mock
await pactum.mock.start(9339, {loggerEnabled: false});
Is it because of my Typescript version, 4.5.4...? Or perhaps my general naivety....?
OS: Windows 10
NPM: 7.24.1
Node: v16.10.0
Typescript: 4.5.4
Pactum: 3.1.1
When my tsconfig.js
has "allowJs": true
, adding a JS file that just requires pactum causes the below:
node_modules/pactum/src/exports/expect.d.ts:39:1 - error TS2309: An export assignment cannot be used in a module with other exported elements.
39 export = expect;
~~~~~~~~~~~~~~~~
node_modules/pactum/src/exports/reporter.d.ts:1:51 - error TS2440: Import declaration conflicts with local declaration of 'Interaction'.
1 import { InteractionRequest, InteractionResponse, Interaction } from './mock';
~~~~~~~~~~~
node_modules/pactum/src/index.d.ts:5:25 - error TS2498: Module '"L:/src/foaf/node_modules/pactum/src/exports/expect"' uses 'export =' and cannot be used with 'export *'.
5 export * as expect from './exports/expect';
~~~~~~~~~~~~~~~~~~
node_modules/pactum/src/index.d.ts:7:27 - error TS2307: Cannot find module './exports/matcher' or its corresponding type declarations.
7 export * as matchers from './exports/matcher';
~~~~~~~~~~~~~~~~~~~
node_modules/pactum/src/index.d.ts:15:25 - error TS2307: Cannot find module './exports/logger' or its corresponding type declarations.
15 export * as logger from './exports/logger';
~~~~~~~~~~~~~~~~~~
node_modules/pactum/src/models/Spec.d.ts:201:63 - error TS2314: Generic type 'Array<T>' requires 1 type argument(s).
201 withMultiPartFormData(key: string, value: string | Buffer | Array | ArrayBuffer, options?: FormData.AppendOptions): Spec;
~~~~~
node_modules/pactum/src/models/Spec.d.ts:398:19 - error TS2304: Cannot find name 'T'.
398 toss(): Promise<T>;
~
Found 7 errors.
tsconfig.json
:
{
"compilerOptions": {
"target": "ES2017",
"module": "commonjs",
"allowJs": true,
"sourceMap": true,
"outDir": "dist",
"strict": true,
"lib": [
"esnext",
],
"resolveJsonModule": true,
"esModuleInterop": true,
"moduleResolution": "node",
"typeRoots": [
"jest-fetch-mock",
"./node_modules/@types",
"./src/types"
],
"baseUrl": ".",
"paths": {
"testlib/*": [
"./test/lib/*"
],
"src/*": [
"./src/*"
]
}
}
}
Setting "allowJs": false
solves the problem.
Is your feature request related to a problem? Please describe.
It would be great to have a inbuilt date manipulating functions like momentjs or luxon
Describe the solution you'd like
const { date } = require('pactum');
date.now();
date.now().add({ days: 2});
date.now().minus({ hours: 2}).format('dd MM yyyy');
Describe the bug
The simple example (see below) shows this error from eslint: Unexpected 'await' of a non-Promise (non-"Thenable") value.
If I disable this error, typescript complains 'await' has no effect on the type of this expression.ts(80007)
The test then works without problems.
To Reproduce
Steps to reproduce the behavior:
test.ts
/* eslint-disable @typescript-eslint/await-thenable */
Expected behavior
No complains.
Screenshots
If applicable, add screenshots to help explain your problem.
Software (please complete the following information):
Additional context
The code:
import {spec} from "pactum";
const url = "http://localhost:8080/api";
describe("Configuration data", () => {
test("should get a response with status code 200", async () => {
await spec()
.get(url)
.expectStatus(200);
});
});
The eslint configuration:
parser: '@typescript-eslint/parser'
plugins:
- node
- promise
- import
- '@typescript-eslint'
- no-useless-assign
- eslint-comments
- dollar-sign
- optimize-regex
- const-case
- jest
- jest-formatting
- unicorn
- security
- array-plural
- no-unsafe-regex
- deprecate
- '@delagen/deprecation'
- sonarjs
- regexp
- '@alasdair/max-len'
- 'tsdoc'
extends:
- 'eslint:recommended'
- 'plugin:eslint-comments/recommended'
- 'plugin:promise/recommended'
- 'plugin:node/recommended'
- 'plugin:import/errors'
- 'plugin:import/warnings'
- 'plugin:import/typescript'
- 'plugin:@typescript-eslint/recommended'
- 'plugin:@typescript-eslint/recommended-requiring-type-checking'
- 'plugin:jquery/slim'
- 'plugin:jquery/deprecated'
- 'plugin:jest/recommended'
- 'plugin:jest/style'
- 'plugin:jest-formatting/recommended'
- 'plugin:unicorn/recommended'
- 'plugin:security/recommended'
- 'plugin:sonarjs/recommended'
- 'plugin:regexp/recommended'
parserOptions:
ecmaVersion: 2021
ecmaFeatures:
impliedStrict: true
project:
- ./server/tsconfig.json
- ./tests/tsconfig.json
- ./ingest/tsconfig.json
- ./common/tsconfig.json
warnOnUnsupportedTypeScriptVersion: false
reportUnusedDisableDirectives: true
settings:
import/parsers: {'@typescript-eslint/parser': [.ts, .tsx]}
import/resolver: {typescript: {}}
import/extensions: [.js, .ts]
import/ignore: [node_modules]
env:
es2021: true
node: true
jest: true
jest/globals: true
rules:
node/no-deprecated-api: error
node/exports-style: [error, exports]
node/no-unsupported-features/node-builtins: [error, {version: '>=16'}]
node/no-unsupported-features/es-builtins: [error, {version: '>=16'}]
node/no-unsupported-features/es-syntax: [off, {version: '>=16'}]
node/no-missing-import:
- off
- allowModules: [marked]
tryExtensions: [.js, .json]
node/handle-callback-err: error
node/global-require: error
node/no-process-exit: off
'@typescript-eslint/consistent-type-assertions': [warn, {assertionStyle: 'as'}]
'@typescript-eslint/array-type': [warn, {default: array, readonly: array}]
'@alasdair/max-len/max-len':
- warn
- code: 115
ignoreTrailingComments: true
ignoreUrls: true
ignoreStrings: true
ignoreTemplateLiterals: true
ignoreRegExpLiterals: true
no-dupe-class-members: off
'@typescript-eslint/no-dupe-class-members': error
no-buffer-constructor: error
no-redeclare: [off, {builtinGlobals: true}]
'@typescript-eslint/no-redeclare': [error, {builtinGlobals: true}]
no-unused-vars: off
'@typescript-eslint/no-unused-vars': error
no-empty-function: off
'@typescript-eslint/no-empty-function': warn
no-useless-constructor: off
'@typescript-eslint/no-useless-constructor': warn
lines-between-class-members: off
'@typescript-eslint/lines-between-class-members': off
no-undef: error
no-extend-native: error
no-sequences: error
no-new: error
no-bitwise: error
no-unsafe-negation: [warn, {enforceForOrderingRelations: true}]
quotes: [off, double, {avoidEscape: true}]
'@typescript-eslint/quotes': [warn, double, {avoidEscape: true}]
eqeqeq: [error, always]
strict: [error, global]
no-loop-func: off
'@typescript-eslint/no-loop-func': error
no-unused-expressions: off
'@typescript-eslint/no-unused-expressions': warn
max-params: [warn, 4]
max-len: [off, 113]
space-before-function-paren: off
'@typescript-eslint/space-before-function-paren':
- error
- anonymous: never
named: never
asyncArrow: always
space-before-blocks: warn
no-shadow: off
'@typescript-eslint/no-shadow':
- error
- hoist: all
builtinGlobals: true
allow: [$, event, self]
comma-spacing: off
'@typescript-eslint/comma-spacing': [error, {before: false, after: true}]
keyword-spacing: off
'@typescript-eslint/keyword-spacing':
- warn
- before: true
after: false
overrides:
else: {after: true}
return: {after: true}
try: {after: true}
catch: {after: false}
case: {after: true}
const: {after: true}
throw: {after: true}
let: {after: true}
do: {after: true}
of: {after: true}
as: {after: true}
finally: {after: true}
from: {after: true}
import: {after: true}
export: {after: true}
default: {after: true}
no-trailing-spaces: warn
no-implicit-coercion: error
id-length: [warn, {exceptions: [$, i, j, k, x, y, w, h, g]}]
prefer-const: warn
for-direction: error
no-template-curly-in-string: error
consistent-return: [error, {treatUndefinedAsUnspecified: false}]
no-unmodified-loop-condition: error
array-bracket-spacing: [warn, never]
object-curly-spacing: off
'@typescript-eslint/object-curly-spacing': ['warn']
brace-style: off
'@typescript-eslint/brace-style': [warn, stroustrup, {allowSingleLine: true}]
spaced-comment: [warn, always, {markers: [':', '-', '+', '::', '/']}]
no-var: error
block-scoped-var: error
yoda: error
camelcase: [warn, {properties: never}]
comma-dangle: [off, never]
'@typescript-eslint/comma-dangle': [off, {arrays: only-multiline, objects: only-multiline}]
max-depth: [warn, 8]
arrow-parens: error
no-confusing-arrow: [error, {allowParens: false}]
dot-location: [error, property]
no-else-return: error
no-throw-literal: off
'@typescript-eslint/no-throw-literal': error
require-await: off
'@typescript-eslint/require-await': error
no-return-await: off
'@typescript-eslint/return-await': error
dot-notation: off
'@typescript-eslint/dot-notation': off
eol-last: [error, always]
newline-per-chained-call: [error, {ignoreChainWithDepth: 3}]
nonblock-statement-body-position: [warn, beside]
space-infix-ops: off
'@typescript-eslint/space-infix-ops': warn
semi-spacing: error
operator-assignment: [error, always]
object-shorthand: [error, properties, {avoidQuotes: true}]
no-process-exit: off
no-negated-condition: warn
no-constant-condition: [error, {checkLoops: false}]
prefer-destructuring:
- error
- VariableDeclarator: {array: false, object: true}
AssignmentExpression: {array: false, object: false}
- enforceForRenamedProperties: false
no-extra-parens: off
'@typescript-eslint/no-extra-parens': [warn, functions]
no-invalid-this: off
'@typescript-eslint/no-invalid-this': [off, {capIsConstructor: false}]
prefer-template: warn
semi: off
'@typescript-eslint/semi': [error, always]
'@typescript-eslint/explicit-function-return-type': [warn, {allowExpressions: true}]
'@typescript-eslint/method-signature-style': warn
'@typescript-eslint/no-implicit-any-catch': warn
'@typescript-eslint/prefer-includes': warn
'@typescript-eslint/prefer-nullish-coalescing': warn
'@typescript-eslint/prefer-optional-chain': warn
'@typescript-eslint/no-base-to-string': warn
'@typescript-eslint/non-nullable-type-assertion-style': warn
'@typescript-eslint/no-unnecessary-boolean-literal-compare': warn
'@typescript-eslint/prefer-readonly': warn
'@typescript-eslint/prefer-readonly-parameter-types': off
'@typescript-eslint/no-confusing-void-expression': [off, {ignoreArrowShorthand: true}]
'@typescript-eslint/explicit-member-accessibility':
- warn
- accessibility: 'explicit'
overrides:
constructors: 'no-public'
properties: 'explicit'
parameterProperties: 'explicit'
methods: 'no-public'
accessors: 'no-public'
no-multiple-empty-lines: [warn, {max: 2, maxEOF: 1}]
prefer-arrow-callback: warn
array-callback-return: [error, {allowImplicit: true}]
init-declarations: off
'@typescript-eslint/init-declarations': off
func-call-spacing: off
'@typescript-eslint/func-call-spacing': warn
default-param-last: off
'@typescript-eslint/default-param-last': warn
optimize-regex/optimize-regex: off
const-case/uppercase: off
import/no-unresolved: off
import/no-named-as-default: error
import/no-named-as-default-member: error
import/default: error
import/no-deprecated: warn
jest-formatting/padding-around-expect-groups: warn
jest/no-disabled-tests: off
array-plural/array-plural:
- off
- allows:
- ignore
- array
- list
- match
- count
- table
unicorn/no-keyword-prefix: [warn, {checkProperties: false}]
unicorn/prefer-array-some: warn
unicorn/prefer-default-parameters: warn
unicorn/prefer-array-index-of: warn
unicorn/prefer-regexp-test: warn
unicorn/consistent-destructuring: warn
unicorn/prefer-string-starts-ends-with: warn
'@typescript-eslint/prefer-string-starts-ends-with': warn
unicorn/numeric-separators-style: [error, number: {onlyIfContainsSeparator: true, minimumDigits: 3}]
unicorn/no-console-spaces: warn
unicorn/prefer-string-replace-all: warn
unicorn/prevent-abbreviations:
- warn
- replacements:
len: false
params: false
doc: false
pkg: false
ctx: false
i: false
j: false
idx: false
args: false
dir: false
checkFilenames: false
promise/catch-or-return: [error, {allowFinally: true}]
dollar-sign/dollar-sign: [warn, ignoreProperties]
no-useless-assign/no-useless-assign: warn
deprecate/function: warn
deprecate/member-expression: warn
deprecate/import: warn
'@delagen/deprecation/deprecation': warn
no-unsafe-regex/no-unsafe-regex: error
'@typescript-eslint/member-delimiter-style': warn
tsdoc/syntax: warn
no-loss-of-precision: off
'@typescript-eslint/no-loss-of-precision': error
no-magic-numbers: [off, {ignoreArrayIndexes: true, ignore: [0]}]
'@typescript-eslint/no-magic-numbers': [off, {ignoreArrayIndexes: true, ignore: [0]}]
promise/always-return: off
linebreak-style: [off, windows]
no-tabs: off
one-var: [off, always]
no-mixed-spaces-and-tabs: off
no-multi-spaces: off
no-plusplus: [off, {allowForLoopAfterthoughts: true}]
no-console: off
unicorn/filename-case: [off, {case: camelCase}]
node/no-missing-require: off
node/no-unpublished-require: off
node/no-unpublished-import: off
unicorn/throw-new-error: 0
unicorn/new-for-builtins: 0
unicorn/no-process-exit: 0
unicorn/prefer-query-selector: 0
unicorn/consistent-function-scoping: 0
unicorn/no-for-loop: 0
unicorn/no-useless-undefined: 0
unicorn/no-array-reduce: 0
security/detect-non-literal-fs-filename: 0
security/detect-object-injection: 0
unicorn/prefer-node-protocol: warn
'@typescript-eslint/interface-name-prefix': 0
indent: [off, tab]
'@typescript-eslint/indent': [off, tab]
no-use-before-define: off
'@typescript-eslint/no-use-before-define': off
'@typescript-eslint/no-non-null-assertion': off
sonarjs/cognitive-complexity: [warn, 50]
sonarjs/no-duplicate-string: [off, 6]
sonarjs/elseif-without-else: 0
sonarjs/no-nested-switch: 0
unicorn/better-regex: 0
unicorn/prefer-json-parse-buffer: 0
PactumJS supports global request settings which are applied to every request that is sent through this library. These global request settings can be overridden at spec
level.
const { request } = require('pactum');
request.setBaseUrl();
request.setDefaultHeaders();
In the similar terms, this library should support global expectations that are applied to all the responses received by this library.
const { response } = require('pactum');
response.setDefaultExpectResponseTime();
Add default global expectations
These expectations should be overridden at spec level as well.
const pactum = require('pactum');
const { response } = pactum;
response.setDefaultExpectResponseTime(1000);
it('should be a teapot', async () => {
await pactum.spec()
.get('http://httpbin.org/status/418')
.expectStatus(418);
// default expectation of response time is applied here
});
it('should not be a teapot', async () => {
await pactum.spec()
.get('http://httpbin.org/status/200')
.expectStatus(200)
.expectResponseTime(500);
// default expectation of response time is overridden here
});
Is your feature request related to a problem? Please describe.
Capture cookies as res.cookies
in stores
and returns
Describe the solution you'd like
stores('TOKEN', 'res.cookies.token')
inspect() method works only for single test case file
test files:
test/CreateHCF.js
test/CreateShifts.js
test/AssignShifts.js
Trigger command: mocha test/CreateHCF.js test/CreateShifts.js test/AssignShifts.js - it does not work in this case, request and response are not printed.
Trigger command:mocha test/CreateHCF.js - it works in this case, request and response are printed.
I want to store the access token to use this value later. I have :
const pactum = require('pactum');
const { Given, When, Then, Before } = require('@cucumber/cucumber');
Before(async () => {
await pactum
.spec()
.post('/credentials')
.withForm({
username: email,
password: passw,
})
.expectStatus(200)
.stores('token', 'access_token');
})
pactum.request.setDefaultHeaders('Authorization', 'Bearer $S{token}');
syntax '$S{token}' is a string, the next request is with "headers": {
"Authorization": "Bearer $S{token}"
},
what am I doing wrong?
I would like to know if I can use an XML payload with pactum
How can I use OAuth / ("Bearer " + token) authentication with Pactumjs, I can use basic username and password authentication just not find a way to use Auth0. Any help would be much appreciated.
Multipart requests combine one or more sets of data into a single body, separated by boundaries. You typically use these requests for file uploads and for transferring data of several types in a single request (for example, a file along with a JSON object).
To support Multipart requests, PactumJS is currently using form-data which is inspired from XMLHttpRequest-2 FormData Interface. form-data internally uses mimes-type package to auto set content-type for file uploads. The overall size of this package is above 300 kB.
PactumJS library strives to be as light as possible. The current size of PactumJS is above 800 kB. (37% of it is from form-data).
Instead of form-data, check if we can use multi-part-lite. This package size is just 20 kB.
PactumJS supports the following HTTP methods to perform a HTTP request.
This issue focuses on expanding the supported list of HTTP methods to TRACE
& OPTIONS
.
await pactum.spec()
.trace('url')
.expectStatus(200);
await pactum.spec()
.options('url')
.expectStatus(200);
Along with it, if a new HTTP method is available in the future then the users of this library should not be blocked by it. So the HTTP methods should be expandable. Introduce two new request making methods - withMethod
& withPath
that takes HTTP method & url as parameters.
await pactum.spec()
.withMethod('CONNECT')
.withPath('url')
.expectStatus(200);
TRACE
& OPTIONS
HTTP methods.request.spec.js
under test/component
folder.Originally posted by martynaol March 28, 2022
I want to store the access token to use this value later. I have :
const pactum = require('pactum');
const { Given, When, Then, Before } = require('@cucumber/cucumber');
Before(async () => {
await pactum
.spec()
.post('/credentials')
.withForm({
username: email,
password: passw,
})
.expectStatus(200)
.stores('token', 'access_token');
})
pactum.request.setDefaultHeaders('Authorization', 'Bearer $S{token}');
syntax '$S{token}' is a string, the next request is with "headers": {
"Authorization": "Bearer $S{token}"
},
what am I doing wrong?
Describe the bug
On your documentation website there is a reference to install cucumber using:
npm install @cucumber/cucumber -g
However, when you require the module later, you use require('cucumber')
, which generates and error.
To Reproduce
Steps to reproduce the behavior:
Check the documentation site, and I just noticed it is the same in the readme here (on github).
Expected behavior
The line should read const { Given, When, Then, Before } = require('@cucumber/cucumber');
Software (please complete the following information):
N/A
Additional context
Add any other context about the problem here.
Hi,
I'm trying to setup PactumJS with a Hapi project. I've written one small test test but I'm getting the following Typescript error/suggestion:
Removing 'await' causes the tests to pass all the time (even when they should fail if I change the expected result). So, await is clearly required but the linter is suggesting otherwise.
Steps to reproduce the behavior:
"dependencies": {
"@hapi/hapi": "^20.2.1"
},
"devDependencies": {
"@types/chai": "^4.3.0",
"@types/hapi__hapi": "^20.0.10",
"@types/mocha": "^9.1.0",
"@types/node": "^17.0.15",
"chai": "^4.3.6",
"mocha": "^9.2.0",
"nodemon": "^2.0.15",
"npm-run-all": "^4.1.5",
"pactum": "^3.1.3",
"ts-node": "^10.5.0",
"typescript": "^4.5.5"
}
and following tsconfig:
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"rootDir": "./src",
"outDir": "./lib",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
},
"exclude": [
"test"
]
}
import pactum from 'pactum';
it('should return 200', async () => {
await pactum.spec()
.get('http://localhost:4000/')
.expectStatus(200);
});
The await keyword does not throw an error but makes an incorrect suggestion that the await keyword is not required but it definitely is.
Expected behaviour
No Typescript suggestion to remove something that is required.
Software (please complete the following information):
This isn't a massive issue, I'm just worried that I / other devs will remove the await keyword and assume the tests are working as expected.
Is your feature request related to a problem? Please describe.
i would like to send some request signed with certificates(PEM/KEY). but i cant passed a the certificate.
Describe the solution you'd like
i would like to passe a certificate via file or string, and it send my request.
Is your feature request related to a problem? Please describe.
If you want to reuse the cookies from a previous request (or across multiple ones), you need to extract the cookies manually from the "set-cookie" from the first request (and from any request that might add a new cookie), and send it along with every subsequent request.
Describe the solution you'd like
It would be nice to be able to do something like:
const cookieJar = require('pactum').cookieJar();
await pactum.spec().get('/...').withCookieJar(cookieJar).expect(...);
await pactum.spec().post('/...').withCookieJar(cookieJar).expect(...);
await pactum.spec().post('/...').withCookieJar(cookieJar).expect(...);
cookieJar
should also have some utility methods to getCookie/setCookie
.
Maybe it also could be done automatically with a new setting pactum.request.setUseCookieJar(true);
that will make all requests made in the same test to use the same cookie jar. Not sure if it's even possible, but it would be nice :) You could override it for a specific request sending a new cookie jar, for instance.
Thanks! I hope it's not too much asking 🙏
Is your feature request related to a problem? Please describe.
After a number of hours, I realised my tests POSTing JSON are failing in Pactum because no content-length header is being sent.
Describe the solution you'd like
Either .withContentLength
or some kind of default. Why would someone not want content-length set automatically if JSON encoding is done automatically?
Describe alternatives you've considered
.withBody(someVar).withHeaders({'content-length': JSON.stringify(someVar).length})
Additional context
I feel like I must have missed something in the docs.
PactumJS supports retry mechanism where an user can define when to retry (strategy), how many times to retry & the delay between retries.
await pactum.spec()
.get('/some/async/operation')
.retry({
count: 2,
delay: 2000,
strategy: ({res}) => { return res.statusCode === 200 }
})
.expectStatus(200);
Enhance the retry mechanism to retry when there are expectation failures.
In the below test, if the endpoint returns a status code other than 202, PactumJS should retry the API request.
await pactum.spec()
.get('/api/endpoint')
.expectStatus(202)
.retry();
The retry logic should apply for other expectation failures as well.
Retry with default options
retry()
Retry with a custom retry count
retry(3);
Retry with a custom retry count & custom delay
retry(3, 5000);
I am using express-session when I signin I generate a cookie session, is there any example on how to store this cookie for future tests where you need to be signed in?
Describe the bug
Most expect methods print the request and response when the assertion fails.
However, the custom expect handler does not show these objects.
To Reproduce
Steps to reproduce the behavior:
const spec = pactum.spec();
spec.get(url);
await spec.toss();
await spec.response().to.have._((ctx) => {
assert.fail('error');
});
Expected behavior
It should show the request and response as other methods do.
Software (please complete the following information):
Is your feature request related to a problem? Please describe.
During component testing, we use useInteraction
to have expectations on the external calls. Same expectations are applied for multiple specs. Some micro-services will cache the response and that makes component tests to remove the cached response from cache server.
Describe the solution you'd like
useInteraction
supports a new boolean property called cache
will have the expectation exercised only once in the entire component testing cycle.
Describe alternatives you've considered
May be expectations would support the call count to be either 0
or 1
.
Interaction handlers are a way to reuse interactions across your test cases. With the current setup, we can only return one interaction in the callback function.
const { addInteractionHandler } = require('pactum').handler;
addInteractionHandler('get users', () => {
return {
request: {
method: 'GET',
path: '/api/users'
},
response: {
status: 200
}
}
});
Enhance the addInteractionHandler
function to return multiple interactions.
const { addInteractionHandler } = require('pactum').handler;
addInteractionHandler('get users with id 1 & 2', () => {
return [
{
request: {
method: 'GET',
path: '/api/users/1'
},
response: {
status: 200,
body: { "id": 1 }
}
},
{
request: {
method: 'GET',
path: '/api/users/2'
},
response: {
status: 200,
body: { "id": 2 }
}
}];
});
addInteractionHandler
function should support multiple interactionsA declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.