diff --git a/lib/Meteor.coffee b/lib/Meteor.coffee index badf914..b54aaf9 100755 --- a/lib/Meteor.coffee +++ b/lib/Meteor.coffee @@ -124,6 +124,12 @@ class Meteor extends EventEmitter else delete env.MONGO_URL if env.MONGO_URL? + if @options["coverage"]? + env.COVERAGE = "1" + env.COVERAGE_APP_FOLDER = path.join(cwd, './') + if @options["loglevel"]? + env.COVERAGE_VERBOSE = "1" + options = { cwd: cwd, env: env, diff --git a/lib/Spacejam.coffee b/lib/Spacejam.coffee index 7ff012d..42edd54 100755 --- a/lib/Spacejam.coffee +++ b/lib/Spacejam.coffee @@ -62,6 +62,15 @@ class Spacejam extends EventEmitter expect(@meteor, "Meteor is already running").to.be.null @options = _.extend @defaultOptions(), options + if @options.coverage? && @options.coverage + @options['phantomjs-script'] = "phantomjs-test-in-console-with-coverage.js"; + if @options.coverage.length > 0 + process.env.COVERAGE_IN_COVERAGE = @options.coverage.indexOf('in_coverage') > -1 ? true : false; + process.env.COVERAGE_OUT_COVERAGE = @options.coverage.indexOf('out_coverage') > -1 ? true : false; + process.env.COVERAGE_OUT_LCOVONLY = @options.coverage.indexOf('out_lcovonly') > -1 ? true : false; + else + log.warn "No coverage action activated. Try spacejam [...] --coverage='out_lcovonly'" + log.debug @options try diff --git a/lib/phantomjs-test-in-console-with-coverage.coffee b/lib/phantomjs-test-in-console-with-coverage.coffee new file mode 100644 index 0000000..e6113b7 --- /dev/null +++ b/lib/phantomjs-test-in-console-with-coverage.coffee @@ -0,0 +1,130 @@ +page = require('webpage').create() +system = require('system') +env = system.env; + +console.log("phantomjs: Running tests at #{system.env.ROOT_URL} using test-in-console and coverage") + +page.onConsoleMessage = (message) -> + console.log(message) + +page.open(system.env.ROOT_URL) + +page.onError = (msg, trace) -> + + mochaIsRunning = page.evaluate -> + return window.mochaIsRunning + + # Mocha will handle and report the uncaught errors for us + if mochaIsRunning + return + + console.log("phantomjs: #{msg}") + + trace.forEach((item) -> + console.log(" #{item.file}: #{item.line}") + ) + phantom.exit(6) + +page.onCallback = (data) -> + ## Callback when sending and saving coverage + if data && data.err + console.log("coverage error: #{data.err}") + phantom.exit(7) + else + phantom.exit(0) + + +checkingStatus = setInterval -> + done = page.evaluate -> + return TEST_STATUS.DONE if TEST_STATUS? + return DONE if DONE? + return false + + if done + failures = page.evaluate -> + return TEST_STATUS.FAILURES if TEST_STATUS? + return FAILURES if FAILURES? + return false + if failures + phantom.exit(2) + else + ## tests are ok, we remove the timer that checks if test are done + clearInterval checkingStatus + try + ## Execute coverage actions + importCoverageDump = env.COVERAGE_IN_COVERAGE == "true" + exportCoverageDump = env.COVERAGE_OUT_COVERAGE == "true" + exportLcovonly = env.COVERAGE_OUT_LCOVONLY == "true" + page.evaluate runCoverage, importCoverageDump, exportCoverageDump, exportLcovonly + catch error + window.callPhantom + err: error +, 500 + +runCoverage = (importCoverageDump, exportCoverageDump, exportLcovonly) -> + ## Define coverage services + window.assertCoverageEnabled = (onSuccess) -> + if ! Package || ! Package['meteor'] || ! Package['meteor']['Meteor'] || ! Package['meteor']['Meteor'].sendCoverage || ! Package['meteor']['Meteor'].exportCoverage + window.callPhantom + err: "Coverage package missing or not correclty launched" + else + onSuccess(); + window.saveClientSideCoverage = (onSuccess) -> + Package['meteor']['Meteor'].sendCoverage (stats,err) -> + console.log("tests are ok and some js on the client side have been covered. Report: ", JSON.stringify(stats)) + if err + window.callPhantom + err: "Failed to send client coverage" + else + onSuccess(); + + window.exportLcovonly = (onSuccess) -> + Package['meteor']['Meteor'].exportCoverage 'lcovonly', (err) -> + if err + window.callPhantom + err: "Failed to save lcovonly coverage" + else + onSuccess(); + + window.exportCoverageDump = (onSuccess) -> + Package['meteor']['Meteor'].exportCoverage 'coverage', (err) -> + if err + window.callPhantom + err: "Failed to save coverage dump" + else + onSuccess(); + + window.importCoverageDump = (onSuccess) -> + Package['meteor']['Meteor'].importCoverage (err) -> + if err + window.callPhantom + err: "Failed to import coverage dump" + else + onSuccess(); + + ## Execute desired tasks + + window.assertCoverageEnabled(-> + window.saveClientSideCoverage(-> + stepFurtherImportCoverageDump = -> + stepFurtherExportCoverageDump = -> + if exportLcovonly + window.exportLcovonly(-> + window.callPhantom + success: "true" + ); + else + window.callPhantom + success: "true" + + if exportCoverageDump + window.exportCoverageDump stepFurtherExportCoverageDump + else + stepFurtherExportCoverageDump() + + if importCoverageDump + window.importCoverageDump stepFurtherImportCoverageDump + else + stepFurtherImportCoverageDump() + ); + ); diff --git a/lib/phantomjs-test-in-console-with-coverage.js b/lib/phantomjs-test-in-console-with-coverage.js new file mode 100644 index 0000000..f1f8011 --- /dev/null +++ b/lib/phantomjs-test-in-console-with-coverage.js @@ -0,0 +1,171 @@ +// Generated by CoffeeScript 1.8.0 +(function() { + var checkingStatus, env, page, runCoverage, system; + + page = require('webpage').create(); + + system = require('system'); + + env = system.env; + + console.log("phantomjs: Running tests at " + system.env.ROOT_URL + " using test-in-console and coverage"); + + page.onConsoleMessage = function(message) { + return console.log(message); + }; + + page.open(system.env.ROOT_URL); + + page.onError = function(msg, trace) { + var mochaIsRunning; + mochaIsRunning = page.evaluate(function() { + return window.mochaIsRunning; + }); + if (mochaIsRunning) { + return; + } + console.log("phantomjs: " + msg); + trace.forEach(function(item) { + return console.log(" " + item.file + ": " + item.line); + }); + return phantom.exit(6); + }; + + page.onCallback = function(data) { + if (data && data.err) { + console.log("coverage error: " + data.err); + return phantom.exit(7); + } else { + return phantom.exit(0); + } + }; + + checkingStatus = setInterval(function() { + var done, error, exportCoverageDump, exportLcovonly, failures, importCoverageDump; + done = page.evaluate(function() { + if (typeof TEST_STATUS !== "undefined" && TEST_STATUS !== null) { + return TEST_STATUS.DONE; + } + if (typeof DONE !== "undefined" && DONE !== null) { + return DONE; + } + return false; + }); + if (done) { + failures = page.evaluate(function() { + if (typeof TEST_STATUS !== "undefined" && TEST_STATUS !== null) { + return TEST_STATUS.FAILURES; + } + if (typeof FAILURES !== "undefined" && FAILURES !== null) { + return FAILURES; + } + return false; + }); + if (failures) { + return phantom.exit(2); + } else { + clearInterval(checkingStatus); + try { + importCoverageDump = env.COVERAGE_IN_COVERAGE === "true"; + exportCoverageDump = env.COVERAGE_OUT_COVERAGE === "true"; + exportLcovonly = env.COVERAGE_OUT_LCOVONLY === "true"; + return page.evaluate(runCoverage, importCoverageDump, exportCoverageDump, exportLcovonly); + } catch (_error) { + error = _error; + return window.callPhantom({ + err: error + }); + } + } + } + }, 500); + + runCoverage = function(importCoverageDump, exportCoverageDump, exportLcovonly) { + window.assertCoverageEnabled = function(onSuccess) { + if (!Package || !Package['meteor'] || !Package['meteor']['Meteor'] || !Package['meteor']['Meteor'].sendCoverage || !Package['meteor']['Meteor'].exportCoverage) { + return window.callPhantom({ + err: "Coverage package missing or not correclty launched" + }); + } else { + return onSuccess(); + } + }; + window.saveClientSideCoverage = function(onSuccess) { + return Package['meteor']['Meteor'].sendCoverage(function(stats, err) { + console.log("tests are ok and some js on the client side have been covered. Report: ", JSON.stringify(stats)); + if (err) { + return window.callPhantom({ + err: "Failed to send client coverage" + }); + } else { + return onSuccess(); + } + }); + }; + window.exportLcovonly = function(onSuccess) { + return Package['meteor']['Meteor'].exportCoverage('lcovonly', function(err) { + if (err) { + return window.callPhantom({ + err: "Failed to save lcovonly coverage" + }); + } else { + return onSuccess(); + } + }); + }; + window.exportCoverageDump = function(onSuccess) { + return Package['meteor']['Meteor'].exportCoverage('coverage', function(err) { + if (err) { + return window.callPhantom({ + err: "Failed to save coverage dump" + }); + } else { + return onSuccess(); + } + }); + }; + window.importCoverageDump = function(onSuccess) { + return Package['meteor']['Meteor'].importCoverage(function(err) { + if (err) { + return window.callPhantom({ + err: "Failed to import coverage dump" + }); + } else { + return onSuccess(); + } + }); + }; + return window.assertCoverageEnabled(function() { + return window.saveClientSideCoverage(function() { + var stepFurtherImportCoverageDump; + stepFurtherImportCoverageDump = function() { + var stepFurtherExportCoverageDump; + stepFurtherExportCoverageDump = function() { + if (exportLcovonly) { + return window.exportLcovonly(function() { + return window.callPhantom({ + success: "true" + }); + }); + } else { + return window.callPhantom({ + success: "true" + }); + } + }; + if (exportCoverageDump) { + return window.exportCoverageDump(stepFurtherExportCoverageDump); + } else { + return stepFurtherExportCoverageDump(); + } + }; + if (importCoverageDump) { + return window.importCoverageDump(stepFurtherImportCoverageDump); + } else { + return stepFurtherImportCoverageDump(); + } + }); + }); + }; + +}).call(this);