Postman how to export api response from collection runner with iteration to a file using node script - postman-collection-runner

I am completely new to writing node scripts in Postman.
My requirement:
I have an api to get user details. I want to iterate for n number of users. I created a Runner collection and it executes. But i want to write each request response to a file.
Can anyone help me how to do this?
I watched some youtube video https://www.youtube.com/watch?v=cCRmry10874 for this. But my case is i have runner collection with data file.
When i exported the collection, i dont get the different values from data file.
const newman = require('newman');
newman.run({
collection: require('./collection.json'),
reporters: 'cli'
}, (err) => {
if(err) { throw err; }
console.log('collection run complete');
});
const fs = require('fs');
fs.writeFile('response.txt', 'Some text', (error) => {
if(error) {
console.error(error);
}
})
Thanks

Can you try it?
newman.run(
{
collection: require("./collection.json"),
reporters: "cli",
iterationData: "./data.json",
},
(err, summary) => {
if (err) {
throw err;
}
const results = summary.run.executions;
results.forEach((result) => {
fs.appendFileSync("response.txt", result.response.text());
});
}
);

If you are not limited to using a textfile, I would suggest using htmlextra.
It provides an HTML webpage with your runs and response body.

Related

Pre-scan web page for dynamic tests

Looking for a definitive answer to the question posed by #JeffTanner here about generating dynamic tests. From that question and the Cypress samples, it's clear that we need to know the number of tests required before generating them.
Problem
We have a web page containing a table of Healthcare analytic data that is refreshed many times during the day. Each refresh the team must check the data, and to divvy up the work we run each row as a separate test. But the number of rows varies every time which means I must count the rows and update the system on each run. Looking for a way to programmatically get the row count.
The HTML is a table of <tbody><tr></tr></tbody>, so the following is enough to get the count but I can't run it in a beforeEach(), the error thrown is "No tests found"
let rowCount;
beforeEach(() => {
cy.visit('/analytics')
cy.get('tbody tr').then($els => rowCount = $els.length)
})
Cypress._.times(rowCount => {
it('process row', () => {
...
})
})
The before:run event fires before the tests start, you can scan the web page there.
Set the event listener in setupNodeEvents(). Cypress commands won't run here, but you can use equivalent Node commands.
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('before:run', async (details) => {
try {
const fetch = require('node-fetch');
const fs = require('fs-extra');
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const response = await fetch(config.env.prescan); // default below
const body = await response.text(); // or pass in command line
const dom = new JSDOM(body);
const rows = dom.window.document.body.querySelectorAll('tr') // query
// save results
fs.writeJson('./cypress/fixtures/analytics-rows.json', {rows:rows.length})
} catch (error) {
console.log('error:', error)
}
})
},
},
env: {
prefetch: 'url-for-analytics-page'
}
})
Test
import {rows} from './cypress/fixtures/analytics-rows.json' // read row count
Cypress._.times(rows, (row) => {
it(`tests row ${row}`, () => {
...
})
}
You can add a script scan-for-rows.js to the project scripts folder, like this
const rp = require('request-promise');
const $ = require('cheerio');
const fs = require('fs-extra');
rp('my-url')
.then(function(html) {
const rowCount = $('big > a', html).length
fs.writeJson('row-count.json', {rowCount})
})
.catch(function(err){
//handle error
});
Then in package.json call a pre-test script every time a new version of the web page appears.
One possibility is to run the above Cypress test in a pretest script which will always run before your main test script.
// package.json
{
...
"scripts": {
"pretest": "npx cypress run --spec cypress/e2e/pre-scan.cy.js",
"test": "npx cypress run --spec cypress/e2e/main-test.cy.js",
}
}
// pre-scan.cy.js
it('scans for table row count', () => {
cy.visit('/analytics');
cy.get('tbody tr').then($els => {
const rowCount = $els.length;
cy.writeFile('cypress/fixtures/rowcount.json', rowCount);
});
});
Here's a way to get the row count in the spec file without using extra packages, plugins, test hooks, or npm scripts.
Basically, you can create a separate module that makes a synchronous HTTP request using the XMLHTTPRequest class to the /analytics endpoint and use the browser's DOMParser class to find the return the number of <tr> tags.
// scripts/get-row-count.js
export function getRowCount() {
let request = new XMLHttpRequest();
// Set async to false because Cypress will not wait for async functions to finish before looking for it() statements
request.open('GET', '/analytics', false);
request.send(null);
const document = new DOMParser().parseFromString(request.response, 'text/html');
const trTags = Array.from(document.getElementsByTagName('tr'));
return trTags.length;
};
Then in the spec file, import the new function and now you can get an updated row count whenever you need it.
import { getRowCount } from '../scripts/get-row-count';
Cypress._.times(getRowCount() => {
it('process row', () => {
...
})
})
The reason for XMLHTTPRequest instead of fetch is because it allows synchronous requests to be made. Synchronous requests are needed because Cypress won't wait for async requests to come back before parsing for it() blocks.
With this, you always have the most up to date row count without it going stale.

How to run the single test with different data set in parallel by using cypress on single machine

I just have the below Test.json file in the fixture folder:
[
{
"searchKeyword":"cypress"
},
{
"searchKeyword":"QA automation"
},
{
"searchKeyword":"stackoverflow"
}
]
The above file contains three different dataset.
I just have the below spec file and It contains one It (Test case) and It will run multiple times based on the above input.
Test.spec.js file:
describe("Run the test parallel based on the input data",() =>{
const baseUrl = "https://www.google.com/";
before("Login to consumer account", () => {
cy.fixture('Test').then(function (data) {
this.data = data;
})
});
it("Search the keyword", function () {
this.data.forEach((testData) =>{
cy.visit(baseUrl);
cy.xpath("//input[#name='q']").type(testData.searchKeyword);
cy.xpath("//input[#value='Google Search']").click();
cy.get("//ul/li[2]").should("be.visible");
});
});
});
The above code is working as expected. But I just want to run the above single test parallelly by using different dataset.
Example: Three browser instance open and it should pick three different data from the Test.json file and run the single test which is available in the Test.spec.js file.
I just need logic to implement for one of my project, But I'm not able to share the code which is more complex that's reason just create some dummy test data and test script to achieve my logic.
Can someone please share yours thoughts to achieve this.
One way to run multiple instances of Cypress in parallel is via the Module API, which is basically using a Node script to start up the multiple instances.
Node script
// run-parallel.js
const cypress = require('cypress')
const fixtures = require('./cypress/fixtures/Test.json')
fixture.forEach(fixture => {
cypress.run({
env: {
fixture
},
})
})
Test
describe("Run the test for given env data",() =>{
const testData = Cypress.env('fixture')
...
it("Search the keyword", function () {
cy.visit(baseUrl);
cy.xpath("//input[#name='q']").type(testData.searchKeyword);
...
});
});
Awaiting results
cypress.run() returns a promise, so you can collate the results as follows
Videos and screenshots are troublesome, since it tries to save all under the same name, but you can specify a folder for each fixture
const promises = fixtures.map(fixture => {
return cypress.run({
config: {
video: true,
videosFolder: `cypress/videos/${fixture.searchKeyword}`,
screenshotsFolder: `cypress/screenshots/${fixture.searchKeyword}`,
},
env: {
fixture
},
spec: './cypress/integration/dummy.spec.js',
})
})
Promise.all(promises).then((results) => {
console.log(results.map(result => `${result.config.env.fixture.searchKeyword}: ${result.status}`));
});

error Policy in Apollo Client React does'nt work

I have aproblem when test Apollo.When I try query with apollo and graphql, i want response return error and partical data, so I set property errorPolicy:'all'. But its not work. I don't no why? Help please!
Here my code:
query { animal {
name
age }, school {
name
numberfd } } `
const { loading,data,error} = useQuery(GET_DASHBOARD_DATA, {
errorPolicy:'all',
onCompleted: (res) => {console.log("complete",res)},
onError : (res,data) => {console.log("ERRRR",res,data)},
})
and i want to receive:
{
error:[...], data:[animal:[...]] }
but its only response error.Here is Apollo's doc: https://www.apollographql.com/docs/react/data/error-handling/
onError type is onError?: (error: ApolloError) => void;. You don't have data inside onError callback.
After useQuery you can add:
console.log('data', data)
console.log('error', error)
I faced the same issue with errorPolicy: 'all', I only received the partial result inside onCompleted callback of useQuery, but no errors.
I created an ErrorLink like this:
private createErrorLink = () => {
return new ApolloLink((operation, forward) => {
return forward(operation).map((response) => {
// filter out errors you don't want to display
const errors = filterSomeErrors(response.errors);
if (errors && response?.data) {
response.data.errors = errors;
}
return response;
});
});
};
Now inside my onCompleted callback I get my data as well as errors. You will have to tweak your types a bit, because seems there is no errors field on response.data by default.
Mind that if you use onError from Apollo and return something from the link, it will retry your request containing errors!

How to stub a call to graphql using cypress?

I'm writing a Vue app that uses vue-apollo to interact with graphql. I'm wondering if it's possible to stub the graphql requests. I thought this should work:
it('should access a story', function() {
cy.server();
cy.route('http://localhost:3002/graphql', {
data: {
Story: { id: 2, title: 'story title', content: 'story content' }
}
});
cy.visit('/stories/2');
});
Unfortunately, I get an error from graphql complaining that id is an Int instead of an ObjectId. Am I missing something?
The problem was that stubbing fetch requests isn't yet implemented in Cypress (which is what Vue Apollo is using). I ended up following these instructions:
Install github/fetch
Add this to cypress/support/index.js:
.
Cypress.on('window:before:load', win => {
win.fetch = null;
win.Blob = null;
});
Now it works!
I got it working with this package here:
npm i #iam4x/cypress-graphql-mock
Add this line to 'support/commands.js'
import "#iam4x/cypress-graphql-mock";
go to your graphiql playground and download your schema
add task command to 'plugins/index.js' (REMEMBER TO CHANGE PATH TO SCHEMA FILE YOU DOWNLOADED EARLIER)
module.exports = (on, config) => {
on("task", {
getSchema() {
return fs.readFileSync(
path.resolve(__dirname, "../../../schema.graphql"),
"utf8"
);
}
});
};
write your tests with loaded schema
beforeEach(() => {
cy.server();
cy.task("getSchema").then(schema => {
cy.mockGraphql({
schema
});
});
});`
describe("Login Form", () => {
it("should redirect after login", () => {
cy.mockGraphqlOps({
operations: {
Login: {
login: {
jwt: "some-token",
user: {
id: "5d5a8e1e635a8b6694dd7cb0"
}
}
}
}
});
cy.visit("/login");
cy.getTestEl("email-input").type("Max Mustermann");
cy.getTestEl("password-input").type("passwort");
cy.getTestEl("submit").click();
cy.getTestEl("toolbar-title").should("exist");
});
})
Visit the original repo for further explanation as i find it less confusing. The package you have installed is just a working fork of this one:
https://github.com/tgriesser/cypress-graphql-mock

Back-end tests with elasticsearch fails without setTimeout

I am writing tests for back-end which uses MongoDB and Elasticsearch. The problem is that without wrapping test with setTimeout test fails, and it looks like elasticsearch can't index mock data into db before test. Here is the code:
let elasticSearch = require('elasticsearch');
let elasticClient = new elasticSearch.Client({
host: 'localhost:9200'
});
let app = require('./dist/app'); //path to my application
let supertest = require('supertest');
before((done) => {
elasticClient.index(elasticMockData, function() {
done();
});
});
beforeEach(() => {
request = supertest(app);
});
it('should get data from elastic', () => {
setTimeout(() => { // if I comment this timeout, test will fail
request.get('/api/elastic')
.end((err, res) => {
expect(res.body.hits.hits.length).not.to.equal(0);
})
}, 1000); // if I comment this timeout, test will fail
});
I think you will agree that timeout is not an elegant and nice solution, which slows every test to 1 second or more. Maybe, am I missing something?
Found a solution, maybe it will be useful for someone.
According to Elasticsearch docs:
By default, the document will be available for get() actions immediately, but will only be available for searching after an index refresh (which can happen automatically or manually).
So, in this case, done() should be called within another callback function:
before((done) => {
elasticClient.index(elasticMockData, function() {
elasticClient.indices.refresh(function (err: any, res: any) {
if (err) {
return;
}
done();
});
});
});

Resources