Mocha doesn't time out or makes a callback when running CasperJS tests
So here is the problem I'm trying to solve with casperjs and mocha. I am trying to check the value of the text of an element on a page to see if it has updated within a period of ... 5-10 seconds. The idea is that I get the value, insert it into the array, wait 500ms, and repeat until there are 20 elements in the array. This is about 10 seconds. Then run the underscore / lodash function _.uniq
on the array and check the length of the array > 1
.
The problem I am facing is that the mocha does not wait for this test to complete because the test assertion succeeds / fails. I thought I could increase the waiting time of the mocha, but that doesn't make any difference. See code below. I have commented this out for readability.
it('has elements whose values update', function () {
// 20 seconds, which should be plenty of time
this.timeout(20000);
casper.then(function() {
// The test array
var values = [],
// So we can stop the intervals
intervalId;
function getValue () {
// Grab element text value
var value = casper.evaluate(function () { return $('#element').text(); });
// Push in to our test array
values.push(value);
// 20 * 500ms == 10 seconds or 10000ms
// When set to 500ms, this block never runs. The test passes before it has a chance to
if (values.length === 20) {
// Stop it from checking the value any further
clearInterval(intervalId);
// Test to see we've had more than one unique value in the 10 seconds
expect(_.uniq(values).length).to.be.gt(1);
}
}
// Wait for the value on the page to populate
// It defaults to '-' when the page loads
casper.waitFor(function () {
return this.evaluate(function () {
return $('#element').text() !== '-';
});
// Start the check with a delay of 500ms between each check
}, function then() {
intervalId = setInterval(getValue, 500);
});
});
});
With the interval value set to 500ms, I get 2-3 element values ββin values
before the mocha moves on to the next test. Even stranger, when I type console.log(values)
them on the screen AFTER the mocha, the test has been determined to pass. The reason is it values.length
never reaches 10, so the call is expect
never called. The test is assumed to pass. Here is the test output at 500ms interval:
Dashboard
β has elements whose values update (202ms)
Values: ["20,832,022"]
Values: ["20,832,022","20,832,372"]
Values: ["20,832,022","20,832,372","20,832,722"]
β has the page title of leads (41ms)
2 passing (11s)
It goes through although 20 elements do not exist. He never checks it out because of a timeout somewhere. Here is the result at 50ms intervals:
Dashboard
β has elements whose values update (341ms)
Values: ["20,400,667"]
Values: ["20,400,667","20,400,718"]
Values: ["20,400,667","20,400,718","20,400,718"]
Values: ["20,400,667","20,400,718","20,400,718","20,400,769"]
Values: ["20,400,667","20,400,718","20,400,718","20,400,769","20,400,769"]
Values: ["20,400,667","20,400,718","20,400,718","20,400,769","20,400,769","20,400,820"]
Values: ["20,400,667","20,400,718","20,400,718","20,400,769","20,400,769","20,400,820","20,400,820"]
Values: ["20,400,667","20,400,718","20,400,718","20,400,769","20,400,769","20,400,820","20,400,820","20,400,871"]
Values: ["20,400,667","20,400,718","20,400,718","20,400,769","20,400,769","20,400,820","20,400,820","20,400,871","20,400,871"]
Values: ["20,400,667","20,400,718","20,400,718","20,400,769","20,400,769","20,400,820","20,400,820","20,400,871","20,400,871","20,400,922"]
Final Values: ["20,400,667","20,400,718","20,400,718","20,400,769","20,400,769","20,400,820","20,400,820","20,400,871","20,400,871","20,400,922"]
β has the page title of leads (41ms)
2 passing (8s)
I get more with 50ms, but it's only half a second of testing. Some of the other values ββon the page take longer to update, are not viable.
I've tried passing a callback done
to the statement it
, but mocha ignores it and doesn't wait for it to be called.
Is this a limitation of the tools or am I using them incorrectly?
I tried to use the callback made using the method below.
it('has elements whose values update', function (done) {
and
expect(_.uniq(values).length).to.be.gt(1);
done();
It still ignores that I marked the test as asynchronous. In 500ms, it still goes through without getting to the if statement or call made. In 50ms, this throws this error:
done() called multiple times
I am using mocha-casperjs . Could this affect this?
source to share
It seems like mocha-casperjs is not using the default done
. He knows the test step is complete because he is using the CasperJS control flow. In your case, you exit the control flow by calling getValue
via setInterval
.
It would be better to refactor your code to use recursive calls getValue
like this:
function getValue () {
// Grab element text value
var value = this.evaluate(function () { return $('#element').text(); });
// Push in to our test array
values.push(value);
// 20 * 500ms == 10 seconds or 10000ms
// When set to 500ms, this block never runs. The test passes before it has a chance to
if (values.length === 20) {
// Test to see we've had more than one unique value in the 10 seconds
expect(_.uniq(values).length).to.be.gt(1);
} else {
this.wait(500, getValue);
}
}
// Wait for the value on the page to populate
// It defaults to '-' when the page loads
casper.waitFor(function () {
return this.evaluate(function () {
return $('#element').text() !== '-';
});
// Start the check with a delay of 500ms between each check
}, function then() {
this.wait(500, getValue);
});
This makes getValue
a cache step.
Another solution without a lot of refactoring is to launch a second one waitFor
, executed along the side of the split control flow. This requires a semi-global variable someGlobalVariable
. Perhaps it can be used for this intervalId
, but it is better to use someGlobalVariable = false;
at the top.
intervalId = setInterval(getValue, 500);
this.waitFor(function check(){
return someGlobalVariable;
}, function then(){
// do something else
}, null, 20000);
and let it stop with
expect(_.uniq(values).length).to.be.gt(1);
someGlobalVariable = true;
source to share