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?

+3


source to share


1 answer


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;

      

+2


source







All Articles