Repository: ember-cli/ember-cli (js)

Issue:
Watchman should not be looked for unless needed.
It seems that we are initializing `watchman` before any invocation when most do not need watching.

A few examples:

```
% ember version

version: 0.1.3-master-0dc44fb0a8
valid watchman found, version: [3.0.0]
node: 0.10.33
npm: 2.1.10
```

```
% ember build
version: 0.1.3-master-0dc44fb0a8
valid watchman found, version: [3.0.0]
Built project successfully. Stored in "dist/".
```

```
% ember generate component foo-bar
version: 0.1.3-master-0dc44fb0a8
valid watchman found, version: [3.0.0]
installing
  create app/components/foo-bar.js
  create app/templates/components/foo-bar.hbs
installing
  create tests/unit/components/foo-bar-test.js
```

We only use file watching for a two commands: `serve` and `test` (as far as I can tell).  We should start watchman in them instead of all the time.

Pull request:
Cleanup WatchDetector
- [x] exec -> execSync (now that we have node 0.12.x)
- [x] only run when actually needed [fixes #2642]
- [x] depends on #6307 (to drop node 0.10.x support)

Patch:
diff --git a/lib/models/command.js b/lib/models/command.js
index c22268374..620163f96 100644
--- a/lib/models/command.js
+++ b/lib/models/command.js
@@ -15,7 +15,7 @@ var CoreObject          = require('core-object');
 var logger              = require('heimdalljs-logger')('ember-cli:command');
 var WatchDetector       = require('../models/watch-detector');
 var SilentError         = require('silent-error');
-var exec                = Promise.denodeify(require('child_process').exec)
+var execSync            = require('child_process').execSync;
 var fs                  = require('fs')
 
 var cache = {};
@@ -192,53 +192,72 @@ var Command = CoreObject.extend({
     @return {Promise}
   */
   validateAndRun: function(args) {
-    var commandOptions = this.parseArgs(args);
-    // if the help option was passed, resolve with 'callHelp' to call help command
-    if (commandOptions && (commandOptions.options.help || commandOptions.options.h)) {
-      logger.info(this.name + ' called with help option');
-      return Promise.resolve('callHelp');
-    }
+    return new Promise(function(resolve) {
+      var commandOptions = this.parseArgs(args);
+      // if the help option was passed, resolve with 'callHelp' to call help command
+      if (commandOptions && (commandOptions.options.help || commandOptions.options.h)) {
+        logger.info(this.name + ' called with help option');
+        return resolve('callHelp');
+      }
 
-    this.analytics.track({
-      name:    'ember ',
-      message: this.name
-    });
+      this.analytics.track({
+        name:    'ember ',
+        message: this.name
+      });
 
-    if (commandOptions === null) {
-      return Promise.resolve();
-    }
+      if (commandOptions === null) {
+        return resolve();
+      }
 
-    if (this.works === 'outsideProject' && this.isWithinProject) {
-      return Promise.reject(new SilentError(
-        'You cannot use the ' + chalk.green(this.name) + ' command inside an ember-cli project.'
-      ));
-    }
+      if (this.works === 'outsideProject' && this.isWithinProject) {
+        throw new SilentError(
+          'You cannot use the ' + chalk.green(this.name) + ' command inside an ember-cli project.'
+        );
+      }
 
-    if (this.works === 'insideProject') {
-      if (!this.project.hasDependencies()) {
-        throw new SilentError('node_modules appears empty, you may need to run `npm install`');
+      if (this.works === 'insideProject') {
+        if (!this.project.hasDependencies()) {
+          throw new SilentError('node_modules appears empty, you may need to run `npm install`');
+        }
       }
-    }
 
-    var detector = new WatchDetector({
-      ui: this.ui,
-      childProcess: { exec: exec },
-      fs: fs,
-      watchmanSupportsPlatform: /^win/.test(process.platform),
-      cache: cache,
-      root: this.project.root
-    });
+      var detector = new WatchDetector({
+        ui: this.ui,
+        childProcess: { execSync: execSync },
+        fs: fs,
+        watchmanSupportsPlatform: /^win/.test(process.platform),
+        cache: cache,
+        root: this.project.root
+      });
 
-    var options = commandOptions.options;
+      var options = commandOptions.options;
 
-    // do stuff to try and provide a good experience when it comes to file watching
-    return detector.findBestWatcherOption(options).then(function(watchPreference) {
-      this.project._watchmanInfo = watchPreference.watchmanInfo;
-      options.watcher = watchPreference.watcher;
-      return this.run(options, commandOptions.args);
+      if (this.hasOption('watcher')) {
+        // do stuff to try and provide a good experience when it comes to file watching
+        var watchPreference = detector.findBestWatcherOption(options);
+        this.project._watchmanInfo = watchPreference.watchmanInfo;
+        options.watcher = watchPreference.watcher;
+      }
+      resolve(this.run(options, commandOptions.args));
     }.bind(this));
   },
 
+  /**
+    Reports if the given command has a command line option by a given name
+
+    @method hasOption
+    @param {String} name
+    @return {Boolean}
+  */
+  hasOption: function(name) {
+    for (var i = 0; i < this.availableOptions.length; i++) {
+      if (this.availableOptions[i].name === name) {
+        return true;
+      }
+    }
+    return false;
+  },
+
   /**
     Merges any options with duplicate keys in the availableOptions array.
     Used primarily by registerOptions.
diff --git a/lib/models/watch-detector.js b/lib/models/watch-detector.js
index b1dcc01b6..8ba97e48b 100644
--- a/lib/models/watch-detector.js
+++ b/lib/models/watch-detector.js
@@ -18,7 +18,6 @@ var POSSIBLE_WATCHERS = [
 ];
 
 var debug = require('heimdalljs-logger')('ember-cli:watcher');
-debugger;
 
 function WatchPreference(watcher) {
   this.watcher = watcher || null;
@@ -96,44 +95,40 @@ WatchDetector.prototype.extractPreferenceFromOptions = function(options) {
 */
 WatchDetector.prototype.testIfNodeWatcherAppearsToWork  = function() {
   var root = this.root;
-  return new Promise(function(resolve) {
-    if (root in this._doesNodeWorkCache) {
-      resolve(this._doesNodeWorkCache[root]);
-      return;
-    }
+  if (root in this._doesNodeWorkCache) {
+    return this._doesNodeWorkCache[root];
+  }
 
-    this._doesNodeWorkCache[root] = false;
+  this._doesNodeWorkCache[root] = false;
+  try {
+    // builds a tmp directory at process.cwd() + '/tmp/' + 'something-unique';
+    var tmpDir = quickTemp.makeOrRemake(this, 'tmp');
+
+    var watcher = this.fs.watch(tmpDir, { persistent: false, recursive: false });
+    watcher.close();
+  } catch (e) {
+    debug.info('testing if node watcher failed with: %o', e)
+    return false;
+  } finally {
     try {
-      // builds a tmp directory at process.cwd() + '/tmp/' + 'something-unique';
-      var tmpDir = quickTemp.makeOrRemake(this, 'tmp');
-
-      var watcher = this.fs.watch(tmpDir, { persistent: false, recursive: false });
-      watcher.close();
+      quickTemp.remove(this, 'tmp');
+      // cleanup dir
     } catch (e) {
-      debug.info('testing if node watcher failed with: %o', e)
-      resolve(false);
-      return;
-    } finally {
-      try {
-        quickTemp.remove(this, 'tmp');
-        // cleanup dir
-      } catch (e) {
-        // not much we can do, lets debug log.
-        debug.info('cleaning up dir failed with: %o', e)
-      }
+      // not much we can do, lets debug log.
+      debug.info('cleaning up dir failed with: %o', e)
     }
+  }
 
-    // it seems we where able to at least watch and unwatch, this should catch
-    // systems that have a very broken NodeWatcher.
-    //
-    // NOTE: we could also add a more advance chance, that triggers a change
-    // and expects to be informed of the change. This can be added in a future
-    // iteration.
-    //
+  // it seems we where able to at least watch and unwatch, this should catch
+  // systems that have a very broken NodeWatcher.
+  //
+  // NOTE: we could also add a more advance chance, that triggers a change
+  // and expects to be informed of the change. This can be added in a future
+  // iteration.
+  //
 
-    this._doesNodeWorkCache[root] = true;
-    resolve(true);
-  }.bind(this));
+  this._doesNodeWorkCache[root] = true;
+  return true;
 };
 
 /*
@@ -160,32 +155,31 @@ WatchDetector.prototype.findBestWatcherOption = function(options) {
     preference = this.checkWatchman();
   }
 
-  return Promise.resolve(preference).then(function(bestOption) {
-    if (bestOption.watcher === NODE) {
-      // although up to this point, we may believe Node is the best watcher
-      // this may not be true because:
-      // * not all platforms that run node, support node.watch
-      // * not all file systems support node watch
-      //
-      return this.testIfNodeWatcherAppearsToWork().then(function(appearsToWork) {
-        return new WatchPreference(appearsToWork ? NODE : POLLING);
-      });
-    } else {
-      return bestOption;
-    }
-  }.bind(this)).then(function(actual) {
-    debug.info('foundBestWatcherOption, preference was: %o, actual: %o', options, actual);
-    if (actual /* if no preference was initial set, don't bother informing the user */ &&
-      original /* if no original was set, the fallback is expected */ &&
-      actual.watcher !== original &&
-
-      // events represents either watcherman or node, but no preference
-      !(original === EVENTS && (actual.watcher === WATCHMAN || actual.watcher === NODE))) {
-      // if there was an initial preference, but we had to fall back inform the user.
-      this.ui.writeLine('was unable to use: "' + original + '", fell back to: "' + actual.watcher + '"')
-    }
-    return actual;
-  }.bind(this));
+  var bestOption = preference;
+  var actual;
+
+  if (bestOption.watcher === NODE) {
+    // although up to this point, we may believe Node is the best watcher
+    // this may not be true because:
+    // * not all platforms that run node, support node.watch
+    // * not all file systems support node watch
+    //
+    var appearsToWork = this.testIfNodeWatcherAppearsToWork();
+    actual = new WatchPreference(appearsToWork ? NODE : POLLING);
+  } else {
+    actual = bestOption;
+  }
+  debug.info('foundBestWatcherOption, preference was: %o, actual: %o', options, actual);
+  if (actual /* if no preference was initial set, don't bother informing the user */ &&
+    original /* if no original was set, the fallback is expected */ &&
+    actual.watcher !== original &&
+
+    // events represents either watcherman or node, but no preference
+    !(original === EVENTS && (actual.watcher === WATCHMAN || actual.watcher === NODE))) {
+    // if there was an initial preference, but we had to fall back inform the user.
+    this.ui.writeLine('was unable to use: "' + original + '", fell back to: "' + actual.watcher + '"');
+  }
+  return actual;
 };
 
 /*
@@ -204,8 +198,9 @@ WatchDetector.prototype.findBestWatcherOption = function(options) {
 WatchDetector.prototype.checkWatchman = function() {
   var result = new WatchPreference(null);
 
-  debug.info('exev("watchman version")');
-  return this.childProcess.exec('watchman version').then(function(output) {
+  debug.info('execSync("watchman version")');
+  try {
+    var output = this.childProcess.execSync('watchman version', { stdio: [] });
     debug.info('watchman version STDOUT: %s', output);
     var version;
     try {
@@ -239,7 +234,7 @@ WatchDetector.prototype.checkWatchman = function() {
     }
 
     return result;
-  }.bind(this), function(reason) {
+  } catch (reason) {
     debug.info('detecting watchman failed %o', reason);
 
     if (this.watchmanSupportsPlatform) {
@@ -252,5 +247,5 @@ WatchDetector.prototype.checkWatchman = function() {
 
     result.watcher = NODE;
     return result;
-  }.bind(this));
+  }
 };


Test patch:
diff --git a/tests/unit/cli/cli-test.js b/tests/unit/cli/cli-test.js
index c70466023..a223d7890 100644
--- a/tests/unit/cli/cli-test.js
+++ b/tests/unit/cli/cli-test.js
@@ -1,6 +1,5 @@
 'use strict';
 
-var EOL           = require('os').EOL;
 var expect        = require('chai').expect;
 var MockUI        = require('../../helpers/mock-ui');
 var MockAnalytics = require('../../helpers/mock-analytics');
@@ -318,12 +317,7 @@ describe('Unit: CLI', function() {
 
           var output = ui.output.trim();
 
-          var options = captor.value;
-          if (/win\d+/.test(process.platform) || options.watcher === 'watchman') {
-            expect(output).to.equal('', 'expected no extra output');
-          } else {
-            expect(output.split(EOL).length).to.equal(2, 'expected no extra output');
-          }
+          expect(output).to.equal('', 'expected no extra output');
         });
       });
     });
@@ -348,12 +342,7 @@ describe('Unit: CLI', function() {
 
           var output = ui.output.trim();
 
-          var options = captor.value;
-          if (/win\d+/.test(process.platform) || options.watcher === 'watchman') {
-            expect(output).to.equal('', 'expected no extra output');
-          } else {
-            expect(output.split(EOL).length).to.equal(2, 'expected no extra output');
-          }
+          expect(output).to.equal('', 'expected no extra output');
         });
       });
     });
diff --git a/tests/unit/commands/generate-test.js b/tests/unit/commands/generate-test.js
index 975c0ddf8..eb83dea09 100644
--- a/tests/unit/commands/generate-test.js
+++ b/tests/unit/commands/generate-test.js
@@ -49,9 +49,11 @@ describe('generate command', function() {
   it('runs GenerateFromBlueprint but with null nodeModulesPath', function() {
     command.project.hasDependencies = function() { return false; };
 
-    expect(function() {
-      command.validateAndRun(['controller', 'foo']);
-    }).to.throw(SilentError, 'node_modules appears empty, you may need to run `npm install`');
+    return command.validateAndRun(['controller', 'foo']).then(function() {
+      expect(true).to.be.false;
+    }).catch(function(reason) {
+      expect(reason.message).to.eql('node_modules appears empty, you may need to run `npm install`');
+    })
   });
 
   it('runs GenerateFromBlueprint with expected options', function() {
diff --git a/tests/unit/models/command-test.js b/tests/unit/models/command-test.js
index 7f159ac0f..403c7d91c 100644
--- a/tests/unit/models/command-test.js
+++ b/tests/unit/models/command-test.js
@@ -31,7 +31,7 @@ var ServeCommand = Command.extend({
     { name: 'live-reload-port', type: Number, description: '(Defaults to port number + 31529)' },
     { name: 'environment', type: String, default: 'development' }
   ],
-  run: function() {}
+  run: function(options) { return options; }
 });
 
 var DevelopEmberCLICommand = Command.extend({
@@ -40,19 +40,19 @@ var DevelopEmberCLICommand = Command.extend({
   availableOptions: [
     { name: 'package-name', key: 'packageName', type: String, required: true }
   ],
-  run: function() {}
+  run: function(options) { return options; }
 });
 
 var InsideProjectCommand = Command.extend({
   name: 'inside-project',
   works: 'insideProject',
-  run: function() {}
+  run: function(options) { return options; }
 });
 
 var OutsideProjectCommand = Command.extend({
   name: 'outside-project',
   works: 'outsideProject',
-  run: function() {}
+  run: function(options) { return options; }
 });
 
 var OptionsAliasCommand = Command.extend({
@@ -80,7 +80,7 @@ var OptionsAliasCommand = Command.extend({
       { 'hw': 'Hello world' }
     ]
   }],
-  run: function() {}
+  run: function(options) { return options; }
 });
 
 describe('models/command.js', function() {
@@ -155,26 +155,53 @@ describe('models/command.js', function() {
     expect(new ServeCommand(options).parseArgs(['-lr', 'false'])).to.have.deep.property('options.liveReload', false);
   });
 
-  it('validateAndRun() should print a message if a required option is missing.', function() {
-    return new DevelopEmberCLICommand(options).validateAndRun([]).then(function() {
-      expect(ui.output).to.match(/requires the option.*package-name/);
+  describe('#validateAndRun', function() {
+
+    it('should print a message if a required option is missing.', function() {
+      return new DevelopEmberCLICommand(options).validateAndRun([]).then(function() {
+        expect(ui.output).to.match(/requires the option.*package-name/);
+      });
     });
-  });
 
-  it('validateAndRun() should print a message if outside a project and command is not valid there.', function() {
-    return new InsideProjectCommand(assign(options, {
-      project: {
-        hasDependencies: function() { return true; },
-        isEmberCLIProject: function() { return false; },
-      }
-    })).validateAndRun([]).catch(function(reason) {
-      expect(reason.message).to.match(/You have to be inside an ember-cli project/);
+    it('should print a message if outside a project and command is not valid there.', function() {
+      return new InsideProjectCommand(assign(options, {
+        project: {
+          hasDependencies: function() { return true; },
+          isEmberCLIProject: function() { return false; },
+        }
+      })).validateAndRun([]).catch(function(reason) {
+        expect(reason.message).to.match(/You have to be inside an ember-cli project/);
+      });
+    });
+
+    it('selects watcher if an option', function() {
+      return new InsideProjectCommand(assign(options, {
+        availableOptions: [{ type: 'string', name: 'watcher' }],
+        project: {
+          hasDependencies: function() { return true; },
+          isEmberCLIProject: function() { return true; },
+        }
+      })).validateAndRun([]).then(function(options) {
+        expect(options).to.have.property('watcher');
+      });
     });
-  });
 
-  it('validateAndRun() should print a message if inside a project and command is not valid there.', function() {
-    return new OutsideProjectCommand(options).validateAndRun([]).catch(function(reason) {
-      expect(reason.message).to.match(/You cannot use.*inside an ember-cli project/);
+    it('selects NO watcher if NOT an option', function() {
+      return new InsideProjectCommand(assign(options, {
+        availableOptions: [{ type: 'string', name: 'foo' }],
+        project: {
+          hasDependencies: function() { return true; },
+          isEmberCLIProject: function() { return true; },
+        }
+      })).validateAndRun([]).then(function(options) {
+        expect(options).to.not.have.property('watcher');
+      });
+    });
+
+    it('should print a message if inside a project and command is not valid there.', function() {
+      return new OutsideProjectCommand(options).validateAndRun([]).catch(function(reason) {
+        expect(reason.message).to.match(/You cannot use.*inside an ember-cli project/);
+      });
     });
   });
 
@@ -569,6 +596,16 @@ describe('models/command.js', function() {
       });
     });
 
+    describe('hasOption', function() {
+      it('reports false if no option with that name is present', function() {
+        expect(command.hasOption('no-option-by-this-name')).to.be.false;
+      });
+
+      it('reports false if no option with that name is present', function() {
+        expect(command.hasOption('port')).to.be.true;
+      });
+    });
+
     describe('getJson', function() {
       beforeEach(function() {
         forEachWithPropertyStub = function(forEach, context) {
diff --git a/tests/unit/models/watch-detector-test.js b/tests/unit/models/watch-detector-test.js
index 5c11df203..eade28661 100644
--- a/tests/unit/models/watch-detector-test.js
+++ b/tests/unit/models/watch-detector-test.js
@@ -47,18 +47,14 @@ describe('WatchDetector', function() {
         throw new Error('Something went wrong');
       };
 
-      return subject.testIfNodeWatcherAppearsToWork().then(function(value) {
-        expect(value).to.be.false;
-      });
+      expect(subject.testIfNodeWatcherAppearsToWork()).to.be.false;
     });
 
     // we could extend this to test also if change events are triggered or not..
     it('reports YES if nothing throws', function() {
       fs.watch = function() { return { close: function() { }}};
 
-      return subject.testIfNodeWatcherAppearsToWork().then(function(value) {
-        expect(value).to.be.true;
-      });
+      expect(subject.testIfNodeWatcherAppearsToWork()).to.be.true;
     });
   });
 
@@ -66,42 +62,40 @@ describe('WatchDetector', function() {
   describe('#findBestWatcherOption', function() {
     describe('input preference.watcher === watchman', function() {
       beforeEach(function() {
-        childProcess.exec = function() {
-          return Promise.resolve('{"version":"3.0.0"}');
+        childProcess.execSync = function() {
+          return '{"version":"3.0.0"}';
         };
       });
 
       it('chooses watchman', function() {
-        return subject.findBestWatcherOption({ watcher: 'watchman' }).then(function(option) {
-          expect(option).to.have.property('watcher', 'watchman');
-          expect(option.watchmanInfo).to.have.property('version');
-          expect(option.watchmanInfo).to.have.property('canNestRoots');
-          expect(option.watchmanInfo).to.have.property('enabled', true)
-          expect(ui.output).not.to.match(/Could not start watchman/);
-          expect(ui.output).not.to.match(/fell back to: "node"/);
-          expect(ui.output).not.to.match(/Visit http:\/\/ember-cli.com\/user-guide\/\#watchman/);
-        });
+        var option = subject.findBestWatcherOption({ watcher: 'watchman' });
+        expect(option).to.have.property('watcher', 'watchman');
+        expect(option.watchmanInfo).to.have.property('version');
+        expect(option.watchmanInfo).to.have.property('canNestRoots');
+        expect(option.watchmanInfo).to.have.property('enabled', true)
+        expect(ui.output).not.to.match(/Could not start watchman/);
+        expect(ui.output).not.to.match(/fell back to: "node"/);
+        expect(ui.output).not.to.match(/Visit http:\/\/ember-cli.com\/user-guide\/\#watchman/);
       });
 
       describe('watchman does not work', function() {
         beforeEach(function() {
-          childProcess.exec = function() {
-            return Promise.reject();
+          childProcess.execSync = function() {
+            throw new Error('');
           };
         });
 
         it('false back to node if it can', function() {
           fs.watch = function() { return { close: function() { }}};
 
-          return subject.findBestWatcherOption({ watcher: 'watchman' }).then(function(option) {
-            expect(option.watchmanInfo).to.have.property('enabled', false)
-            expect(option).to.have.property('watcher', 'node');
-            expect(option.watchmanInfo).to.have.property('version');
-            expect(option.watchmanInfo).to.have.property('canNestRoots');
-            expect(ui.output).to.match(/Could not start watchman/);
-            expect(ui.output).to.match(/fell back to: "node"/);
-            expect(ui.output).to.match(/Visit http:\/\/ember-cli.com\/user-guide\/\#watchman/);
-          });
+          var option = subject.findBestWatcherOption({ watcher: 'watchman' });
+          expect(option.watchmanInfo).to.have.property('enabled', false)
+          expect(option).to.have.property('watcher', 'node');
+          expect(option.watchmanInfo).to.have.property('version');
+          expect(option.watchmanInfo).to.have.property('canNestRoots');
+          expect(ui.output).to.match(/Could not start watchman/);
+          expect(ui.output).to.match(/fell back to: "node"/);
+          expect(ui.output).to.match(/Visit http:\/\/ember-cli.com\/user-guide\/\#watchman/);
         });
 
         it('false back to polling if node does not work', function() {
@@ -109,15 +103,14 @@ describe('WatchDetector', function() {
             throw new Error('something went wrong');
           };
 
-          return subject.findBestWatcherOption({ watcher: 'watchman' }).then(function(option) {
-            expect(option).to.have.property('watcher', 'polling');
-            expect(option.watchmanInfo).to.have.property('enabled', false)
-            expect(option.watchmanInfo).to.have.property('version');
-            expect(option.watchmanInfo).to.have.property('canNestRoots');
-            expect(ui.output).to.match(/Could not start watchman/);
-            expect(ui.output).to.match(/fell back to: "polling"/);
-            expect(ui.output).to.match(/Visit http:\/\/ember-cli.com\/user-guide\/\#watchman/);
-          });
+          var option = subject.findBestWatcherOption({ watcher: 'watchman' });
+          expect(option).to.have.property('watcher', 'polling');
+          expect(option.watchmanInfo).to.have.property('enabled', false)
+          expect(option.watchmanInfo).to.have.property('version');
+          expect(option.watchmanInfo).to.have.property('canNestRoots');
+          expect(ui.output).to.match(/Could not start watchman/);
+          expect(ui.output).to.match(/fell back to: "polling"/);
+          expect(ui.output).to.match(/Visit http:\/\/ember-cli.com\/user-guide\/\#watchman/);
         });
       });
     });
@@ -125,11 +118,10 @@ describe('WatchDetector', function() {
     describe('input preference.watcher === polling', function() {
       it('simply works', function() {
         // we assuming polling can never not work, if it doesn't sorry..
-        return subject.findBestWatcherOption({ watcher: 'polling' }).then(function(option) {
-          expect(option.watchmanInfo).to.have.property('enabled', false)
-          expect(option).to.have.property('watcher', 'polling');
-          expect(ui.output).to.eql('');
-        });
+        var option = subject.findBestWatcherOption({ watcher: 'polling' });
+        expect(option.watchmanInfo).to.have.property('enabled', false)
+        expect(option).to.have.property('watcher', 'polling');
+        expect(ui.output).to.eql('');
       })
     });
 
@@ -138,10 +130,9 @@ describe('WatchDetector', function() {
         fs.watch = function() { return { close: function() { }}};
 
         // we assuming polling can never not work, if it doesn't sorry..
-        return subject.findBestWatcherOption({ watcher: 'node' }).then(function(option) {
-          expect(option).to.have.property('watcher', 'node');
-          expect(ui.output).to.eql('');
-        });
+        var option = subject.findBestWatcherOption({ watcher: 'node' });
+        expect(option).to.have.property('watcher', 'node');
+        expect(ui.output).to.eql('');
       });
 
       it('false back to polling if watch fails', function() {
@@ -149,10 +140,9 @@ describe('WatchDetector', function() {
           throw new Error('OMG');
         };
         // we assuming polling can never not work, if it doesn't sorry..
-        return subject.findBestWatcherOption({ watcher: 'node' }).then(function(option) {
-          expect(option).to.have.property('watcher', 'polling');
-          expect(ui.output).to.eql('was unable to use: "node", fell back to: "polling"' + EOL);
-        });
+        var option = subject.findBestWatcherOption({ watcher: 'node' });
+        expect(option).to.have.property('watcher', 'polling');
+        expect(ui.output).to.eql('was unable to use: "node", fell back to: "polling"' + EOL);
       });
 
       it('falls back to polling if unwatch fails', function() {
@@ -163,10 +153,9 @@ describe('WatchDetector', function() {
           throw new Error('OMG');
         };
         // we assuming polling can never not work, if it doesn't sorry..
-        return subject.findBestWatcherOption({ watcher: 'node' }).then(function(option) {
-          expect(option).to.have.property('watcher', 'polling');
-          expect(ui.output).to.eql('was unable to use: "node", fell back to: "polling"' + EOL);
-        });
+        var option = subject.findBestWatcherOption({ watcher: 'node' });
+        expect(option).to.have.property('watcher', 'polling');
+        expect(ui.output).to.eql('was unable to use: "node", fell back to: "polling"' + EOL);
       })
     });
 
@@ -177,86 +166,80 @@ describe('WatchDetector', function() {
       it('true: hides the "watchman not found, falling back to XYZ message"', function() {
         subject.watchmanSupportsPlatform = true;
 
-        childProcess.exec = function() {
-          return Promise.reject();
+        childProcess.execSync = function() {
+          throw new Error();
         };
         fs.watch = function() { return { close: function() { }}};
 
-        return subject.checkWatchman().then(function(result) {
-          expect(result).to.have.property('watcher', 'node');
-          expect(ui.output).to.eql('');
-        });
+        var result = subject.checkWatchman();
+        expect(result).to.have.property('watcher', 'node');
+        expect(ui.output).to.eql('');
       });
 
       it('false: shows the "watchman not found, falling back to XYZ message"', function() {
         subject.watchmanSupportsPlatform = false;
         fs.watch = function() { return { close: function() { }}};
 
-        childProcess.exec = function() {
-          return Promise.reject();
+        childProcess.execSync = function() {
+          throw new Error();
         };
 
-        return subject.checkWatchman().then(function(result) {
-          expect(result).to.have.property('watcher', 'node');
-          expect(ui.output).to.match(/Could not start watchman/);
-          expect(ui.output).to.match(/Visit http:\/\/ember-cli.com\/user-guide\/\#watchman/);
-        });
+        var result = subject.checkWatchman();
+        expect(result).to.have.property('watcher', 'node');
+        expect(ui.output).to.match(/Could not start watchman/);
+        expect(ui.output).to.match(/Visit http:\/\/ember-cli.com\/user-guide\/\#watchman/);
       });
     });
     it('prefers watchman if everything appears to be good', function() {
-      childProcess.exec = function() {
-        return Promise.resolve('{"version":"3.0.0"}');
+      childProcess.execSync = function() {
+        return '{"version":"3.0.0"}';
       };
 
-      return subject.checkWatchman().then(function(preference) {
-        expect(preference).to.have.property('watcher', 'watchman');
-        expect(ui.output).to.not.match(/Could not start watchman/);
-        expect(ui.output).to.not.match(/falling back to NodeWatcher/);
-        expect(ui.output).to.not.match(/ember-cli\.com\/user-guide\/\#watchman/);
-        expect(ui.output).to.not.match(/Looks like you have a different program called watchman/);
-        expect(ui.output).to.not.match(/Invalid watchman found/);
-      });
+      var preference = subject.checkWatchman();
+      expect(preference).to.have.property('watcher', 'watchman');
+      expect(ui.output).to.not.match(/Could not start watchman/);
+      expect(ui.output).to.not.match(/falling back to NodeWatcher/);
+      expect(ui.output).to.not.match(/ember-cli\.com\/user-guide\/\#watchman/);
+      expect(ui.output).to.not.match(/Looks like you have a different program called watchman/);
+      expect(ui.output).to.not.match(/Invalid watchman found/);
     });
 
     describe('fallse back to NODE', function() {
       var iff = it;
 
       iff('the exec rejects', function() {
-        childProcess.exec = function() {
-          return Promise.reject();
+        childProcess.execSync = function() {
+          throw new Error();
         };
 
-        return subject.checkWatchman().then(function(preference) {
-          expect(preference).to.have.property('watcher', 'node');
-          expect(ui.output).to.match(/Could not start watchman/);
-          expect(ui.output).to.match(/ember-cli\.com\/user-guide\/\#watchman/);
-        });
+        var preference = subject.checkWatchman();
+        expect(preference).to.have.property('watcher', 'node');
+        expect(ui.output).to.match(/Could not start watchman/);
+        expect(ui.output).to.match(/ember-cli\.com\/user-guide\/\#watchman/);
       });
 
       iff('the `watchman version` doesn\'t parse', function() {
-        childProcess.exec = function() {
-          return Promise.resolve("not json");
+        childProcess.execSync = function() {
+          return 'not json';
         };
 
-        return subject.checkWatchman().then(function(preference) {
-          expect(preference).to.have.property('watcher', 'node');
-          expect(ui.output).to.match(/Looks like you have a different program called watchman/);
-          expect(ui.output).to.match(/ember-cli\.com\/user-guide\/\#watchman/);
-        });
+        var preference = subject.checkWatchman();
+        expect(preference).to.have.property('watcher', 'node');
+        expect(ui.output).to.match(/Looks like you have a different program called watchman/);
+        expect(ui.output).to.match(/ember-cli\.com\/user-guide\/\#watchman/);
       });
 
 
       iff('the `watchman version` doesn\'t satisfy => 3.0.0', function() {
-        childProcess.exec = function() {
-          return Promise.resolve('{"version":"2.9.9"}');
+        childProcess.execSync = function() {
+          return '{"version":"2.9.9"}';
         };
 
-        return subject.checkWatchman().then(function(preference) {
-          expect(preference).to.have.property('watcher', 'node');
-          expect(ui.output).to.match(/Invalid watchman found/);
-          expect(ui.output).to.match(/version: \[2\.9\.9\] did not satisfy/);
-          expect(ui.output).to.match(/ember-cli\.com\/user-guide\/\#watchman/);
-        });
+        var preference = subject.checkWatchman();
+        expect(preference).to.have.property('watcher', 'node');
+        expect(ui.output).to.match(/Invalid watchman found/);
+        expect(ui.output).to.match(/version: \[2\.9\.9\] did not satisfy/);
+        expect(ui.output).to.match(/ember-cli\.com\/user-guide\/\#watchman/);
       });
     });
   });