Mocha fails to adhere to timeout or done callback during the execution of CasperJS tests

Trying to address a challenge using casperjs and mocha, I am attempting to verify if an element's text value on a page updates within a timeframe of 5-10 seconds. The approach involves extracting the value, storing it in an array, waiting for 500ms, and repeating this process until the array contains 20 items (which equates to roughly 10 seconds). Subsequently, applying underscore/lodash's _.uniq function to the array to confirm that its length is > 1.

The issue arises as mocha does not wait for this process to complete before determining the success/failure of the test. While adjusting mocha's timeout setting was attempted, it did not yield any change in behavior. Please refer to the commented code snippet below for clarity.

it('validates elements with dynamic values', function () {
  // Setting a longer timeout to account for potential delays
  this.timeout(20000);

  casper.then(function() {
        // Initializing the test array
    var values = [],
        // For stopping the intervals
        intervalId;

    function getValue () {
      // Capturing the text value of the element
      var value = casper.evaluate(function () { return $('#element').text(); });

      // Adding to the test array
      values.push(value);

      // Executing further checks only when there are 20 items in the array
      if (values.length === 20) {

        // Halting further value checks
        clearInterval(intervalId);

        // Verifying if more than one unique value was obtained within the designated period
        expect(_.uniq(values).length).to.be.gt(1);
      } 
    }

    // Waiting for the page element to populate with value
    // Initially set to '-'
    casper.waitFor(function () {
      return this.evaluate(function () {
        return $('#element').text() !== '-';
      });

    // Initiating the check with a 500ms delay between each iteration
    }, function then() {
      intervalId = setInterval(getValue, 500);
    });
  });
});

With the 500ms interval, just 2-3 element values are retrieved in the values array before mocha proceeds to the next test. Surprisingly, the console log statements containing the values appear on screen after mocha has assessed the test as successful. This discrepancy stems from values.length never reaching 10, causing the expect assertion to be bypassed, leading to an erroneous pass status. Below are the test results observed at a 500ms interval:

Dashboard
✓ validates elements with dynamic values (202ms)
Values: ["20,832,022"]
Values: ["20,832,022","20,832,372"]
Values: ["20,832,022","20,832,372","20,832,722"]

✓ confirms the page title of leads (41ms)

2 passing (11s)

Despite not reaching the expected 20 items, the test passes prematurely due to a timeout constraint. The following output depicts the outcome with a 50ms interval:

Dashboard

✓ validates elements with dynamic values (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"]

✓ confirms the page title of leads (41ms)

2 passing (8s)

Although more values were captured at a 50ms interval, this duration is insufficient for capturing all necessary updates on the page. Various attempts were made including employing the done callback within the it statement, however, mocha fails to acknowledge it or wait for its invocation.

Testing conditions with a forced asynchronous declaration exhibit similar behaviors, either prematurely passing at a 500ms interval without reaching the validation stage or producing a 'done() called multiple times' error under a 50ms interval. Consideration of the framework used (mocha-casperjs) as a factor influencing these outcomes may be warranted.

Answer №1

It appears that mocha-casperjs does not rely on the default done method. Instead, it recognizes the completion of a test step through CasperJS' control flow mechanism. In your scenario, you disrupt the control flow by invoking getValue using a setInterval.

A more efficient approach would involve restructuring your code to incorporate recursive calls to getValue, like so:

function getValue () {
  // Retrieve the text value of an element
  var value = this.evaluate(function () { return $('#element').text(); });

  // Add the value to our test array
  values.push(value);

  // 20 * 500ms == 10 seconds or 10000ms
  // This block never executes when set to 500ms; the test passes quickly
  if (values.length === 20) {
    // Check for multiple unique values in the 10-second interval
    expect(_.uniq(values).length).to.be.gt(1);
  } else {
    this.wait(500, getValue);
  }
} 

// Wait for the page's value to populate (defaults to '-')
casper.waitFor(function () {
  return this.evaluate(function () {
    return $('#element').text() !== '-';
  });

// Initiate the check with a 500ms delay between each iteration
}, function then() {
  this.wait(500, getValue);
});

This modification turns getValue into a casper step.

Alternatively, without extensive restructuring, you can run a separate waitFor concurrently with the disrupted control flow. This alternative relies on a semi-global variable named someGlobalVariable. You could potentially utilize intervalId for this purpose, though initializing someGlobalVariable = false; at the outset is likely preferable.

intervalId = setInterval(getValue, 500);
this.waitFor(function check(){
    return someGlobalVariable;
}, function then(){
   // Perform additional actions
}, null, 20000);

To stop this process, use:

expect(_.uniq(values).length).to.be.gt(1);
someGlobalVariable = true;

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Filtering a Two-Dimensional Array Using JavaScript

I am working with a basic 2D array that contains x, y coordinates as shown below: var c = [ [1,10], [2,11], [3,12], [4,13], [5,15] ]; I want to know how I can extract pairs from the array that meet specific conditi ...

Utilize JavaScript, MySQL, and PHP to input data into a database

My JS function is supposed to make an ajax request, but for some reason it's not working. I've checked the URL in an alert and all variables are declared. var request = new XMLHttpRequest(); var url = "ajax_js/q_ajax.php?q="+ques+ ...

JavaScript Async Ordering

I have a specific question regarding asynchronous operations in Javascript. I am currently building a Node.js API to interact with an OrientDB database, using the Node-orient package for basic connectivity functions. Some of these functions are as follows: ...

Equal-Height Slide Deck Holder

I'm struggling to maintain a consistent height of 700px for my image slideshow, which consists of four images with varying heights. I attempted setting the img at max-height: 700px, but unfortunately that didn't yield the desired outcome. You ca ...

How to highlight text within an iframe using the mouse and displaying the selected text in a separate div

I'm currently able to select text with the mouse and display that selection in a div. However, I'm struggling to do the same thing when dealing with an iframe displaying a page on the same domain. Despite trying various solutions found here, I h ...

How do I retrieve the NodesValue from the childNodes in an HTML tag?

<p title="The test paragraph">This example demonstrates some <b>HTML content that may be<br>present</b> in your file</p> txt=document.getElementsByTagName("p")[0].childNodes[0].nodeValue; alert("<p>The text from the in ...

How can I create a new PHP table using data from an existing table?

I have a table displayed on my website with the code snippet providedview the table image here Here is the code for generating this table: <?php $query = $db->query("SELECT * FROM bit_exchanges ORDER BY id DESC LIMIT 20"); if($query-> ...

Certain functions are successful while others are unsuccessful when using Postman

Hey there! I'm diving headfirst into the world of coding and trying my hand at building an application using NodeJs and ExpressJs. I've been testing the backend with Postman, and while some requests are working perfectly, others are throwing me o ...

Tips for adjusting the up and down controls and spins of a date input after modifying its height

After adjusting the height of my inputs (date type) to 40px, I noticed that the up and down controls are no longer aligned with the text inside the field. I am looking for a solution to either adjust the height of the spins or remove them if necessary in ...

Error alert: items.appendChild does not function

I'm running into an issue while trying to add buttons to the existing list items. Below is my code snippet: function buttonDelete() { var items = document.getElementsByTagName("li"); var button = document.createElement("button"); button.appendChild( ...

Problems arising from Jquery append functionality

When using the append method, my inner div is only attaching one WHEAT-COLORED-BOX, whereas when using appendTo, my inner div attaches all the required number of WHEAT-COLORED-BOXES. Therefore, in this case, appendTo gives the correct result while append f ...

What is the best way to extract the ID from an event in TypeScript?

HTML Code: <ion-checkbox color="dark" checked="false" id="1on" (ionChange)="onTap($event)" ></ion-checkbox> TypeScript Code: onTap(e) { console.log(e); console.log(e.checked); } I am trying to retrieve the id of the checkbox. H ...

JavaScript and jQuery experiencing difficulty rendering proper style and image in output display

I am currently working on code that extracts information from a JSON variable and displays it on a map. The code looks like this: marker.info_window_content = place.image + '<br/>' +"<h4>" + place.name + "</h4> ...

When I request the value of a JavaScript object, I am met with 'undefined'

I have been working on creating a Google map application that involves loading markers from a database and displaying them on a map. To accomplish this, I decided to create an array and define an object as shown below: function shop_info(name, latitude, l ...

Using buttons to adjust the height of multiple div elements through scrolling

On my page, there is a unique structure that includes: <div id="about" class="section"> <div class="button"> <img src="/images/arrow.png"> </div> </div> <div id="films" class="section"> <div clas ...

JavaScript is used to dynamically generate HTML content by utilizing jQuery methods

jquery is loaded in my html before my JS code. In my puzzle.js file I have the following: class Puzzle { constructor(ID, Name, Status) { this.ID = "main" + ID; this.Name = Name; this.Status = Status; this.mainDiv = ""; } generateD ...

Is it possible to send an email with an attachment that was generated as a blob within the browser?

Is there a way to attach a file created in the browser as a blob to an email, similar to embedding its direct path in the url for a local file? The file is generated as part of some javascript code that I am running. Thank you in advance! ...

Unidentified function error triggered by jQuery when clicked

Having trouble accessing a function defined by my colleague for a click event. The code snippet provided below is causing issues, any ideas on what could be wrong? function Start(data) { this.move= function() { .... }; $('.button').click( ...

Sorting customization within a complex nested array structure

Sorting a nested array can sometimes be tricky. Consider a JSON structure like the one shown below: var orders = [{ 'orderId': 1, 'sales': [{ 'salesNumbers': 3 }] }, { 'orderId': 2, ...

What is the method for adding/removing the 'hidden' attribute within a <p hidden> element

What is the best way to toggle the visibility of 'hidden' in the element <p hidden>My Text</p>? I attempted removing the attribute and setting it to false, but unfortunately, neither method seemed to work. let paragraphElements = d ...