Risto-Stevcev/grunt-simple-protractor

View on GitHub
tasks/protractor.js

Summary

Maintainability
B
6 hrs
Test Coverage
/* 
 * grunt-simple-protractor
 * https://github.com/Risto-Stevcev/grunt-simple-protractor
 *
 * Copyright (c) 2015 Risto Stevcev
 * Licensed under the MIT license 
 */

module.exports = function(grunt) {
  var http = require('http')
  var path = require('path')
  var fs = require('fs')



  grunt.registerMultiTask('protractor', 'Run tests with protractor', function() {
    var server, seleniumProcessId, webdriverProcess
    var done = this.async()
    var options = this.options({
      nodeBinary: 'node',
      autoWebdriver: true,
      autoLocalServer: true,
      localServerPort: 8080,
      seleniumAddress: 'http://localhost:4444/wd/hub'
    })

    var simpleProtractorOpts = ['runAsync', 'autoLocalServer', 'localServerPort', 
                                'autoWebdriver', 'debugWebdriver', 'nodeBinary', 'configFile']



    function finishTask() {
      if (server) {
        server.close()
        grunt.log.debug('Local server connection closed')
      }

      if (webdriverProcess) {
        webdriverProcess.kill('SIGINT')
        grunt.log.debug('Exited WebDriver process')
      }

      if (seleniumProcessId) {
        process.kill(seleniumProcessId, 'SIGINT')
        grunt.log.debug('Exited Selenium Standalone process')
      }

      done()
    }



    function runWebdriver(protractorLibPath) {
      var webdriverBinPath = path.resolve(protractorLibPath, '../../bin/webdriver-manager')
      grunt.log.debug('Webdriver process started: ' + 
                      options.nodeBinary + ' ' + webdriverBinPath + ' start')

      webdriverProcess = grunt.util.spawn({
        cmd: options.nodeBinary,
        args: [webdriverBinPath, 'start'],
        opts: { stdio: 'pipe' }
      }) 

      webdriverProcess.stdout.pipe(process.stdout)
      webdriverProcess.stderr.pipe(process.stderr)

      webdriverProcess.stdout.on('data', function findSeleniumPid(chunk) {
        chunk = chunk.toString('ascii')
        var matchObj = chunk.match(/seleniumProcess\.pid: [0-9]{0,7}/)
        if (matchObj)
          seleniumProcessId = matchObj[0].split(' ')[1]
      })
    }



    function runLocalServer() {
      server = http.createServer(function(request, response) {
        fs.readFile('.' + request.url, 'utf8', function(err, data) {
          if (err) return 
          response.end(data)
        })
      })

      server.listen(options.localServerPort)
      grunt.log.debug('Local server listening on http://localhost:' + options.localServerPort)
    }



    function runProtractor(protractorLibPath) {
      var protractorArgs = []
      Object.keys(options).forEach(function(key) {
        if (!simpleProtractorOpts.some(function(opt) { return opt === key })) {
          if (typeof options[key] === 'boolean' && options[key] === true) {
            protractorArgs.push('--' + key)
          }
          else {
            protractorArgs.push('--' + key)
            protractorArgs.push(options[key])
          }
        }
      })


      var protractorBinPath = path.resolve(protractorLibPath, '../../bin/protractor')
      if (options.configFile)
        protractorArgs.unshift(options.configFile)
      protractorArgs.unshift(protractorBinPath)

      grunt.log.debug('Starting protractor: ' + 
                      options.nodeBinary + ' ' + protractorArgs.join(' '))



      var protractorProcess = grunt.util.spawn({
        cmd: options.nodeBinary,
        args: protractorArgs,
        opts: { stdio: 'pipe' }
      }, 
      function(error, result, code) {
        grunt.log.debug('Protractor finished. (Code ' + code + ')')

        if (options.runAsync) {
          grunt.event.emit('protractor', error, result, finishTask)
        }
        else {
          if (error) {
            finishTask()
            grunt.fail.fatal('Protractor task failed.')
          }
          else {
            finishTask()
          }
        }
      })

      protractorProcess.stdout.pipe(process.stdout)
      protractorProcess.stderr.pipe(process.stderr)
    }
    


    function runGruntSimpleProtractor() {
      var protractorLibPath = require.resolve('protractor')

      if (options.autoLocalServer)
        runLocalServer()

      /* Run protractor when webdriver server starts */
      if (options.autoWebdriver) {
        runWebdriver(protractorLibPath)

        if (webdriverProcess && webdriverProcess.stderr)
          webdriverProcess.stderr.on('data', function waitUntilServer(chunk) {
            chunk = chunk.toString('ascii')
            var matchObj = chunk.match(/Started .*Server/)
            if (matchObj)
              runProtractor(protractorLibPath)
          })
      }
      else {
        runProtractor(protractorLibPath)
      }
    }


    runGruntSimpleProtractor()
  })
}