I have some cypress tests where there can appear at any time a message box with an incident message. Usually after a click, but because of the async loading not always just after.
If the incident does not affect the next step in the test, the test just goes on without failing.
Ideally, I would like to catch at all times such message boxes and prevent just hopping over it without handling it properly.
How would I build such an listener who checks after, let's say, after every "cy.XX" event?
after each click is not working, because I don't know if such a message box appears. So waiting for a certain amount of time, slows down the tests.
Message Box example:
<div class="MuiBox-root css-k008qs" data-e2e-notification-message="">
<div data-e2e-notification-message-severity="ERROR">etc etc.
<span>Something went wrong ....</span></div></div>
Related
So I'm trying to write some cypress code and the documentation imo isn't really clear.
I have two scenarios.
A page is loaded with no loading spinner.
A page is loaded with a loading spinner.
I would like to write code that would satisfy both scenarios and let the test just continue.
If the page does not have a loading spinner element: Continue with the tests as usual.
If the page does have a loading spinner element: Wait until the element disappears and then continue
Cypress has a lot of fancy functions but the documentation on how to use them just isn't clear enough.
I tried with the following piece of code:
try {
cy.getByTestId('loader-spinner')
.should('exist')
.then(el => {
el.should('not.exist');
});
} catch (error) {
cy.getByTestId('loader-spinner').should('not.exist');
}
Because of the timing aspect it can be tricky to get this test right.
Controlling Triggers
You really need to know what controls the spinner - usually it's a call to API. You can then delay that call (or rather it's response) to "force" the spinner to appear.
To do that, use an intercept
cy.intercept(url-for-api-call,
(req) => {
req.on('response', (res) => res.delay(100)) // enough delay so that spinner appears
}
)
// whatever action triggers the spinner, e.g click a button
cy.getByTestId('loader-spinner') // existence is implied in this command
// if the spinner does not appear
// the test will fail here
cy.getByTestId('loader-spinner').should('not.exist') // gone after delay finishes
Two scenarios
First off, I don't think your two scenario idea is going to help you write the test correctly.
You are trying to conditionally test using try..catch (nice idea, but does not work). The trouble is conditional testing is flaky because of the timing aspect, you get the test working in a fast environment then it starts to break in a slower one (e.g CI).
Better to control the conditions (like delay above) then test page behaviour under that condition.
To test that the spinner isn't appearing, return a stub in the intercept It should be fast enough to prevent the spinner showing.
cy.intercept(url-for-api-call, {stubbed-response-object})
// whatever action triggers the spinner, e.g click a button
cy.getByTestId('loader-spinner').should('not.exist') // never appears
Take a look at When Can The Test Blink?
You should be able to just use a should('not.exist') assertion, causing Cypress to wait for the element to not exist. Remember, Cypress automatically retries up until the timeout, so if you haven't changed the global timeout, then the following will try for up to 4 seconds.
cy.getByTestId('loader-spinner')
.should('not.exist');
If you find the test failing because the element still exists, you can bump the timeout. Below, I've defined a 10s (10000ms) timeout for the should() command.
cy.getByTestId('loader-spinner')
.should('not.exist', { timeout: 10000 });
Additionally, you may find that the element does still exist, but is not visible. In that case, change not.exist to not.be.visible
The page I am testing, it's loading forever due to the slow network(or Internet censorship, some of the resources are bound to fail loading). However most of elements of the page are present within 1 second.
Since Selenium won't have an element clicked until the page's fully loaded, I want to use pageLoadTimeout() to stop the page from loading after 5 seconds and then handle the timeout and do something on the page. And the code works for the page which I specified in get(url).
try {
driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS);
driver.get(url);
}
catch (TimeoutException e){
}
finally {
driver.findElement(By.xpath("xpath here")).click();
}
However this won't work if you're trying to click a link and then be navigated to a new page. You're will soon get
org.openqa.selenium.TimeoutException
because the code above didn't handle this new page's timeout exception. Then I'll have to add another try-catch-finally to prevent this new page from infinitely loading. This will get trickier if there're a lot of links you have to go thru before you are actually reaching the page you wanna test.
Does anyone has a solution to this?
Once pageLoadTimeout is added in the script, the WebDriver instance waits for 5 seconds for every page to get loaded before throwing an exception. If the page is not loaded in 5 seconds of time, then it throws TimeOutException at run time.
You should try increasing the timeout.
Your approach - stopping page loading after 5 seconds - probably will not work.
WebDriver intentionally waits for a full page load. Many ajaxifed webpages havily use onload event to fire some javascript code just after a whole page has been loaded. This javascript code usually does some actions that prepares the page for use.
If you do not wait for a full page load and you start clicking or typing some data on this page, it's very likely that your test will not work - some fields could not be yet editable, clicking on buttons or links may not work etc.
WebDriver tries to prevent such errors, and most of it's methods like clicking and writing data are waiting for the full page to load by default.
I'm trying to add event tracking in a tabs navigation...
so onclick of the tabs i have something like that:
onclick="_gaq.push(['_trackEvent', 'Tabs', 'Click', 'TabName']);"
I have also added GA Debug add-on in chrome.
Every time i'm clicking i'm getting this in the console:
Track Event
ga_debug.js:24 User has been sampled out. Aborting hit.
Does anyone know why I'm getting this?
Check setSampleRate parameter in your GA configuration. This probably cause your problem, because script cancel hit if Math.random value is lower than setter sample rate.
It is not a bug. If you need to test some configuration, set it for 100 during test and on production environment set it back to your desired value.
From what I understand of Capybara's autowait feature, it waits for the DOM to change, so I guess it's waiting for all AJAX requests to complete and/or the main frame to finish loading.
I have a test case in which I need to:
fill in a field (name_1)
click a save button
check the object is saved properly
When I fill in the name_1 field, some JS from the app I'm testing fills in other mandatory fields automatically (notably, link_rewrite_1).
Problem is, when I check for the other field to be actually filled, it is not!
I'm thinking the JS that fills the other fields has not had time to complete when the test is run, and the test doesn't wait since there is no AJAX call pending.
Here is the relevant code snippet:
fill_in 'name_1', :with => 'Bob' #some javascript should run and fill link_rewrite_1
find('#link-Seo').click
page.should_not have_field('link_rewrite_1', with: "")
In plain English, I fill in name_1 and expect link_rewrite_1 not to be empty.
I've tried to insert a sleep 1 before the last check, but it doesn't change anything. Since sleep will pause the execution of the entire ruby thread, maybe it just freezes webkit and changes nothing, I don't know.
Am I right in suspecting a timing issue or is there likely something else going on here?
After further debugging, it seems like it is a driver issue. Capybara-webkit just doesn't execute my JS correctly. Works fine with selenium-webdriver.
I have a unique situation over here. I have a button on a form which produces a popup if there are some errors in the form. [I know this is not good practice, but the developers of the product would not be changing that behavior!] The form navigates to a different page if all the required fields are correctly populated. Now, I need to write a script in order to click the "Submit" button on the form which either might produce a popup or navigate to the next page.
I have the used the click_no_wait on the "Submit" button and handled the popup using AutoIt as per Javascript Popups in Watir. Now, if all the information is valid and the form navigates to the next page, I use a delay in the script by following some of the techniques described in How to wait with Watir. I am using a Watir::wait_until() to wait in the script.
Now sometimes because of some network issues, it takes time to go to the next page (report-generation) page when the form is submitted and thus the script fails because of the timeout value specified in the wait_until.
I was wondering whether there is a way to intercept the onload event of the HTML page in Watir, since the onload event isn't fired until the entire page is loaded. By that way I could have an accurate estimate of the timeout value and not experiment with it. Thus, my script will pass 100% rather than say 98% right now.
Thanks for any help on this topic.
You could try setting up a rescue for the time out, then looping a reasonable amount of times (2 or 3?) if it encounters a timeout.
E.g.
# All your button clicking and autoit stuff here
i = 0
begin
b.wait_until{ # the thing you're waiting to happen }
rescue TheSpecificTimeOutException
# Sorry I can't remember it, the command prompt will tell you exactly
# which one
if i < 3
i += 1
retry
else
raise
end
end
I'm sure i'll have messed something up in the above, or there'll be more concise ways of doing it, but you get the idea. When it times out, give it another few tries before giving up.