diff --git a/lib/jasmine-core/boot.js b/lib/jasmine-core/boot.js index 5fab6d3f..cd1a29a6 100644 --- a/lib/jasmine-core/boot.js +++ b/lib/jasmine-core/boot.js @@ -73,24 +73,21 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. var filterSpecs = !!queryString.getParam("spec"); - var stoppingOnSpecFailure = queryString.getParam("failFast"); - env.stopOnSpecFailure(stoppingOnSpecFailure); - - var throwingExpectationFailures = queryString.getParam("throwFailures"); - env.throwOnExpectationFailure(throwingExpectationFailures); - - var hideDisabled = queryString.getParam("hideDisabled"); - env.hideDisabled(hideDisabled); + var config = { + failFast: queryString.getParam("failFast"), + oneFailurePerSpec: queryString.getParam("oneFailurePerSpec"), + hideDisabled: queryString.getParam("hideDisabled") + }; var random = queryString.getParam("random"); if (random !== undefined && random !== "") { - env.randomizeTests(random); + config.random = random; } var seed = queryString.getParam("seed"); if (seed) { - env.seed(seed); + config.seed = seed; } /** @@ -121,10 +118,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. filterString: function() { return queryString.getParam("spec"); } }); - env.specFilter = function(spec) { + config.specFilter = function(spec) { return specFilter.matches(spec.getFullName()); }; + env.configure(config); + /** * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. */ diff --git a/lib/jasmine-core/boot/boot.js b/lib/jasmine-core/boot/boot.js index 97a04f85..2d684628 100644 --- a/lib/jasmine-core/boot/boot.js +++ b/lib/jasmine-core/boot/boot.js @@ -51,24 +51,21 @@ var filterSpecs = !!queryString.getParam("spec"); - var stoppingOnSpecFailure = queryString.getParam("failFast"); - env.stopOnSpecFailure(stoppingOnSpecFailure); - - var throwingExpectationFailures = queryString.getParam("throwFailures"); - env.throwOnExpectationFailure(throwingExpectationFailures); - - var hideDisabled = queryString.getParam("hideDisabled"); - env.hideDisabled(hideDisabled); + var config = { + failFast: queryString.getParam("failFast"), + oneFailurePerSpec: queryString.getParam("oneFailurePerSpec"), + hideDisabled: queryString.getParam("hideDisabled") + }; var random = queryString.getParam("random"); if (random !== undefined && random !== "") { - env.randomizeTests(random); + config.random = random; } var seed = queryString.getParam("seed"); if (seed) { - env.seed(seed); + config.seed = seed; } /** @@ -99,10 +96,12 @@ filterString: function() { return queryString.getParam("spec"); } }); - env.specFilter = function(spec) { + config.specFilter = function(spec) { return specFilter.matches(spec.getFullName()); }; + env.configure(config); + /** * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. */ diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index b7481850..f04d34a4 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -80,7 +80,7 @@ jasmineRequire.HtmlReporter = function(j$) { function HtmlReporter(options) { - var env = options.env || {}, + var config = function() { return (options.env && options.env.configuration()) || {}; }, getContainer = options.getContainer, createElement = options.createElement, createTextNode = options.createTextNode, @@ -167,9 +167,9 @@ jasmineRequire.HtmlReporter = function(j$) { this.resultStatus = function(status) { if(status === 'excluded') { - return env.hidingDisabled() ? 'jasmine-excluded-no-display' : 'jasmine-excluded'; - } - return 'jasmine-' + status; + return config().hideDisabled ? 'jasmine-excluded-no-display' : 'jasmine-excluded'; + } + return 'jasmine-' + status; }; this.jasmineDone = function(doneResult) { @@ -179,7 +179,7 @@ jasmineRequire.HtmlReporter = function(j$) { var i; alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's')); - banner.appendChild(optionsMenu(env)); + banner.appendChild(optionsMenu(config())); if (stateBuilder.specsExecuted < totalSpecsDefined) { var skippedMessage = 'Ran ' + stateBuilder.specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all'; @@ -339,7 +339,7 @@ jasmineRequire.HtmlReporter = function(j$) { } } - function optionsMenu(env) { + function optionsMenu(config) { var optionsMenuDom = createDom('div', { className: 'jasmine-run-options' }, createDom('span', { className: 'jasmine-trigger' }, 'Options'), createDom('div', { className: 'jasmine-payload' }, @@ -375,27 +375,27 @@ jasmineRequire.HtmlReporter = function(j$) { ); var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast'); - failFastCheckbox.checked = env.stoppingOnSpecFailure(); + failFastCheckbox.checked = config.failFast; failFastCheckbox.onclick = function() { - navigateWithNewParam('failFast', !env.stoppingOnSpecFailure()); + navigateWithNewParam('failFast', !config.failFast); }; var throwCheckbox = optionsMenuDom.querySelector('#jasmine-throw-failures'); - throwCheckbox.checked = env.throwingExpectationFailures(); + throwCheckbox.checked = config.oneFailurePerSpec; throwCheckbox.onclick = function() { - navigateWithNewParam('throwFailures', !env.throwingExpectationFailures()); + navigateWithNewParam('throwFailures', !config.oneFailurePerSpec); }; var randomCheckbox = optionsMenuDom.querySelector('#jasmine-random-order'); - randomCheckbox.checked = env.randomTests(); + randomCheckbox.checked = config.random; randomCheckbox.onclick = function() { - navigateWithNewParam('random', !env.randomTests()); + navigateWithNewParam('random', !config.random); }; var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled'); - hideDisabled.checked = env.hidingDisabled(); + hideDisabled.checked = config.hideDisabled; hideDisabled.onclick = function() { - navigateWithNewParam('hideDisabled', !env.hidingDisabled()); + navigateWithNewParam('hideDisabled', !config.hideDisabled); }; var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'), diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 797b2c29..1b86ef10 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -794,14 +794,62 @@ getJasmineRequireObj().Env = function(j$) { var currentSpec = null; var currentlyExecutingSuites = []; var currentDeclarationSuite = null; - var throwOnExpectationFailure = false; - var stopOnSpecFailure = false; - var random = true; - var hidingDisabled = false; - var seed = null; - var handlingLoadErrors = true; var hasFailures = false; + /** + * This represents the available options to configure Jasmine. + * Options that are not provided will use their default values + * @interface Configuration + */ + var config = { + /** + * Whether to randomize spec execution order + * @name Configuration#random + * @type Boolean + * @default true + */ + random: true, + /** + * Seed to use as the basis of randomization. + * Null causes the seed to be determined randomly at the start of execution. + * @name Configuration#seed + * @type function + * @default null + */ + seed: null, + /** + * Whether to stop execution of the suite after the first spec failure + * @name Configuration#failFast + * @type Boolean + * @default false + */ + failFast: false, + /** + * Whether to cause specs to only have one expectation failure. + * @name Configuration#oneFailurePerSpec + * @type Boolean + * @default false + */ + oneFailurePerSpec: false, + /** + * Function to use to filter specs + * @name Configuration#specFilter + * @type function + * @default true + */ + specFilter: function() { + return true; + }, + /** + * Whether or not reporters should hide disabled specs from their output. + * Currently only supported by Jasmine's HTMLReporter + * @name Configuration#hideDisabled + * @type Boolean + * @default false + */ + hideDisabled: false + }; + var currentSuite = function() { return currentlyExecutingSuites[currentlyExecutingSuites.length - 1]; }; @@ -834,10 +882,63 @@ getJasmineRequireObj().Env = function(j$) { }); } - this.specFilter = function() { - return true; + /** + * Configure your jasmine environment + * @name Env#configure + * @argument {Configuration} configuration + * @function + */ + this.configure = function(configuration) { + if (configuration.specFilter) { + config.specFilter = configuration.specFilter; + } + + if (configuration.hasOwnProperty('random')) { + config.random = !!configuration.random; + } + + if (configuration.hasOwnProperty('seed')) { + config.seed = configuration.seed; + } + + if (configuration.hasOwnProperty('failFast')) { + config.failFast = configuration.failFast; + } + + if (configuration.hasOwnProperty('oneFailurePerSpec')) { + config.oneFailurePerSpec = configuration.oneFailurePerSpec; + } + + if (configuration.hasOwnProperty('hideDisabled')) { + config.hideDisabled = configuration.hideDisabled; + } }; + /** + * Get the current configuration for your jasmine environment + * @name Env#configuration + * @function + * @returns {Configuration} + */ + this.configuration = function() { + var result = {}; + for (var property in config) { + result[property] = config[property]; + } + return result; + }; + + Object.defineProperty(this, 'specFilter', { + get: function() { + self.deprecated('Getting specFilter directly from Env is deprecated, please check the specFilter option from `configuration`'); + return config.specFilter; + }, + set: function(val) { + self.deprecated('Setting specFilter directly on Env is deprecated, please use the specFilter option in `configure`'); + config.specFilter = val; + } + }); + this.addSpyStrategy = function(name, fn) { if(!currentRunnable()) { throw new Error('Custom spy strategies must be added in a before function or a spec'); @@ -965,13 +1066,16 @@ getJasmineRequireObj().Env = function(j$) { * @name Env#throwOnExpectationFailure * @function * @param {Boolean} value Whether to throw when a expectation fails + * @deprecated Use the `oneFailurePerSpec` option with {@link Env#configure} */ this.throwOnExpectationFailure = function(value) { - throwOnExpectationFailure = !!value; + this.deprecated('Setting throwOnExpectationFailure directly on Env is deprecated, please use the oneFailurePerSpec option in `configure`'); + this.configure({oneFailurePerSpec: !!value}); }; this.throwingExpectationFailures = function() { - return throwOnExpectationFailure; + this.deprecated('Getting throwingExpectationFailures directly from Env is deprecated, please check the oneFailurePerSpec option from `configuration`'); + return config.oneFailurePerSpec; }; /** @@ -979,13 +1083,16 @@ getJasmineRequireObj().Env = function(j$) { * @name Env#stopOnSpecFailure * @function * @param {Boolean} value Whether to stop suite execution when a spec fails + * @deprecated Use the `failFast` option with {@link Env#configure} */ this.stopOnSpecFailure = function(value) { - stopOnSpecFailure = !!value; + this.deprecated('Setting stopOnSpecFailure directly is deprecated, please use the failFast option in `configure`'); + this.configure({failFast: !!value}); }; this.stoppingOnSpecFailure = function() { - return stopOnSpecFailure; + this.deprecated('Getting stoppingOnSpecFailure directly from Env is deprecated, please check the failFast option from `configuration`'); + return config.failFast; }; /** @@ -993,13 +1100,16 @@ getJasmineRequireObj().Env = function(j$) { * @name Env#randomizeTests * @function * @param {Boolean} value Whether to randomize execution order + * @deprecated Use the `random` option with {@link Env#configure} */ this.randomizeTests = function(value) { - random = !!value; + this.deprecated('Setting randomizeTests directly is deprecated, please use the random option in `configure`'); + config.random = !!value; }; this.randomTests = function() { - return random; + this.deprecated('Getting randomTests directly from Env is deprecated, please check the random option from `configuration`'); + return config.random; }; /** @@ -1007,16 +1117,19 @@ getJasmineRequireObj().Env = function(j$) { * @name Env#seed * @function * @param {Number} value The seed value + * @deprecated Use the `seed` option with {@link Env#configure} */ this.seed = function(value) { + this.deprecated('Setting seed directly is deprecated, please use the seed option in `configure`'); if (value) { - seed = value; + config.seed = value; } - return seed; + return config.seed; }; this.hidingDisabled = function(value) { - return hidingDisabled; + this.deprecated('Getting hidingDisabled directly from Env is deprecated, please check the hideDisabled option from `configuration`'); + return config.hideDisabled; }; /** @@ -1024,7 +1137,8 @@ getJasmineRequireObj().Env = function(j$) { * @function */ this.hideDisabled = function(value) { - hidingDisabled = !!value; + this.deprecated('Setting hideDisabled directly is deprecated, please use the hideDisabled option in `configure`'); + config.hideDisabled = !!value; }; this.deprecated = function(deprecation) { @@ -1038,9 +1152,9 @@ getJasmineRequireObj().Env = function(j$) { var queueRunnerFactory = function(options, args) { var failFast = false; if (options.isLeaf) { - failFast = throwOnExpectationFailure; + failFast = config.oneFailurePerSpec; } else if (!options.isReporter) { - failFast = stopOnSpecFailure; + failFast = config.failFast; } options.clearStack = options.clearStack || clearStack; options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}; @@ -1155,8 +1269,8 @@ getJasmineRequireObj().Env = function(j$) { } var order = new j$.Order({ - random: random, - seed: seed + random: config.random, + seed: config.seed }); var processor = new j$.TreeProcessor({ @@ -1186,7 +1300,7 @@ getJasmineRequireObj().Env = function(j$) { return order.sort(node.children); }, excludeNode: function(spec) { - return !self.specFilter(spec); + return !config.specFilter(spec); } }); @@ -1353,7 +1467,7 @@ getJasmineRequireObj().Env = function(j$) { expectationFactory: expectationFactory, asyncExpectationFactory: asyncExpectationFactory, expectationResultFactory: expectationResultFactory, - throwOnExpectationFailure: throwOnExpectationFailure + throwOnExpectationFailure: config.oneFailurePerSpec }); return suite; @@ -1459,7 +1573,7 @@ getJasmineRequireObj().Env = function(j$) { fn: fn, timeout: timeout || 0 }, - throwOnExpectationFailure: throwOnExpectationFailure + throwOnExpectationFailure: config.oneFailurePerSpec }); return spec; diff --git a/spec/core/EnvSpec.js b/spec/core/EnvSpec.js index 5c9118c8..f731d36b 100644 --- a/spec/core/EnvSpec.js +++ b/spec/core/EnvSpec.js @@ -27,7 +27,7 @@ describe("Env", function() { }); it('can configure specs to throw errors on expectation failures', function() { - env.throwOnExpectationFailure(true); + env.configure({oneFailurePerSpec: true}); spyOn(jasmineUnderTest, 'Spec'); env.it('foo', function() {}); @@ -37,7 +37,7 @@ describe("Env", function() { }); it('can configure suites to throw errors on expectation failures', function() { - env.throwOnExpectationFailure(true); + env.configure({oneFailurePerSpec: true}); spyOn(jasmineUnderTest, 'Suite'); env.describe('foo', function() {}); @@ -46,6 +46,22 @@ describe("Env", function() { })); }); + it('defaults to multiple failures for specs', function() { + spyOn(jasmineUnderTest, 'Spec'); + env.it('bar', function() {}); + expect(jasmineUnderTest.Spec).toHaveBeenCalledWith(jasmine.objectContaining({ + throwOnExpectationFailure: false + })); + }); + + it('defaults to multiple failures for suites', function() { + spyOn(jasmineUnderTest, 'Suite'); + env.describe('foo', function() {}); + expect(jasmineUnderTest.Suite).toHaveBeenCalledWith(jasmine.objectContaining({ + throwOnExpectationFailure: false + })); + }); + describe('#describe', function () { it("throws an error when given arguments", function() { expect(function() { diff --git a/spec/core/integration/CustomMatchersSpec.js b/spec/core/integration/CustomMatchersSpec.js index 6c1fba2b..17e66354 100644 --- a/spec/core/integration/CustomMatchersSpec.js +++ b/spec/core/integration/CustomMatchersSpec.js @@ -4,7 +4,7 @@ describe("Custom Matchers (Integration)", function() { beforeEach(function() { env = new jasmineUnderTest.Env(); - env.randomizeTests(false); + env.configure({random: false}); }); it("allows adding more matchers local to a spec", function(done) { diff --git a/spec/core/integration/CustomSpyStrategiesSpec.js b/spec/core/integration/CustomSpyStrategiesSpec.js index ba82362b..796d3478 100644 --- a/spec/core/integration/CustomSpyStrategiesSpec.js +++ b/spec/core/integration/CustomSpyStrategiesSpec.js @@ -3,7 +3,7 @@ describe('Custom Spy Strategies (Integration)', function() { beforeEach(function() { env = new jasmineUnderTest.Env(); - env.randomizeTests(false); + env.configure({random: false}); }); it('allows adding more strategies local to a suite', function(done) { diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index 694ffcc5..dc690984 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -17,7 +17,7 @@ describe("Env integration", function() { }; env.addReporter({ jasmineDone: assertions}); - env.randomizeTests(false); + env.configure({random: false}); env.describe("A Suite", function() { env.it("with a spec", function() { @@ -46,7 +46,7 @@ describe("Env integration", function() { }; env.addReporter({ jasmineDone: assertions }); - env.randomizeTests(false); + env.configure({random: false}); env.describe("Outer suite", function() { env.it("an outer spec", function() { @@ -81,7 +81,7 @@ describe("Env integration", function() { }; env.addReporter({ jasmineDone: assertions }); - env.randomizeTests(false); + env.configure({random: false}); env.describe("Outer suite", function() { @@ -200,7 +200,7 @@ describe("Env integration", function() { var env = new jasmineUnderTest.Env(); env.addReporter({jasmineDone: done}); - env.randomizeTests(false); + env.configure({random: false}); env.describe("tests", function() { var firstTimeThrough = true, firstSpecContext, secondSpecContext; @@ -783,9 +783,11 @@ describe("Env integration", function() { }); }); - env.specFilter = function(spec) { - return /^first suite/.test(spec.getFullName()); - }; + env.configure({ + specFilter: function(spec) { + return /^first suite/.test(spec.getFullName()); + } + }); env.execute(); }); @@ -953,7 +955,7 @@ describe("Env integration", function() { }; env.addReporter({ jasmineDone: assertions }); - env.randomizeTests(false); + env.configure({random: false}); env.describe("tests", function() { env.it("test with mock clock", function() { @@ -1476,8 +1478,7 @@ describe("Env integration", function() { "specStarted", "specDone" ]); - env.randomizeTests(true); - env.seed('123456'); + env.configure({random: true, seed: '123456'}); reporter.jasmineDone.and.callFake(function(doneArg) { expect(reporter.jasmineStarted).toHaveBeenCalled(); @@ -1491,7 +1492,7 @@ describe("Env integration", function() { }); env.addReporter(reporter); - env.randomizeTests(true); + env.configure({random: true}); env.execute(); }); @@ -1662,7 +1663,7 @@ describe("Env integration", function() { }); env.addReporter(reporter); - env.randomizeTests(false); + env.configure({random: false}); env.describe("testing custom equality testers", function() { env.it("with a custom tester", function() { @@ -1698,7 +1699,7 @@ describe("Env integration", function() { }); env.addReporter(reporter); - env.randomizeTests(false); + env.configure({random: false}); env.describe("testing custom equality testers", function() { env.beforeAll(function() { env.addCustomEqualityTester(function(a, b) { return true; }); }); @@ -1739,7 +1740,7 @@ describe("Env integration", function() { }); env.addReporter(reporter); - env.randomizeTests(false); + env.configure({random: false}); env.describe("testing custom equality testers", function() { env.it("with a custom tester", function() { @@ -1792,7 +1793,7 @@ describe("Env integration", function() { }); env.addReporter(reporter); - env.randomizeTests(false); + env.configure({random: false}); env.describe("testing custom equality testers", function() { env.beforeAll(function() { env.addCustomEqualityTester(function(a, b) { return true; })}); diff --git a/spec/core/integration/SpecRunningSpec.js b/spec/core/integration/SpecRunningSpec.js index b7289438..1bd670b4 100644 --- a/spec/core/integration/SpecRunningSpec.js +++ b/spec/core/integration/SpecRunningSpec.js @@ -4,7 +4,7 @@ describe("spec running", function () { beforeEach(function() { jasmine.getEnv().registerIntegrationMatchers(); env = new jasmineUnderTest.Env(); - env.randomizeTests(false); + env.configure({random: false}); }); it('should assign spec ids sequentially', function() { @@ -740,8 +740,7 @@ describe("spec running", function () { it("should run the tests in a consistent order when a seed is supplied", function(done) { var actions = []; - env.seed('123456'); - env.randomizeTests(true); + env.configure({random: true, seed: '123456'}); env.beforeEach(function () { actions.push('topSuite beforeEach'); @@ -865,7 +864,7 @@ describe("spec running", function () { }); }); - env.throwOnExpectationFailure(true); + env.configure({oneFailurePerSpec: true}); var assertions = function() { expect(actions).toEqual([ @@ -900,7 +899,7 @@ describe("spec running", function () { }); }); - env.throwOnExpectationFailure(true); + env.configure({oneFailurePerSpec: true}); var assertions = function() { expect(actions).toEqual([ @@ -932,6 +931,89 @@ describe("spec running", function () { }); }); + env.configure({oneFailurePerSpec: true}); + + var assertions = function() { + expect(actions).toEqual([ + 'beforeEach', + 'afterEach' + ]); + done(); + }; + + env.addReporter({jasmineDone: assertions}); + + env.execute(); + }); + + it("skips to cleanup functions after an error with deprecations", function(done) { + var actions = []; + + spyOn(env, 'deprecated'); + + env.describe('Something', function() { + env.beforeEach(function() { + actions.push('outer beforeEach'); + throw new Error("error"); + }); + + env.afterEach(function() { + actions.push('outer afterEach'); + }); + + env.describe('Inner', function() { + env.beforeEach(function() { + actions.push('inner beforeEach'); + }); + + env.afterEach(function() { + actions.push('inner afterEach'); + }); + + env.it('does it' , function() { + actions.push('inner it'); + }); + }); + }); + + env.throwOnExpectationFailure(true); + + var assertions = function() { + expect(actions).toEqual([ + 'outer beforeEach', + 'inner afterEach', + 'outer afterEach' + ]); + expect(env.deprecated).toHaveBeenCalled(); + done(); + }; + + env.addReporter({jasmineDone: assertions}); + + env.execute(); + }); + + it("skips to cleanup functions after done.fail is called with deprecations", function(done) { + var actions = []; + + spyOn(env, 'deprecated'); + + env.describe('Something', function() { + env.beforeEach(function(done) { + actions.push('beforeEach'); + done.fail('error'); + actions.push('after done.fail'); + }); + + env.afterEach(function() { + actions.push('afterEach'); + }); + + env.it('does it' , function() { + actions.push('it'); + }); + }); + env.throwOnExpectationFailure(true); var assertions = function() { @@ -939,6 +1021,42 @@ describe("spec running", function () { 'beforeEach', 'afterEach' ]); + expect(env.deprecated).toHaveBeenCalled(); + done(); + }; + + env.addReporter({jasmineDone: assertions}); + + env.execute(); + }); + + it("skips to cleanup functions when an async function times out with deprecations", function(done) { + var actions = []; + + spyOn(env, 'deprecated'); + + env.describe('Something', function() { + env.beforeEach(function(innerDone) { + actions.push('beforeEach'); + }, 1); + + env.afterEach(function() { + actions.push('afterEach'); + }); + + env.it('does it' , function() { + actions.push('it'); + }); + }); + + env.throwOnExpectationFailure(true); + + var assertions = function() { + expect(actions).toEqual([ + 'beforeEach', + 'afterEach' + ]); + expect(env.deprecated).toHaveBeenCalled(); done(); }; @@ -965,8 +1083,7 @@ describe("spec running", function () { }); }); - env.randomizeTests(false); - env.stopOnSpecFailure(true); + env.configure({random: false, failFast: true}); var assertions = function() { expect(actions).toEqual(['fails']); @@ -976,5 +1093,36 @@ describe("spec running", function () { env.addReporter({ jasmineDone: assertions }); env.execute(); }); + + it("does not run further specs when one fails when configured with deprecated option", function(done) { + var actions = []; + + spyOn(env, 'deprecated'); + + env.describe('wrapper', function() { + env.it('fails', function() { + actions.push('fails'); + env.expect(1).toBe(2); + }); + }); + + env.describe('holder', function() { + env.it('does not run', function() { + actions.push('does not run'); + }); + }); + + env.configure({random: false}); + env.stopOnSpecFailure(true); + + var assertions = function() { + expect(actions).toEqual(['fails']); + expect(env.deprecated).toHaveBeenCalled(); + done(); + }; + + env.addReporter({ jasmineDone: assertions }); + env.execute(); + }); }); }); diff --git a/spec/html/HtmlReporterSpec.js b/spec/html/HtmlReporterSpec.js index 2e92684c..8b40139c 100644 --- a/spec/html/HtmlReporterSpec.js +++ b/spec/html/HtmlReporterSpec.js @@ -518,7 +518,7 @@ describe("HtmlReporter", function() { } }); - env.stopOnSpecFailure(true); + env.configure({failFast: true}); reporter.initialize(); reporter.jasmineDone({}); @@ -574,7 +574,7 @@ describe("HtmlReporter", function() { } }); - env.stopOnSpecFailure(true); + env.configure({failFast: true}); reporter.initialize(); reporter.jasmineDone({}); @@ -628,7 +628,7 @@ describe("HtmlReporter", function() { } }); - env.throwOnExpectationFailure(true); + env.configure({oneFailurePerSpec: true}); reporter.initialize(); reporter.jasmineDone({}); @@ -684,7 +684,7 @@ describe("HtmlReporter", function() { } }); - env.throwOnExpectationFailure(true); + env.configure({oneFailurePerSpec: true}); reporter.initialize(); reporter.jasmineDone({}); @@ -713,7 +713,7 @@ describe("HtmlReporter", function() { } }); - env.hideDisabled(false); + env.configure({hideDisabled: false}); reporter.initialize(); reporter.jasmineDone({}); @@ -738,7 +738,7 @@ describe("HtmlReporter", function() { } }); - env.hideDisabled(true); + env.configure({hideDisabled: true}); reporter.initialize(); reporter.jasmineDone({}); @@ -748,27 +748,24 @@ describe("HtmlReporter", function() { it("should not display specs that have been disabled", function() { var env = new jasmineUnderTest.Env(), - container = document.createElement('div'), - - getContainer = function() {return container;}, - - reporter = new jasmineUnderTest.HtmlReporter({ - env: env, - getContainer: getContainer, - createElement: function() { return document.createElement.apply(document, arguments); }, - createTextNode: function() { return document.createTextNode.apply(document, arguments); } - }); - env.hideDisabled(true); - reporter.initialize(); - reporter.specDone({ - id: 789, - status: "excluded", - fullName: "symbols should have titles", - passedExpectations: [], - failedExpectations: [] + container = document.createElement('div'), + getContainer = function() {return container;}, + reporter = new jasmineUnderTest.HtmlReporter({ + env: env, + getContainer: getContainer, + createElement: function() { return document.createElement.apply(document, arguments); }, + createTextNode: function() { return document.createTextNode.apply(document, arguments); } }); - + env.configure({hideDisabled: true}); + reporter.initialize(); + reporter.specDone({ + id: 789, + status: "excluded", + fullName: "symbols should have titles", + passedExpectations: [], + failedExpectations: [] + }); var specEl = container.querySelector('.jasmine-symbol-summary li'); expect(specEl.getAttribute("class")).toEqual("jasmine-excluded-no-display"); @@ -792,7 +789,7 @@ describe("HtmlReporter", function() { } }); - env.randomizeTests(false); + env.configure({random: false}); reporter.initialize(); reporter.jasmineDone({}); @@ -817,7 +814,7 @@ describe("HtmlReporter", function() { } }); - env.randomizeTests(true); + env.configure({random: true}); reporter.initialize(); reporter.jasmineDone({}); @@ -844,7 +841,7 @@ describe("HtmlReporter", function() { } }); - env.randomizeTests(false); + env.configure({random: false}); reporter.initialize(); reporter.jasmineDone({}); @@ -873,7 +870,7 @@ describe("HtmlReporter", function() { } }); - env.randomizeTests(true); + env.configure({random: true}); reporter.initialize(); reporter.jasmineDone({}); diff --git a/src/core/Env.js b/src/core/Env.js index f5a62a29..19105525 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -23,14 +23,62 @@ getJasmineRequireObj().Env = function(j$) { var currentSpec = null; var currentlyExecutingSuites = []; var currentDeclarationSuite = null; - var throwOnExpectationFailure = false; - var stopOnSpecFailure = false; - var random = true; - var hidingDisabled = false; - var seed = null; - var handlingLoadErrors = true; var hasFailures = false; + /** + * This represents the available options to configure Jasmine. + * Options that are not provided will use their default values + * @interface Configuration + */ + var config = { + /** + * Whether to randomize spec execution order + * @name Configuration#random + * @type Boolean + * @default true + */ + random: true, + /** + * Seed to use as the basis of randomization. + * Null causes the seed to be determined randomly at the start of execution. + * @name Configuration#seed + * @type function + * @default null + */ + seed: null, + /** + * Whether to stop execution of the suite after the first spec failure + * @name Configuration#failFast + * @type Boolean + * @default false + */ + failFast: false, + /** + * Whether to cause specs to only have one expectation failure. + * @name Configuration#oneFailurePerSpec + * @type Boolean + * @default false + */ + oneFailurePerSpec: false, + /** + * Function to use to filter specs + * @name Configuration#specFilter + * @type function + * @default true + */ + specFilter: function() { + return true; + }, + /** + * Whether or not reporters should hide disabled specs from their output. + * Currently only supported by Jasmine's HTMLReporter + * @name Configuration#hideDisabled + * @type Boolean + * @default false + */ + hideDisabled: false + }; + var currentSuite = function() { return currentlyExecutingSuites[currentlyExecutingSuites.length - 1]; }; @@ -63,10 +111,63 @@ getJasmineRequireObj().Env = function(j$) { }); } - this.specFilter = function() { - return true; + /** + * Configure your jasmine environment + * @name Env#configure + * @argument {Configuration} configuration + * @function + */ + this.configure = function(configuration) { + if (configuration.specFilter) { + config.specFilter = configuration.specFilter; + } + + if (configuration.hasOwnProperty('random')) { + config.random = !!configuration.random; + } + + if (configuration.hasOwnProperty('seed')) { + config.seed = configuration.seed; + } + + if (configuration.hasOwnProperty('failFast')) { + config.failFast = configuration.failFast; + } + + if (configuration.hasOwnProperty('oneFailurePerSpec')) { + config.oneFailurePerSpec = configuration.oneFailurePerSpec; + } + + if (configuration.hasOwnProperty('hideDisabled')) { + config.hideDisabled = configuration.hideDisabled; + } }; + /** + * Get the current configuration for your jasmine environment + * @name Env#configuration + * @function + * @returns {Configuration} + */ + this.configuration = function() { + var result = {}; + for (var property in config) { + result[property] = config[property]; + } + return result; + }; + + Object.defineProperty(this, 'specFilter', { + get: function() { + self.deprecated('Getting specFilter directly from Env is deprecated, please check the specFilter option from `configuration`'); + return config.specFilter; + }, + set: function(val) { + self.deprecated('Setting specFilter directly on Env is deprecated, please use the specFilter option in `configure`'); + config.specFilter = val; + } + }); + this.addSpyStrategy = function(name, fn) { if(!currentRunnable()) { throw new Error('Custom spy strategies must be added in a before function or a spec'); @@ -194,13 +295,16 @@ getJasmineRequireObj().Env = function(j$) { * @name Env#throwOnExpectationFailure * @function * @param {Boolean} value Whether to throw when a expectation fails + * @deprecated Use the `oneFailurePerSpec` option with {@link Env#configure} */ this.throwOnExpectationFailure = function(value) { - throwOnExpectationFailure = !!value; + this.deprecated('Setting throwOnExpectationFailure directly on Env is deprecated, please use the oneFailurePerSpec option in `configure`'); + this.configure({oneFailurePerSpec: !!value}); }; this.throwingExpectationFailures = function() { - return throwOnExpectationFailure; + this.deprecated('Getting throwingExpectationFailures directly from Env is deprecated, please check the oneFailurePerSpec option from `configuration`'); + return config.oneFailurePerSpec; }; /** @@ -208,13 +312,16 @@ getJasmineRequireObj().Env = function(j$) { * @name Env#stopOnSpecFailure * @function * @param {Boolean} value Whether to stop suite execution when a spec fails + * @deprecated Use the `failFast` option with {@link Env#configure} */ this.stopOnSpecFailure = function(value) { - stopOnSpecFailure = !!value; + this.deprecated('Setting stopOnSpecFailure directly is deprecated, please use the failFast option in `configure`'); + this.configure({failFast: !!value}); }; this.stoppingOnSpecFailure = function() { - return stopOnSpecFailure; + this.deprecated('Getting stoppingOnSpecFailure directly from Env is deprecated, please check the failFast option from `configuration`'); + return config.failFast; }; /** @@ -222,13 +329,16 @@ getJasmineRequireObj().Env = function(j$) { * @name Env#randomizeTests * @function * @param {Boolean} value Whether to randomize execution order + * @deprecated Use the `random` option with {@link Env#configure} */ this.randomizeTests = function(value) { - random = !!value; + this.deprecated('Setting randomizeTests directly is deprecated, please use the random option in `configure`'); + config.random = !!value; }; this.randomTests = function() { - return random; + this.deprecated('Getting randomTests directly from Env is deprecated, please check the random option from `configuration`'); + return config.random; }; /** @@ -236,16 +346,19 @@ getJasmineRequireObj().Env = function(j$) { * @name Env#seed * @function * @param {Number} value The seed value + * @deprecated Use the `seed` option with {@link Env#configure} */ this.seed = function(value) { + this.deprecated('Setting seed directly is deprecated, please use the seed option in `configure`'); if (value) { - seed = value; + config.seed = value; } - return seed; + return config.seed; }; this.hidingDisabled = function(value) { - return hidingDisabled; + this.deprecated('Getting hidingDisabled directly from Env is deprecated, please check the hideDisabled option from `configuration`'); + return config.hideDisabled; }; /** @@ -253,7 +366,8 @@ getJasmineRequireObj().Env = function(j$) { * @function */ this.hideDisabled = function(value) { - hidingDisabled = !!value; + this.deprecated('Setting hideDisabled directly is deprecated, please use the hideDisabled option in `configure`'); + config.hideDisabled = !!value; }; this.deprecated = function(deprecation) { @@ -267,9 +381,9 @@ getJasmineRequireObj().Env = function(j$) { var queueRunnerFactory = function(options, args) { var failFast = false; if (options.isLeaf) { - failFast = throwOnExpectationFailure; + failFast = config.oneFailurePerSpec; } else if (!options.isReporter) { - failFast = stopOnSpecFailure; + failFast = config.failFast; } options.clearStack = options.clearStack || clearStack; options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}; @@ -384,8 +498,8 @@ getJasmineRequireObj().Env = function(j$) { } var order = new j$.Order({ - random: random, - seed: seed + random: config.random, + seed: config.seed }); var processor = new j$.TreeProcessor({ @@ -415,7 +529,7 @@ getJasmineRequireObj().Env = function(j$) { return order.sort(node.children); }, excludeNode: function(spec) { - return !self.specFilter(spec); + return !config.specFilter(spec); } }); @@ -582,7 +696,7 @@ getJasmineRequireObj().Env = function(j$) { expectationFactory: expectationFactory, asyncExpectationFactory: asyncExpectationFactory, expectationResultFactory: expectationResultFactory, - throwOnExpectationFailure: throwOnExpectationFailure + throwOnExpectationFailure: config.oneFailurePerSpec }); return suite; @@ -688,7 +802,7 @@ getJasmineRequireObj().Env = function(j$) { fn: fn, timeout: timeout || 0 }, - throwOnExpectationFailure: throwOnExpectationFailure + throwOnExpectationFailure: config.oneFailurePerSpec }); return spec; @@ -836,7 +950,7 @@ getJasmineRequireObj().Env = function(j$) { error: error && error.message ? error : null }); - if (self.throwingExpectationFailures()) { + if (config.oneFailurePerSpec) { throw new Error(message); } }; diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index 99f3213e..a5ad4c63 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -51,7 +51,7 @@ jasmineRequire.HtmlReporter = function(j$) { function HtmlReporter(options) { - var env = options.env || {}, + var config = function() { return (options.env && options.env.configuration()) || {}; }, getContainer = options.getContainer, createElement = options.createElement, createTextNode = options.createTextNode, @@ -138,9 +138,9 @@ jasmineRequire.HtmlReporter = function(j$) { this.resultStatus = function(status) { if(status === 'excluded') { - return env.hidingDisabled() ? 'jasmine-excluded-no-display' : 'jasmine-excluded'; - } - return 'jasmine-' + status; + return config().hideDisabled ? 'jasmine-excluded-no-display' : 'jasmine-excluded'; + } + return 'jasmine-' + status; }; this.jasmineDone = function(doneResult) { @@ -150,7 +150,7 @@ jasmineRequire.HtmlReporter = function(j$) { var i; alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's')); - banner.appendChild(optionsMenu(env)); + banner.appendChild(optionsMenu(config())); if (stateBuilder.specsExecuted < totalSpecsDefined) { var skippedMessage = 'Ran ' + stateBuilder.specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all'; @@ -310,7 +310,7 @@ jasmineRequire.HtmlReporter = function(j$) { } } - function optionsMenu(env) { + function optionsMenu(config) { var optionsMenuDom = createDom('div', { className: 'jasmine-run-options' }, createDom('span', { className: 'jasmine-trigger' }, 'Options'), createDom('div', { className: 'jasmine-payload' }, @@ -346,27 +346,27 @@ jasmineRequire.HtmlReporter = function(j$) { ); var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast'); - failFastCheckbox.checked = env.stoppingOnSpecFailure(); + failFastCheckbox.checked = config.failFast; failFastCheckbox.onclick = function() { - navigateWithNewParam('failFast', !env.stoppingOnSpecFailure()); + navigateWithNewParam('failFast', !config.failFast); }; var throwCheckbox = optionsMenuDom.querySelector('#jasmine-throw-failures'); - throwCheckbox.checked = env.throwingExpectationFailures(); + throwCheckbox.checked = config.oneFailurePerSpec; throwCheckbox.onclick = function() { - navigateWithNewParam('throwFailures', !env.throwingExpectationFailures()); + navigateWithNewParam('throwFailures', !config.oneFailurePerSpec); }; var randomCheckbox = optionsMenuDom.querySelector('#jasmine-random-order'); - randomCheckbox.checked = env.randomTests(); + randomCheckbox.checked = config.random; randomCheckbox.onclick = function() { - navigateWithNewParam('random', !env.randomTests()); + navigateWithNewParam('random', !config.random); }; var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled'); - hideDisabled.checked = env.hidingDisabled(); + hideDisabled.checked = config.hideDisabled; hideDisabled.onclick = function() { - navigateWithNewParam('hideDisabled', !env.hidingDisabled()); + navigateWithNewParam('hideDisabled', !config.hideDisabled); }; var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),