I'm writing test in Postman and I have multiple requests grouped like this:
Some test title:
Create a user (set of "pre-requests"):
sending a few requests required to create a user, necessary to run tests
Some action on a created user (here I'm testing what is in the test title)
one or more requests
Another test title:
Create a user (set of "pre-requests", the same as in test 1.):
sending a few requests required to create a user, necessary to run tests
Some action on a created user (not related ot test 1.)
one or more requests
To summarize I need to create a user before every request when I want to test something.
My question - How can I re-use "Create a user" set of requests without copying it?
This is how you can re-use the set of requests in pre-testcases and Test by setting environment variable and call it using eval function
pre-test case -
var Create_a_user = () => {
pm.sendRequest("http://mocktarget.apigee.net/json", function(err, res) {
tests["Status code is 200"] = pm.expect(res).to.have.property('code', 200);
console.log('firstName',res.json().firstName);
});
pm.sendRequest("http://mocktarget.apigee.net/json", function(err, res) {
tests["Status code is 200"] = pm.expect(res).to.have.property('code', 200);
console.log("lastName - "+ res.json().lastName);
});
pm.sendRequest("http://mocktarget.apigee.net/json", function(err, res) {
tests["Status code is 200"] = res.code === 200;
console.log("city - "+ res.json().lastName.city);
});
};
pm.environment.set("Create_a_user", Create_a_user.toString());
Test -
eval(pm.environment.get("Create_a_user"))();
output -
firstName - John
lastName - Doe
city - San Jose
Disclaimer -
Use Eval function carefully, it may fizzled up your code or its execution.
If i'm understanding correctly what you want is unfortunately not currently supported. I've been waiting on this feature a while myself.
https://github.com/postmanlabs/postman-app-support/issues/1535
Related
I'm trying to use postman for some basic API security tests and I have this URL:
http://example.com/api/v1/users/{{userID}}
{{userID}} is set to some user on site, and I want to set three tests that check if request is valid, if request has IDOR and if request has SQL injection.
This is the idea:
// userID is set to 20 ( valid user )
pm.test("Initial valid request", function () {
pm.expect(pm.response.text()).to.include("Peter"); });
*CHANGE THE VALUE OF {{userID}} to 30 to test for IDOR*
* URL should be set to http://example.com/api/v1/users/30 *
pm.test("IDOR protection valid", function () {
pm.expect(pm.response.text()).to.include("User not found."); });
*CHANGE THE VALUE OF {{userID}} to 20'or'1 to test for SQL injection*
* URL should be set to http://example.com/api/v1/users/20'or'1 *
pm.test("SQL injection test", function () {
pm.expect(pm.response.text()).to.include("You have an error"); });
My question is how do I change the values of {{userID}} so that next request uses changed value and not the one from environment variables.
Thanks
From the docs:
Tests will execute after the request runs
So each test will run based on the one request. So doing something like the following in your test
pm.collectionVariables.set('userID', 'IDOR*')
// or
pm.variables.set('userID', 'IDOR*')
Won't have the effect you're after as it doesn't make a request per test.
One potential way to solve this would be to have multiple requests, all of which have set the different variable values in the Pre-request Script. As an example, you might have a request that looks like this:
And then the related test:
I need to make requests to an API that accepts authentication tokens and I want to be able to use a dynamically generated token by running cmd.exe /c GenerateToken.bat instead of having to run my program and then manually paste the value in Postman every time.
I imagine something that looks like this:
How can I set the value of a HTTP header to contain the stdout output of a program or a batch file?
Short answer is, you can't. This is deliberate, both pre-request and test scripts (the only way, other than a collection runner, to make your environment dynamic) run in the postman sandbox, which has limited functionality.
More information of what is available is in the postman-sandbox Github repository page and in postman docs (scroll to the bottom to see what libraries you can import)
You do have a few options, as described in comments - postman allows sending requests and parsing the response in scripts, so you can automate this way. You do need a server to handle the requests and execute your script (simplest option is probably a small server suporting CGI - I won't detail it here as I feel it's too big of a scope for this answer. Other options are also available, such as a small PHP or Node server)
Once you do have a server, the pre-request script is very simple:
const requestOptions = {
url: `your_server_endpoint`,
method: 'GET'
}
pm.sendRequest(requestOptions, function (err, res) {
if (err) {
throw new Error(err);
} else if (res.code != 200) {
throw new Error(`Non-200 response when fetching token: ${res.code} ${res.status}`);
} else {
var token = res.text();
pm.environment.set("my_token", token);
}
});
You can then set the header as {{my_token}} in the "Headers" tab, and it will be updated once the script runs.
You can do something similar to this from Pre-request Scripts at the collection level.
This is available in postman for 9 different authorization and authentication methods.
this is a sample code taken from this article, that show how to do this in Pre-request Scripts for OAuth2
// Refresh the OAuth token if necessary
var tokenDate = new Date(2010,1,1);
var tokenTimestamp = pm.environment.get("OAuth_Timestamp");
if(tokenTimestamp){
tokenDate = Date.parse(tokenTimestamp);
}
var expiresInTime = pm.environment.get("ExpiresInTime");
if(!expiresInTime){
expiresInTime = 300000; // Set default expiration time to 5 minutes
}
if((new Date() - tokenDate) >= expiresInTime)
{
pm.sendRequest({
url: pm.variables.get("Auth_Url"),
method: 'POST',
header: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': pm.variables.get("Basic_Auth")
}
}, function (err, res) {
pm.environment.set("OAuth_Token", res.json().access_token);
pm.environment.set("OAuth_Timestamp", new Date());
// Set the ExpiresInTime variable to the time given in the response if it exists
if(res.json().expires_in){
expiresInTime = res.json().expires_in * 1000;
}
pm.environment.set("ExpiresInTime", expiresInTime);
});
}
We have a lot of API level automated tests written as collections of requests in Postman.
We have a script to run all collections in automated manner.
Is there a way to label/run only subset of requests e.g. with some label e.g. as smoke suite, without copying requests to new collection(s) and run then explicitly (as this yields the need to maintain same tests in 2 places...)?
There might be labels, groups or some script that skips the request is env variable is set...
you can create folders and organize test like
smoke_and_regression
smoke_only etc
you can specify which folder to run using --folder arguent when using newman as command line tool
you can also control the execution flow using postman.setNextRequest .
and also you can run newman as an npm module.
you just need to write a logic to read the collection file and get all folder names containing "smoke" for eg and pass it as an array
const newman = require('newman'); // require newman in your project
// call newman.run to pass `options` object and wait for callback
newman.run({
collection: require('./sample-collection.json'),
reporters: 'cli',
folder: folders
}, function (err) {
if (err) { throw err; }
console.log('collection run complete!');
});
Just update for the comments:
in old and new UI you can select which folder to execute in collection runner
Get all requests in the collection:
you can also get information about all the requests in a collection by using :
https://api.getpostman.com/collections/{{collection_UUID}}
to get uuid and api key goto :
https://app.getpostman.com
Now for generating api key >
goto account settings > api key and generate api key.
to get collection uuid goto specific workspace and collection and copy the uuid part from url:
Now in your collection
Rename all requests as:
get user details [Regression][Smoke][Somethingelse]
get account details [Regression]
Then Create a new request called initial request and keep it as the first request in your collection:
url: https://api.getpostman.com/collections/8xxxxtheuuidyoucopied
authorization: apikey-header : key: X-Api-Key and value: yourapikey
test-script :
pm.environment.unset("requestToRun")
reqeustlist = pm.response.json().collection.item.map((a) => a.name)
requestToRun = reqeustlist.filter((a) => a.includes(pm.environment.get("tag")))
let val = requestToRun.pop()
pm.environment.set("requestToRun", requestToRun)
val ? postman.setNextRequest(val) : postman.setNextRequest(null)
Now set the envirnoment variable as what you want to look for eg: run script that contains text "Regression" then set pm.environment.set("tag","Regression")
Now in your collection-pre-request add:
if (pm.info.requestName !== "initial request") {
let requestToRun = pm.environment.get("requestToRun")
let val = requestToRun.pop()
pm.environment.set("requestToRun", requestToRun)
val ? postman.setNextRequest(val) : postman.setNextRequest(null)
}
Output:
Example collection:
https://www.getpostman.com/collections/73e771fe61f7781f8598
Ran only reqeusts that has "Copy" in its name
I'm writing unit test for my Meteor 1.4.2 application, where few of my methods requires authentication before processing.
How should I test these methods?
So far, I've written a test with practicalmeteor:mocha to create a new user and login with that user.
describe('login method', function () {
let logingKey;
beforeEach(function () {
Meteor.users.remove({});
const createUser = Meteor.server.method_handlers['registerUser'];
let params = {
username: 'testUsername'
}
res = createUser.apply({}, [params]);
logingKey = res.key;
});
it('can provide authentication', function () {
const loginUser = Meteor.server.method_handlers['login'];
let params = {
key: logingKey
}
console.log(params);
loginUser.apply({}, [params]);
});
I've written a custom login handler to login with the generated key which works fine with application, but in test results I'm getting following error.
Error: Cannot read property 'id' of undefined
at AccountsServer.Ap._setLoginToken (packages/accounts-base/accounts_server.js:889:35)
at packages/accounts-base/accounts_server.js:288:10
at Object.Meteor._noYieldsAllowed (packages/meteor.js:671:12)
at AccountsServer.Ap._loginUser (packages/accounts-base/accounts_server.js:287:10)
at AccountsServer.Ap._attemptLogin (packages/accounts-base/accounts_server.js:349:12)
at Object.methods.login (packages/accounts-base/accounts_server.js:533:21)
at Object.methodMap.(anonymous function) (packages/meteorhacks_kadira.js:2731:30)
at Test.<anonymous> (imports/api/methods/loginUser.tests.js:30:17)
at run (packages/practicalmeteor:mocha-core/server.js:34:29)
at Context.wrappedFunction (packages/practicalmeteor:mocha-core/server.js:63:33)
What could be wrong here? any suggestions are welcome, thanks in advance.
Original post on meteor forum
UPDATE
Ok! here is my confustion, Let say I've a write a unit test for this method, How should I verify or get the userId here.
Meteor.methods({
userStatus:function(update){
check(update, {online: String})
if (! this.userId) {
throw new Meteor.Error('error-not-authorized','User need to login', {method: "userStatus"})
}
try {
Meteor.users.update(Meteor.userId(),{$set: {'status.online': !!parseInt(update.online)}})
} catch (e) {
console.error("Error",e);
}
}
});
You are directly invoking a method handler without an appropriate context (which should be a Method Invocation object, while you provide an empty object). The login method handler attempts to get the connection id and fails to do so.
If you want to test the integration of your package with the accounts-base package (and basically you do, as you are calling some of its code), you can create a connection and call the method with that connection.
let connection = DDP.connect(Meteor.absoluteUrl());
// prepare the login data
const params = {/*...*/};
connection.call('login', params);
// test post conditions
connection.disconnect();
Edit (following question edit):
The answer remains pretty much the same. Once you have called the login method and logged in the user, the connection state on the server should include the logged-in user's id. Now you can call the methods that require the user to be logged in.
Note that you should probably use this.userId on all occasions (and not Meteor.userId()).
I have a Collection that has three endpoints. The first one creates an asset, the second one adds a file to the asset, and the third one lists all the assets.
How can I run the second one, the one that adds a file to the asset, more than once per each iteration of the Runner?
I'd like the test to create an asset and add multiple files to it for each iteration.
Any suggestions? I know I can duplicate the endpoint, but I was wondering if there was a programmatic way to do it.
Create 2 environment variables:
"Counter" (Number of times you want the request to run)
"RequestNumber" = 1 (To track the current request number)
Add this code to the test section of the request you want to run multiple times:
const counter = pm.environment.get("Counter");
const requestNumber = pm.environment.get("RequestNumber") || 1;
if (requestNumber < counter) {
postman.setNextRequest("RequestName");
requestNumber ++;
pm.environment.set("RequestNumber", requestNumber);
}
else {
pm.environment.set("RequestNumber", 1);
}
Instead of using postman.setNextRequest(), a bit cleaner way to hit the same endpoint is to use pm.sendRequest().
In Test or Pre-request Script, you can create a request object that would describe the request you want to send (URL, HTTP method, headers body, etc.) and put it in pm.sendRequest() function.
Consider:
const requestObject = {
url: 'https://postman-echo.com/post',
method: 'POST',
header: 'headername1:value1',
body: {
mode: 'raw',
raw: JSON.stringify({ key: "this is json" })
}
}
pm.sendRequest(requestObject, (err, res) => {
console.log(res);
});
To run the same request multiple times just put the function in for/for..in/for..of/forEach loop.
Consider:
for(let iteration = 0; iteration < 5; iteration++) {
pm.sendRequest(requestObject, (err, res) => {
console.log(res);
});
}
If you want you can modify the requestObject inside your loop.
Check out the Postman Documentation for more details.
So far, there is no straight forward solution using Postman, to configure several hits for the same request within a folder/collection.
Nevertheless, you can write some code in Pre-request script section, by adding a counter with number of hits you want and call postman.setNextRequest("request_name") method (read more about it from here) with you current request.
Out of Postman app scope, you can export your collection (as JSON file) and write some javascript code using newman which is a Command-line companion utility for Postman (more about newman from here) which gets a run method with a lot of iteration count and data options that would help you (for example, putting your second request in folder and iterates through it).
Hope that helps!