diff --git a/lib/utils.js b/lib/utils.js index 6ab1277409..56b9d63c48 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -63,8 +63,9 @@ exports.isString = function(obj) { exports.slug = function(str) { return str .toLowerCase() - .replace(/ +/g, '-') - .replace(/[^-\w]/g, ''); + .replace(/\s+/g, '-') + .replace(/[^-\w]/g, '') + .replace(/-{2,}/g, '-'); }; /** diff --git a/test/unit/mocha.spec.js b/test/unit/mocha.spec.js index c676d5f96b..219564d3aa 100644 --- a/test/unit/mocha.spec.js +++ b/test/unit/mocha.spec.js @@ -17,9 +17,16 @@ describe('Mocha', function() { }); describe('constructor', function() { + var mocha; + beforeEach(function() { + mocha = sandbox.createStubInstance(Mocha); + mocha.timeout.returnsThis(); + mocha.retries.returnsThis(); sandbox.stub(Mocha.prototype, 'timeout').returnsThis(); sandbox.stub(Mocha.prototype, 'global').returnsThis(); + sandbox.stub(Mocha.prototype, 'retries').returnsThis(); + sandbox.stub(Mocha.prototype, 'rootHooks').returnsThis(); }); it('should set _cleanReferencesAfterRun to true', function() { @@ -34,8 +41,8 @@ describe('Mocha', function() { }); }); - describe('when "options.timeout" is `false`', function() { - it('should set a timeout of 0', function() { + describe('when `timeout` option is `false`', function() { + it('should attempt to set timeout', function() { // eslint-disable-next-line no-new new Mocha({timeout: false}); expect(Mocha.prototype.timeout, 'to have a call satisfying', [0]).and( @@ -44,8 +51,8 @@ describe('Mocha', function() { }); }); - describe('when "options.global" is provided', function() { - it('should pass "options.global" to #global()', function() { + describe('when `global` option is an `Array`', function() { + it('should attempt to set globals', function() { // eslint-disable-next-line no-new new Mocha({global: ['singular']}); expect(Mocha.prototype.global, 'to have a call satisfying', [ @@ -53,6 +60,34 @@ describe('Mocha', function() { ]).and('was called once'); }); }); + + describe('when `retries` option is present', function() { + it('should attempt to set retries`', function() { + // eslint-disable-next-line no-new + new Mocha({retries: 1}); + expect(Mocha.prototype.retries, 'to have a call satisfying', [1]).and( + 'was called once' + ); + }); + }); + + describe('when `retries` option is not present', function() { + it('should not attempt to set retries', function() { + // eslint-disable-next-line no-new + new Mocha({}); + expect(Mocha.prototype.retries, 'was not called'); + }); + }); + + describe('when `rootHooks` option is truthy', function() { + it('shouid attempt to set root hooks', function() { + // eslint-disable-next-line no-new + new Mocha({rootHooks: ['a root hook']}); + expect(Mocha.prototype.rootHooks, 'to have a call satisfying', [ + ['a root hook'] + ]).and('was called once'); + }); + }); }); describe('#allowUncaught()', function() { diff --git a/test/unit/utils.spec.js b/test/unit/utils.spec.js index 3c68ddd186..a54535b1a5 100644 --- a/test/unit/utils.spec.js +++ b/test/unit/utils.spec.js @@ -14,7 +14,7 @@ describe('lib/utils', function() { sandbox.restore(); }); - describe('clean', function() { + describe('clean()', function() { it('should remove the wrapping function declaration', function() { expect( utils.clean('function (one, two, three) {\n//code\n}'), @@ -149,7 +149,7 @@ describe('lib/utils', function() { }); }); - describe('stringify', function() { + describe('stringify()', function() { var stringify = utils.stringify; it('should return an object representation of a string created with a String constructor', function() { @@ -525,7 +525,7 @@ describe('lib/utils', function() { }); }); - describe('type', function() { + describe('type()', function() { /* eslint no-extend-native: off */ var type = utils.type; @@ -588,7 +588,7 @@ describe('lib/utils', function() { }); }); - describe('isPromise', function() { + describe('isPromise()', function() { it('should return true if the value is Promise-ish', function() { expect( utils.isPromise({ @@ -612,7 +612,7 @@ describe('lib/utils', function() { }); }); - describe('escape', function() { + describe('escape()', function() { it('replaces the usual xml suspects', function() { expect(utils.escape('a>bc>d>'), 'to be', '>a>bc>d>'); @@ -634,7 +634,7 @@ describe('lib/utils', function() { }); }); - describe('deprecate', function() { + describe('deprecate()', function() { var emitWarning; beforeEach(function() { @@ -674,7 +674,7 @@ describe('lib/utils', function() { }); }); - describe('warn', function() { + describe('warn()', function() { var emitWarning; beforeEach(function() { @@ -710,13 +710,17 @@ describe('lib/utils', function() { }); }); - describe('sQuote/dQuote', function() { + describe('sQuote()', function() { var str = 'xxx'; it('should return its input as string wrapped in single quotes', function() { var expected = "'xxx'"; expect(utils.sQuote(str), 'to be', expected); }); + }); + + describe('dQuote()', function() { + var str = 'xxx'; it('should return its input as string wrapped in double quotes', function() { var expected = '"xxx"'; @@ -724,7 +728,7 @@ describe('lib/utils', function() { }); }); - describe('createMap', function() { + describe('createMap()', function() { it('should return an object with a null prototype', function() { expect(Object.getPrototypeOf(utils.createMap()), 'to be', null); }); @@ -743,4 +747,26 @@ describe('lib/utils', function() { ); }); }); + + describe('slug()', function() { + it('should convert the string to lowercase', function() { + expect(utils.slug('FOO'), 'to be', 'foo'); + }); + + it('should convert whitespace to dashes', function() { + expect( + utils.slug('peanut butter\nand\tjelly'), + 'to be', + 'peanut-butter-and-jelly' + ); + }); + + it('should strip non-alphanumeric and non-dash characters', function() { + expect(utils.slug('murder-hornets!!'), 'to be', 'murder-hornets'); + }); + + it('should disallow consecutive dashes', function() { + expect(utils.slug('poppies & fritz'), 'to be', 'poppies-fritz'); + }); + }); });