Collection Pre-Script should only be run once

Collection Pre-Script should only be run Once!

the flow should be

  1. Collection Pre-Script (for initialization of value prior to collection run)
  2. Request Pre-Script
  3. Request Test (post script)
    … Loops
    #. Collection Test (post script)

The current setup makes no sense, yeah ok you can have some of the script run for each request, BUT! this makes it impossible to Initalize a set a variablse.

My Case.

I place a JSON Array of object in the Collection Pre-Script that defines the variable (scope) in each Request Script I read the JSON and loop thru all the calls for this request defined in the Collection.

With the Collection Pre-Script running each time you have no way programmatically to assign varialbles as pre-sets. The calling of collection pre-scripts, destroys looping

Please no - it is working as prescribed responses.

Hey @BJohansen

Welcome to the community! :rocket:

Thanks for posting the question here instead of in Github, this is a better place for this.

You’re repeatedly mentioning Pre Script but it’s a Pre-request Script like the one in the Request and Folder level, these work in the same way that just allow you to not repeat the same script in 100s of individual requests.

A Pre-Script that runs only once, as a kind of setup condition, would be a new feature request.

Please no - it is working as prescribed responses.

It is indeed working as expected so that’s the only response to this right now :smiley:

If might be worth breaking down what you have in place at the moment and explain the decision for having that code in that particular area of the collection.

The more detail you can provide, the easier it will be for members of the community to help you.

Can i attach a zip file do this forum?

You can just add the different formated code blocks you have for the collection pre-requests and the scripts in the request.

It will allow you also to explain what the code is doing as the zip file would be a bit meaningless as no one could run it against that endpoint.

Goal of Project: Create with Postman a series of calls to each of our API Endpoints that have multiple different assertions per endpoint.

  1. New Collection, Edit collection Pre-Request Script, place this code
//this is where you set your JSON test array
pm.globals.set("tests",`[
  {
    "Request": "login", 
    "callData": [
      {
        "value": "gooduser", 
        "varName": "loginPassword"
      }, 
      {
        "value": "Ben10", 
        "varName": "loginUsername"
      }, 
      {
        "value": "fakevalue", 
        "varName": "recaptcha"
      }
    ], 
    "callName": "Login", 
    "callVersion": "1", 
    "expectedResult": [
      {
        "node": "callStatus", 
        "value": 1000
      }, 
      {
        "node": "responseStatus", 
        "value": 1000
      }
    ], 
    "testType": "pass"
  }, 
  {
    "Request": "login", 
    "callData": [
      {
        "value": "baduser", 
        "varName": "loginPassword"
      }, 
      {
        "value": "Ben9", 
        "varName": "loginUsername"
      }, 
      {
        "value": "fakevalue", 
        "varName": "recaptcha"
      }
    ], 
    "callName": "Login", 
    "callVersion": "1", 
    "expectedResult": [
      {
        "node": "callStatus", 
        "value": 1000
      }, 
      {
        "node": "responseStatus", 
        "value": 6033
      }
    ], 
    "testType": "fail"
  }
]`);


//----------------
//do not edit below
//-----------------
var jsonObject = JSON.parse(pm.globals.get("tests"));
for (var i = 0; i < jsonObject.length; i++){
    pm.globals.unset(jsonObject[i].callName.toLowerCase()+"_array");
    pm.globals.unset(jsonObject[i].callName.toLowerCase()+"_idx");
}

console.log("cleared globals")
  1. New Request Add Request to Collection

Body:
raw XML

<?xml version="1.0" encoding="utf-8" ?>
<MTMRequest>
	<login version="1">
		<username>{{loginUsername}}</username>
		<password>{{loginPassword}}</password>
		<recaptcha>fakevalue</recaptcha>
	</login>
</MTMRequest>
  1. Request Pre-Request Script
//place the name of the call here, name of root and call nodes
var rootNode = 'MTMResponse';
var callNode = ('login'); 

//bring in tests array of objects from collection
var jsonObject = JSON.parse(pm.globals.get("tests"));
callNode = callNode.toLowerCase();


//look for call index
var idx = pm.globals.get(callNode+"_idx");
if (idx === undefined) {
    //init call globals
    console.log('init')

    idx = 0;
    pm.globals.set(callNode+"_idx",0);
    //loop throw tests array from globals to create sub array of calls
    var subTests = [];
    for (var i = 0; i < jsonObject.length; i++){
        if (jsonObject[i].callName.toLowerCase() === callNode.toLowerCase()) {
            subTests.push(jsonObject[i]);
        }
    }
    pm.globals.set(callNode+"_array",subTests);
    var curObject = subTests[idx]
 
} else {
    var subTests = pm.globals.get(callNode+"_array");
    var curObject = subTests[idx]
}

console.log("pre - "+idx);
console.log(curObject.testType);

//set variabls here
for (var i = 0; i < curObject.callData.length; i++){
    pm.variables.set(curObject.callData[i].varName,curObject.callData[i].value);
}

postman.setNextRequest(curObject.callName);

  1. Tests script
//place the name of the call here, name of root and call nodes
var rootNode = 'MTMResponse';
var callNode = 'login'; 

var idx = pm.globals.get(callNode+"_idx");
var subTests = pm.globals.get(callNode+"_array");
var curObject = subTests[idx]

console.log("test - "+idx);
console.log(curObject.testType);

//perform test


//determing next call
idx++;
if (idx > (subTests.length - 1)) {
     //reset call globals
    pm.globals.unset(callNode+"_array");
    pm.globals.unset(callNode+"_idx");

    //call next test
    postman.setNextRequest(null);
} else {
    pm.globals.set(callNode+"_idx",idx);
    postman.setNextRequest(curObject.callName);
}

Issues

  1. I can’t run this using “Send” because it doesn’t make the 2 calls
  2. postman.setNextRequest(curObject.callName); (Doesn’t work)
  3. if I run the collection, the first time it only runs Once (if i had tested with send prior)

Hey @vdespa, @pfarrell, @odanylewycz, @allen.helton or anyone else in the community :grin:

Anything that you can help with here, I can see a few improvements but I would love to get your views too :grin:

This is exactly my Point, When I create a collection and it has a Pre-Script the first thing I think about is that that script is run in Collection Scope.

The fact that your giving us scripting capabilities and not have a setup scripting area or that you are using it an adder to request scripts, when I can just copy and paste between give me Pause.

The feature is called a Pre-request Script with a label at the top of the Collection Pre-request Script editor stating that its run for every request in the Collection.

It was added to that part of the Collection and Sub-Folders to reduce the amount of repetition in the request themselves.

Copy and pasting will work for 1 or 2 requests just fine and won’t be too much of a time burden but users have more than a few Folders, sub-folders and requests in there Collections, they have hundreds and copy and pasting or repeating yourself is a time burden.

What’s the reason behind trying to handle all the requests, that could be separated out and a workflow created like you have done already, in a single request?

1 Like

all I gave you was one API Call, there will be Many API call that we want to test. This will be used by other dev and none technical QA department. Each Request is a API call with all the tests to be defined in main JSON file. The goal was to have the code so that our other devs can be just adding to JSON and the code would run.

The flow can also be determined by the JSON data

Also this way would allow Devs to just Run one of the API Request and It should run all the tests needed based on JSON

This command seems to be useless. with regards to using the Send
postman.setNextRequest(curObject.callName);

would be nice if there was a…
pm.setNextRequest(curObject.callName);

Hi @BJohansen,

Welcome to the community! :clap:

I must say you have some interesting code there. While it looks to be very comprehensive, it may be a bit overcomplicating.

To align with your goal, you can break things out. So as an architectural example, you can create variables in your environment that each represent good data input, good data output, bad data input, bad data output, etc. Organizing it this way makes it simpler. Then in addition, you can make a separate request with those differing input conditions / data, and expected output. While it may have some redundancy, it will be more clear, in terms of Postman UI and the results section.

I do see how you are organizing everything and I understand it, but it may be excessive for one request. The Pre-Request Script is intended for everything needed to initialize your one request. This most commonly is authentication, but can also be data initialization. Tests section is just as it sounds, its the validation after one request is executed. After this execution flow is over, you would move onto the next request. What I see you trying to do is make multiple requests within the same execution flow. While ideally that does sound like it makes sense, Postman was not optimized for that execution flow.

As @dannydainton suggested, breaking each out into its own request will work with Postman Architecture much better. So your first test case will be one request, and when that finishes, the second request (a new Postman Request) will be the second test case, etc.

As for the Collection Pre-Request Script, I do understand what you are thinking there, however its not applied in that hierarchical fashion. As Danny mentioned, this is meant for reducing redundancy on a per request basis. Again, this is a place where you would do authentication, as thats the most common thing needed before executing a new request. Its not a one-time execution per collection, although that could be a good idea as well, and a enhancement request.

There is no looping that actually happens over the Collection Object or request object itself, this is where you have to separate them out, as noted. However again, that could be an interesting feature request.

In final, I would separate out those calls as two different tests. Isolate their data as well as two separate JSON objects, ideally in the environments tab, but also can in the Pre-Request section for that request. Then isolate the test data as well per request. And that should achieve your goal.

If you are interested in running multiple iterations, I would suggest looking into Postman Collection Runner, as that may also satisfy your goals.

https://learning.postman.com/docs/running-collections/intro-to-collection-runs/

I hope this helps.

1 Like

:thinking: comment removed

What does curObject.callName resolve to? Is it the requestName? Is it a string? Can you show what’s logged out?

Are you sure it’s going down the right path and hit the place where you think it is?

What is not working in regards to that function, without more information, no one is going to know what’s happening. We can’t see what you can. :grin:

You mentioned ‘non technical QA’, I’m not sure how you define that in your context but by looking at your code, they are not going to instantly know what you’re doing without some advanced JS knowledge.

Is it running the same “Login” request after this, when run in the runner?

What’s the warning on that request?

Can you share a screen shot of what the global variables look like after the run?

yes, its running the same, that the point the JSON thats running this this has 2 pass defined. If i want it to pass thru 10 times, thats what it should do.

the warning is because im using a local cert

I ran into this myself. I got around it by testing for a variable not existing and then executing my initialization logic. Inside that logic I set/created the variable that I was testing for. My logic is simple, and included below.

if ( !pm.variables.has(“TotalCF”) ) {
pm.variables.set(“TotalCF”,0);
console.log(“Initialize collection error counter”);
}

Ah, Yes, it gets around the Initializaion issue. Still think need a collection start and end script inputs. Thanks, Marked yours as solution