Search code examples
javascriptnode.jsgruntjsmocha.jsintegration-testing

How to pass arguments/parameters to mocha tests invoked via Grunt


I have a Gruntfile.js through which i'm invoking mochaTest using grunt-mocha-test module. I can pass an argument/parameter to the gruntTask from command line but i'm struggling to pass the same parameter into the spec file running via the above module. The code looks like below,

mochaTest: {
  test: {
    options: {
      reporter: 'spec',
      quiet: false,
      clearRequireCache: false,
      clearCacheFilter: (key) => true,
      noFail: false
    },
    src: [
          'test/createSpec.js'
         ]
  }
}

Task is registered like below,

grunt.registerTask('e2etest', function(scope) {
  console.log(scope); // logs user/session based on the parameter passed
  grunt.task.run('mochaTest');
});
// Above task is invoked like,
grunt e2etest:user
(or)
grunt e2etest:session

I need to pass this value (user/session) into mochaTest so it can be accessed inside the spec file. Fundamentally the aim is to run the createSpec.js file both for user and session, this values is parametrized inside the spec file and based on the value passed the suite would run.

Is there a possibility to do this? Please advise.


Solution

  • You can utilize nodes process.argv to read the argument (i.e. user or session) from within the file named createSpec.js.

    To better understand how, follow these steps:

    1. At the top of createSpec.js add the following line of code:

      console.log(process.argv);
      
    2. Then run grunt e2etest:user via your CLI and you should see the following logged to your console:

      [ 'node', '/usr/local/bin/grunt', 'e2etest:user' ]

      Note: the information you want is positioned at index two of the array.

    3. Now, delete the line we just added which reads console.log(process.argv); from createSpec.js.


    createSpec.js

    So, the steps above (1-3) illustrated that the arguments (user or session) can be accessed in createSpec.js utilizing process.argv. In which case you could do something like the following inside createSpec.js.

    const argument = process.argv[2].split(':').pop();
    
    if (argument === 'user') {
      // Run `user` specific tests here...
    } else if (argument === 'session') {
      // Run `session` specific tests here...
    }
    

    Note, we're using process.argv[2].split(/:/).pop(); to extract either user or session from the array item positioned at index two, whose initial value will be either e2etest:user or e2etest:session respectively.


    Gruntfile

    Your createSpec.js file is now somewhat dependent on the grunt task named e2etest being invoked correctly. For example, if a user were to run grunt e2etest without providing the arguments then createSpec.js is not going to do much.

    To enforce the correct usage of the e2etest task (i.e. it must be run using either grunt e2etest:user or grunt e2etest:session), you could change your task in your Gruntfile as follows:

    grunt.registerTask('e2etest', function(scope) {
      if (!scope || !(scope === 'user' || scope === 'session')) {
        grunt.warn(`Must be invoked with: ${this.name}:user or ${this.name}:session`);
      }
      grunt.task.run('mochaTest');
    });
    

    The gist above initially checks that an argument has been provided and is either user or session. If the argument is incorrect or missing then grunt.warn is utilized to warn the user.

    If your version of nodejs does not support ES6 Template literals then use grunt.warn as follows instead:

    grunt.warn('Must be invoked with: ' + this.name + ':user or ' + this.name + ':session');
    

    Additional comment

    The code/gist shown in the createSpec.js section above will work if your use-case is exactly as you mention in your question. I.e. you invoke via the commandline using grunt e2etest:user or grunt e2etest:session. However, if that changes and you cannot guarantee that e2etest:user or e2etest:session will be exactly positioned at index two of the process.argv array, then you may need to do the following at the top of createSpec.js instead:

    // Return the value in the array which starts with
    // `e2etest` then extract the string after the colon `:`
    const argument = process.argv.filter(arg => {
      return arg.match(/^e2etest:.*/);
    }).toString().split(':').pop();
    
    if (argument === 'user') {
      // Run `user` specific tests here...
    } else if (argument === 'session') {
      // Run `session` specific tests here...
    }