Adds new configuration option to failSpecWithNoExpectations that will report specs without expectations as failures if enabled
This commit is contained in:
committed by
Steve Gravrock
parent
e8870db8d3
commit
7263a38c3f
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -118,7 +118,7 @@ The easiest way to run the tests in **Internet Explorer** is to run a VM that ha
|
|||||||
|
|
||||||
1. Ensure all specs are green in browser *and* node
|
1. Ensure all specs are green in browser *and* node
|
||||||
1. Ensure eslint and prettier are clean as part of your `npm test` command. You can run `npm run cleanup` to have prettier re-write the files.
|
1. Ensure eslint and prettier are clean as part of your `npm test` command. You can run `npm run cleanup` to have prettier re-write the files.
|
||||||
1. Build `jasmine.js` with `grunt buildDistribution` and run all specs again - this ensures that your changes self-test well
|
1. Build `jasmine.js` with `npm run build` and run all specs again - this ensures that your changes self-test well
|
||||||
1. Revert your changes to `jasmine.js` and `jasmine-html.js`
|
1. Revert your changes to `jasmine.js` and `jasmine-html.js`
|
||||||
* We do this because `jasmine.js` and `jasmine-html.js` are auto-generated (as you've seen in the previous steps) and accepting multiple pull requests when this auto-generated file changes causes lots of headaches
|
* We do this because `jasmine.js` and `jasmine-html.js` are auto-generated (as you've seen in the previous steps) and accepting multiple pull requests when this auto-generated file changes causes lots of headaches
|
||||||
* When we accept your pull request, we will generate these files as a separate commit and merge the entire branch into master
|
* When we accept your pull request, we will generate these files as a separate commit and merge the entire branch into master
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"posttest": "eslint src/**/*.js spec/**/*.js && prettier --check src/**/*.js spec/**/*.js",
|
"posttest": "eslint src/**/*.js spec/**/*.js && prettier --check src/**/*.js spec/**/*.js",
|
||||||
"test": "grunt execSpecsInNode",
|
"test": "grunt execSpecsInNode",
|
||||||
"cleanup": "prettier --write src/**/*.js spec/**/*.js",
|
"cleanup": "prettier --write src/**/*.js spec/**/*.js",
|
||||||
|
"build": "grunt buildDistribution",
|
||||||
"serve": "node spec/support/localJasmineBrowser.js",
|
"serve": "node spec/support/localJasmineBrowser.js",
|
||||||
"serve:performance": "node spec/support/localJasmineBrowser.js jasmine-browser-performance.json",
|
"serve:performance": "node spec/support/localJasmineBrowser.js jasmine-browser-performance.json",
|
||||||
"ci": "node spec/support/ci.js",
|
"ci": "node spec/support/ci.js",
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ describe('TreeProcessor', function() {
|
|||||||
|
|
||||||
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn('foo');
|
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn('foo');
|
||||||
|
|
||||||
expect(leaf.execute).toHaveBeenCalledWith('foo', false);
|
expect(leaf.execute).toHaveBeenCalledWith('foo', false, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('runs a node with no children', function() {
|
it('runs a node with no children', function() {
|
||||||
@@ -368,10 +368,10 @@ describe('TreeProcessor', function() {
|
|||||||
expect(queueableFns.length).toBe(3);
|
expect(queueableFns.length).toBe(3);
|
||||||
|
|
||||||
queueableFns[1].fn('foo');
|
queueableFns[1].fn('foo');
|
||||||
expect(leaf1.execute).toHaveBeenCalledWith('foo', false);
|
expect(leaf1.execute).toHaveBeenCalledWith('foo', false, false);
|
||||||
|
|
||||||
queueableFns[2].fn('bar');
|
queueableFns[2].fn('bar');
|
||||||
expect(leaf2.execute).toHaveBeenCalledWith('bar', false);
|
expect(leaf2.execute).toHaveBeenCalledWith('bar', false, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cascades errors up the tree', function() {
|
it('cascades errors up the tree', function() {
|
||||||
@@ -397,7 +397,7 @@ describe('TreeProcessor', function() {
|
|||||||
expect(queueableFns.length).toBe(2);
|
expect(queueableFns.length).toBe(2);
|
||||||
|
|
||||||
queueableFns[1].fn('foo');
|
queueableFns[1].fn('foo');
|
||||||
expect(leaf.execute).toHaveBeenCalledWith('foo', false);
|
expect(leaf.execute).toHaveBeenCalledWith('foo', false, false);
|
||||||
|
|
||||||
queueRunner.calls.mostRecent().args[0].onComplete('things');
|
queueRunner.calls.mostRecent().args[0].onComplete('things');
|
||||||
expect(nodeComplete).toHaveBeenCalled();
|
expect(nodeComplete).toHaveBeenCalled();
|
||||||
@@ -433,7 +433,7 @@ describe('TreeProcessor', function() {
|
|||||||
expect(nodeStart).toHaveBeenCalledWith(node, 'bar');
|
expect(nodeStart).toHaveBeenCalledWith(node, 'bar');
|
||||||
|
|
||||||
queueableFns[1].fn('foo');
|
queueableFns[1].fn('foo');
|
||||||
expect(leaf1.execute).toHaveBeenCalledWith('foo', true);
|
expect(leaf1.execute).toHaveBeenCalledWith('foo', true, false);
|
||||||
|
|
||||||
node.getResult.and.returnValue({ im: 'disabled' });
|
node.getResult.and.returnValue({ im: 'disabled' });
|
||||||
|
|
||||||
@@ -445,6 +445,35 @@ describe('TreeProcessor', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should execute node with correct arguments when failSpecWithNoExpectations option is set', function() {
|
||||||
|
var leaf = new Leaf(),
|
||||||
|
node = new Node({ children: [leaf] }),
|
||||||
|
root = new Node({ children: [node] }),
|
||||||
|
queueRunner = jasmine.createSpy('queueRunner'),
|
||||||
|
nodeStart = jasmine.createSpy('nodeStart'),
|
||||||
|
nodeComplete = jasmine.createSpy('nodeComplete'),
|
||||||
|
processor = new jasmineUnderTest.TreeProcessor({
|
||||||
|
tree: root,
|
||||||
|
runnableIds: [],
|
||||||
|
queueRunnerFactory: queueRunner,
|
||||||
|
nodeStart: nodeStart,
|
||||||
|
nodeComplete: nodeComplete,
|
||||||
|
failSpecWithNoExpectations: true
|
||||||
|
}),
|
||||||
|
treeComplete = jasmine.createSpy('treeComplete'),
|
||||||
|
nodeDone = jasmine.createSpy('nodeDone');
|
||||||
|
|
||||||
|
processor.execute(treeComplete);
|
||||||
|
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||||
|
queueableFns[0].fn(nodeDone);
|
||||||
|
|
||||||
|
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||||
|
expect(queueableFns.length).toBe(2);
|
||||||
|
|
||||||
|
queueableFns[1].fn('foo');
|
||||||
|
expect(leaf.execute).toHaveBeenCalledWith('foo', true, true);
|
||||||
|
});
|
||||||
|
|
||||||
it('runs beforeAlls for a node with children', function() {
|
it('runs beforeAlls for a node with children', function() {
|
||||||
var leaf = new Leaf(),
|
var leaf = new Leaf(),
|
||||||
node = new Node({
|
node = new Node({
|
||||||
@@ -600,11 +629,11 @@ describe('TreeProcessor', function() {
|
|||||||
queueableFns[0].fn();
|
queueableFns[0].fn();
|
||||||
|
|
||||||
expect(nonSpecified.execute).not.toHaveBeenCalled();
|
expect(nonSpecified.execute).not.toHaveBeenCalled();
|
||||||
expect(specified.execute).toHaveBeenCalledWith(undefined, false);
|
expect(specified.execute).toHaveBeenCalledWith(undefined, false, false);
|
||||||
|
|
||||||
queueableFns[1].fn();
|
queueableFns[1].fn();
|
||||||
|
|
||||||
expect(nonSpecified.execute).toHaveBeenCalledWith(undefined, true);
|
expect(nonSpecified.execute).toHaveBeenCalledWith(undefined, true, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('runs nodes and leaves with a specified order', function() {
|
it('runs nodes and leaves with a specified order', function() {
|
||||||
|
|||||||
@@ -2138,6 +2138,41 @@ describe("Env integration", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when spec has no expectations', function() {
|
||||||
|
var env, reporter;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
env = new jasmineUnderTest.Env();
|
||||||
|
reporter = jasmine.createSpyObj('reporter', ['jasmineDone', 'suiteDone', 'specDone']);
|
||||||
|
|
||||||
|
env.addReporter(reporter);
|
||||||
|
env.it('is a spec without any expectations', function() {
|
||||||
|
// does nothing, just a mock spec without expectations
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should report "failed" status if "failSpecWithNoExpectations" is enabled', function(done) {
|
||||||
|
reporter.jasmineDone.and.callFake(function(e) {
|
||||||
|
expect(e.overallStatus).toEqual('failed');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
env.configure({ failSpecWithNoExpectations: true });
|
||||||
|
env.execute();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should report "passed" status if "failSpecWithNoExpectations" is disabled', function(done) {
|
||||||
|
reporter.jasmineDone.and.callFake(function(e) {
|
||||||
|
expect(e.overallStatus).toEqual('passed');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
env.configure({ failSpecWithNoExpectations: false });
|
||||||
|
env.execute();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('When a top-level beforeAll fails', function() {
|
describe('When a top-level beforeAll fails', function() {
|
||||||
it('is "failed"', function(done) {
|
it('is "failed"', function(done) {
|
||||||
var env = new jasmineUnderTest.Env(),
|
var env = new jasmineUnderTest.Env(),
|
||||||
|
|||||||
@@ -62,19 +62,19 @@ describe('HtmlReporter', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('when a spec is done', function() {
|
describe('when a spec is done', function() {
|
||||||
it('logs errors to the console and prints a special symbol if it is an empty spec', function() {
|
describe('and no expectations ran', function() {
|
||||||
if (typeof console === 'undefined') {
|
var container, reporter;
|
||||||
console = { warn: function() {} };
|
beforeEach(function() {
|
||||||
}
|
if (typeof console === 'undefined') {
|
||||||
|
console = { warn: function() {}, error: function() {} };
|
||||||
|
}
|
||||||
|
|
||||||
var env = new jasmineUnderTest.Env(),
|
container = document.createElement('div');
|
||||||
container = document.createElement('div'),
|
|
||||||
getContainer = function() {
|
|
||||||
return container;
|
|
||||||
},
|
|
||||||
reporter = new jasmineUnderTest.HtmlReporter({
|
reporter = new jasmineUnderTest.HtmlReporter({
|
||||||
env: env,
|
env: new jasmineUnderTest.Env(),
|
||||||
getContainer: getContainer,
|
getContainer: function() {
|
||||||
|
return container;
|
||||||
|
},
|
||||||
createElement: function() {
|
createElement: function() {
|
||||||
return document.createElement.apply(document, arguments);
|
return document.createElement.apply(document, arguments);
|
||||||
},
|
},
|
||||||
@@ -83,21 +83,39 @@ describe('HtmlReporter', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
spyOn(console, 'warn');
|
spyOn(console, 'warn');
|
||||||
|
spyOn(console, 'error');
|
||||||
|
|
||||||
reporter.initialize();
|
reporter.initialize();
|
||||||
|
});
|
||||||
reporter.specDone({
|
|
||||||
status: 'passed',
|
it('should log warning to the console and print a special symbol when empty spec status is passed', function() {
|
||||||
fullName: 'Some Name',
|
reporter.specDone({
|
||||||
passedExpectations: [],
|
status: 'passed',
|
||||||
failedExpectations: []
|
fullName: 'Some Name',
|
||||||
|
passedExpectations: [],
|
||||||
|
failedExpectations: []
|
||||||
|
});
|
||||||
|
expect(console.warn).toHaveBeenCalledWith(
|
||||||
|
"Spec 'Some Name' has no expectations."
|
||||||
|
);
|
||||||
|
var specEl = container.querySelector('.jasmine-symbol-summary li');
|
||||||
|
expect(specEl.getAttribute('class')).toEqual('jasmine-empty');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log error to the console and print a failure symbol when empty spec status is failed', function() {
|
||||||
|
reporter.specDone({
|
||||||
|
status: 'failed',
|
||||||
|
fullName: 'Some Name',
|
||||||
|
passedExpectations: [],
|
||||||
|
failedExpectations: []
|
||||||
|
});
|
||||||
|
expect(console.error).toHaveBeenCalledWith(
|
||||||
|
"Spec 'Some Name' has no expectations."
|
||||||
|
);
|
||||||
|
var specEl = container.querySelector('.jasmine-symbol-summary li');
|
||||||
|
expect(specEl.getAttribute('class')).toEqual('jasmine-failed');
|
||||||
});
|
});
|
||||||
expect(console.warn).toHaveBeenCalledWith(
|
|
||||||
"Spec 'Some Name' has no expectations."
|
|
||||||
);
|
|
||||||
var specEl = container.querySelector('.jasmine-symbol-summary li');
|
|
||||||
expect(specEl.getAttribute('class')).toEqual('jasmine-empty');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reports the status symbol of a excluded spec', function() {
|
it('reports the status symbol of a excluded spec', function() {
|
||||||
|
|||||||
@@ -65,6 +65,16 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
failFast: false,
|
failFast: false,
|
||||||
|
/**
|
||||||
|
* Whether to fail the spec if it ran no expectations. By default
|
||||||
|
* a spec that ran no expectations is reported as passed. Setting this
|
||||||
|
* to true will report such spec as a failure.
|
||||||
|
* @name Configuration#failSpecWithNoExpectations
|
||||||
|
* @since 3.5.0
|
||||||
|
* @type Boolean
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
failSpecWithNoExpectations: false,
|
||||||
/**
|
/**
|
||||||
* Whether to cause specs to only have one expectation failure.
|
* Whether to cause specs to only have one expectation failure.
|
||||||
* @name Configuration#oneFailurePerSpec
|
* @name Configuration#oneFailurePerSpec
|
||||||
@@ -167,6 +177,11 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
config.failFast = configuration.failFast;
|
config.failFast = configuration.failFast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configuration.hasOwnProperty('failSpecWithNoExpectations')) {
|
||||||
|
config.failSpecWithNoExpectations =
|
||||||
|
configuration.failSpecWithNoExpectations;
|
||||||
|
}
|
||||||
|
|
||||||
if (configuration.hasOwnProperty('oneFailurePerSpec')) {
|
if (configuration.hasOwnProperty('oneFailurePerSpec')) {
|
||||||
config.oneFailurePerSpec = configuration.oneFailurePerSpec;
|
config.oneFailurePerSpec = configuration.oneFailurePerSpec;
|
||||||
}
|
}
|
||||||
@@ -641,6 +656,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
tree: topSuite,
|
tree: topSuite,
|
||||||
runnableIds: runnablesToRun,
|
runnableIds: runnablesToRun,
|
||||||
queueRunnerFactory: queueRunnerFactory,
|
queueRunnerFactory: queueRunnerFactory,
|
||||||
|
failSpecWithNoExpectations: config.failSpecWithNoExpectations,
|
||||||
nodeStart: function(suite, next) {
|
nodeStart: function(suite, next) {
|
||||||
currentlyExecutingSuites.push(suite);
|
currentlyExecutingSuites.push(suite);
|
||||||
defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
|
defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
return this.asyncExpectationFactory(actual, this);
|
return this.asyncExpectationFactory(actual, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
Spec.prototype.execute = function(onComplete, excluded) {
|
Spec.prototype.execute = function(onComplete, excluded, failSpecWithNoExp) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var onStart = {
|
var onStart = {
|
||||||
@@ -95,7 +95,7 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
var complete = {
|
var complete = {
|
||||||
fn: function(done) {
|
fn: function(done) {
|
||||||
self.queueableFn.fn = null;
|
self.queueableFn.fn = null;
|
||||||
self.result.status = self.status(excluded);
|
self.result.status = self.status(excluded, failSpecWithNoExp);
|
||||||
self.resultCallback(self.result, done);
|
self.resultCallback(self.result, done);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -166,7 +166,7 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
return this.result;
|
return this.result;
|
||||||
};
|
};
|
||||||
|
|
||||||
Spec.prototype.status = function(excluded) {
|
Spec.prototype.status = function(excluded, failSpecWithNoExpectations) {
|
||||||
if (excluded === true) {
|
if (excluded === true) {
|
||||||
return 'excluded';
|
return 'excluded';
|
||||||
}
|
}
|
||||||
@@ -175,11 +175,17 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
return 'pending';
|
return 'pending';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.result.failedExpectations.length > 0) {
|
if (
|
||||||
|
this.result.failedExpectations.length > 0 ||
|
||||||
|
(failSpecWithNoExpectations &&
|
||||||
|
this.result.failedExpectations.length +
|
||||||
|
this.result.passedExpectations.length ===
|
||||||
|
0)
|
||||||
|
) {
|
||||||
return 'failed';
|
return 'failed';
|
||||||
} else {
|
|
||||||
return 'passed';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 'passed';
|
||||||
};
|
};
|
||||||
|
|
||||||
Spec.prototype.getFullName = function() {
|
Spec.prototype.getFullName = function() {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ getJasmineRequireObj().TreeProcessor = function() {
|
|||||||
queueRunnerFactory = attrs.queueRunnerFactory,
|
queueRunnerFactory = attrs.queueRunnerFactory,
|
||||||
nodeStart = attrs.nodeStart || function() {},
|
nodeStart = attrs.nodeStart || function() {},
|
||||||
nodeComplete = attrs.nodeComplete || function() {},
|
nodeComplete = attrs.nodeComplete || function() {},
|
||||||
|
failSpecWithNoExpectations = !!attrs.failSpecWithNoExpectations,
|
||||||
orderChildren =
|
orderChildren =
|
||||||
attrs.orderChildren ||
|
attrs.orderChildren ||
|
||||||
function(node) {
|
function(node) {
|
||||||
@@ -222,7 +223,11 @@ getJasmineRequireObj().TreeProcessor = function() {
|
|||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
fn: function(done) {
|
fn: function(done) {
|
||||||
node.execute(done, stats[node.id].excluded);
|
node.execute(
|
||||||
|
done,
|
||||||
|
stats[node.id].excluded,
|
||||||
|
failSpecWithNoExpectations
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,12 +112,13 @@ jasmineRequire.HtmlReporter = function(j$) {
|
|||||||
this.specDone = function(result) {
|
this.specDone = function(result) {
|
||||||
stateBuilder.specDone(result);
|
stateBuilder.specDone(result);
|
||||||
|
|
||||||
if (
|
if (noExpectations(result)) {
|
||||||
noExpectations(result) &&
|
var noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
|
||||||
typeof console !== 'undefined' &&
|
if (result.status === 'failed') {
|
||||||
typeof console.error !== 'undefined'
|
console.error(noSpecMsg);
|
||||||
) {
|
} else {
|
||||||
console.warn("Spec '" + result.fullName + "' has no expectations.");
|
console.warn(noSpecMsg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!symbols) {
|
if (!symbols) {
|
||||||
@@ -140,7 +141,7 @@ jasmineRequire.HtmlReporter = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.displaySpecInCorrectFormat = function(result) {
|
this.displaySpecInCorrectFormat = function(result) {
|
||||||
return noExpectations(result)
|
return noExpectations(result) && result.status === 'passed'
|
||||||
? 'jasmine-empty'
|
? 'jasmine-empty'
|
||||||
: this.resultStatus(result.status);
|
: this.resultStatus(result.status);
|
||||||
};
|
};
|
||||||
@@ -363,6 +364,16 @@ jasmineRequire.HtmlReporter = function(j$) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.failedExpectations.length === 0) {
|
||||||
|
messages.appendChild(
|
||||||
|
createDom(
|
||||||
|
'div',
|
||||||
|
{ className: 'jasmine-result-message' },
|
||||||
|
'Spec has no expectations'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return failure;
|
return failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -654,9 +665,12 @@ jasmineRequire.HtmlReporter = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function noExpectations(result) {
|
function noExpectations(result) {
|
||||||
|
var allExpectations =
|
||||||
|
result.failedExpectations.length + result.passedExpectations.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
result.failedExpectations.length + result.passedExpectations.length ===
|
allExpectations === 0 &&
|
||||||
0 && result.status === 'passed'
|
(result.status === 'passed' || result.status === 'failed')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user