I am trying to call a graphql and get the data from cookies, it runs well in postman app. However when I trying to run this postman collection on the command line with Newman
In terminal:
newman run postman_collection.json -e environment.json
then it gave me the error
[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block,
or by rejecting a promise which was not handled with .catch().
The promise rejected with the reason "TypeError: CookieJar.getAll() requires a callback function".]
{
code: 'ERR_UNHANDLED_REJECTION'
}
And the Test script code is like this
pm.test("Get a test data", function () {
const jsonData = pm.response.json();
pm.expect(jsonData.data.createTest.success).to.eql(true);
});
pm.test("Test data cookies set", async function () {
const cookieJar = pm.cookies.jar();
const url = pm.environment.get("service-url");
const cookies = await cookieJar.getAll(url);
const cookieNames = cookies.map(cookie => cookie.name);
pm.expect(cookieNames).to.include("test-token");
pm.expect(cookieNames).to.include("legacy-test-token");
});
So I assume the error is because getAll() requires a callback function, Do you know what I'm doing wrong? How can I improve it, Can you help me solve this? Many thanks
'it runs well in postman app' --> I doubt it. I tried and it always passed.
I added a callback, also changed a setting Whitelist Domain in Postman GUI.
pm.test("Test data cookies set", function () {
const cookieJar = pm.cookies.jar();
const url = pm.environment.get("service-url");
cookieJar.getAll(url, (error, cookies)=> {
if(error) console.log(error);
const cookieNames = cookies.map(cookie => cookie.name);
pm.expect(cookieNames).to.include("test-token");
pm.expect(cookieNames).to.include("legacy-test-token");
});
});
Related
Next JS. I am trying to set some cookies in my /api/tokencheck endpoint. Here is a very simplified version of the code:
import { serialize } from 'cookie';
export default (req, res) => {
/* I change this manually to simulate if a cookie is already set */
let cookieexists = 'no';
async function getToken() {
const response = await fetch('https://getthetokenurl');
const data = await response.json();
return data.token;
}
if (cookieexists === 'no') {
getToken().then((token) => {
res.setHeader('Set-Cookie', serialize('token', token, { path: '/' }));
});
return res.status(200).end();
} else {
return res.status(200).end();
}
};
I have tried a ton of variations as to where to put my return.res.status... code, and tried many different ways to return a success code, but depending on where I put the code I variously end up with either of the following errors:
"API resolved without sending a response for /api/checkguestytoken, this may result in stalled requests."
or
"unhandledRejection: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client"
I seem to have some gap in my knowledge about how the API works in Next JS because I cannot figure out how to just run the async function, get a result, set a couple of cookies and then exit with a 200. Could someone please tell me what I'm doing wrong?
I am using Postman to call API. I have a couple to call, so I made a collection and I am able to run it.
I am trying to get the results of the API saved in a file (JSON is fine) and then everytime I call the API, to get the file updated. It is possible to automatically save a response for each API call?
Could you please how can I do it? I have tried with newman, but I`m not being succesful. Thank you.
Managed to get results in JSON files, although I have to update it manually. Followed this video on Youtube and this is the code in .js (if helps anyone in the future)
const newman = require('newman'); // require newman in your project
const fs = require('fs');
// call newman.run to pass `options` object and wait for callback
newman.run({
collection: require('./name_of_postman_collection.json'),
reporters: 'cli'
}).on('beforeRequest', (error, data) => {
if (error) {
console.log(error);
return;
}
console.log(data);
})
.on('request', (error, data) =>{
if (error) {
console.log(error);
return;
}
const fileName = `response ${data.item.name}.json`;
const content = data.response.stream.toString();
fs.writeFile(fileName, content, function (error) {
if (error) {
console.error(error);
}
});
});
I am still trying to find out how to automate the process, to get refreshed files every 2-3 hours for example.
I have added a command getCSRFToken that is used by other commands to get the CSRF token for making requests to my app:
Cypress.Commands.add("getCSRFToken", () => {
cy.getCookie('XSRF-TOKEN').then((cookie) => {
if (!cookie) {
return cy.request('HEAD', '/')
.its('headers')
.then((headers) => {
const token = headers['x-xsrf-token'];
if (!token) {
throw new Error('XSRF token not found');
}
return cy.setCookie('XSRF-TOKEN', token)
.then(() => token);
});
}
return cookie.value;
});
});
The portion that makes a HEAD request is for usage of this function when no pages have yet been visited in the test, for example when making POST requests to create test data.
AFAICT this looks like it should work to me, however it seems subsequent calls to getCookie doesn't actually retrieve anything:
I thought returning the setCookie promise and getCookie promise might make a difference but it does not seem like that is the case.
By default, Cypress clears up all cookies before every test is run. They have an api to keep a cookie for the next test execution which is Cypress.Cookies.preserveOnce
Back to your use case, you can call Cypress.Cookies.preserveOnce('XSRF-TOKEN') in the suite-level beforeEach in every suite where you want to get the token. If you don't want to repeat the call, you can move it inside your getCSRFToken command.
Cypress.Commands.add("getCSRFToken", () => {
Cypress.Cookies.preserveOnce('XSRF-TOKEN')
cy.getCookie('XSRF-TOKEN').then((cookie) => {
.....
});
});
I'm trying to define a function that sends a request in a collection Pre-Request scripts:
const doRequest = (callback) => {
const echoPostRequest = {
url: 'https://postman-echo.com/post',
method: 'POST',
header: 'headername1:value1',
body: {
mode: 'raw',
raw: JSON.stringify({ key: 'this is json' })
}
};
console.log('ready to send request');
pm.sendRequest(echoPostRequest, function (err, res) {
console.log('request sent', err ? err : res.json());
callback();
});
}
glbl = {
doRequest: doRequest
}
Then, in my main test (a simple GET to google), I have this in Pre-Request script:
glbl.doRequest(() => console.log('works!'));
However, the callback is never called, and the "request sent" log is never printed.
This is the output of my postman console:
ready to send request 11:58:02.257
GET http://www.google.com 11:58:02.262
Do you know what I'm doing wrong?
I can provide the exported collection as well if it helps.
Thanks!
Edit: it I move everything in the Pre-request scripts of the request (not the collection), everything works fine
There's a few things happening here.
Local scoping issues
Your glbl variable is missing a var, const or let keyword.
Missing this keyword does not cause the variable to bubble up and become global on it's own. The environment Pre-request Script and request Pre-request Script are of different scopes.
As you've experienced, when you move the script to solely the request level, everything is sitting in the same scope so this works fine.
Creating global functions
Postman has the facility to create your own global variables. This can be done programmatically through pm.globals.set and pm.globals.get.
https://www.getpostman.com/docs/v6/postman/environments_and_globals/variables#accessing-variables-through-scripts
There are some limitations to these variables: you can only store strings in them, so the object and function that you've created will not persist if we don't do something to change their type.
In this case before we set any variables we need to ensure we:
toString any functions
JSON.stringify any objects
Now the Pre-request script for our collection will look like:
const doRequest = (callback) => {
const echoPostRequest = {
url: 'https://postman-echo.com/post',
method: 'POST',
header: 'headername1:value1',
body: {
mode: 'raw',
raw: JSON.stringify({ key: 'this is json' })
}
};
console.log('ready to send request');
pm.sendRequest(echoPostRequest, function (err, res) {
console.log('request sent', err ? err : res.json());
callback();
});
};
const glbl = {
doRequest: doRequest.toString()
};
pm.globals.set('glbl', JSON.stringify(glbl));
In order to use this at a request level, we need to update our Pre-request Script there too:
const glbl = JSON.parse(pm.globals.get('glbl'));
const doRequest = eval(glbl.doRequest);
doRequest(() => console.log('works!'));
After several tests I found a very ugly hack to export JS objects from a pre-request script to an other.
Of curse you have to ensure that the script that expose values is called before the module that uses the exported stuff.
The hack came from the following considerations:
You can't export js values other than string in postman, but you can add properties in the modules exposed by nodejs, so I imported the "util" module of nodejs and injected stuff there.
const util = require("util");
util.myExport = {
myMethod(){
// ...
}
};
The pm object exposed is different in each script executed by postman (require("util").myExport.pm === pm returns false if require("util").myExport.pm was defined in another module), and only the current one can perform operation, so if I want to use pm in some of the exported method, I have to pass a reference of the current pm object. otherwise no method can be invoked.
const util = require("util");
util.myExport = {
myMethod(_pm){ // note that `_pm` is the reference passed here,
_pm.sendRequest(/*...*/) // otherwise this line wont work
}
};
If you define an asynchronous function (such as a wrapper for setTimeout), it wont open the new process (nor thread, as well as with Promise or async/await functions) unless you use the properties exposed in the caller module. So you can not perform asynchronous operation if you are not using the current module stuff.
const util = require("util");
util.myExport = {
myMethod(scope){
scope.setTimeout(() => { // async function from the caller module
scope.pm.sendRequest(/*...*/) // pm from the caller module
}, 9999)
}
};
Now you are ready to go! Just import the nodejs "util" module to have your functions in the current module, then you can call them as usual.
const util = require("util");
util.myExport.myMethod(this)
I'm using axios 0.18.0, jest 22.4.2 and I'm trying to test a simple request using Axios and Jest based on the Axios documentation example and Jest Async / Await documentation
// services.js
import axios from 'axios';
export const getUser = () => axios.get('https://api.github.com/users/mzabriskie');
// services.spec.js
import { getUser } from './services';
it('should return data from github user', async () => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
const result = await getUser();
console.log('RESULT -->', result);
});
Once the DEFAULT_TIMEOUT_INTERVAL is passed (in this example 30 seconds), the test gives the following error message:
Error: Timeout - Async callback was not invoked within timeout
specified by jasmine.DEFAULT_TIMEOUT_INTERVAL
And it never reaches the console.log statement.
Any idea what I might be missing here or how to debug this?
So it turns out that the problem was using the dependency jest-mock-axios which it seems once it's configured it never allows HTTP requests to go through in the tests, even if you are not using it in a specific test (like in the original question example).
So in order to fix this all related requests tests must have defined mocks in order to work (or else remove the jest-mock-axios dependency entirely if you wish to test real API requests).