Tips for effectively waiting for the backend in Protractor

Today, I find myself in the midst of testing a web page that allows users to send messages to each other via a textinput. The process involves sending a POST request to the server which then saves the message in the var/mail/new folder on disk.

After automating the message sending process with Protractor, I utilize browser.waitForAngular() and browser.driver.sleep(4000) to allow enough time for the backend to write the mail on disk.

However, despite these efforts, the check for the email's presence fails. Upon inspecting the Unix shell, I can verify that the email was indeed sent. Furthermore, the following test marked within Jasmine using it confirms the existence of the email.

I am puzzled as to why browser.driver.sleep(4000) is proving ineffective in waiting for the backend to progress. How should I go about rectifying this issue within the code?

it("is possible to send a message", function() {
    shared.loginContributor();

    var mailsBeforeMessaging =
        fs.readdirSync(browser.params.mail.queue_path + "/new");
    console.log('mailsBeforeMessaging');
    console.log(mailsBeforeMessaging.length);
    console.log(fs.lstatSync(browser.params.mail.queue_path + "/new"));

    var usersListing = new UserPages.UsersListing().get();
    var annotatorPage = usersListing.getUserPage("annotator");

    annotatorPage.sendMessage("title5", "content64");

    exec("/tmp/check.sh");

    // we expect the message widget to disappear
    var button = element(by.css(".user-profile-info-button"));
    console.log('waiting');
    browser.wait(EC.elementToBeClickable(button), 5000);
    console.log('waiting is finished');
    expect(EC.elementToBeClickable(button)).toBeTruthy();

    // wait for mail to be dumped on the disk?
    browser.waitForAngular();
    browser.driver.sleep(4000);

    exec("/tmp/check.sh");

    var mailsAfterMessaging =
        fs.readdirSync(browser.params.mail.queue_path + "/new");
    console.log('mailsAfterMessaging');
    // ERROR: here the number of emails is NOT incremented
    console.log(mailsAfterMessaging.length);
    console.log(fs.lstatSync(browser.params.mail.queue_path + "/new"));
});

it("xyz", function() {

    console.log(fs.lstatSync(browser.params.mail.queue_path + "/new"));
    // here the number of emails is incremented
    var mailsAfterMessaging =
        fs.readdirSync(browser.params.mail.queue_path + "/new");
    console.log('mailsAfterMessaging');
    console.log(mailsAfterMessaging.length);
});

Answer №1

Most of the functions in Protractor do not actually execute immediately. Instead, they queue up something to be done later and return a promise to carry out the task. It is only after an it block schedules several tasks that they start happening through the promises registered in the ControlFlow.

On the other hand, your checks are all running right away, before any of the Protractor functions can complete their tasks.

To handle waiting and dependencies explicitly in your tests, use the then method like this:

annotatorPage.sendMessage("title5", "content64").then(function() {
    exec("/tmp/check.sh");
});

or:

browser.wait(EC.elementToBeClickable(button), 5000).then(function() {
   console.log('wait-for-click has completed'); // B
});
console.log('wait-for-clickable has been scheduled'); // A

Check out the Protractor Control Flow documentation and the Webdriver JS API doc for more information.

Don't worry, it's not just you. This API can be quite confusing to learn because it behaves very differently from typical synchronous programming techniques.

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

Using the HTTP DELETE method in Node.js

Is there a specific configuration required before sending DELETE requests to a node.js application? I am able to send GET, POST, and PUT requests successfully, but for some reason DELETE requests are not functioning. When I try DELETE http://localhost:80 ...

A guide to calculating the sum of columns using TypeScript and integrating it with Angular 8

Currently, I am attempting to calculate the average of all columns and display it at the footer of my table. The table data is fetched from an API resulting in a structure like this: <tr *ngFor="let item of items"> <td>{{item.num1 ...

Using jQuery for real time countdown and count up synchronization with server-side values

Script: Every day, I receive a json response with specific event timings: items: { fajr: '5:23 am', sharooq: '7:23 am', dhur: '1:34 pm', asr: '4:66 pm': magrib: '6:23 pm', isha: '8:01 pm'} Upon ...

What is the best way to use JavaScript to access all child classes and their respective tags of a parent element in an HTML document?

I am in the process of designing a webpage where users can select a dish by checking a checkbox, and then specify the quantity they would like to order. I want to implement a logic where the quantity of a dish only increases when the checkbox for that dish ...

Develop a JavaScript application that contains a collection of strings, and efficiently sorts them with a time complexity of O(nlog n)

Seeking assistance in developing a JavaScript program that contains an array of strings and must sort them efficiently in O(nlog n) time. Grateful for any guidance... ...

Send an AJAX request to the server, retrieve data from the database, encode it into JSON format, display the

As I embark on a new coding journey, I find myself grappling with the concepts of ajax. Despite being relatively new to it, I'm facing challenges in getting my code to function as intended. One particular segment involves a textbox that triggers a Jav ...

creating a Vue app using Node results in an HTML page with no content due to syntax errors

After creating a VueJs page using the CLI, I wanted to share it with others who might not have Vue CLI or Node installed. Just like opening .html files in a browser, I tried to open the index.html file after building it. However, when I opened the file, a ...

Unable to transform moment.js string from specific location to unix time, or any other format

Struggling to convert a datetime string in a different language format to unix time using moment.js. Any tips or workarounds would be greatly appreciated! moment.locale('de'); var c = moment('20.06.2015').format("X"); //getting an Inva ...

Generate numerous div elements by utilizing ng-repeat

I am trying to generate 'n' red blocks with text (where n represents the number of elements in an array), but unfortunately, I am seeing a blank page. <html> <body> <script src="https://ajax.googleapis.com/ajax/libs/angu ...

Vue 3 Options API makes handling empty this.$refs easy

Previously in Vue 2, I was able to retrieve a property from component children (rendered within a v-for loop) using this.$refs along with a dynamically-assigned :ref attribute. However, this code no longer works in Vue 3. Upon logging out this.$refs, I no ...

Unable to retrieve the parent element of an event target in AngularJS when using Internet Explorer 11

function determineClosestAncestor(startElement, callback) { const parent = startElement.parentElement; if (!parent) return undefined; return callback(parent) ? parent : determineClosestAncestor(parent, callback); }; $document.on('click', e ...

Is it possible to populate an empty list of objects within the Page_Load scope after the page has finished loading?

I am facing a challenge where I need to populate the list var docfiles = new List<string>(); with file names uploaded by the user using dropzone js. However, the list remains empty because when the page loads for the first time, httpRequest.Files.C ...

Combining two arrays of objects in JavaScript to create a new array, using the properties of the objects

I am facing an issue with handling two arrays of JSON objects in JavaScript. I am trying to create a new array by mapping on the "Word_No" property of both arrays. Here is an example of how the arrays look like: wordInfo (total length: 4000): [ { ...

When rendering inside *.map in React, the first object of the array may not be rendered

When the SearchCard component is being rendered, it seems to be skipping the first object in the array- const cardArrayTrackSearch = this.state.searchtrack.map((user, i) => { return ( <SearchCard key={i} reload={th ...

React and Material UI: Ensuring Proper Whitespace Handling in Strings

Exploring the use of Typography component from Material UI (https://material-ui.com/api/typography/) The main objective is to maintain the new lines and spaces in a saved string. For instance, if the string contains leading spaces and new lines, it shoul ...

the pop-up modal function is malfunctioning

I can't get my pop up to work properly. When I click the button, the screen dims as if a pop up is going to appear, but nothing shows up. Can someone please assist me with this issue? Here is the HTML file: <!DOCTYPE html> <html lang="en"&g ...

The incorporation of ASP.NET with Cors cookies enhances security and functionality

Currently, I am utilizing an MVC server with IIS express running on port x. My client code is executed using an express server on port y, and requests for data are sent to the server located at localhost:x. An issue arises as the SessionId cookie is not c ...

What is the best way to retrieve the chosen option when clicking or changing using jQuery?

CSS <form name='category_filter' action='/jobseek/search_jobs/' method='get'> <select id="id_category" class="" name="category"> <option value="" selected="selected">All</option> <option v ...

Replicate and refresh characteristics

As a newcomer to this platform, I have found stackoverflow to be an invaluable resource over the past year. Currently, I am working on creating a complex form that requires the user to add subgroups. Using jquery (1.5.1 - perhaps it's time for an upd ...

Dual Camera Toggle Functionality with Three.js Orbit Controls

I am facing an issue with two cameras in one scene, one viewport, and one renderer. I switch between cameras using HTML buttons. ISSUES Issue 1 When using camera1, there is no response from moving the mouse. However, when I switch to camera2, the orbit ...