How to handle or recover/retry after "Selenium.StaleElementReferenceException" error with Atata? - atata

I'm writing a test suite using Atata and am receiving this exception "Selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document" trying to iterate over all the <tr> elements in a <table>'s <tbody> element.
The issue appears to be rooted in the DataTables jQuery library being used in the web app being tested; everytime the 'draw()' method is invoked on the client/JavaScript side, it removes all <tr> and their enclosing <td> elements and re-creates them. This means the test only works for the very first <tr>.
Basically with each <tr>, my test clicks a button in each table row that causes DataTables.js to re-draw the entire table each time; the only thing that changes between each re-draw is 2 CSS classes get modified on the current <tr> element:
Before button click:
<tr class="bringup-overdue reminder odd" role="row">
After button click:
<tr class="bringup-completed d-none reminder odd" role="row">
The number of rows remains the same after each re-draw, and except for the CSS class changes, all the HTML code for the table remains exactly the same, but because all existing DOM-references have been lost, the "Selenium.StaleElementReferenceException" exception keeps happening. The re-draw is an AJAX operation, not a full page reload.
Is there any way to get Atata to simply refresh all of its internal references to those newly-re-created elements? I know from working directly with the Selenium API, you can simply re-try calling 'FindElement', like in this answer here, but I can't seem to find an equivalent Atata API for that.

Related

How to format Power Automate's "Create HTML table" to display hyperlink in email pointing to SharePoint

With a SharePoint List as a data source, I have a Power Automate workflow that groups by a field, then emails unique people a list of stuff that's applicable to them. In the email, there should be hyperlinks pointing to editable SP List items. I have the flow working except the hyperlinks in email are not working as expected. Here is the
body of email instead of the expected body of email with hyperlinks. I used "concat('Link')" as a value in "Create HTML table" step and "replace(replace(replace(body('Create_HTML_table'), '<a href="', ''), '<a/>', '')" in "Send an Email" step per this article: . Here is an illustration of the issue.
Firstly, in the list of available fields, use 'Link to item' rather than 'Title' for your link, whether the Title links or not.
Secondly; you can just type the special characters (like the HTML tag greater than ">") normally in the replace, like I have below. However I believe that the two solutions I've given you will perhaps provide a more slick email.
Logic Solution
Rather than relying on nested replace functions, you can parse the created html and make an cleaner result.
Still create the HTML table, but in the item value, put link then insert the SharePoint ID from the dynamic content. If you run this, as an example, the result for the 10th ever item in the list will format like this:
link10
Now run a Apply to each on the Get items action you made the table from, and for each item, you will replace the link# with the required url from the Link to item field in an html link wrapped around the title.
Insert that amended code into the email.
For the flow I have gone as verbose as I can to ensure the logic is obvious, it stands to reason that much of this might be minimised (image after description):
Get items - SharePoint pull, no filter, only 3 items (car, boat, plane).
Create HTML table - Details:
'From' - The "value" dynamic content from 'Get items'.
#{outputs('Get_items')?['body/value']}
'Columns' - "Custom" with one entry:
'Header' - "item"
'Value' - "link#{item()?['ID']}"
Variables - Initialise these variables:
linkVAR - Initialize an empty string variable.
htmlTabStVAR - Initialize an empty string variable.
findVAR - Initialize an empty string variable.
linkVAR - Initialize a string variable with the output of the 'Create HTML table' action.
Apply to each - 'Select an output from previous steps' must be the same as the table in #2.
Set htmlTabStVAR - This should be the output of the Set htmlTabEnVAR
#{variables('htmlTabEnVAR')}
Set findVAR - This sets the variable the replace function will use to find the right item:
link#{items('Apply_to_each')?['ID']}
Set linkVAR - This sets the desired HTML for the link:
#{items('Apply_to_each')?['Title']}
Set htmlTabStVAR - This should be the output of the Set htmlTabEnVAR
replace(variables('htmlTabStVAR'), variables('findVAR'), variables('linkVAR'))
Setup your email, here is the body that I used:
<p>this works</p>
<p>table:</p>
#{variables('htmlTabEnVAR')}
Here's the flow image:
Here's the email, and the resultant HTML (from the flow history):
<p>this works</p>
<p>table:</p>
<table>
<thead>
<tr>
<th>item</th>
</tr>
</thead>
<tbody>
<tr>
<td>
car
</td>
</tr>
<tr>
<td>
boat
</td>
</tr>
<tr>
<td>
plane
</td>
</tr>
</tbody>
</table>
To minimise the Apply to each you can remove the link and find variables and use this, longer, replace function in the expression for the htmlTabEnVAR:
replace(variables('htmlTabStVAR'), concat('link', items('Apply_to_each')?['ID']), concat('', items('Apply_to_each')?['Title'], ''))
One Step Minimised
Fair warning; if you're not going to use the unique characters I use below, test which ones don't parse well in flow, first, I found some that caused issues, like "æ".
So, in order to minimise the whole thing in to one step after the HTML creation, you can use the email section like this:
In the HTML table, use unlikely characters to wrap the ID and Title fields from SharePoint. I've used "ĐĐĐ", "œœœ", and "ĐœĐœĐ":
ĐĐĐ#{item()?['ID']}œœœ#{item()?['Title']}ĐœĐœĐ
In the email, go to the body, and ensure you have placed the following expression in the "Code view" (click the '</>' button), replacing:
[COMPANY] with your company sub-domain,
[SITE] with the relevant SharePoint site
[LISTNAME] with the relevant list name
replace(replace(replace(string, 'ĐĐĐ', ''), 'ĐœĐœĐ', '')
Apologies for my lack of clarity: we're both correct...I have the group by working as stated...but now I can't get my group by and your hyperlink solution working side by side. It looks like the issue is between the concat() in "Create HTML table" and/or replace() in the email body. I have tried to illustrate the issue further in the attachments, please refer to those. Thank you!
page 1 of issue;
page 2 of issue

Trouble with finding element by xpath (selenium module in python)

I am using the selenium module to scrape a website (expedia) in order to retrieve the flight ticket prices.
I am having trouble when I want click an an element (the search button) to send the information, sometimes it goes well but the majority of the time I get the next exception:
selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted: Element <button type="submit" class="btn-primary btn-action gcw-submit">...</button> is not clickable at point (77, 492). Other element would receive the click: <th scope="col" class="datepicker-day-name">...</th>
(Session info: chrome=80.0.3987.87)
The way that I do is:
First I locate the element by xpath:
find = browser.find_element_by_xpath("//button[#class='btn-primary btn-action gcw-submit']")
time.sleep(5)
Then I click it:
find.click()
And as I told sometimes this operation is done with success sometimes not.
I am open to any suggestions.
Thank you!

How can we modify DOM element on template engines (ejs) dynamically?

In my NodeJS project, I am fetching a long list of data from a database (Firebase), and showing it to the user. For security purposes, I am doing the fetching in NodeJS (i.e. not on the client-side), and hence my current implementation requires me to pass this long list to my template engine (ejs). In my client side (i.e. my template engine), I have a a HTML element of a table, and I want to fill this with the list. The passing of the list itself is not really a problem, but the filling is what I am struggling with. The table that I am wanting to fill is as follows:
<table class="table table-bordered" id="myTable"
<thead>
<tr>
<th>Name</th>
<th>Gender</th>
</tr>
</thead>
<tbody id="table_body"></tbody>
</table>
If I were to fetch the data from the client directly from the database, then this would not be a problem since modifications of DOM element (i.e. the table in this case) is allowed. However, since I am fetching from the server-side, and then passing the data to the client-side, I have no idea how to fill the table.
At one point during my struggle to answer this question, I thought about generating the entire HTML table on the server side as one giant string, and then shoving this on the template engine. I'm not too sure whether this is the right way of going about it though.

page.click() i'ts not working properly in an <a href> tag

Working on a grid (table) that some columns have a text that is actually a link to the detail of something using a <a href="url"> tag.
Using await page.click(my_target); was working perfectly for my main tables but in this case, the click event doesn't do anything:
<table>
<tbody>
<tr><td>
<a ng-show="true" href="/edit/001">Some text</a>
</tr></td>
</tbody>
</table>
Looks like this:
The click event on puppeteer can work in unexpected ways.
The problem came when the text stacks in two lines, so accordingly to the documentation of puppeteer the click works: "This method fetches an element with selector, scrolls it into view if needed, and then uses page.mouse to click in the center of the element. If there's no element matching selector, the method throws an error."
Behavior in each case would be something like this:
If you can see our click will point to the center and for the second picture it wouldn't reach the text/link. So you can use an element selector following a click event:
await page.$eval(my_target, element => element.click());

How to extract the hover box information in watir and print it to a STDOUT

I have to print the hover box information content on to stdout and i tried it in the below fashion it didn't work for me .
data = $browser.div(:class => "homeSectionLabel textWidget",:text => /Pool A/ ).hover
print "Data #{data} \n"
And the other problem that i have other widget called Pool B with same class name . How to access that hover information
<div class="widgetContainer poolContainer">
<div class="healthBadge healthUnknown" style="top: -5px; left: -5px;"></div>
<div class="homeSectionLabel textWidget">Pool‌·A</div>
<div class="perfDisplay homePoolPerf">
</div>
<div class="homePoolVolText textWidget">9‌·Volumes,‌·0‌·Snapshots</div>
<div class="spaceMeterContainer poolMeter" style="width: 265px; height: 20px;">
</div>
<table class="tableWidget homeTiers" cellspacing="0" cellpadding="0" border="0">
</table>
</div>
Anyhelp is really appreciated .
Thanks!
Aditya
This is not much of an answer at the moment, but what I have to say won't fit in a comment
The 'content' as in the text within a div is normally accessed with the .text method
'tooltip' text can be done in a number of ways, it could be via alt attributes, it could be via javascript triggered via an 'onmouseover' event, or it could be CSS driven usually via the :hover psuedoclass.
if a div is merely changing it's display property or location so that it becomes visible to the user, then all you need to do is figure out how to locate that div, and get the .text from it
mydata = browser.div(:how => 'what').text
If the content of the div (or some other container) is changing as a result of the mouseover/hover, then you need to simulate the action, wait a brief bit to allow client side code to run, and THEN get the .text from the container that was changed.
Without seeing a page that has the code working on it, it is hard to tell which is the case, although given that I see nothing like 'onmouseover' in the code you supplied, my first bet would be on this being CSS driven.
The code you have above is returning the result of the div object executing the .hover method, and that is going to be nil as far as I know since that method causes something to happen, but does NOT return a value.
Is the 'Pool A' the text you are trying to capture, or is it what you mouse_over to cause the other text to become visible to the user? If it is what you mouseover, then have you searched the HTML to see if you can find the text that appears in some other div?
If you just need to get the text from every div of a given class, then try something like this
browser.divs(:class => "homeSectionLabel textWidget").each do |div|
puts div.text
end
Based on the most recent comment, this will gather the class names from all of the divs on the page and print it to the console.
$browser.divs.each do |div|
puts div.class
end
Replace "puts div.class" with a file directive if you want it in a file. Any output here is simple Ruby.

Resources