Skip to content

Commit

Permalink
Support test suite on Windows
Browse files Browse the repository at this point in the history
Based on work by Tyler Waters <tyler.waters@gmail.com> in #1814.

This commit contains the following changes:

- Add quotation marks to Makefile variables for programs. The variables
  use POSIX-style paths, which cannot be used on Windows to launch a
  program except when quoted. Using double quotation marks instead of
  single since the latter is not available on Windows
- Use os-tmpdir module to get an acceptable directory for temporary
  usage instead of relying on the POSIX /tmp
- Use process.execPath as an authoritative path for Node.js executable
- Detect whether symbolic links are supported on the platform before
  testing. On Windows, creating symlinks can fail since it needs
  additional user permissions
- Fix hook tests. The tests parse output of the "dot" reporter to
  separate output of individual tests. The "dot" reporter uses "·"
  symbol (U+2024 ONE DOT LEADER) under POSIX environments and "." symbol
  (U+002E FULL STOP) under Windows, which means that having "." in the
  echoed message makes it ambiguous to be parsed in Windows. To fix this
  issue, two separate changes are necessary:
  - Use a dynamically created regular expression to split the tests
    based on the specific dot character used on the platform
  - Replace "." with "-" in echoed messages in fixtures for hook tests
    to avoid ambiguity with the character output by the reporter

Changes from #1814 include:

- Rebasing
- Use process.execPath as an authoritative path for Node.js executable
- Avoid external dependencies for child_process.spawn()
- Detect whether symbol links are supported on the platform before
  testing. On Windows, creating symlinks can fail since it needs
  additional user permissions

Fixes #1813.
  • Loading branch information
TimothyGu authored and boneskull committed Jun 29, 2016
1 parent 96d9e06 commit 8fe36a3
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 144 deletions.
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BROWSERIFY := node_modules/.bin/browserify
ESLINT := node_modules/.bin/eslint
KARMA := node_modules/.bin/karma
BROWSERIFY := "node_modules/.bin/browserify"
ESLINT := "node_modules/.bin/eslint"
KARMA := "node_modules/.bin/karma"

REPORTER ?= spec
TM_BUNDLE = JavaScript\ mocha.tmbundle
Expand Down
20 changes: 13 additions & 7 deletions mocha.js
Original file line number Diff line number Diff line change
Expand Up @@ -2474,7 +2474,7 @@ function coverageClass(coveragePctg) {
return 'terrible';
}

}).call(this,require('_process'),"/lib/reporters")
}).call(this,require('_process'),"/lib\\reporters")
},{"./json-cov":23,"_process":58,"fs":43,"jade":43,"path":43}],21:[function(require,module,exports){
(function (global){
/* eslint-env browser */
Expand Down Expand Up @@ -4814,7 +4814,13 @@ Runner.prototype.hook = function(name, fn) {
}
if (err) {
if (err instanceof Pending) {
suite.pending = true;
if (name === 'beforeEach' || name === 'afterEach') {
self.test.pending = true;
} else {
suite.tests.forEach(function(test) {
test.pending = true;
});
}
} else {
self.failHook(hook, err);

Expand Down Expand Up @@ -5028,7 +5034,7 @@ Runner.prototype.runTests = function(suite, fn) {
// execute test and hook(s)
self.emit('test', self.test = test);
self.hookDown('beforeEach', function(err, errSuite) {
if (suite.isPending()) {
if (test.isPending()) {
self.emit('pending', test);
self.emit('test end', test);
return next();
Expand Down Expand Up @@ -5355,8 +5361,8 @@ function filterLeaks(ok, globals) {
}

// in firefox
// if runner runs in an iframe, this iframe's window.getInterface method not init at first
// it is assigned in some seconds
// if runner runs in an iframe, this iframe's window.getInterface method
// not init at first it is assigned in some seconds
if (global.navigator && (/^getInterface/).test(key)) {
return false;
}
Expand Down Expand Up @@ -6117,8 +6123,8 @@ exports.slug = function(str) {
exports.clean = function(str) {
str = str
.replace(/\r\n?|[\n\u2028\u2029]/g, '\n').replace(/^\uFEFF/, '')
.replace(/^function *\(.*\)\s*\{|\(.*\) *=> *\{?/, '')
.replace(/\s+\}$/, '');
// (traditional)-> space/name parameters body (lambda)-> parameters body multi-statement/single keep body content
.replace(/^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/, '$1$2$3');

var spaces = str.match(/^\n?( *)/)[1].length;
var tabs = str.match(/^\n?(\t*)/)[1].length;
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@
"growl": "1.9.2",
"jade": "0.26.3",
"mkdirp": "0.5.1",
"os-tmpdir": "1.0.1",
"supports-color": "1.2.0",
"to-iso-string": "0.0.2"
},
Expand Down
6 changes: 4 additions & 2 deletions test/acceptance/fs.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
var fs = require('fs');
var path = require('path');
var tmpFile = path.join.bind(path, require('os-tmpdir')());

describe('fs.readFile()', function(){
describe('when the file exists', function(){
it('should succeed', function(done){
fs.writeFile('/tmp/mocha', 'wahoo', done)
fs.writeFile(tmpFile('mocha'), 'wahoo', done)
})
})

describe('when the file does not exist', function(){
it('should fail', function(done){
// uncomment
// fs.readFile('/tmp/does-not-exist', done);
// fs.readFile(tmpFile('does-not-exist'), done);
done();
})
})
Expand Down
75 changes: 51 additions & 24 deletions test/acceptance/lookup-files.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,83 @@
var utils = require('../../lib/utils');

describe('lookupFiles', function() {
var fs = require('fs'), path = require('path'), existsSync = fs.existsSync ||
path.existsSync;
var fs = require('fs'),
path = require('path'),
existsSync = fs.existsSync || path.existsSync,
tmpDir = require('os-tmpdir')(),
tmpFile = path.join.bind(path, tmpDir),
symlinkSupported = false;

fs.writeFileSync(tmpFile('mocha-utils.js'), 'yippy skippy ying yang yow');
try {
fs.symlinkSync(tmpFile('mocha-utils.js'), tmpFile('mocha-utils-link.js'));
symlinkSupported = true;
} catch (ignored) {
}

cleanup();

beforeEach(function() {
fs.writeFileSync('/tmp/mocha-utils.js', 'yippy skippy ying yang yow');
fs.symlinkSync('/tmp/mocha-utils.js', '/tmp/mocha-utils-link.js');
fs.writeFileSync(tmpFile('mocha-utils.js'), 'yippy skippy ying yang yow');
if (symlinkSupported) {
fs.symlinkSync(tmpFile('mocha-utils.js'), tmpFile('mocha-utils-link.js'));
}
});

it('should not choke on symlinks', function() {
expect(utils.lookupFiles('/tmp', ['js'], false))
(symlinkSupported ? it : it.skip)('should not choke on symlinks', function() {
expect(utils.lookupFiles(tmpDir, ['js'], false))
.to
.contain('/tmp/mocha-utils-link.js')
.contain(tmpFile('mocha-utils-link.js'))
.and
.contain('/tmp/mocha-utils.js')
.contain(tmpFile('mocha-utils.js'))
.and
.have
.length(2);
expect(existsSync('/tmp/mocha-utils-link.js'))
expect(existsSync(tmpFile('mocha-utils-link.js')))
.to
.be(true);
fs.renameSync('/tmp/mocha-utils.js', '/tmp/bob');
expect(existsSync('/tmp/mocha-utils-link.js'))
fs.renameSync(tmpFile('mocha-utils.js'), tmpFile('bob'));
expect(existsSync(tmpFile('mocha-utils-link.js')))
.to
.be(false);
expect(utils.lookupFiles('/tmp', ['js'], false))
expect(utils.lookupFiles(tmpDir, ['js'], false))
.to
.eql([]);
});

it('should accept a glob "path" value', function() {
expect(utils.lookupFiles('/tmp/mocha-utils*', ['js'], false))
var res = utils.lookupFiles(tmpFile('mocha-utils*'), ['js'], false)
.map(path.normalize.bind(path));

var expectedLength = 0;
var ex = expect(res)
.to
.contain('/tmp/mocha-utils-link.js')
.and
.contain('/tmp/mocha-utils.js')
.and
.contain(tmpFile('mocha-utils.js'));
expectedLength++;

if (symlinkSupported) {
ex = ex.and
.contain(tmpFile('mocha-utils-link.js'));
expectedLength++;
}

ex.and
.have
.length(2);
.length(expectedLength);
});

afterEach(function() {
afterEach(cleanup);

function cleanup() {
[
'/tmp/mocha-utils.js',
'/tmp/mocha-utils-link.js',
'/tmp/bob'
'mocha-utils.js',
'mocha-utils-link.js',
'bob'
].forEach(function(path) {
try {
fs.unlinkSync(path);
fs.unlinkSync(tmpFile(path));
} catch (ignored) {
}
});
});
}
});
5 changes: 3 additions & 2 deletions test/color.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
var assert = require('assert');
var child_process = require('child_process');
var path = require('path');

describe('Mocha', function() {
this.timeout(1000);

it('should not output colors to pipe', function(cb) {
var command = 'bin/mocha --grep missing-test';
child_process.exec(command, function(err, stdout, stderr) {
var command = [path.join('bin', 'mocha'), '--grep', 'missing-test'];
child_process.execFile(process.execPath, command, function(err, stdout, stderr) {
if (err) return cb(err);

assert(stdout.indexOf('[90m') === -1);
Expand Down
78 changes: 39 additions & 39 deletions test/integration/fixtures/hooks/multiple.hook.async.error.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,54 +9,54 @@ describe('1', function () {
console.log('1 before each');
});

describe('1.1', function () {
describe('1-1', function () {
before(function () {
console.log('1.1 before');
console.log('1-1 before');
});
beforeEach(function (done) {
console.log('1.1 before each');
console.log('1-1 before each');
process.nextTick(function () {
throw new Error('1.1 before each hook failed');
throw new Error('1-1 before each hook failed');
});
});
it('1.1 test 1', function () {
console.log('1.1 test 1');
it('1-1 test 1', function () {
console.log('1-1 test 1');
});
it('1.1 test 2', function () {
console.log('1.1 test 2');
it('1-1 test 2', function () {
console.log('1-1 test 2');
});
afterEach(function () {
console.log('1.1 after each');
console.log('1-1 after each');
});
after(function (done) {
console.log('1.1 after');
console.log('1-1 after');
process.nextTick(function () {
throw new Error('1.1 after hook failed');
throw new Error('1-1 after hook failed');
});
});
});

describe('1.2', function () {
describe('1-2', function () {
before(function () {
console.log('1.2 before');
console.log('1-2 before');
});
beforeEach(function () {
console.log('1.2 before each');
console.log('1-2 before each');
});
it('1.2 test 1', function () {
console.log('1.2 test 1');
it('1-2 test 1', function () {
console.log('1-2 test 1');
});
it('1.2 test 2', function () {
console.log('1.2 test 2');
it('1-2 test 2', function () {
console.log('1-2 test 2');
});
afterEach(function (done) {
console.log('1.2 after each');
console.log('1-2 after each');
process.nextTick(function () {
throw new Error('1.2 after each hook failed');
throw new Error('1-2 after each hook failed');
});
});
after(function () {
console.log('1.2 after');
console.log('1-2 after');
});
});

Expand All @@ -77,45 +77,45 @@ describe('2', function () {
});
});

describe('2.1', function () {
describe('2-1', function () {
before(function () {
console.log('2.1 before');
console.log('2-1 before');
});
beforeEach(function () {
console.log('2.1 before each');
console.log('2-1 before each');
});
it('2.1 test 1', function () {
console.log('2.1 test 1');
it('2-1 test 1', function () {
console.log('2-1 test 1');
});
it('2.1 test 2', function () {
console.log('2.1 test 2');
it('2-1 test 2', function () {
console.log('2-1 test 2');
});
afterEach(function () {
console.log('2.1 after each');
console.log('2-1 after each');
});
after(function () {
console.log('2.1 after');
console.log('2-1 after');
});
});

describe('2.2', function () {
describe('2-2', function () {
before(function () {
console.log('2.2 before');
console.log('2-2 before');
});
beforeEach(function () {
console.log('2.2 before each');
console.log('2-2 before each');
});
it('2.2 test 1', function () {
console.log('2.2 test 1');
it('2-2 test 1', function () {
console.log('2-2 test 1');
});
it('2.2 test 2', function () {
console.log('2.2 test 2');
it('2-2 test 2', function () {
console.log('2-2 test 2');
});
afterEach(function () {
console.log('2.2 after each');
console.log('2-2 after each');
});
after(function () {
console.log('2.2 after');
console.log('2-2 after');
});
});

Expand Down
Loading

0 comments on commit 8fe36a3

Please sign in to comment.