I have following html code. And I want to using Ruby Mechanize select dropdown element wit specific text (I want to click on it). Example Chinese. My question is how to do this? I am new in Mechanize.
<form class="form-inline search search-large" action="/translate" method="get">
<input id="q" name="q" type="text" placeholder="Search" class="input-large" value="" autofocus="autofocus" data-pons-redirect-input="true" data-pons-autofocus="true" autocomplete="off">
<div class="btn-group source open" data-pons-lang="de">
<button class="btn btn-large dropdown-toggle" data-toggle="dropdown">
<span class="text">Chinese</span>
<i class="icon-angle-down"></i>
</button>
<ul class="dropdown-menu">
<li>
<a href="#" class="language">
<span class="text">Chinese</span>
<span class="flag flag_zh"></span>
</a>
</li>
<li>
<a href="#" class="language">
<span class="text">Elvish</span>
<span class="flag flag_lb"></span>
</a>
</li>
</ul>
</div>
</form>
Bad News
As far as I see, your example page is too involved to let mechanize interface it with e.g. a .click method. Actually it will be able to follow the links (""), but I guess this will not help you much, because it seems there is some javascript or other black magic involved.
You can try first to see if the page will work nicely (not guaranteed) with mechanize by disabling JavaScript in your browser.
Good News
Anyway, at the end you will want mechanize to do certain kinds of HTTP requests - triggered by JS or not does not matter. That you will be able to do with mechanize (although it might not necessarily be the best choice for all scenarios).
Tips
I encourage you to use your browsers developer thing (often fired up by pressing F12) and see what is really happening, e.g. which form gets submitted with which values. And don't forget to check if its the same when used with and without javascript (mechanize will not execute JavaScript as far as i know).
Also, when developing your mechanize code, use irb or another repl like pry to try your code live. Your mechanize agent or page will have a method save or save_as or similar with which you can always save the current page and review it in your browser or favorite text editor. And remember _ in irb gives you your last return value.
Related
I have the follwing html on my site's header
<header>
<div class="logo_container">
<a href="/">
<img src="xxx" alt="">
</a>
</div>
<nav class="">
<ul>
<li>
<a href="xxx" title="xxxx" >xxx</a>
</li>
<li>
<a href="xxxx" title="xxx" >xxx</a>
</li>
<li>
xxx
</li>
<li>
</ul>
</nav>
<div class="toggle_menu" role="button" aria-label="open menu" tabindex="1"><em class="fa-solid fa-bars"></em>
</div>
</header>
At this header the nav is hiding on mobile device and shows up when the user press the div.toggle_menu.
The way this is read by VoiceOver screen reader of iphone 14, is "Button, open menu, end banner".
I would like it to say just "open menu". So I remove the role button and left only the aria-label="open menu".
Now it reads just "End of banner". Νο "Open menu" or "button".
I am quite new on aria and I am not sure what do I have to do.
Any help is appreciated.
To make it short: You shouldn’t do that. There is a good reason screen readers read the way they do and you should respect that. Its users rely on that.
That being said, it’s great that you are diving into ARIA and caring about screen reader’s experience.
Role
The role is very important for screen reader users, to know what to expect in terms of interaction and keyboard control. Roles communicate interaction patterns.
The whole point of ARIA is to add meaning to otherwise meaningless elements, where you cannot use the proper HTML element.
By removing the role, you are leaving a meaningless <div>, which might be focusable, but it would be way less intuitive to screen reader users to know how to interact with it. Assistive technology couldn’t know what it’s good for, voice control software would probably not let you click on it.
The accessible name provided by aria-label cannot be used on any element. The role determines if the name should (or must) be used or not. VoiceOver will not announce names for meaningless elements like <div>.
Tabindex 1
By adding tabindex="1", you are putting the button before any other focusable page contents, which messes with the expected focus order.
I guess you placed it so that you could have the button after the navigation. But a large part of screen reader users are sighted, and rely on contents exposed by their screen reader to match with what they can see. The logo comes before the button, and it would be irritating if it’s not focused first.
Refer to the ARIA Authoring Practices Guide
When it comes to your toggle button, you should implement the ARIA pattern, which requires not only the role button, but also aria-expanded to explain to assistive technology that the button opens and closes something, and its state.
The button should be before the contents that get expanded.
See Disclosure (Show/Hide) on the ARIA Authoring Practices Guide (APG)
<header>
<div class="logo_container">
<a href="/">
<img src="xxx" alt="Home, ACME">
</a>
</div>
<button class="toggle_menu" aria-label="open menu" aria-expanded="false"><em class="fa-solid fa-bars"></em></button>
<nav hidden>
<ul>
<li>
xxx
</li>
<li>
xxx
</li>
<li>
xxx
</li>
<li>
</ul>
</nav>
</header>
I have been stumped on this for a couple hours and can not figure a way around it.
Larvel 8 with Livewire
I have a very basic form.
<form action="/dashboard/payment" method="POST">
#csrf
<button type="submit" class="btn btn-primary my-3 w-100" id="checkout-button">
<span wire:loading>Please Wait</span>
<span wire:loading.remove>Pay - $
<span>100</span>
<br>
<small>Description of payment</small>
</span>
</button>
</form>
But the form tag itself it is not rendering the html. It is only rendering the button inside.
When incrementing a value with another button, the form tag is then rendered into html and the button can be used as expected.
The incrementing button only ++ to a value and updates the database with the new value.
This is the only thing holding me back, I have searched everywhere but cant find any information about form tags not rendering.
Note: Neither the opening tag or the closing tag is rendered until the other button is pressed.
Any ideas or information would be fantastic and greatly appreciated.
I have few dropdowns on my page, with buttons opening and closing a dropdown. Everything goes well after initial page load, but after changing to a different page, the dropdown opens with a click, but never closes. It seems that button's aria-expanded is stuck on true and the dropped down div has classes collapse open, which tries to collapse but won't ever do it (clicking the button gives the div collapsing class and then returns).
I have no idea why this happens and and if it's got to do with Liferay, freemarker, css or any of those...
This is my application display template:
<div id="a_language_selector">
<button
aria-controls="a_language_list"
aria-expanded="false"
role="button"
data-toggle="collapse"
data-target="#a_language_list"
>
<!-- CHANGE THIS -->
<#liferay.language key="EN" />
</button>
<ul
id="a_language_list"
class="panel-collapse collapse"
aria-labelledby="a_language_list"
>
<#if entries?has_content>
<#list entries as navigationEntry>
<li aria-label="${navigationEntry.getName()}">
<a href="${navigationEntry.getURL()}">
${navigationEntry.getName()}
</a>
</li>
</#list>
</#if>
</ul>
</div>
The answer was found and has to do with Liferay's own javascript (SennaJS)!
Changing a page in Liferay doesn't update the whole site and leaves old information lying around the session, breaking the collapsing.
I added this line to my portal-ext.properties and while it now loads after all page changes, it works well!
javascript.single.page.application.enabled=false
More information found here (help.liferay.com)
Below is my HTML
<div id="slectrole" class="collapse in" role="tabpanel" aria-labelledby="selectrole">
<div class="panel-body">
<div class="dropdown">
<input class="search-control jsSayt jsRolesFreeText" onfocus="this.placeholder = ''" onblur="this.placeholder = 'Eg: Delivery, BPO, Driver'" placeholder="Eg: Delivery, BPO, Driver" value="" aria-expanded="false" aria-haspopup="true" data-toggle="dropdown" type="text">
<ul class="jsSaytList jsRolesFilter">
<li id="jsFilter_subRole_1" class="checkbox-inline jsFilterSubRole jsRoleValue_1" data-value="Accountant">
<input id="Accountant" class="radio-custom jsFilterRadio jsRole" value="Accountant" name="Role" data-roleid="1" type="radio">
<label class="radio-custom-label" for="Accountant">Accountant</label>
Below is the code I am using to click the radio button:
wait.until(EC.visibility_of_element_located((By.XPATH, "//div[#id='slectrole']/descendant::li[#data-value='Accountant']/label[#for='Accountant']")))
driver.find_element_by_xpath("//div[#id='slectrole']/descendant::li[#data-value='Accountant']/label[#for='Accountant']").click()
The code runs ok but it does not select the radio button.
OK, so I can understand your frustration, I tried your code and wasn't able to .click() (select) the element when located via xpath. See bellow print-screen:
As you can see, it was only clicking the radio-button when issuing a .click() via a CSS-located element.
Question No.1: Are you bound to the xpath locator strategy in one way or another?
If NOT, then just use a regulat CSS selector: 'input[id="Accountant"]'.
Else, you have to figure out what is wrong with the website you are testing, or switch to another WebElement locator strategy. (e.g.: ID, Class, CSS, LinkText, etc.)
If you would opt to go with the CSS locator-strategy, then your code would look like this:
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "label[for='Accountant']")))
driver.find_element_by_css("input[id='Accountant']").click()
Alternatively, you can try to click on the <label> tag attached to the radio-button, which in my console works the same way:
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "label[for='Accountant']")))
driver.find_element_by_css("label[for='Accountant']").click()
Explanation: In a real-life scenario, you can select the radio-button both via the actual radio-button, or via its label. That's why your solution worked.
Question No.2: Why are you using such a long xpath selector?
In order to have a optimal selector, you should ALWAYS go with the shortest, combination of tags/attributes that will UNIQUELY identify your target element. Else you will be susceptible to website changes, flaky test cases, etc.
You can perform the click on the drop down and then wait for the radio button to appear, before clicking it. Hence, try following:
driver.find_element_by_xpath("//div[#id='slectrole']/div/div[#class='dropdown']/input[1]")).click()
wait = WebDriverWait(driver, 10)
wait.until(EC.visibility_of_element_located((By.XPATH, '//div[#id='slectrole']/descendant::li[#data-value='Accountant']/input[1]')))
driver.find_element_by_xpath("//div[#id='slectrole']/descendant::li[#data-value='Accountant']/input[1]").click()
Let me know, if above code works for you.
I'm trying to do some screen scraping, and I've gotten down to this last step. I'm trying to download a file, which is accessed via a button from the following html:
<button class="pdf ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" role="button" aria-disabled="false">
<span class="ui-button-text">
<span class="icon-32 pdf-32"></span>
<span class="btn-txt"> PDF file </span>
I'm used to clicking buttons with the following ruby code:
browser.button(:value, "Sign In").click
But with this .. there doesn't seem to be any value I can use. Can anyone help me out?
I can think of a couple possibilities. One is that you can do a regular expression match on the value. Try:
browser.button(:value, /PDF file/).click
But you don't have to use the value, you can use a uniquely identifying attribute. In this case, you may be able to use the class, e.g.
browser.button(:class, "pdf").click
If the pdf class is not unique, you can add an :index to identify which one of the matches to click.