A lot of the functions exposed by Protractor return promises.
Do I need to structure my Jasmine tests using Protractor using things like async tests (with the done parameter), and .then, or does Protractor provide some magic to do this for me?
WebDriverJS takes care of that with the control-flow. Protractor adds the modification of Jasmine's expect to keep the thens at bay. It's best explained here.
Yes, there is some magic that protractor performs in order to wait for each promise to resolve.
The best description of the process is in the protractor documentation: How It Works.
This means we don't have to structure the tests as async using a done. We can simply assert using expect (in Jasmine) and everything should work.
Related
I want to test in Javascript using Mocha.
Approach that I want to use is ->
- Keep the test cases in Database.
- Before running the tests fetch the test cases from Database.
- Generate tests(it functions) dynamically using the data fetched from Database.
- Execute the tests.
Issue that I'm having is that when and where to make the Database call to fetch the test cases??
This call cannot be in the before hook because it runs before it but not describe. So, test cases need to fetched even before the describe is called.
Please suggest something that will be helpful in implementing the above mentioned approach.
I have searched a lot for implementing this approach and the only valid solution that I have got is using the parameter delay.
delay flag can be passed to mocha and you can make mocha wait till the async calls are resolved(for me database calls).
After async calls are resolved, run() function can be called which will start the execution of the tests.
I have a few functional tests in Jasmine that will periodically fail due to something in the DOM not having finished composing. I would like to be able to have these tests retry a couple of times rather than failing the test suite.
I'm looking for something similar to the way that Mocha behaves with https://mochajs.org/#retry-tests or, even better, the ability to specify a wait and then retry.
Per Jasmine's owner:
this is functionality we'd like to keep out of jasmine itself.
source: https://github.com/jasmine/jasmine/issues/960
protractor-flake has been recommended to solve this, assuming you are using Protractor.
I am new to the angular/protractor world so this is a really basic question. According to this spec, we can write protractor test for a web element like below:
var foo = element(by.id('foo'));
expect(foo.getText()).toEqual('Inner text');
However, foo.getText() returns a promise type, not a string, how can 'expect' compare that returned promise object against another string? Is there any documentation that explains this usage?
Yes, the expect(), if used with Protractor, understands promises - it would resolve a promise before making an expectation making writing Protractor tests easier. This is actually done in a separate project which Protractor depends on - jasminewd2 which patches jasmine's expect() to resolve the promises and wraps jasmine's describe(), it() and other test control block functions to be executed inside the Control Flow.
Note that, it also supports promises on both sides of the assertion, you can do, for instance:
let elementText1 = $('.ng-scope p').getText();
let elementText2 = $('#transformedtext>h4').getText();
expect(elementText1).toEqual(elementText2);
As far as Protractor documentation goes, this is partially described here.
Lately a colleague and I have had some disagreements on the "right" way to implement Cucumber step definitions using Protractor and Chai as Promised. Our contention comes from a mutual lack of understanding of precisely what is going with promise resolution in the context of Cucumber.
We're testing against an AngularJS application, so resolving promises and asynchronous behavior is a necessary evil. The biggest problem we've had is forcing synchronous test behavior and getting Cucumber to wait on promises between step definitions. In some cases, we've observed situations such that Cucumber seems to plow straight through step definitions before Webdriver even executes them. Our solutions to this problem vary...
Consider the hypothetical scenario:
Scenario: When a user logs in, they should see search form
Given a user exists in the system
When the user logs into the application
Then the search form should be displayed
Most of the confusion originates in the Then step. In this example the definition should assert that all fields for the search form exist on the page, meaning multiple isPresent() checks.
From the documentation and examples I was able to find, I felt the assertion should look something like this:
this.Then(/the search form should be displayed/, function(next) {
expect(element(by.model('searchTerms')).isPresent()).to.eventually.be.true;
expect(element(by.model('optionsBox')).isPresent()).to.eventually.be.true;
expect(element(by.button('Run Search')).isPresent()).to.eventually.be.true.and.notify(next);
});
However, my colleague contends that in order to satisfy promise resolution, you need to chain your expects with then() like this:
this.Then(/the search form should be displayed/, function(next) {
element(by.model('searchTerms')).isPresent().then(function(result) {
expect(result).to.be.true;
}).then(function() {
element(by.model('optionsBox')).isPresent().then(function(result) {
expect(result).to.be.true;
}).then(function() {
element(by.button('Run Search')).isPresent().then(function(result) {
expect(result).to.be.true;
next;
});
});
});
});
The latter feels really wrong to me, but I don't really know if the former is correct either. The way I understand eventually() is that it works similarly to then(), in that it waits for the promise to resolve before moving on. I would expect the former example to wait on each expect() call in order, and then call next() through notify() in the final expect() to signal to cucumber to move on to the next step.
To add even more confusion, I've observed other colleagues write their expects like this:
expect(some_element).to.eventually.be.true.then(function() {
expect(some_other_element).to.eventually.be.true.then(function() {
expect(third_element).to.eventually.be.true.then(function() {
next();
});
});
});
So the questions I think I'm alluding to are:
Is any of the above even kinda right?
What does eventually() really do? Does it force synchronous behavior like then()?
What does and.notify(next) really do? Is it different from calling next() inside of a then()?
Is there a best practices guide out there that we haven't found yet that gives more clarity on any of this?
Many thanks in advance.
Your feeling was correct, your colleague was wrong (though it was a reasonable mistake!). Protractor automatically waits for one WebDriver command to resolve before running a second. So in your second code block, element(by.button('Run Search')).isPresent() will not resolve until both element(by.model('optionsBox')).isPresent() and element(by.model('searchTerms')).isPresent() are done.
eventually resolves promises. An explanation is here: https://stackoverflow.com/a/30790425/1432449
I do not believe it's different from putting next() inside of then()
I do not believe there is a best practices guide. Cucumber is not a core focus of the Protractor team, and support for it is largely provided by the community on github. If you or someone you know would like to write a best practices guide, we (the protractor team) would welcome a PR!
What works for me is this - The function below searches for something that will always equal true - in the case the existence of a html tag. I call this function at the end of each test, passing in the callback
function callbackWhenDone(callback) {
browser.wait(EC.presenceOf(element(by.css('html'))))
.then(function () {callback();})
}
This is the usage in a simple test:
this.Given(/^I go on "([^"]*)"$/, function (arg1, callback) {
browser.get('/' + arg1);
callbackWhenDone(callback);
});
A bit of a hack I know but it gets the job done and looks pretty clean when used everywhere
I'm using a testing setup with Mocha.js and a lot of promises within the tests. The tests depend on setting up stuff in the DOM, and between tests, the DOM is cleared. However, sometimes the tests run slowly and time out. In this case, their promises continue to execute but the DOM is cleared before the next test, so the promise may incorrectly throw errors into the next test. Is there a way to cancel or destroy all outstanding promises in-between tests? We are using when.js promises.
when.js supports a cancel() method. You could call it from a afterEach or after block in mocha. You might need to create an array at the top of each mocha file (or as global) to track your outstanding promises.