pactumjs / pactum

REST API Testing Tool for all levels in a Test Pyramid
https://pactumjs.github.io
MIT License
538 stars 52 forks source link

Handling HTTP methods using Axios NPM library for secured servers? #311

Closed rkanil closed 6 months ago

rkanil commented 7 months ago

Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

I have an application that can be accessed via 'axios' npm library only. Axios provides HTTP requests. I tried using the regular library provided by Pactum and it did not work.

Describe the solution you'd like A clear and concise description of what you want to happen.

If you can implement Axios library into your 'GET', 'POST', 'PUT', 'PATCH' and other methods that would really help solve the problem. The Axios HTTP request can be in addition to the existing 'Fetch' implementation that can use a different implement of spec ( ).

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

If you can point me to the file that you used to make the HTTP requests such as 'GET', 'POST', 'PUT' and others, I can look and try to help update.

Additional context Add any other context or screenshots about the feature request here.

leelaprasadv commented 7 months ago

Hey @rkanil, PactumJS's built-in lightweight http client is like any other http client (axios, fetch, postman etc). If you are able to make a call with axios you should be able to make API calls via any client (provided proper request details are included).

I would like to understand more about the issue, can you maybe share additional details on the issue?

rkanil commented 7 months ago

Hi @leelaprasadv,

pactum.spec().post(method, endpoint) throws the error, in fact all the HTTP method throw the error and unable to communicate with the server. I ensured all the port connection calls are available, as Postman and thunderclinet work fine. Also, when i use the https://reqres.in sample website it works fine without the TLSSocket error, only when accessing my server pactum throws the error.

Step definition file: const pactum = require('pactum'); const { Given, When, Then, Before, After } = require ('@cucumber/cucumber'); let spec = pactum.spec(); Before (() => { request.setBaseUrl('https://');});

Given (I make a /^(.) request to (.)$/, function (method, endpoint) { specmethod.toLowerCase();});

Axios access that works on my server: const {default: axios} = require('axios'); const https = require('https')

const agent = new https.Agent({rejectUnauthorized: false,}); let body = {username: "uname", password:"password"}

const res = axios.post('', body, {httpsAgent: agent}); res.then(function(result){ console.log(result.data.value)});

So, it works with Axios but not with Pactum HTTP method implementation, and the error is observed only when accessing my server, the external server work fine. There are no security or cookies set when accessing my server via Postman or Thunderclient. please review and suggest. We can talk if that's ok with you.

leelaprasadv commented 7 months ago

@rkanil , The reason it works with above axios code is because you are disabling tls validations. Which is not recommended for security reasons, instead you should try getting the certs for the agent (as required). There seems something wrong with this private server ssl certs, maybe check that?

If you still trust this private server, you can go ahead and do the same with pactumJS as well i.e., adding user agent configuration.

Here is a working example in this PR https://github.com/pactumjs/pactum/pull/293

Please note that in the above example it was disabled because it was a local demo https server.

Read more about the core agent config here https://pactumjs.github.io/api/requests/withCore.html#withcore

rkanil commented 7 months ago

Hi @leelaprasadv,

That worked - setting the https agent like: const agent = new https.Agent({ rejectUnauthorized: false // Ignore self-signed certificate errors }); it('POST - Get value', async () => { await pactum.spec() .post('https://myserver/api/login') .withCore({agent: agent }) .expectStatus(200) });

Now wondering - how i can use this in a feature file - scenario here is my feature file Feature file: Feature: login Scenario: Get value Given I make POST request to /login And I set body to """ { "username": "uname", "password": "password" } """ When I receive a response Then I expect response should have a status 200

My Step definition file is: const pactum = require('pactum'); const { Given, When, Then, Before, After } = require ('@cucumber/cucumber'); let spec = pactum.spec();

Before (() => { request.setBaseUrl('https://');});

Given (I make a /^(.) request to (.)$/, function (method, endpoint) { specmethod.toLowerCase();});

please review and suggest.

leelaprasadv commented 7 months ago

Please check https://github.com/pactumjs/pactum-cucumber-boilerplate https://pactumjs.github.io/introduction/test-style.html#test-style for sample BDD Style tests.

Just add spec.withCore(...) in you step definitions appropriately based on your test setup.

rkanil commented 7 months ago

@leelaprasadv Thank you. It worked, I added the spec.withCore ({agent: agent}) in the step definition file of the pactum-cucumber-boilerplate project, like this Before (()=> { spec = pactum.spec(); spec.withCore({agent:agent})

However, when I try to print the response output using a step defintion and feature 'Then' statement getting error

New Step Definition in steps.js file

Then("I print the output", function (){
const bearerToken = spec.response().json //<< this step is unclear to me on how to get the response body value
console.log(bearerToken)
})

in Feature file scenario i gave the step as

`Scenario: Get Bearer Token
Given I make a POST request to /api/v5/login
And I set body to 
"""
{
"username": "xxx"
"password":"yyy"
}
""""
When I receive a response
Then I expect response should have a status 200
And I store response at data.accessToken as bearerToken << here also the 'data.accessToken' parameter is returning null from the json output
Then I print the output`

my response output from postman looks like this { "accessToken": "xxxxxxxxx", "expires: 01102024-10" } wondering, how i can access the accessToken and print it to console log and also store to a variable?