Search code examples
javascriptnode.jses6-promisenewman

How to chain newman test runs?


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){.


Solution

  • 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()