131 lines
6.1 KiB
Plaintext
Raw Normal View History

== Why is this an issue?
2021-04-28 16:49:39 +02:00
Each assertion should test one condition and have only one reason to fail or succeed. If an assertion success depends on multiple conditions it becomes difficult to understand if the test passed for the right reason. It also makes debugging more difficult when the test fails.
This rule raises an issue when the following Chai assertions are found:
* When ``++.not++`` and https://www.chaijs.com/api/bdd/#method_throw[``++.throw++``] are used together and at least one argument is provided to ``++.throw++``. Such assertions succeed when the target either does not throw any exception, or when it throws an exception different from the one provided.
* When ``++.not++`` and https://www.chaijs.com/api/bdd/#method_include[``++.include++``] are used together and an ``++object++`` is given to ``++.include++``. Such assertions succeed when one or multiple key/values are missing.
* When ``++.not++`` and https://www.chaijs.com/api/bdd/#method_property[``++.property++``] are used together and ``++.property++`` is given at least two arguments. Such assertions succeed when the target either doesn't have the requested property, or when this property exists but has a different value.
* When ``++.not++`` and https://www.chaijs.com/api/bdd/#method_ownpropertydescriptor[``++.ownPropertyDescriptor++``] are used together and ``++.ownPropertyDescriptor++`` is given at least two arguments. Such assertions succeed when the target either doesn't have the requested property descriptor, or its property descriptor is not deeply equal to the given descriptor
* When ``++.not++`` and https://www.chaijs.com/api/bdd/#method_members[``++.members++``] are used together. Such assertions succeed when one or multiple members are missing.
* When https://www.chaijs.com/api/bdd/#method_change[``++.change++``] and https://www.chaijs.com/api/bdd/#method_by[``++.by++``] are used together. Such assertions succeed when the target either decreases or increases by the given delta
* When ``++.not++`` and https://www.chaijs.com/api/bdd/#method_increase[``++.increase++``] are used together. Such assertions succeed when the target either decreases or stays the same.
* When ``++.not++`` and https://www.chaijs.com/api/bdd/#method_decrease[``++.decrease++``] are used together. Such assertions succeed when the target either increases or stays the same.
* When ``++.not++`` negates https://www.chaijs.com/api/bdd/#method_decrease[``++.by++``]. Such assertions succeed when the target didn't change by one specific delta among all the possible deltas.
* When ``++.not++`` and https://www.chaijs.com/api/bdd/#method_decrease[``++.finite++``] are used together. Such assertions succeed when the target either is not a ``++number++``, or is one of ``++Nan++``, positive ``++Infinity++``, negative ``++Infinity++``.
=== Noncompliant code example
2021-04-28 16:49:39 +02:00
2022-02-04 17:28:24 +01:00
[source,javascript]
2021-04-28 16:49:39 +02:00
----
const expect = require('chai').expect;
describe("uncertain assertions", function() {
const throwsTypeError = () => { throw new TypeError() }
it("uses chai 'expect'", function() {
expect(throwsTypeError).to.not.throw(ReferenceError) // Noncompliant
expect({a: 42}).to.not.include({b: 10, c: 20}); // Noncompliant
expect({a: 21}).to.not.have.property('b', 42); // Noncompliant
expect({a: 21}).to.not.have.ownPropertyDescriptor('b', { // Noncompliant
configurable: true,
enumerable: true,
writable: true,
value: 42,
});
expect([21, 42]).to.not.have.members([1, 2]); // Noncompliant
var myObj = { value: 1 }
const incThree = () => { myObj.value += 3; };
const decThree = () => { myObj.value -= 3; };
const doNothing = () => {};
expect(incThree).to.change(myObj, 'value').by(3); // Noncompliant
expect(decThree).to.change(myObj, 'value').by(3); // Noncompliant
expect(decThree).to.not.increase(myObj, 'value'); // Noncompliant
expect(incThree).to.not.decrease(myObj, 'value'); // Noncompliant
expect(doNothing).to.not.increase(myObj, 'value'); // Noncompliant
expect(doNothing).to.not.decrease(myObj, 'value'); // Noncompliant
expect(incThree).to.increase(myObj, 'value').but.not.by(1); // Noncompliant
let toCheck;
expect(toCheck).to.not.be.finite; // Noncompliant
});
});
----
=== Compliant solution
2021-04-28 16:49:39 +02:00
2022-02-04 17:28:24 +01:00
[source,javascript]
2021-04-28 16:49:39 +02:00
----
const expect = require('chai').expect;
describe("uncertain assertions", function() {
const throwsTypeError = () => { throw new TypeError() }
it("uses chai 'expect'", function() {
expect(throwsTypeError).to.throw(TypeError)
expect({a: 42}).to.not.have.any.keys('b', 'c');
expect({a: 21}).to.not.have.property('b');
expect({a: 21}).to.not.have.ownPropertyDescriptor('b');
expect([21, 42]).to.not.include(1).and.not.include(2);
var myObj = { value: 1 }
const incThree = () => { myObj.value += 3; };
const decThree = () => { myObj.value -= 3; };
const doNothing = () => {};
expect(incThree).to.increase(myObj, 'value').by(3);
expect(decThree).to.decrease(myObj, 'value').by(3);
expect(decThree).to.decrease(myObj, 'value').by(3);
expect(incThree).to.increase(myObj, 'value').by(3);
expect(doNothing).to.not.change(myObj, 'value');
expect(incThree).to.increase(myObj, 'value').by(3);
let toCheck;
// Either of the following is valid
expect(toCheck).to.be.a('string');
expect(toCheck).to.be.NaN;
expect(toCheck).to.equal(Infinity);
expect(toCheck).to.equal(-Infinity);
});
});
----
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
Refactor this uncertain assertion; it can succeed for multiple reasons.
=== Highlighting
The part of the assertion which is uncertain. We simply not highlight parts which are ok.
Example: In the following case
``++expect(throwsTypeError).to.exist.and.to.not.throw(ReferenceError);++``
The primary location should be on
``++and.to.not.throw(ReferenceError)++``
endif::env-github,rspecator-view[]