Playwright retry on actions - playwright

I have a scenario here:
Click element A (a button), trigger element B (say, a div) to appear. However due to multiple factors, clicking might fail to trigger the event. The reason could be clicking too soon when he page is actually fully settled. So I need to redo the click a couple of times. There not seem to be a mechanism with in Playwright to do step level retry when condition is not met.
It sounds like a common requirement in test automation though. I am wondering how do you tackle this problem.
Some suggestion or custom code to retry failed steps?

I think what you're looking for is .toPass
await expect(async () => {
await page.locator('button').click();
await expect(page.locator('div')).toBeVisible();
}).toPass();
It'll retry the code you'll give it and wait for it to pass.

Related

Playwright: how to wait until there is no animation on the page?

I'm trying to figure out how to check whether the page has fully loaded in Playwright. await page.waitForLoadState('networkidle'); doesn't always work for me on Javascript-heavy sites. I've resorted to taking a screenshot base64, waiting 100 ms, taking a new screenshot, and comparing whether those are the same. However this doesn't seem ideal, is there any way to ask Playwright when the last animation frame was redrawn?
There are several options that may help you.
1. Solution 1:
First, you can maybe determine which element is loading last, and then go with
page.waitForSelector('yourselector')
or even wait for multiple selectors to appear
page.waitForSelector('yourselector1','yourselector2')
2. Solution 2
page.waitForLoadState('domcontentloaded')
Because
page.waitForLoadState('networkidle')
by default will wait for network event and if 0.5 seconds nothing is network trafficking it will say, I am no longer need to wait. And that is why you maybe have stohastic beh.
If the given solution doesn't work for you, you can try with locator.
page.locator(selector[, options])
It has multiple api like locator.isDisabled or locator.waitFor([options]) or locator.isVisible([options]) or locator.frameLocator(selector) ....... a lot more.
see the below link here:
https://playwright.dev/docs/api/class-locator

Zabbix alert event generation mode and multiple OK event generation

I have a trigger with:
PROBLEM event generation mode: Multiple
OK event closes: All problems
That trigger fires at the expression for the trapper item, which's updated by the crontab multiple times a day. Every time trapper gets a new value, it should be reported by the alert (cause' every time it gets a different value, which is important). But when it's OK, one message should be enough.
Action has "Send message to user groups" operation with a single step, "Immediately" start option and "Default" step duration (3600s).
Recovery operation set to "Send message to user groups" option.
Action also has only folowing conditions in the drop-down:
Application
Host
Host group
Maintenance status
Tag
Tag value
Template
Time period
Trigger
Trigger name
Trigger severity
What may be the reason for multiple duplicating alert messages with OK status, coming at the same moment from the same trigger (and the same alert)?
Have you tried global event correlation ?
It is possible to correlate events created by completely different
triggers and apply the same operations to them all. By creating
intelligent correlation rules it is actually possible to save yourself
from thousands of repetitive notifications and focus on root causes of
a problem!
https://www.zabbix.com/documentation/3.4/manual/config/event_correlation/global

Capybara test intermittently failing when using Selenium driver

I've got an integration test here which is passing flawlessly using the poltergeist driver every time, but when I run this test using Selenium it passes on average 3 times and fails 1 time.
def fill_in_inclusion_criteria
find("div.measure#age label[for='16']").click
find("div.measure#substance_use_met label[for='1']").click
find("div.measure#participant_consent label[for='1']").click
click_link("Next")
end
When it fails, the error that I get back is this
expected to find css "div.measure#participant_consent" but there were no matches. Also found "", which matched the selector but not all filters.
The participant consent button appears when div.measure#age label[for='16'] is clicked, so it's dependent on Javascript. I see this happening in Firefox most of the time, but when it errors, the div isn't visible on the page.
It seems like it's not waiting for the element to display on the page before clicking it, but I thought that wrapping it in a "find" waits for the element to be visible on the page before trying to click it?
Any idea why this could be happening?
The one confusing thing with your question is that the error message you posted isn't actually for the code you've shown, since if it was the error message would be expected to find css "div.measure#participant_consent label[for='1']" ... . Assuming that's just a copy paste error/from a previous slightly different version of the code and the line you specified is where the error is actually coming from:
Since the previous find/click lines are working there are 2 potential reasons for the third one to not find the label element
The age label[for='16'] element click either isn't actually occurring, or is occurring before the JS that enables the showing behavior is attached. You can check for this by adding a sleep for a few seconds before it and seeing whether the failures go away
The participant_consent find/click isn't waiting long enough for the element to appear. find waits up to Capybara.default_max_wait_time seconds for elements to appear, so if that is long enough you could increase that setting, or pass a :wait option to find to override the setting for that call
find("div.measure#participant_consent label[for='1']", wait: 10).click
Technically, there is a third potential cause but it's highly unlikely due to the sporadic nature of the failure, which would be a JS failure on the page. You can check for this by rescuing the error and pausing your test so that you can look at the developer console in the browser for any errors.

How do you test a submit button being disabled after clicking in capybara?

We are trying to disable a certain submit button after clicking on it. Something like this:
assert !page.has_css?("#review_button[disabled='disabled']")
click_button "Review"
assert page.has_css?("#review_button[disabled='disabled']")
The problem, of course, is that the form submits before the second assertion is checked. Is there any way to disable the actual submission of the form, or suspend it until after the second assertion is checked?
I remember having this same issue and never found a good way to do this, because as you said, it only gets to the next assert when the "Review" action completes.
What I ended up doing, considering that the action that the button did took a long time (and thus justifies having the button be disabled) is to make the action create a Delayed Job job and then let it run asynchronously. Then it's pretty easy to mock that out and make it sleep for a few seconds (or what have you) to check that the button is disabled.

Should I just let the user hang?

I am not really sure what to do in this situation. I have some jquery ui 1.7 tabs that are ajax enabled. Now when a tab is clicked it goes to my asp.net mvc controller action method. That then does whatever is needed and return a partial view.
Now I don't know why but sometimes my server hangs but then again I am guessing all servers hang since sometimes when I go to sites it take forever to load but if you do a refresh it loads up instantly and that's the same case with my site.
My site will load up a tab super fast for X number of times then all of a sudden a request will just hang and maybe like 15seconds later it will load up. Or if you just refresh the page it will go back and start loading them up super fast again.
The problem though is the request is sent to the server where it hangs. So I tried to setup a jquery timeout on all my ajax stuff and that calls an abort to the jquery ui tabs.
But it never works and I guess from what I gathered reading on this site is because the request is on the server and abort won't stop stuff on the server. So if I look at firebug that request that hanged is stil running.
Now this causes a huge problem for me since it screws up the entire page what is heavily ajax. Like if the user tries to click on say another tab they will most likely have to click 2 times to get it to load up. Another thing what happens is if that request ever finish hanging whatever tab they are on will merge with that tab. So sometimes one tab will have parts from all the other tabs.
So if it hangs and does not finish it really messes with the ajax tabs. I have no clue how to fix this.
So I am not sure what to do.
Let them hang for however long it takes the server to figure out how to finish that request(when a ajax request is made I disable all tabs. This is because if a person say loaded up a tab and did not let it finish and tried to go to another tab the same problem would occur with the tabs merging together). Or abort the request and have a screwed up tabs.
Great choices I got. Anyone got any better choices?
Thanks
We have a similar situation here in that the 1st person to hit the site for the day will incure a 15 second delay while things are loaded.
In our situation, on all calls to the server via jQuery, I have set a normal javascript timeout for 2 seconds. After 2 seconds I pop up a small div saying something like things are talking longer than expected and please be patient.
after a further 6 seconds i close that div and open a new one with more of an apology.
not a great solution but it does keep the user in the loop, comfortable that things are ticking along and that we acknowledge things are not perfect.
warm and fuzzies as we call them here. :)
I'm not sure what you mean by "jquery timeout". if you mean setTimeout, that definately won't work. If you mean, on the other hand,
$.ajax({
url:"myserverprocess",
timeout: 200,
error: function () { /* try again */ },
success: function (myadata) { alert("mydata")}
});
then that should work. Try the timeout option if you haven't yet.
edit:
you could try :
$(selector).tabs({
ajaxOptions: {
url:"myserverprocess",
timeout: 200,
error: function () { /* try again */ },
success: function (myadata) { alert("mydata")}
}
});
We've had good success using jquery queue manager - http://www.protofunc.com/scripts/jquery/ajaxManager/
When a second request is performed it aborts the first request. I'm not sure about a timeout, but there are several options you can play with.
You could use Jquery to set a timeout on your ajax call and then catch it in the error section. Once caught, you could deal with retrying or doing any needed cleanup.

Resources