From 62d48c64ea2a7095cfbe06028ca286d3462694c6 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 24 May 2016 08:23:27 +0200 Subject: [PATCH] Add --main-process flag to run specs in the main process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …so that we can write unit tests for code in the main process. Below a list of conventions we'll be adopting: 1. Use mocha as the test framework. 2. Use chai as the assertion library. 3. Name specs `foo-bar.spec.js`, to prevent the renderer process from running specs written fro the main process e.g. when calling `atom --test spec`. 4. Write specs in ES6. Although somewhat inconsistent with the conventions we use for renderer process specs, this will hopefully be a first step towards migrating our entire Jasmine 1.3 test suite to a more modern environment. --- build/tasks/spec-task.coffee | 34 ++++++++++++++++++++++++++----- package.json | 4 ++++ spec/browser/mocha-test-runner.js | 31 ++++++++++++++++++++++++++++ src/browser/main.coffee | 13 ++++++++++-- 4 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 spec/browser/mocha-test-runner.js diff --git a/build/tasks/spec-task.coffee b/build/tasks/spec-task.coffee index c1067231c..e47b1a60f 100644 --- a/build/tasks/spec-task.coffee +++ b/build/tasks/spec-task.coffee @@ -93,13 +93,37 @@ module.exports = (grunt) -> env: _.extend({}, process.env, {ELECTRON_ENABLE_LOGGING: true, ATOM_INTEGRATION_TESTS_ENABLED: true}) stdio: 'inherit' - grunt.log.ok "Launching core specs." + grunt.log.ok "Launching core specs (renderer process)." spawn options, (error, results, code) -> if process.platform is 'win32' process.stderr.write(fs.readFileSync('ci.log')) if error fs.unlinkSync('ci.log') - else - # TODO: Restore concurrency on Windows + + callback(null, error) + + runMainProcessSpecs = (callback) -> + appPath = getAppPath() + resourcePath = process.cwd() + mainProcessSpecsPath = path.resolve('spec/browser') + + if process.platform in ['darwin', 'linux'] + options = + cmd: appPath + args: ["--test", "--main-process", "--resource-path=#{resourcePath}", mainProcessSpecsPath] + opts: + env: process.env + stdio: 'inherit' + else if process.platform is 'win32' + options = + cmd: process.env.comspec + args: ['/c', appPath, "--test", "--main-process", "--resource-path=#{resourcePath}", mainProcessSpecsPath] + opts: + env: process.env + stdio: 'inherit' + + grunt.log.ok "Launching core specs (main process)." + spawn options, (error, results, code) -> + if process.platform isnt 'windows' packageSpecQueue?.concurrency = concurrency callback(null, error) @@ -117,9 +141,9 @@ module.exports = (grunt) -> if process.env.ATOM_SPECS_TASK is 'packages' [runPackageSpecs] else if process.env.ATOM_SPECS_TASK is 'core' - [runCoreSpecs] + [runCoreSpecs, runMainProcessSpecs] else - [runCoreSpecs, runPackageSpecs] + [runCoreSpecs, runMainProcessSpecs, runPackageSpecs] method specs, (error, results) -> failedPackages = [] diff --git a/package.json b/package.json index 3f8ab99ec..7125f7fed 100644 --- a/package.json +++ b/package.json @@ -177,5 +177,9 @@ "waitsForPromise", "indexedDB" ] + }, + "devDependencies": { + "chai": "^3.5.0", + "mocha": "^2.5.1" } } diff --git a/spec/browser/mocha-test-runner.js b/spec/browser/mocha-test-runner.js new file mode 100644 index 000000000..623a537d9 --- /dev/null +++ b/spec/browser/mocha-test-runner.js @@ -0,0 +1,31 @@ +"use babel" + +import Mocha from 'mocha' +import fs from 'fs-plus' +import {assert} from 'chai' +import util from 'util' + +export default function (testPaths) { + global.assert = assert + + const mocha = new Mocha({reporter: 'dot'}) + for (let testPath of testPaths) { + if (fs.isDirectorySync(testPath)) { + for (let testFilePath of fs.listTreeSync(testPath)) { + if (/\.spec\.(coffee|js)$/.test(testFilePath)) { + mocha.addFile(testFilePath) + } + } + } else { + mocha.addFile(testPath) + } + } + + mocha.run(function (failures) { + if (failures === 0) { + process.exit(0) + } else { + process.exit(1) + } + }) +} diff --git a/src/browser/main.coffee b/src/browser/main.coffee index 6bf8817f9..1120fd6c3 100644 --- a/src/browser/main.coffee +++ b/src/browser/main.coffee @@ -9,6 +9,7 @@ fs = require 'fs-plus' path = require 'path' temp = require 'temp' yargs = require 'yargs' +previousConsoleLog = console.log console.log = require 'nslog' start = -> @@ -16,7 +17,13 @@ start = -> args.env = process.env setupAtomHome(args) setupCompileCache() - return if handleStartupEventWithSquirrel() + if handleStartupEventWithSquirrel() + return + else if args.test and args.mainProcess + console.log = previousConsoleLog + resourcePath = if fs.existsSync(args.devResourcePath) then args.devResourcePath else require.resolve('../..') + require(path.join(args.devResourcePath, 'spec/browser/mocha-test-runner'))(args.pathsToOpen) + return # NB: This prevents Win10 from showing dupe items in the taskbar app.setAppUserModelId('com.squirrel.atom.atom') @@ -130,6 +137,7 @@ parseCommandLine = -> options.boolean('safe').describe('safe', 'Do not load packages from ~/.atom/packages or ~/.atom/dev/packages.') options.boolean('portable').describe('portable', 'Set portable mode. Copies the ~/.atom folder to be a sibling of the installed Atom location if a .atom folder is not already there.') options.alias('t', 'test').boolean('t').describe('t', 'Run the specified specs and exit with error code on failures.') + options.alias('m', 'main-process').boolean('m').describe('m', 'Run the specified specs in the main process.') options.string('timeout').describe('timeout', 'When in test mode, waits until the specified time (in minutes) and kills the process (exit code: 130).') options.alias('v', 'version').boolean('v').describe('v', 'Print the version information.') options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.') @@ -154,6 +162,7 @@ parseCommandLine = -> safeMode = args['safe'] pathsToOpen = args._ test = args['test'] + mainProcess = args['main-process'] timeout = args['timeout'] newWindow = args['new-window'] pidToKillWhenClosed = args['pid'] if args['wait'] @@ -186,6 +195,6 @@ parseCommandLine = -> {resourcePath, devResourcePath, pathsToOpen, urlsToOpen, executedFrom, test, version, pidToKillWhenClosed, devMode, safeMode, newWindow, logFile, socketPath, userDataDir, profileStartup, timeout, setPortable, - clearWindowState, addToLastWindow} + clearWindowState, addToLastWindow, mainProcess} start()