Conditional mocha test - javascript

I use mocha for some integration testing and have many test sets.
Each set has initialization tests. When such tests fail, the rest of the set should not run at all, because if one fails then each will fail.
The thing is that I can't avoid such initialization tests, because part of the code/environment is generated by some tool which does not guarantee any correct result.
Is it possible to implement this using mocha ?

Using the BDD interface, the normal way to do this with Mocha is to put anything that sets up the testing environment into before or beforeEach:
describe("foo", function () {
describe("first", function () {
before(function () {
// Stuff to be performed before all tests in the current `describe`.
});
beforeEach(function () {
// Stuff to perform once per test, before the test.
});
it("blah", ...
// etc...
});
describe("second", function () {
before(function () {
// Stuff to be performed before all tests in the current `describe`.
});
beforeEach(function () {
// Stuff to perform once per test, before the test.
});
it("blah", ...
// etc...
});
});
If the before or beforeEach that a test depends on fails, then the test is not run. Other tests that don't depend on it will still run. So in the example above if the callback passed to before in the describe named first fails, the tests in the describe named second won't be affected at all and will run, provided that their own before and beforeEach callbacks don't fail.
Other than this, Mocha is designed to run tests that are independent from each other. So if one it fails, then the others are still run.

I found mocha-steps which basically allow you to write a "chain" of it()s (called step()) and mocha will abort the suite if one of them breaks, thus avoiding the cascade of inevitable failures, and I found pull request 8 marks subsequent steps and subsuites as pending. So I can write:
describe("businessCode()", function() {
step("should be not null", function() {
assert(businessCode() != null)
});
step("should be a number", function() {
assert(typeof businessCode() === 'number');
});
step("should be greater than 10", function() {
assert(businessCode() > 10);
});
describe("thingThatCallsBusinessCode()", function() {
step("should be greater than 10", function() {
assert(thingThatCallsBusinessCode() != null);
});
});
});
If e.g. businessCode() returns a boolean, only the should be a number test will fail; the subsequent ones (and the subsuite will be marked as pending).

Related

jest: How to teardown after (just) an individual test

jest provides afterEach, beforeEach, afterAll and beforeAll to complete setup and teardown logic. What I would like to do, is to clear up after one particular test. Consider the following:
describe("a family of tests it makes sense to group together", () => {
...
test("something I want to test", () => {
// some setup needed for just this test
global.foo = "bar"
// the test
expect(myTest()).toBe(true)
// clear up
delete global.foo
}
...
}
The problem with the above...
If the test above fails for some reason, then delete global.foo is never run. This means that potentially all of the tests following it will fail. Rather than seeing 1 test fail, I see a whole load of tests fail, which could be confusing.
Potential (non-ideal) solutions
One solution is just to add delete global.foo into my afterEach. It doesn't really need to be run after every test, but it doesn't do any harm either. Another solution would be to put the particular test by itself so that afterEach would only apply to it. But this doesn't seem ideal either - if that test belongs with other tests, it aught to be possible for it to remain with them.
My question:
Is there a way to run teardown logic for just a specific test (without running it inside the actual test). In my particular use-case the first outlined solution is fine, but I can imagine there might be situations where finer grained control is needed. If my teardown method took a long time for example I wouldn't want to repeat it lots, as this would slow down the whole test-suite.
In many cases tests can share a common afterEach clean-up even if it's needed for one of them, as long as it doesn't affect others.
Otherwise, this is what block structure is responsible for. One or several tests can be grouped with nested describe just to have their own afterEach, etc blocks, and the only downside is that it makes the report less pretty:
describe("a family of tests it makes sense to group together", () => {
...
describe("something I want to test", () => {
beforeEach(() => {
global.foo = "bar"
});
test("something I want to test", () => {
expect(myTest()).toBe(true)
}
afterEach(() => {
delete global.foo
});
});
beforeEach and afterEach can be desugared to try..finally:
test("something I want to test", () => {
try {
global.foo = "bar"
expect(myTest()).toBe(true)
} finally {
delete global.foo
}
})
This also allows for asynchronous tests but requires them to be written with async instead of done.
I know that this is an old question, but for anyone who stumbles upon this challenge in the future, here's a small library I wrote way back when, called jest-after-this that does just that:
import { afterThis } from 'jest-after-this';
it('should do something that requires a cleanup', () => {
global.foo = 'something';
afterThis(() => {
delete global.foo;
});
// ... rest of test here can fail, the cleanup method will run anyways
});
Hope this helps :)

Testing style set using Mocha

I'm trying to test some "style set" functions, and I'm facing issues because I need to wait until the element if fully rendered, then read its property and check if it was sucesfully changed. I know that this is pretty obvious, but I was wondering if there is a way to do the same but without waiting.
For example, I want to test this function:
function changeWidth() {
document.getElementById('test').style.width = '200px';
}
And I use this test in Mocha:
it('Width should be 200px', () => {
changeWidth();
assert.equal(document.getElementById('test').style.width, '200px');
});
That assertion will always returns false. The following test will work:
it('Width should be 200px', () => {
changeWidth();
window.setTimeout( () => {
assert.equal(document.getElementById('test').style.width, '200px');
}, 1000);
});
It has to be a better way to accomplish the same without using timeouts. Can someone guide me? Thanks!
There are two things I noted:
No, you cannot force a render to happen synchronously. The browser decides, so the test will be async and a bit messy. That being said, there are (a bit) more elegant answers than setTimeout.
Your test is synchronous, while the logic is asynchronous. That means your test will always pass, as the assertion is called after the test has finished (see this). You need to pass a callback to the test that can be called when the test has finished.
You could do the tests somewhat cleaner by using requestAnimationFrame. Just create a helper that will run each function passed to it in a seperate animation frame and you will be guaranteed separate render phases.
function runSteps(fns) {
if(!fns.length) return;
var current = fns[0];
var rest = fns.slice(1);
requestAnimationFrame(function() {
current();
runSteps(rest);
})
}
// note the `done` argument - it is what makes Mocha able to know
// when the test is finished. See https://stackoverflow.com/questions/20748918/cannot-run-mocha-js-in-synchronous-mode
it('should run dom render steps chronologically', function(done) {
function assertWidthChanged(){
assert.equal(
document.getElementById('test').style.width,
'200px'
);
}
runSteps([
changeWidth,
assertWidthChanged,
done
]);
}

How to skip to next next describe on error in Mocha?

I have a bunch of describes that test different parts of an API. In one section, all the tests are dependent on one test succeeding. I want to make Mocha run the first test, and if it fails, skip all following tests and run the next test suite for the next section of the API.
mocha --bail would stop testing altogether after the first fail, and won't continue to the next section.
mocha-steps is a viable solution, but I prefer not to use any external libraries. In addition, it doesn't skip steps after the failure, it doesn't print them altogether. Like I said, it's a viable solution, but not ideal.
What would be the best way to implement this behavior in vanilla Mocha?
Put what you call your "first test" in a before hook inside a describe block that contains all the other tests:
describe("bunch of related tests", function () {
before(function () {
// "first test" here
});
it("test 1", function () { ... });
it("test 2", function () { ... });
// ...
});
This is the proper way in "vanilla Mocha" to set a dependency between the code in the before hook and each of the tests. If the before hook fails, Mocha will report it, and it will skip all the tests in the describe block. If you have other tests elsewhere, they will still run.
Although I up-voted the accepted answer, I wasn't able to get a Mocha it test to run inside a before function. Instead I had to separate the first test into its own describe and set a variable if the test passed, then check the variable in the before of the describe containing all the other tests.
let passed = false
describe('first test', function() {
it('run the first test', function(done) {
if (theTestPassed)
passed = true
done()
})
})
describe('rest of the tests', function() {
before(function() {
if (!passed)
throw new Error('skip rest of the tests')
});
it('second test', ...)
it('third test', ...)
});

Jasmine jquery testing of a function with no parameters

I have a following function:
function prompt_mandatory_field_completion(){
$("#mandatory_fail").show(150, function() {
setTimeout(function() {
$("#mandatory_fail").fadeOut(500)
}, 2000);
});
window.scrollTo(0,0)
}
That I would like to test with jasmine but regardless to what I put in my spec file the test seems to pass.
The spec file contains the following code :
it(' NEED TO FIX THAT FADE OUT Should prompt user to fill in mandatory questions via prompt_mandatory_field_completion function', function() {
prompt_mandatory_field_completion();
setTimeout(2000, function(){
expect($('#mandatory_fail').css('display').toEqual('random thing'));
});
In my SpecRunner.html I am using the following function that I run in before each test in this description block:
function setupFixtures(){
setFixtures('<div id="mandatory_fail" style="display:none;"></div>');
prompt_mandatory_field_completion();
};
Any idea how to make this into a meaningful test? I guess I have been staring at it way too long and poking it from all the directions.
Best,
Adam
You're trying to write a functional test of asynchronous behavior. You might have a lot better experience trying to use protractor for this sort of test. It's tuned more toward asserting things that will eventually be true.
However, jasmine does have an asynchronous facility since about 2.0, known as done(), that will insist that all of the asynchronous code has run before the test passes or fails.
You have to pass the done function to get asynchronous tests :
it(' NEED TO FIX THAT FADE OUT Should prompt user to fill in mandatory questions via prompt_mandatory_field_completion function', function(done) {
prompt_mandatory_field_completion();
setTimeout(2000, function(){
expect($('#mandatory_fail').css('display').toEqual('random thing'));
done();
});
}, 3000);
You can also pass a timeout as a last parameter, depending on what you've set in your jasmine's settings.
Otherwise, Jasmine will consider this test to fail if its execution exceed its timeout.

How do I run a mocha test only after the prior asynchronous test has passed?

Using the mocha javascript testing framework, I want to be able to have several tests (all asynchronous) only execute after the previously defined test has passed.
I don't want to have to nest these tests within each other.
describe("BBController", function() {
it("should save", function(done) {});
it("should delete", function(done) {});
})
Use the --bail option. Make sure you are using at least mocha 0.14.0. (I've tried it with older versions without success.)
First, there's nothing you need to do for mocha to run a test only after the previous one has finished. That's how mocha works by default. Save this to test.js:
describe("test", function () {
this.timeout(5 * 1000); // Tests time out in 5 seconds.
it("first", function (done) {
console.log("first: do nothing");
done();
});
it("second", function (done) {
console.log("second is executing");
// This test will take 2.5 seconds.
setTimeout(function () {
done();
}, 2.5 * 1000);
});
it("third", function (done) {
console.log("third is executing");
// This test will time out.
});
it("fourth", function (done) {
console.log("fourth: do nothing");
done();
});
});
Then execute it with:
mocha -R spec test.js
You will not see the fourth test start until:
The first and second tests are finished.
The third tests has timed out.
Now, run it with:
mocha -R spec --bail test.js
Mocha will stop as soon as test 3 fails.
if your tests are set up properly, only testing a small piece of business logic then you can run your tests asynchronously but they should not hold up other tests. the way to get a test to complete is to do the following:
describe("BBController", function() {
it("should save", function(done) {
// handle logic
// handle assertion or other test
done(); //let mocha know test is complete - results are added to test list
});
it("should delete", function(done) {
// handle logic
// handle assertion or other test
done(); //let mocha know test is complete - results are added to test list
});
});
again, no test should need to wait for another test to run to pass, if you have this issue then you should look at ways to impove your dependency injection or prep your tests with a before method

Categories