Protractor locator can't find html element in phantomjs only - angularjs

I have a few tests that are running fine in chrome, but if I switch to phantomjs, I have the following error:
Unable to find element with css selector '.selected-recipients a'
My test is simply this:
it('should navigate when clicking edit', function() {
var editLink = element(by.css('.selected-recipients a')).element(by.css('.edit-preview'));
editLink.click();
expect(browser.getCurrentUrl()).toContain('#/recipients');
});
This works fine on chrome. The problem is phantomjs. I found a post that suggests that the problem might have to do with window size, but that didn't solve the problem for me:
https://github.com/angular/protractor/issues/585
I also tried to use by.id instead of by.css and I have the same problem. All other tests in this file work fine and some do use by.css, so it doesn't look like a problem with phantomjs understanding this locator. It seems like the element is not in the page at all.
Any ideas? Thanks

When phantomjs is acting in a strange way I dump a screen shot.
Probably not what you are looking for, but it is an idea. :)
page.open("http://www.stackoverflow.com", function()
{
page.render('script_ending.png');
}
Another idea is to try dumping the html to a file, to see if the element is there.
Or try changing the DOM, inserting an element, then see if you can find it.
Or try searching by just the class name, to see at what point it fails... maybe there is no child element of tag a.

Related

codeceptjs react testing - Clickable element was not found by text|CSS|XPath

I have a project made with react and rest api(php+mysql).I have to put it through a codeceptjs test.The app is working properly with countless of manual testing, and as far as I can see, the codeceptjs test is working too, but it gives the following error:
Error: Clickable element "ADD" was not found by text|CSS|XPath
at new ElementNotFound (node_modules/codeceptjs/lib/helper/errors/ElementNotFound.js:14:11)
at assertElementExists (node_modules/codeceptjs/lib/helper/WebDriver.js:2835:11)
at WebDriver.click (node_modules/codeceptjs/lib/helper/WebDriver.js:917:7)
at processTicksAndRejections (internal/process/task_queues.js:97:5)I }) => {
I.amOnPage('/');
I.click('ADD');
I.seeElement('#product_form');
I.fillField('#sku', 'SKUTest000');
I.fillField('#name', 'NameTest000');
I.fillField('#price', '25');
I.waitForElement('#productType');
I.selectOption('#productType','DVD');
I.waitForElement('#size');
I.fillField('#size','200');
I.click('Save');
My add element looks like this:
<Link title="ADD" to="/add-product">ADD</Link>
Can someone please help me out why is this error appearing and how can I solve it? Thanks in advance!
Update:
I did a couple more tests, and I noticed that sometimes it gives back less/different errors depending on the test's time. For example:
http://165.227.98.170/open?testName=ed
http://165.227.98.170/open?testName=ah
http://165.227.98.170/open?testName=bc
My guess is that is has to do with how react loads in the html elements and manages the rest api calls. How/what should I change in the app to accomodate the test script?
Seems like the problem was I put the whole home page's load after the rest api call by accident.

Can i access the ng-app value in a protractor test?

I simplified the code i need to test to this:
<html ng-app="home" ng-strict-di=""><head>....
And i am running some protractor tests, i want to access the value of ng-app so i can compare and see which app is running in each page.
I have tried
var appName = element(by.xpath('/html/#ng-app'))
but it is not returning a usable promise or text i can compare with
appName.getText().then(function(name) {
expect(name).toBe('home')
});
But protractor complains:
InvalidSelectorError: invalid selector: The result of the xpath expression "/html/#ng-app" is: [object Attr]. It should be an element.
So i'm a bit baffled as how can i access my angular app name from protractor to test for app running independently of localization of labels.
Any insight into this enigma?
And it seems like magically, when you order your thoughts to formulate the question, the answer comes to you.
the trick is to get the html as element
var appNameHtml = element(by.xpath('/html'))
and then, in the test, get the ng-app attribute and use it:
appNameHtml.getAttribute('ng-app').then(function(value) {
expect(value).toBe('home');
});
And bingo, you can extract the app name.
Maybe this is a very basic question, but it was driving me insane :)
your answer will suffice I guess in this case. But just wanted to highlight a more generic approach in case ng-app may reside not only on html element.
var elementWithNgApp = element(by.css('*[ng-app]'))
And then wanted to add one more thing. You need not resolve the promise of getAttribute to do an expect on its value. Jasmine resolves the promise for you. You can have something like this
expect(elementWithNgApp.getAttribute('ng-app')).toBe('home');

Non-angular page opened with click - angular not defined using ignoreSynchronization or waiting for Angular without

After a lot of research, and tinkering, I can't seem to actually get my Protractor test to do anything else other than have an Angular related error, even though I am using browser to avoid Angular being detected at all.
The test involves an Angular app, opening a dropdown in it, and clicking on the link for the console; the console opens a non-Angular admin page in a separate window.
So based on the many informative SO posts I found, I first used this...
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
//expect for new window here
});
});
Which appeared to work, as I could get to the window through repl pretty easily.
The issue is when either of the following were added...
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
expect(browser.getLocationAbsUrl()).toContain('/console/login.jsp');
expect(browser.driver.findElement(By.css('th.login')).getText()).toEqual('Login');
});
});
One expect check the URL and the other checks for the header element on the page, which is a table header. When I run this, I get the following:
Error while waiting for Protractor to sync with the page: "angular could not be found on the window"
When I decide to use browser.ignoreSynchronization = true, both in the function, or in a beforeEach, with or without a following afterEach setting it to false, I get the following:
JavascriptError: angular is not defined
I can't seem to get any "useful" errors to help me debug it, and trying it in repl does not help, as I get the same issue.
To be comprehensive, trying my URL expect without getting the second window will give me the root, and the other will fail.
Just doing one or the other will cause the same problem.
Changing to regular syntax (element(by.css...)) does not change things.
So much for my first question...
It appears that my use of browser.getLocationAbsUrl() is meant to be used for an Angular page, and was causing my issue...
Essentially, even though I believed I was using pure Webdriver calls, that call still required Angular on the page to work...
As stated in another post, the use of browser.driver.getCurrentUrl() is a non-Angular call using Webdriver, and fixed the problem. Thus, the final code is the following...
browser.sleep(1000); //to wait for the page to load
browser.driver.getAllWindowHandles().then(function(handles) {
browser.driver.switchTo().window(handles[1]).then(function() {
expect(browser.driver.getCurrentUrl()).toContain('/console/login.jsp');
expect(browser.driver.findElement(By.css('th.login')).getText()).toEqual('Login');
});
});
This works without setting ignoreSynchronization, BTW.
I realized it would probably be something relatively simple to fix it, just didn't expect I'd get it that quickly (I intended on submitting the question last night, but posted it this morning instead).
In any case, I hope this will at least be a good reference for anyone else facing the same issue.
Seems like getLocationAbsUrl is angular abs url.
Try using the native driver getCurrentUrl instead.
-- expect(browser.getLocationAbsUrl()).toContain('/console/login.jsp');
++ expect(browser.driver.getCurrentUrl() ...

Some of your tests did a full page reload - error when running Jasmine tests

I'm running into an issue where when I run my tests on Jasmine, I get this error below. The problem is, it seems to happen when I try to execute a certain amount of tests. It doesn't seem to be tied to a particular test, as if I comment out some, the tests pass. If I uncomment some tests, the error appears. If I comment out ones that were uncommented before, they all pass again. (ie if I have red, green, blue and orange test and it fails, I comment out orange and blue it passes, then I uncomment blue and orange it fails again, but if I comment out red and green it passes again).
Chrome 41.0.2272 (Mac OS X 10.10.1) ERROR Some of your tests did a
full page reload! Chrome 41.0.2272 (Mac OS X 10.10.1): Executed 16 of
29 (1 FAILED) ERROR (0.108 secs / 0.092 secs)
I'm stumped as to what is going on. The more tests I add, that's when this becomes an issue. Has anyone encountered this before? I have no idea what could be causing it, as nothing in any of my tests do any kind of redirection, and they all pass universally on another persons machine.
In my case the problem was that in my source code I had code directly setting the href on the location object, like window.location.href = 'somewhere';
In my specs I set up a onbeforeunload listener that just returns a string instead of allowing the redirect to take place:
beforeAll(() => {
window.onbeforeunload = () => 'Oh no!';
});
I suppose you are using window.location somewhere in your targeted code. In order to pass it just create a spy for the window.onbeforeunload
Example:
window.onbeforeunload = jasmine.createSpy();
Or even better use $window instead, and this will not happen.
Make sure that your tests are properly isolating all modules under test with mocks/spies. The behavior you are seeing says to me that your tests are not truly running in isolation - they are changing some state somewhere that will trigger a reload.
I recently encountered this error with Karma 0.13.12. I upgraded to Karma 0.13.14 and my tests work again. The problem for me (and probably also for #mqklin) was related to https://github.com/karma-runner/karma/issues/1656 and https://github.com/jasmine/jasmine/issues/945.
There are many ways this error can happen.
If your component has a form element, this might be the cause.
Whenever a button on the form is clicked, this error can happen, even tho your component contains no navigation logic.
What worked for me was upgrading Karma from 1.4.0 to 1.4.1 and changing the maximumSpecCallbackDepth in my jasmine.js file from 20 to 100.
creating a spy on the function which has the window.location / reload fixed the issue for me
Hope you have used window.location = "some url" in your code;
Faced similar problem, and solved by using the below changes.
Replaced window.location in the code with,
window.location.assign("some url");
Do the below in unit test:
spyOn(window.location, "assign").and.callFake(() => {
// Dummy assign call - so that your actual call will be faked and the reload will not happen.
});
You also need to make sure that modules are not being loaded twice. In my case, I had an AngularJS module file -e.g., auth.controller.js which contents were already bundled in a core.js file. Once I excluded the bundled files on karma, the error disappeared.
Try to reduce amount of describe sections or completely remove them. I don't know why, but it works for me.
I was using setTimeout(() => window.location.replace('/'), 10);
I used below code in my unit test and it worked for me.
spyOn(global, 'setTimeout');
In case it was ng-submit callback, which doesn't call "event.preventDefault()" and the browser reloads page. Mocking $location doesn't help in that situation.
According to angularjs documentation you should inject the $window module to be able to solve the testability issue you get. If you really want to do a full page refresh while routing, which will reload the whole application. But anyway...
So for example in component
.controller('ExampleController', ['$scope', '$window', function($scope, $window**)
{
$scope.doRerouteWithPageReload = function() {
return this.$window.location.href = "/myUrl";
};
And then in your test-file you import $window to the test-controller your way, then where you assign spies you can do something like this:
$window = { location: {href: jasmine.createSpy() };
And then the actual test is something like this:
expect($window.location.href).toBe("/myUrl");
Angularjs documentation for reading more about $window.
It will solve this Karma redirect error!
var html = '<script type="text/javascript">';
html += 'window.location = "' + urlToRedirect +'"';
html += '</script>';
$( '.wrapper' ).append( html );

Check text in a DOM element using Protractor

Here’s what I’m trying to do while testing an Angular app with Protractor. I would like to get a certain element, which is somewhat like this:
<div class="someClass">
<p>{{textFromBoundModel}}</p>
</div>
then get its html, and check whether it contains the text that I expect it to have.
I tried to get this element first by the cssContainingText method, but it didn't quite work (not sure why; maybe because the text within the paragraph is produced dynamically). So now I’m getting this element using just the by.css locator. Next, I'm checking whether it contains the text I’m testing for:
// this is Cucumber.js
this.Then(/^Doing my step"$/, function(callback){
var el = element(by.css('.someClass'));
expect(el).to.contain("some interesting string");
callback();
});
});
but this doesn't work. Problem is, el is some kind of a locator object, and I can’t figure out how to get html of the element it found in order to test against this html. Tried .getText(), with no success.
Any suggestions?
Does:
expect(el.getText()).to.eventually.contain("some interesting string");
work?
I believe you need the .eventually to wait for a promise to resolve, and you need the .getText() to get at the content of the div.
See the chai-as-promised stuff at the head of the cucumber sample.
Try the below solution worked for me
Solution 1 :
expect(page.getTitleText()).toContain('my app is running!');
Solution 2 :
expect<any>(page.getTitleText()).toEqual('my app is running!');

Resources