1

I'd like to chain several Newman collection test runs. In my particular case, the first test run needs to pass some data to the second test run. How would I go about this?

In my current (not working) solution, I set a object in the global variables used by newman and pass that data to a variable accessible to the second test run. I noticed the newman run only got triggered after running through all the code. I figured I could try using a Promise to make the code wait until the first test run is finished before doing the second test run.

This is what I currently have:

var output

let run1 = new Promise(function (onResolve, onReject){
    let out
    let error

    newman
        .run({ /* options like collection etc go here */ })
        .on('done', function (err, summary) {
            if(err) {
                error = err
            }

            out = summary.globals.values.members.find(item => /* some query here */).value
        })

        if(out){
            onResolve(out);
        } else{
            onReject(error);
        }
    })

run1.then(
    //when "onreslove" got triggered
    function(value) {
        console.log('test run successful')
        output = value
    },
    //when "onReject" got triggered
    function(error){
        console.log('test run failed with error!\n')
        console.log(error)
        return
    }
)

if (output){
    let run2 = new Promise(function(onReslove, onReject) {
        let error
        let testData = require(/* path to json test data file*/)
        
        //some logic here that adds the data from the output variable to the "testData" object.

        newman.run({ /* some options here */})
        .on('done', function (err, summary) {
            if (err) {
                console.log(err)
                error = err
            }
        })

        if(!error){
            onResolve();
        } else{
            onReject(error);
        }
    })

    run2.then(
        //when onResolve got triggered
        function() { console.log(`test run successful`)},
        //when onReject got triggered
        function(error) {
            console.log('test run failed with error!\n')
            console.log(error)
            return
        }
    )
} else{
    console.log(`Expected output value, received ${output} instead.`)
}

I'm currently stuck, out will always be undefined because the "done" event didn't trigger yet at the time my debug session reached if(output){.

PixelPlex
  • 749
  • 5
  • 21
  • You need to put the `run2` inside the `.then()` callback of `run1`, or use `async`/`await` – Bergi May 27 '21 at 13:32
  • @Bergi thx for the suggestion. From what I know about Promises (very little), code within `.then()` should execute when the promise is "fulfilled". The problem I have when I place `run2` inside the `.then()` callback of `run1`, the promise is already `fulfilled` before `newman.run()` started its test run. [this answer](https://stackoverflow.com/questions/58406612/runing-newman-inside-of-nodejs-module) looks promising though. I might try this and if it doesn't work out I'll settle for what I already have using those callbacks. – PixelPlex May 31 '21 at 07:49
  • "*the promise is already fulfilled before newman.run() started its test run*" - I don't see how that's a problem - you *want* the second run to start only after the first one has fulfilled its promise, right? – Bergi May 31 '21 at 11:06
  • Well, the _first test run_ didn't start but the promise status was already fulfilled. The second test run needs data produced by the first test run, but since the first one didn't run yet, I get errors in the code that tries to provide that data to the second run, the variable `out` will be undefined, failing to pass on the data. – PixelPlex May 31 '21 at 12:47
  • 1
    Oh. Right. You're not [converting the callback API to promises](https://stackoverflow.com/q/22519784/1048572) correctly. I missed that the resolve/reject calls were outside of the callback, and only saw the lack of chaining. – Bergi May 31 '21 at 13:25

1 Answers1

4

Using the newman callback functionality

According to the API Reference, newman.run accepts a callback function. This callback function can than be used to initiate a second, nested run.

newman.run(
    { /* test run options */ },
    function(err, summary){
        console.log('first run finished')

        if (err) {
            console.log(err)
            return            
        }

        let output = summary.globals.values.members.find(/* some array query */).value
        let testData = require(/*path to test data json file*/)
        
        //some logic here to add the output to the testData for the next run            

        newman.run(
            {/* test run options */},
            function(err, summary){
                if (err) {
                    console.log(err)
                    return
                }

                console.log('second run finished')
            }
            
        )
    })

Using the newman "done" event and a promise

Subsequent newman test runs can be chained by the .then callback of a promise that did a test run:

function newmanRun(options) {
    return new Promise(function(onResolve){
        newman
        .run(options)
        .on('done', function (err, summary) {
            if (err) {
                console.log(`\ntest run failed!\n${err}`)
                return
            }

            console.log(`\ntest run succeeded!\n`)
            onResolve(summary)
        })
    })
}

function run1() {
    let options = { /* newman test run options */ }    
    newmanRun(options).then(
        //when "onResolve" got triggered
        function(summary) {    
            let output = summary.globals.values.members.find(/*query here*/).value
            run2(output)
        }
     )
}

function run2(input){    
    let testData = {}//path to test data file
    // some logic here to pass the output data from the previous run as input for the next test run.

    let options = {  /* use your test data variable in the newman options object*/  }
    
    newmanRun(options).then(
        //when "onResolve" got triggered
        function(summary) {    
            console.log('test run finished.')
            
        }
     )
}

//now we just need to call the run1 function to start the test run chain:
run1()

USING ASYNC/AWAIT

I personally think this is the cleanest way since it doesn't involve nesting one test run into another.

/**
 * Returns a promise to do a newman test run with the provided options. Use the `.then()` method to execute any callback function when the test run completed.
 * @param {Object} options See https://github.com/postmanlabs/newman#api-reference for details on the options object.
 * @returns {Promise} When the promise is fulfilled, a callback function with newman run summary as argument gets called.
 */
async function newmanRun(options) {
    return new Promise(function(onResolve){
        newman
        .run(options)
        .on('done', function (err, summary) {
            if (err) {
                console.log(`\ntest run failed!${err}`)
                return
            }

            console.log(`\ntest run succeeded!`)
            onResolve(summary)
        });
    })
}

async function run1(data) {
    //create the newman options here, e.g. data file, collection to run, etc...
    let options = { /* pass your data from the function parameter to the options here */ }
   
    return newmanRun(options) //returns a promise 
}

async function run2(data){
    //create the newman options here, e.g. data file, collection to run, etc...
    let options = { /* pass your data from the function parameter to the options here */ }

    return newmanRun(options) //returns a promise
}

async function start(){
    //load the test data and start iterating the newman test run chain.
    let input = JSON.parse(readFileSync(/** path to yor data file here */))


    summary = await run1(/* pass the data from input variable here */)
    output = summary.globals.values.members.find(/* query to fetch whatever data returned from the test run */).value

    await run2(/* the data from output here as input for the next test run*/)
}

start()
PixelPlex
  • 749
  • 5
  • 21