Test Driving JavaScript: Grunt with Gradle

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

A few weeks ago Daniel Sundman wrote a blog entry about how to test drive JavaScript with Grunt. Today we’ll talk about how to run your Jasmine Grunt setup using Gradle!

There are no standard plugins for Grunt in Gradle, but it’s easy to add all the code manually. After all, this is Gradle not Maven 😉

We’ll assume that node and grunt-cli are already installed see (Test Driving JavaScript with Grunt).

Define an NPM Task

To ensure that all the grunt dependencies are present we’ll add an exec task to Gradle to run npm install. This task needs to be run whenever we make changes to the packages.json file, so we’ll add that as an input. We’ll also specify node_modules as the output directory. To define an Exec task type we need to import org.gradle.api.tasks.Exec, so our build.gradle file will look like this:

import org.gradle.api.tasks.Exec
task npm(type: Exec) {
   group = "Build"
   description = "Installs all Node.js dependencies defined in package.json"
   commandLine = ["npm", "install"]
   inputs.file "package.json"
   outputs.dir "node_modules"
}

Define a GruntTask Type

Next we want to create a new task type. A GruntTask that we’ll use to run all of our grunt commands (This is a much nicer solution than using Exec like we did for the npm task, here’s the write-up: Calling GruntJS tasks from Gradle). Since the Grunt command is different depending on the operating system we’ll need to set the command based on the operating system. Luckily this is easy to do using ant’s Os condition. So this is what we’ll add to our grunt file:
import org.apache.tools.ant.taskdefs.condition.Os

class GruntTask extends Exec {
   private String gruntExecutable = Os.isFamily(Os.FAMILY_WINDOWS) ? "grunt.cmd" : "grunt"
   def gruntArgs = ""
   public GruntTask() {
       super()
       this.setExecutable(gruntExecutable)
   }
   public void setGruntArgs(String gruntArgs) {
       this.args = "$gruntArgs".trim().split(" ") as List
   }
}

Putting it all together

Now that our setup is complete we can add the jasmine task
task jasmine(type: GruntTask) {
   group = "Verification"
   description = "Runs the Jasmine tests."
   gruntArgs = "jasmine"
}

Finally we just need to add some depends statements:

jasmine.dependsOn npm
check.dependsOn jasmine

Now you can run it from the command line:

gradle jasmine

If you run it again, you’ll notice it executes the tests even though no code has been modified. This is easily fixed by adding inputs to the jasmine task:

task jasmine(type: GruntTask) {
   group = "Verification"
   description = "Runs the Jasmine tests."
   gruntArgs = "jasmine"
   inputs.dir "[relative-path-to-source]"
   inputs.file file("Gruntfile.js")
} 

It’s that simple!

9 Comments

  • 1
    Olle Hallin
    2013-04-30 - 14:48 | Permalink

    Very nice!

    Improvement:

    Collect the output from Grunt to a file.
    Show the error output on the console should jasmine fail.

    I’ll show how to change the GruntTask to achieve that:


    class GruntTask extends Exec {
    private String gruntExecutable = Os.isFamily(Os.FAMILY_WINDOWS) ? "grunt.cmd" : "grunt"

    def gruntArgs = ""

    def output = new ByteArrayOutputStream()
    def File outputFile = null

    public GruntTask() {
    super()
    this.setExecutable(gruntExecutable)

    // Don't fail immediately after executing the command, we must save the output to a file first...
    this.setIgnoreExitValue(true)

    // Capture output...
    this.setStandardOutput(output)
    this.setErrorOutput(output)
    }

    public void setGruntArgs(String gruntArgs) {
    this.args = "$gruntArgs".trim().split(" ") as List

    // Construct an output file name with gruntArgs...
    def reportsDir = new File(project.buildDir, "reports")
    this.outputFile = new File(reportsDir, gruntArgs +".txt")
    this.outputs.file outputFile

    // After executing command...
    this.doLast {
    // Save output to a file
    output.close()
    outputFile.parentFile.mkdirs()
    outputFile.text = output.toString()

    // Log errors (if any)
    def result = getExecResult()
    if (result.exitValue != 0) {
    logger.error(output.toString())
    }

    // Fail build if Grunt failed
    result.assertNormalExitValue()
    }
    }

    It’s that simple!

    (Imagine doing this with Maven…)

  • 2
    2013-04-30 - 14:56 | Permalink

    Yeah, this is a really nice improvement! Thanks Olle!

  • 3
    SullyRafiq
    2013-09-10 - 11:18 | Permalink

    Great little tutorial. Works a charm. Thanks for posting

  • 5
    ravi
    2014-01-31 - 21:45 | Permalink

    How gradle recognizes npm command? I am getting beloe exception from gradle build task

    npm’ is not recognized as an internal or external command

    • 6
      2014-01-31 - 21:49 | Permalink

      Hi, have you installed node.js? You can find the information that you need here: http://nodejs.org/

      • 7
        ravi
        2014-02-03 - 18:08 | Permalink

        Yes , I did install Node.js and successfully run npm commends on my windows command prompt.
        I am getting npm’ is not recognized as an internal or external command while running through build file (gradle)

        • 8
          ravi
          2014-02-03 - 20:00 | Permalink

          it working . Thanks for your earlier replies

          I updated my build process task to have below statements to run successful build . if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine = [“cmd”, “/c”, “npm”, “install”] } else { commandLine = [“npm”, “install”] }

  • Leave a Reply

    Your email address will not be published. Required fields are marked *