(I have seen this SO discussion, but was not sure how to apply it to my case, so I’m asking a new question. Hope it’s not a duplicate)
I am testing a form written in Angular using Protractor with Cucumber.js.
So what I would like to do is to tell Protractor to go click on the title of a field (which is a link) then, when that field appears, enter some text in it, then move on to the title of the next field, and so on.
Here is my step in Cucumber:
When I fill the form with the following data
| field | content |
| First Name | John |
| Last Name | Doe |
| Address | Some test address |
# and so forth
Here’s a half-hearted attempt at step definition:
this.When(/^I fill the form with the following data$/, function (table, callback) {
data = table.hashes();
# that gives me an array of objects such as this one:
# [ { field: 'First Name', content: 'John' },...]
for (var i = 0; i < data.length; i++){
var el = element(by.cssContainingText('#my-form a', data[i].field));
el.click().then(function(){
var fieldEl = el.element(by.xpath("../.."))
.element(by.css('textarea'));
fieldEl.sendKeys(data[i].content);
});
}
};
callback();
});
But of course, this isn't working, because even before Protractor has time to click on a field name and enter the necessary data into the field, the callback function is called, and Cucumber moves to the next step.
So my question is, how can I, using Protractor with Cucumber.js, write the step to insert data defined in the Cucumber table into the form fields? Is this feasible using a for loop?
Your loop is enqueuing promises, so the loop finishes before any "clicking" or sending of keys happens. You need to invoke callback
after all the promises have resolved.
I see two solutions (I think). You could keep track of the promises in an array, and then use protractor.promise.all
(see http://spin.atomicobject.com/2014/12/17/asynchronous-testing-protractor-angular/) to wait for the array of promises to finish. First save the promise in a var promises = []
array:
var p = el.click().then(function(){ ... });
promises.push(p)
Then outside the loop:
protractor.promise.all(promises).then(callback);
Or, you can rely on the ControlFlow to keep your promises ordered in the loop, and call the callback in the last iteration of the loop:
var p = fieldEl.sendKeys(data[i].content);
if (i === data.length - 1) { // beware: you want to check "i" inside the loop and not in a promise created in the loop.
p.then(callback);
}
Despite all the text to the contrary, I cannot promise that either of these work. Hopefully they at least point you in the right direction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With