Protractor - changing pages/views - jasmine

I have a test case in Protractor which loads the home page and then clicks a button that redirects to another page. In that other page I want to grab the value of an element.
describe('todo list', function() {
it('should find the contact phone number from the home page', function() {
browser.get('http://homepage...');
element(by.id('re_direct_to_contact_page')).click();
var number = element(by.id('phonenumber')).getText();
expect(number).toEqual('412-....-...');
});
});
However although it loads the page it does not check the element value and the test case fails.
How can Protractor load another page to check a value?
NOTE: - I made up this example but in my real test case I am sending data from one page to another so I cannot load the page I want directly.
EDIT: STACK TRACE
protractor conf.js Using the selenium server
at http://localhost:4444/wd/hub [launcher] Running 1 instances of
WebDriver
Error: Error while waiting for Protractor to sync with the page:
"[ng:test] http://errors.angularjs.or/1.4.0/ng/test"
StackTrace: undefined
1 test, 1 assertion, 1 failure

It's possible that you might be facing a timing issue. Try re-structuring your test from this:
var number = element(by.id('phonenumber')).getText();
expect(number).toEqual('412-....-...');
To this:
expect(element(by.id('phonenumber')).getText()).toEqual('412-....-...');
While Jasmine and Protractor try to resolve every promise before moving on, sometimes it doesn't happen as quickly as you would like. Putting the entire promise chain into the expect helps to enforce the resolution of all of them before going through the matcher.

Related

Wait for angular to be stable, bevor continuing the test execution

I have a Web Application which I am currenly testing using Cypress. I have a problem That some pages executes client side rendering. after the page has been loaded / items has been clicked
I need to wait for the client-side rendering to finish, before the framework continues the test execution.
On the Console.
I need something like
const testability = window.getAngularTestability(window.getAllAngularRootElements()[0]);
if (testability.isStable()) {
doneCb(true);
} else {
testability.whenStable((didWork) => {
doneCb(didWork);
}, TIME_OUT);
to work with cypress/typescript. I can not get the method getAngularTestability on the window object
I have considered using cy.exec but it seems to be executed on the system not on the app.

Cypress not retrying assertion

My Cypress test is acting inconsistently due to an assertion set on header text. Here is my code:
cy.get('.heading-large').should('contain', 'dashboard') // passes
cy.contains('View details').first().click()
cy.get('.heading-large').should('contain', 'Registration details') // sometimes fails
If it fails, it is because the heading still contains 'dashboard' - Cypress appears not to have retried but gives error Timed out retrying: expected '<h1.heading-large>' to contain 'Registration details'
From reading about Cypress retry-ability, my understanding is that the should assertion should keep trying until timeout, which is set as "defaultCommandTimeout" : 5000. This feels true even if I have an element with the same identifier across two pages. There are no major performance issues with the app I'm testing.
The test seems more likely to fail if I am not watching the window and this issue looks like a possible cause.
Can anyone help determine: is there an issue with my test or Cypress, and how might I improve the test? I'm using Cypress 5.1.0 and Chrome 85 on MacOS Catalina.
It is failing occasionally because the request that fills the header with information has not resolved by the time the timeout has been reached.
You can solve this by setting up a route with a route alias to wait for that exact response from the request to resolve before you proceed with the click.
In other words, When you click(), there is a request sent that grabs the information you want to check for in the next get(). This response for this request has sometimes not resolved by the time your get() reaches timeout. You could increase the timeout but that's not recommended and not good practice here. Instead, wait for that specific response with route & route alias. If you do that, in every case, the last get() won't get called until the information it is looking for has been resolved.
I don't know your request but it would work something like this:
// setup the route and alias
cy.server()
cy.route("/youRequestUrlHere").as("myLovelyAlias")
// first get
cy.get('.heading-large').should('contain', 'dashboard')
// this click fires the request url from route() above
cy.contains('View details').first().click()
// wait for route to resolve using route alias
cy.wait("#myLovelyAlias").then((response) => {
// next get called after response resolves
cy.get('.heading-large').should('contain', 'Registration details')
}
Reference:
Route & alias
Route
Best Practice - get()
Network Request - wait()
edit:
As mentioned above, you could also cheat and set the defaultCommandTimeout to a higher number but that is not recommended because you could still run into cases where the response resolution takes longer than the timeout you've set. The route/wait pattern is the better, more stable approach.
Just in case you want to know how its done though, you would change your get() to something like:
cy.get('.heading-large', {defaultCommandTimeout: 60000}).should('contain', 'Registration details')
Again, other way would be much better.
Reference:
Cypress configuration
It looks like we need to wait for the Cypress bug "Some tests flake only if test runner's browser loses focus (or run headlessly)" to be fixed. This is because I have tried the alternative, helpful answers but am consistently facing the original issue when the window is out of focus.
Thank you to those who have answered and commented.

Cypress async form validation - how to capture (possibly) quick state changes

I have some async form validation code that I'd like to put under test using Cypress. The code is pretty simple -
on user input, enter async validation UI state (or stay in that state if there are previous validation requests that haven't been responded to)
send a request to the server
receive a response
if there are no pending requests, leave async validation UI state
Step 1 is the part I want to test. Right now, this means checking if some element has been assigned some class -- but the state changes can happen very fast, and most of the time (not always!) Cypress times out waiting for something that has ALREADY happened (in other words, step 4 has already occurred by the time we get around to seeing if step 1 happened).
So the failing test looks like:
cy.get("#some-input").type("...");
cy.get("#some-target-element").should("have.class", "class-to-check-for");
Usually, by the time Cypress gets to the second line, step 4 has already ran and the test fails. Is there a common pattern I should know about to solve this? I would naturally prefer not to have change the code under test.
Edit 1:
I'm not certain that I've 100% solved the "race" condition here, but if I use the underlying native elements (discarding the jQuery abstraction), I haven't had a failure yet.
So, changing:
cy.get("#some-input").type("...")
to:
cy.get("#some-input").then(jQueryObj => {
let nativeElement = jQueryObj[0];
nativeElement.value = "...";
nativeElement.dispatchEvent(new Event("input")); // make sure the app knows this element changed
});
And then running Cypress' checks for what classes have / haven't been added has been effective.
You can stub the server request that happens during form validation - and slow it down, see delay parameter https://docs.cypress.io/api/commands/route.html#Use-delays-for-responses
While the request is delayed, your app's validation UI is showing, you can validate it and then once the request finishes, check if the UI goes away.

Cypress:Is there any way to check invisibility of an element

In our application when user do some actions that require communicatiion with server -a loading bar will be displayed on top panel.Once the action completed-Loading bar will be disappeared.In tests we are using this as a check before we move to next step.
In selenium i am checking the disappearance of loading bar as shown below
WebDriverLongWait.Until(ExpectedConditions.InvisibilityOfElementLocated(By.Id("loading-bar")));
Is there a similar way to check invisibility of an element in Cypress
instead of waiting for loading bar i am waiting for the request to finish
as shown below cy.server()
cy.route('POST','**/saveExpression').as('saveExpression')
cy.get('.IEE-save-button',{ timeout: 100000 }).contains('Apply Expression').click();
cy.wait('#saveExpression').then((xhr)=>
{
cy.contains('browse',{timeout: 60000}).click()
})
In this scenario, it's ideal to use .should('not.be.visible'). To place in your example as below,
cy.get('#loading-bar').should('not.be.visible')
Since loading bar indicator is dependent on some network request, you can wait for the XHR request to finish before making an assertion. You could use the wait() function of cypress. For instance:
// Wait for the route aliased as 'getAccount' to respond
cy.server()
cy.route('/accounts/*').as('getAccount')
cy.visit('/accounts/123')
cy.wait('#getAccount').then((xhr) => {
cy.get('#loading-bar').should('not.be.visible')
})

How can I implement wait_for_page_to_load in Selenium 2?

I am new to automated web testing and I am currently migrating from an old Selenium RC implementation to Selenium 2 in Ruby. Is there a way to halt the execution of commands until the page gets loaded, similar to "wait_for_page_to_load" in Selenium RC?
I fixed a lot of issues I was having in that department adding this line after starting my driver
driver.manage.timeouts.implicit_wait = 20
This basically makes every failed driver call you make retry for maximum 20 seconds before throwing an exception, which is usually enough time for your AJAX to finish.
Try using Javascript to inform you!
I created a couple methods that checks via our javascript libraries and waits to see if the page has finished loading the DOM and that all ajax requests are complete. Here's a sample snippet. The javascript you will need to use is just going to depend on your library.
Selenium::WebDriver::Wait.new(:timeout => 30).until { #driver.execute_script("[use javascript to return true once loaded, false if not]"}
I then wrapped these methods in a clickAndWait method that clicks the element and calls the waitForDomLoad and waitForAjaxComplete. Just for good measure, the very next command after a clickAndWait is usually a waitForVisble element command to ensure that we are on the right page.
# Click element and wait for page elements, ajax to complete, and then run whatever else
def clickElementAndWait(type, selector)
#url = #driver.current_url
clickElement(type, selector)
# If the page changed to a different URL, wait for DOM to complete loading
if #driver.current_url != #url
waitForDomLoad
end
waitForAjaxComplete
if block_given?
yield
end
end
If you are using capybara, whenever you are testing for page.should have_content("foo"), capybara will not fail instantly if the page doesn't have the content (yet) but will wait for a while to see if an ajax call will change that.
So basically: after you click, you want to check right away for have_content("some content that is a consequence of that click").

Resources