Angular Protractor tests fail with Select2 inside Modal - javascript

I’m trying to run my angular e2e tests with protractor. I’ve got some situations where a select exists inside a modal. Depending on the machine running the tests, this sometimes fails as protractor can’t find the select with:
NoSuchElementError: No element found using locator: By.cssSelector("div#s2id_items”)
On a slower machine this works every time, while on faster machines it often fails. My guess is that the modal is still being animated when protractor tries to access the selector, hence, resulting in failure.
I’ve tried to disable animations without success with the code bellow inside the onPrepare directive in my protractor config:
var disableNgAnimate = function() {
angular.module('disableNgAnimate', []).run(['$animate', function($animate) {
$animate.enabled(false);
}]);
};
browser.addMockModule('disableNgAnimate',disableNgAnimate);
I’m using angular 1.4.3 with bootstrap 3.3.5 and protractor 2.1.0.
Thanks
Edit:
1 - I'm not using explicit waits and I wouldn't like to, as these would either considerably slow down tests or still be prone to failure in some scenarios.

You could try using Expected Conditions for wait, such as:
var EC = protractor.ExpectedConditions;
var myElement= element(by.css('div#s2id_items'));
browser.wait(EC.presenceOf(myElement), 5000);
//rest of your code
This wait will not slow down your tests, as it will only wait long enough for the element to be shown, and fail after 5 sec if it isn't.
EDIT: For clickable, animated objects you can either try built-in "elementToBeClickable" condition (just replace presenceOf in the above example), or write your own, that would do whatever you like (function returning true of false). E2E tests should "think" as a user would, and a user would wait for the animation to end, so maybe it would be best if you used explicit wait for the animation after all.

Related

Why does protractor not locate element when it's referenced on 2 consecutive lines?

If I use the following code in an it block in my spec.ts file:
element(by.css(".header-text")).getText().then(function(text) {
console.log(text);
});
expect(element(by.css(".header-text")).getText()).toEqual("Project");
I get the following outputted to my console:
Project
Expected '' to equal 'Project'.
Expected :"Project"
Actual :""
A few observations with this.
If I remove the first "line" of code with the console.log, the expect works as expected.
When I run this code first thing after starting up my machine it works the first 2-3 runs. Which is weird because protractor starts a new browser each run (I thought and appear to observe) and there shouldn't be some type of caching going on.
It appears to me that this seems to be some type of "when measured, the value changes" behavior that I really don't expect out of programming, but I'm new to Javascript/Angular/Protractor, so maybe this is just something that happens and you have to have the tribal knowledge that it behaves this way.
This isn't project breaking, I have my test working the way I want. I would just like an explanation as to why this behavior occurs.
You are already resolving the promise, so you could just use it at the same time.
element(by.css(".header-text")).getText()
.then(function(text) {
console.log(text);
expect(text).toEqual("Project");
});
The expect method is supposed to resolve promises, but why ask twice if you already have it.
The other thing to check for is anything in your application that will make it look like Angular has done it's job, but then changes the title - as it appears that you may be getting the title before it is populated in some cases which suggests a race condition.

Strategy for selenium-webdriver in javascript for testing in different environments

I've been making a functional tests using selenium-webdriver using yadda library. The problem it's that in my different environments the same test suite working different. Example:
On tests, the result it's different based on the environment that I entry.
Local localhost:5000
Open my search site
․ when i go to my site: 2169ms
․ when i write a text on the search input: 21ms
․ when i click the search button: 130ms
․ then i get the results page.": 46ms
Staging mystaging.domain.com
Open my search site:
StaleElementReferenceError: {"errorMessage":"Element is no longer attached to the DOM","request":{"headers":{"Accept":"application/json; charset=utf-8","Connection":"close","Content-Length":"2"
Production www.domain.com
Open my search site
․ when i go to my site: 2169ms
․ when i write a text on the search input: 21ms
․ when i click the search button: 130ms
․ then i get the results page.": 46ms
At this time, only the staging tests are failing, but in other situations when the internet connection it's slow, the tests fails in production but pass in staging.
The main problem it's that the browser doesn't have the DOM ready for the test and they doesn't find the element required for the test.
My approach for trying to solve this, it's wait that appear the root element of my page like this:
return driver.wait(() => driver.isElementPresent(By.css(".my__homepage")), 50000);
But this isn't enough for me, because the test suites are still failing randomly.So, my question it's:
Which could be a best approach for run in different environments the tests suite dealing with the elements that isn't ready on the browser ?
I am showing you a simple C# code which I did for my work in IE browser but it can work similarly for other browsers and languages.
private static WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(120)); //max driver wait timeout 120 seconds
try
{
//waiting for document to be ready
IJavaScriptExecutor jsExecutor = (IJavaScriptExecutor)driver;
wait.Until(sc => jsExecutor.ExecuteScript("return document.readyState").Equals("complete"));
//waiting for an element.
//use 'ExpectedConditions.ElementToBeClickable' as in some cases element gets loaded but might not be still ready to be clicked
wait.Until(ExpectedConditions.ElementToBeClickable(By.Id("elementID")));
}
catch (Exception ex)
{
}
Basically I am putting a wait for the document to be ready using JavaScript executor
Also I am putting an implicit wait for each element that I would access. I am using expected condition as ElementToBeClickable because sometime ElementIsPresent does not mean element can be accessed as per your needs.
Note: Addiotinally you might also have to check for other element properties (like enabled/disabled, etc) depending on your needs.

Sencha test timeout, waiting

I'm starting with Sencha test and trying run some simple tests.
I start with simple webpage and it works. Now when I create simple form i ext, and try to test it using localhost, I have communicate
Failed: Timeout waiting for target (input[name="name"]) to be available
I'm doing it exactly same way just change the elements names, so it should work.
I know that it can be cos page loading is too long so I try add function for wait (both with time and until it find element), nothing helps.
Any ideas?

How to have protractor reliable results?

I'm using Protractor (v 1.3.1) to run E2E tests for my Angular 1.2.26 application.
But sometimes, tests are ok, sometimes not. It seems that sometimes the check is done before display is updated (or something like "synchronisation" problem).
I try many options :
add browser.driver.sleep instructions,
disable effects with browser.executeScript('$.fx.off = true')
add browser.waitForAngular() instructions
without success.
What are the bests practice to have reliables E2E tests with protractor?
JM.
Every time I have similar issues, I'm using browser.wait() with "Expected Conditions" (introduced in protractor 1.7). There is a set of built-in expected conditions that is usually enough, but you can easily define your custom expected conditions.
For example, waiting for an element to become visible:
var EC = protractor.ExpectedConditions;
var e = element(by.id('xyz'));
browser.wait(EC.visibilityOf(e), 10000);
expect(e.isDisplayed()).toBeTruthy();
Few notes:
you can specify a custom error message in case the conditions would not be met and a timeout error would be thrown, see Custom message on wait timeout error:
browser.wait(EC.visibilityOf(e), 10000, "Element 'xyz' has not become visible");
you can set EC to be a globally available variable pointing to protractor.ExpectedConditions. Add this line to the onPrepare() in your config:
onPrepare: function () {
global.EC = protractor.ExpectedConditions;
}
as an example of a custom expected condition, see this answer
Another point which is very important in testing with Protractor is understanding the ControlFlow. You may find explaination and code example here : When should we use .then with Protractor Promise?
Jean-marc
There are two things to consider.
The first is that you should properly sequence all protractor actions (as also hinted by #jmcollin92). For this, I typically use .then on every step.
The second important thing is to make sure that a new test it(...) only starts after the previous it(...) has completed.
If you use the latest version of Protractor, you can use Jasmine 2.x and its support for signalling the completion of a test:
it('should do something', function(done) {
clicksomething().then(function() {
expect(...);
done();
});
});
Here the done argument is invoked to signal that the test is ready. Without this, Protractor will schedule the clicksomething command, and then immediately move on with the next test, returning to the present test only once clicksomething has completed.
Since typically both tests inspect and possibly modify the same browser/page, your tests become unpredictable if you let them happen concurrently (one test clicks to the next page, while another is still inspecting the previous page).
If you use an earlier version of Protractor (1.3 as you indicate), the Jasmine 1.3 runs and waitsFor functions can be used to simulate this behavior.
Note that the whole point of using Protractor is that Protractor is supposed to know when Angular is finished. So in principle, there should be no need to ever call waitForAngular (my own test suite with dozens of scenarios does not include a single wait/waitForAngular). The better your application-under-test adheres to Angular's design principles, the fewer WaitForAngular's you should need.
I would add that disabling ngAnimate may not be enough. You may also have to disable all transition animation by injecting CSS (What is the cleanest way to disable CSS transition effects temporarily?).

How do you mock out the File Picker in the browser for unit testing?

I am interested in how to globally mock out the file picker in the browser. Specifically, I am most interested in doing this in Firefox but would prefer a general solution.
I only care about preventing the file picker dialog from appearing. I do not need to be able to assert that it did open. The problem is that I have unit tests for JavaScript code that open the file picker. When the dialog opens, it halts the execution of the test suite.
An example situation is that I am testing the onRender method of a Backbone.View. That method renders a subview, which will open the File Picker when it is rendered. Since I am not directly testing that subview, I would prefer not to mock out portions of its behavior when I am only interested in unit testing some other part of the onRender method.
Example:
//Test file
it("should do something", function() {
var view = new App.Views.SomeView();
spyOn(view.modelBinder, "bind");
view.render();
expect(view.modelBinder.bind).toHaveBeenCalled();
});
//View file
onRender : function () {
this.modelBinder.bind(this.el, this.model);
this.$("#thing").html(this.subview.render().el); //This line has a side effect that opens file picker
}
Essentially, I do not want to explicitly mock out the behavior that causes the file picker to be opened because it is not what I am interested in testing here. Doing so will make the test suite much more brittle and difficult to maintain.
Use sinon to mock/spy/stub out the calls. You can test for the calls being made instead of actually making the calls.
That way you can test that the function has been called without calling the actual function that displays the dialog.
To answer your question: Just don't.
I would replace subview.render() with an empty function to avoid the undesired side effect. You say however:
"I do not want to explicitly mock out the behavior that causes the
file picker to be opened because it is not what I am interested in testing..."
Which is a little contradictory. If you want to Unit-Test App.Views.SomeView, you will have to mock out external collaborators, specially when not interesting, and including your file picker. On the other hand, you should not mess with the SUT when unit-testing it.
Mocking would in fact make your test more prone to be red, but is the only way to make sure your production code does not suffer from ill forms of coupling (IMHO, A common pitfall with Backbone.js apps.)
The only place in which you would need to avoid the file-picker to display, is when unit-testing your file-picker itself, in that case you could use sinon as sugested or leave it without coverage if you are using jQuery. Remember the "Never mock a type you don't own" rule.

Categories