diff --git a/lib/jasmine-core/jasmine-html.js b/lib/jasmine-core/jasmine-html.js index 14cf7a0a..e4c34a73 100644 --- a/lib/jasmine-core/jasmine-html.js +++ b/lib/jasmine-core/jasmine-html.js @@ -90,7 +90,8 @@ jasmineRequire.HtmlReporter = function(j$) { filterSpecs = options.filterSpecs, timer = options.timer || noopTimer, htmlReporterMain, - symbols; + symbols, + deprecationWarnings = []; this.initialize = function() { clearPrior(); @@ -128,6 +129,7 @@ jasmineRequire.HtmlReporter = function(j$) { if (result.status === 'failed') { failures.push(failureDom(result)); } + addDeprecationWarnings(result); }; this.specStarted = function(result) { @@ -156,6 +158,8 @@ jasmineRequire.HtmlReporter = function(j$) { if (result.status === 'failed') { failures.push(failureDom(result)); } + + addDeprecationWarnings(result); }; this.jasmineDone = function(doneResult) { @@ -225,6 +229,14 @@ jasmineRequire.HtmlReporter = function(j$) { } } + addDeprecationWarnings(doneResult); + + var warningBarClassName = 'jasmine-bar jasmine-warning'; + for(i = 0; i < deprecationWarnings.length; i++) { + var warning = deprecationWarnings[i]; + alert.appendChild(createDom('span', {className: warningBarClassName}, 'DEPRECATION: ' + warning)); + } + var results = find('.jasmine-results'); results.appendChild(summary); @@ -405,6 +417,17 @@ jasmineRequire.HtmlReporter = function(j$) { return addToExistingQueryString('spec', els.join(' ')); } + function addDeprecationWarnings(result) { + if (result && result.deprecationWarnings) { + for(var i = 0; i < result.deprecationWarnings.length; i++) { + var warning = result.deprecationWarnings[i].message; + if (!j$.util.arrayContains(warning)) { + deprecationWarnings.push(warning); + } + } + } + } + function find(selector) { return getContainer().querySelector('.jasmine_html-reporter ' + selector); } diff --git a/lib/jasmine-core/jasmine.css b/lib/jasmine-core/jasmine.css index 941ecc50..5111cbfe 100644 --- a/lib/jasmine-core/jasmine.css +++ b/lib/jasmine-core/jasmine.css @@ -33,6 +33,13 @@ body { overflow-y: scroll; } .jasmine_html-reporter .jasmine-bar.jasmine-passed { background-color: #007069; } .jasmine_html-reporter .jasmine-bar.jasmine-incomplete { background-color: #bababa; } .jasmine_html-reporter .jasmine-bar.jasmine-skipped { background-color: #bababa; } +<<<<<<< HEAD +||||||| merged common ancestors +.jasmine_html-reporter .jasmine-bar.jasmine-errored { background-color: #ca3a11; } +======= +.jasmine_html-reporter .jasmine-bar.jasmine-errored { background-color: #ca3a11; } +.jasmine_html-reporter .jasmine-bar.jasmine-warning { background-color: #ba9d37; color: #333; } +>>>>>>> master .jasmine_html-reporter .jasmine-bar.jasmine-menu { background-color: #fff; color: #aaa; } .jasmine_html-reporter .jasmine-bar.jasmine-menu a { color: #333; } .jasmine_html-reporter .jasmine-bar a { color: white; } diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index b11c58ae..23bb6861 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -514,6 +514,7 @@ getJasmineRequireObj().Spec = function(j$) { * @property {String} fullName - The full description including all ancestors of this spec. * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec. * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec. + * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec. * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec. */ @@ -523,6 +524,7 @@ getJasmineRequireObj().Spec = function(j$) { fullName: this.getFullName(), failedExpectations: [], passedExpectations: [], + deprecationWarnings: [], pendingReason: '' }; } @@ -639,6 +641,10 @@ getJasmineRequireObj().Spec = function(j$) { return this.getSpecName(this); }; + Spec.prototype.addDeprecationWarning = function(msg) { + this.result.deprecationWarnings.push(this.expectationResultFactory({ message: msg })); + }; + var extractCustomPendingMessage = function(e) { var fullMessage = e.toString(), boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage), @@ -909,6 +915,14 @@ getJasmineRequireObj().Env = function(j$) { handlingLoadErrors = false; }; + this.deprecated = function(msg) { + var runnable = currentRunnable() || topSuite; + runnable.addDeprecationWarning(msg); + if(typeof console !== 'undefined' && typeof console.warn !== 'undefined') { + console.error('DEPRECATION: ' + msg); + } + }; + var queueRunnerFactory = function(options, args) { var failFast = false; if (options.isLeaf) { @@ -924,6 +938,7 @@ getJasmineRequireObj().Env = function(j$) { options.onException = options.onException || function(e) { (currentRunnable() || topSuite).onException(e); }; + options.deprecated = self.deprecated; new j$.QueueRunner(options).execute(args); }; @@ -1083,12 +1098,14 @@ getJasmineRequireObj().Env = function(j$) { * @property {IncompleteReason} - Explanation of why the suite was incimplete. * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level. + * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level. */ reporter.jasmineDone({ overallStatus: overallStatus, incompleteReason: incompleteReason, order: order, - failedExpectations: topSuite.result.failedExpectations + failedExpectations: topSuite.result.failedExpectations, + deprecationWarnings: topSuite.result.deprecationWarnings }, function() {}); }); }); @@ -1214,6 +1231,7 @@ getJasmineRequireObj().Env = function(j$) { var focusedRunnables = []; this.fdescribe = function(description, specDefinitions) { + this.deprecated('fit and fdescribe will cause your suite to report an \'incomplete\' status in Jasmine 3.0'); ensureIsNotNested('fdescribe'); ensureIsFunction(specDefinitions, 'fdescribe'); var suite = suiteFactory(description); @@ -1338,6 +1356,7 @@ getJasmineRequireObj().Env = function(j$) { }; this.fit = function(description, fn, timeout){ + this.deprecated('fit and fdescribe will cause your suite to report an \'incomplete\' status in Jasmine 3.0'); ensureIsNotNested('fit'); ensureIsFunctionOrAsync(fn, 'fit'); var spec = specFactory(description, fn, currentDeclarationSuite, timeout); @@ -4505,6 +4524,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (typeof(this.onComplete) !== 'function') { throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete)); } + this.deprecated = attrs.deprecated; } QueueRunner.prototype.execute = function() { @@ -5604,13 +5624,15 @@ getJasmineRequireObj().Suite = function(j$) { * @property {String} description - The description text passed to the {@link describe} that made this suite. * @property {String} fullName - The full description including all ancestors of this suite. * @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite. + * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. */ this.result = { id: this.id, description: this.description, fullName: this.getFullName(), - failedExpectations: [] + failedExpectations: [], + deprecationWarnings: [] }; } @@ -5729,6 +5751,10 @@ getJasmineRequireObj().Suite = function(j$) { } }; + Suite.prototype.addDeprecationWarning = function(msg) { + this.result.deprecationWarnings.push(this.expectationResultFactory({ message: msg })); + }; + function isFailure(args) { return !args[0]; } diff --git a/release_notes/2.99.md b/release_notes/2.99.md new file mode 100644 index 00000000..405474fa --- /dev/null +++ b/release_notes/2.99.md @@ -0,0 +1,19 @@ +# Jasmine-Core 2.99 Release Notes + +## Summary + +This release is part of the upgrade path to Jasmine 3.0. It deprecates some functionality that will change. + +## Changes + +* Add ability to report deprecation warnings from within the suite and display them in the HTML reporter +* Add deprecation messages for things that will change/break in 3.0 +* * done for async functionality will now add a failure if it is invoked with an Error +* * Env.catchExceptions and the query param are going away, in favor of a more fully functional fail fast handler +* * jasmine.Any(Object) will no longer match null +* * Unhandled errors during suite load will be caught and reported as failures by Jasmine +* * Calling execute more than once on the same spec will definitely fail in 3.0 + +------ + +_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ diff --git a/spec/core/SpecSpec.js b/spec/core/SpecSpec.js index e20ad2bb..df75d122 100644 --- a/spec/core/SpecSpec.js +++ b/spec/core/SpecSpec.js @@ -206,6 +206,7 @@ describe("Spec", function() { fullName: 'a suite with a spec', failedExpectations: [], passedExpectations: [], + deprecationWarnings: [], pendingReason: '' }, 'things'); }); diff --git a/spec/core/integration/EnvSpec.js b/spec/core/integration/EnvSpec.js index e8c6b13d..58109f8c 100644 --- a/spec/core/integration/EnvSpec.js +++ b/spec/core/integration/EnvSpec.js @@ -2298,4 +2298,47 @@ describe("Env integration", function() { }); }); }); + + it('should report deprecation warnings on the correct specs and suites', function(done) { + var env = new jasmineUnderTest.Env(), + reporter = jasmine.createSpyObj('reporter', ['jasmineDone', 'suiteDone', 'specDone']); + + reporter.jasmineDone.and.callFake(function(result) { + expect(result.deprecationWarnings).toEqual([ + jasmine.objectContaining({ message: 'top level deprecation' }) + ]); + + expect(reporter.suiteDone).toHaveBeenCalledWith(jasmine.objectContaining({ + fullName: 'suite', + deprecationWarnings: [ + jasmine.objectContaining({ message: 'suite level deprecation' }) + ] + })); + + expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({ + fullName: 'suite spec', + deprecationWarnings: [ + jasmine.objectContaining({ message: 'spec level deprecation' }) + ] + })); + + done(); + }); + + env.addReporter(reporter); + + env.deprecated('top level deprecation'); + + env.describe('suite', function() { + env.beforeAll(function() { + env.deprecated('suite level deprecation'); + }); + + env.it('spec', function() { + env.deprecated('spec level deprecation'); + }); + }); + + env.execute(); + }); }); diff --git a/spec/html/HtmlReporterSpec.js b/spec/html/HtmlReporterSpec.js index 0307d7f6..1d5a384e 100644 --- a/spec/html/HtmlReporterSpec.js +++ b/spec/html/HtmlReporterSpec.js @@ -177,6 +177,47 @@ describe("HtmlReporter", function() { }); }); + describe('when there are deprecation warnings', function() { + it('displays the messages in their own alert bars', 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); } + }); + + reporter.initialize(); + + reporter.jasmineStarted({}); + reporter.specDone({ + status: 'passed', + deprecationWarnings: [{ message: 'spec deprecation' }], + failedExpectations: [], + passedExpectations: [] + }); + reporter.suiteDone({ + status: 'passed', + deprecationWarnings: [{ message: 'suite deprecation' }], + failedExpectations: [] + }); + reporter.jasmineDone({ + deprecationWarnings: [{ message: 'global deprecation' }], + failedExpectations: [] + }); + + var alertBars = container.querySelectorAll(".jasmine-alert .jasmine-bar"); + + expect(alertBars.length).toEqual(4); + expect(alertBars[1].innerHTML).toMatch(/spec deprecation/); + expect(alertBars[1].getAttribute("class")).toEqual('jasmine-bar jasmine-warning'); + expect(alertBars[2].innerHTML).toMatch(/suite deprecation/); + expect(alertBars[3].innerHTML).toMatch(/global deprecation/); + }); + }); + describe("when Jasmine is done", function() { it("adds a warning to the link title of specs that have no expectations", function() { if (!window.console) { diff --git a/src/core/Env.js b/src/core/Env.js index 74d18a6d..f9fa181e 100644 --- a/src/core/Env.js +++ b/src/core/Env.js @@ -200,6 +200,14 @@ getJasmineRequireObj().Env = function(j$) { handlingLoadErrors = false; }; + this.deprecated = function(msg) { + var runnable = currentRunnable() || topSuite; + runnable.addDeprecationWarning(msg); + if(typeof console !== 'undefined' && typeof console.warn !== 'undefined') { + console.error('DEPRECATION: ' + msg); + } + }; + var queueRunnerFactory = function(options, args) { var failFast = false; if (options.isLeaf) { @@ -215,6 +223,7 @@ getJasmineRequireObj().Env = function(j$) { options.onException = options.onException || function(e) { (currentRunnable() || topSuite).onException(e); }; + options.deprecated = self.deprecated; new j$.QueueRunner(options).execute(args); }; @@ -374,12 +383,14 @@ getJasmineRequireObj().Env = function(j$) { * @property {IncompleteReason} - Explanation of why the suite was incimplete. * @property {Order} order - Information about the ordering (random or not) of this execution of the suite. * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level. + * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level. */ reporter.jasmineDone({ overallStatus: overallStatus, incompleteReason: incompleteReason, order: order, - failedExpectations: topSuite.result.failedExpectations + failedExpectations: topSuite.result.failedExpectations, + deprecationWarnings: topSuite.result.deprecationWarnings }, function() {}); }); }); diff --git a/src/core/QueueRunner.js b/src/core/QueueRunner.js index 71082efb..932c50ba 100644 --- a/src/core/QueueRunner.js +++ b/src/core/QueueRunner.js @@ -31,6 +31,7 @@ getJasmineRequireObj().QueueRunner = function(j$) { if (typeof(this.onComplete) !== 'function') { throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete)); } + this.deprecated = attrs.deprecated; } QueueRunner.prototype.execute = function() { diff --git a/src/core/Spec.js b/src/core/Spec.js index 5732b2aa..ef5f0d02 100644 --- a/src/core/Spec.js +++ b/src/core/Spec.js @@ -25,6 +25,7 @@ getJasmineRequireObj().Spec = function(j$) { * @property {String} fullName - The full description including all ancestors of this spec. * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec. * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec. + * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec. * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason. * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec. */ @@ -34,6 +35,7 @@ getJasmineRequireObj().Spec = function(j$) { fullName: this.getFullName(), failedExpectations: [], passedExpectations: [], + deprecationWarnings: [], pendingReason: '' }; } @@ -150,6 +152,10 @@ getJasmineRequireObj().Spec = function(j$) { return this.getSpecName(this); }; + Spec.prototype.addDeprecationWarning = function(msg) { + this.result.deprecationWarnings.push(this.expectationResultFactory({ message: msg })); + }; + var extractCustomPendingMessage = function(e) { var fullMessage = e.toString(), boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage), diff --git a/src/core/Suite.js b/src/core/Suite.js index ca7906a8..b64d9489 100644 --- a/src/core/Suite.js +++ b/src/core/Suite.js @@ -21,13 +21,15 @@ getJasmineRequireObj().Suite = function(j$) { * @property {String} description - The description text passed to the {@link describe} that made this suite. * @property {String} fullName - The full description including all ancestors of this suite. * @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite. + * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite. * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite. */ this.result = { id: this.id, description: this.description, fullName: this.getFullName(), - failedExpectations: [] + failedExpectations: [], + deprecationWarnings: [] }; } @@ -146,6 +148,10 @@ getJasmineRequireObj().Suite = function(j$) { } }; + Suite.prototype.addDeprecationWarning = function(msg) { + this.result.deprecationWarnings.push(this.expectationResultFactory({ message: msg })); + }; + function isFailure(args) { return !args[0]; } diff --git a/src/html/HtmlReporter.js b/src/html/HtmlReporter.js index bef88a20..33e2a4fc 100644 --- a/src/html/HtmlReporter.js +++ b/src/html/HtmlReporter.js @@ -60,7 +60,8 @@ jasmineRequire.HtmlReporter = function(j$) { filterSpecs = options.filterSpecs, timer = options.timer || noopTimer, htmlReporterMain, - symbols; + symbols, + deprecationWarnings = []; this.initialize = function() { clearPrior(); @@ -98,6 +99,7 @@ jasmineRequire.HtmlReporter = function(j$) { if (result.status === 'failed') { failures.push(failureDom(result)); } + addDeprecationWarnings(result); }; this.specStarted = function(result) { @@ -126,6 +128,8 @@ jasmineRequire.HtmlReporter = function(j$) { if (result.status === 'failed') { failures.push(failureDom(result)); } + + addDeprecationWarnings(result); }; this.jasmineDone = function(doneResult) { @@ -195,6 +199,14 @@ jasmineRequire.HtmlReporter = function(j$) { } } + addDeprecationWarnings(doneResult); + + var warningBarClassName = 'jasmine-bar jasmine-warning'; + for(i = 0; i < deprecationWarnings.length; i++) { + var warning = deprecationWarnings[i]; + alert.appendChild(createDom('span', {className: warningBarClassName}, 'DEPRECATION: ' + warning)); + } + var results = find('.jasmine-results'); results.appendChild(summary); @@ -375,6 +387,17 @@ jasmineRequire.HtmlReporter = function(j$) { return addToExistingQueryString('spec', els.join(' ')); } + function addDeprecationWarnings(result) { + if (result && result.deprecationWarnings) { + for(var i = 0; i < result.deprecationWarnings.length; i++) { + var warning = result.deprecationWarnings[i].message; + if (!j$.util.arrayContains(warning)) { + deprecationWarnings.push(warning); + } + } + } + } + function find(selector) { return getContainer().querySelector('.jasmine_html-reporter ' + selector); } diff --git a/src/html/_HTMLReporter.scss b/src/html/_HTMLReporter.scss index f74ed7ff..4d53ee9d 100644 --- a/src/html/_HTMLReporter.scss +++ b/src/html/_HTMLReporter.scss @@ -218,6 +218,11 @@ body { background-color: $neutral-color; } + &.jasmine-warning { + background-color: $pending-color; + color: $text-color; + } + &.jasmine-menu { background-color: #fff; color: $faint-text-color;