I am experimenting with AppiumLibrary in RobotFramework and have a simple test for a requirement that states: "the Set button should exist on this page.". I am testing this by retrieving the button that has a specified ID and then checking if that button has the right text.
I am able to retrieve the button I want via ID however am having trouble getting the actual text on the button.
Here is how the button is defined on the web page:
<button id="button-set" class="button ng-binding" style="width: 20%">Set</button>
Very simple! Using Appium Desktop in web/hybrid app mode and clicking on the Set button it says the "text" attribute shows "Set". However I've learned that using the attributes in Appium Desktop arent valid when searching for elements on a webpage, for example searching by the Class attribute in Appium Desktop (android.widget.Button) is not correct because on the web page the class for the button is instead: "button ng-binding".
I have tried the following:
# this retrieves the button fine, by ID
PAGE SHOULD CONTAIN ELEMENT xpath=//button[#id="button-set"]
# these all return 'None'
${name}= GET ELEMENT ATTRIBUTE xpath=//button[#id="button-set"] name
${text}= GET ELEMENT ATTRIBUTE xpath=//button[#id="button-Set"] text
So, I am unsure which Attribute to use to retrieve the text when retrieving element by ID. Instead, I have tried to retrieve the element this way:
# this also passes fine - I feel like I should also make sure this button has the correct ID, to make the mapping
# between test procedures and cases easier, but if this is as good as it gets then
# this can be argued for
PAGE SHOULD CONTAIN ELEMENT xpath=//button[contains(text(),'set')]
# however, the following does not make sense, this returns "button" instead of "button-set", which makes me think the xpath query is not correct
${id2}= GET ELEMENT ATTRIBUTE xpath=//button[contains(text(),'set')] id
# again, both of these return 'None'
${name2}= GET ELEMENT ATTRIBUTE xpath=//button[contains(text(),'set')] name
${text2}= GET ELEMENT ATTRIBUTE xpath=//button[contains(text(),'set')] text
I have also tried the following:
${element}= GET WEBELEMENT xpath=//button[#id="button-set"]
# this returns "button-set" as you'd expect:
${id3}= GET ELEMENT ATTRIBUTE ${element} id
# these again return 'None'
${name3}= GET ELEMENT ATTRIBUTE ${element} name
${text3}= GET ELEMENT ATTRIBUTE ${element} text
I feel like this should be a very simple thing to do, and can see in other questions that you would use the Name attribute when using pure Appium. However, using the Robot Framework library instead, that these doesn't appear to be the right approach. I must be doing something pretty simple wrong here, can anyone point it out?
Thank you!
Stumbling across the same issue when trying to fetch element's attributes via Get Element Attribute keyword. It seems that when fetching for the element's text, your best bet is to use Get Text keyword. Switching to Get Text keyword solved the problem on my case. Please see the links below for further details. Spoiler: there aren't any real explanations as to why the Get Element Attribute is flaky.
https://serhatbolsu.github.io/robotframework-appiumlibrary/AppiumLibrary.html#Get%20Text
https://github.com/serhatbolsu/robotframework-appiumlibrary/issues/98
Related
I'm running Rails 5.x, with, Cucumber, Siteprism and Capybara through chromedriver. Most things work except..
I have a tiny bit of javascript that changes the class on an element in response to an event. But Capybara never sees the change. It only ever sees the class the element has when the page initially loaded.
Using Chrome, and debugging my Cucumber steps, I can see the element has the new class, but Capybara doesn't see it.
This must be an issue other people have encountered and solved, though I can't find the right subject title.
example coffeescript
$(document).on('focus', 'tbody#item-entry > tr > td > input', (e) ->
$(#).closest('tr').addClass('focused-row')
$(#).closest('td').addClass('focused-cell')
)
example html after the focus event has been triggered
<tr class="focused-row">
<td>ignore this </td>
</tr>
The purpose is to change the background colour of the row containing an input element that has focus. It works.
But Capybara, can't see the class, but it can see any classes added when the page is loaded. e.g.
expect(siteprism_stuff.root_element['class']).to match(/focused-row/)
Ignore the SitePrism stuff, that just gets the right element. root_element is the Capybara class for the dom node.
Now I know it's getting the right Capybara element because if I change my view to put stuff in the class for each row, then it sees that perfectly OK. What it can't see is the any new class added via Coffeescript. Although it's visible in the Chrome inspector, and changes the background color of the focused row as required.
You're specifying an "ends with" CSS attribute selector ($=)
input[class$='form-control']
which since the class attribute for the element you're interested in
<input type="search" class="form-control form-control-sm" placeholder="" aria-controls="universitiesTable">
doesn't end with 'form-control' is correctly not matching. You probably just want to use a normal CSS class selector input.form-control if continuing to do it the way you are. Any of the following options should find the search field and fill in the data you are trying to fill in.
fill_in 'Search:', with: string
fill_in type: 'search', with: string
find(:field, type: 'search').set(string)
find('input.form-control').set(string)
Note: Your question is still unclear as to whether you are seeing the class added in the inspector in test mode, and whether the line color is changing while the tests are running (or whether you're only seeing that in dev mode) - This answer assumes the JS is actually running in test mode and you're seeing the line color change while the tests are running.
You don't show how you're actually triggering the focus event but I'll assume you're clicking the element. The thing to understand when working with Capybara is that the browser works asynchronously, so when something like click has been done, the actions triggered by that click have not necessarily been done yet. Because of that, whenever doing any type of expectation with page elements you should always be using the matchers provided by Capybara rather than the basic matchers provided by RSpec. The Capybara provided matchers include waiting/retrying behavior to handle the asynchronous nature of dealing with the browser. In this case, assuming siteprism_stuff.root_element is the row element then you could be doing something like
expect(siteprism_stuff.root_element).to match_css('.focused-row')
or depending on exactly how your siteprism page objects are setup you could pass the class option to the siteprism existence checker
# `page_section` and `have_row` would need to be replaced with whatever is correct for your site prism page object
expect(page_section).to have_row(class: ['.focused-row'])
Currently I have a checkbox wrapped by a label.
<label for="exercise_form_division_ids_34">
<input class="check_boxes optional division-checkboxes" type="checkbox" value="34" name="form[division_ids][]" id="exercise_form_division_ids_34"> Technology
</label>
In my integration test I tried to use
within '.organizations' do
find("label[for='exercise_form_division_ids_34").click
end
OR
check "exercise_form_division_ids_#{department.id}", allow_label_click: true
But I still get this nable to find visible checkbox "calltree_exercise_form_division_ids_2" that is not disabled
Unable to find visible checkbox "exercise_form_division_ids_" that is not disabled
With the limited info provided you have a few potential possibilities.
The label/checkbox aren't actually inside an element with the class of the organizations on the page.
The error Unable to find visible checkbox "exercise_form_division_ids_" that is not disabled shows that no id is actually getting inserted into your selector which would tend to indicate that department isn't actually persisted in your test.
You may be assuming 34 is the correct id based on what it is in your dev environment but that may not be what it is in your test environment.
To narrow down the possibilities the first thing to do would be to grab a screenshot in your with test with page.save_and_open_screenshot (assuming you're using a driver which supports screenshots) and make sure there is actually a visible checkbox on the page. If not, you're probably not creating the required objects in the DB prior to your test starting.
Secondly look at the page in your browser and make sure the elements visible on the screen are actually the checkbox and/or the label. If both label & checkbox are being hidden and replaced with some JS widget then you'd need to interact with whatever elements the widget creates in the page (just like a user would). If only the checkbox is being hidden via JS/CSS but the label is visible then
check('Technology', allow_label_click: true) # check matching on label text
should work.
I need to disable a select element in grails depending on its value. The problem is when I started to add the disable property something is quite wrong with the code.
An example is when the form is sent to the backend, its as if there is no value for that select element and the value sent is null. But, when I checked the DOM, there is a selected attribute in the element. I tried to remove that disabled property because I have a feeling that it has something to do with the bug that I'm encountering and I was right because after removing it, everything worked correctly again.
this is the select tag
<g:select name="detail-entryNameId"
value="${journalEntryName.savingId}"
from="${journalEntryNameInstanceList}"
optionKey="savingId"
optionValue="displayName"
readonly="${journalEntryInstance.paymentMade}"
/>
One more thing about this element is that it can occur as many as possible, which means I have a table and in every row, that element exist so I cannot simply manipulate it.
I've also read in this post how can i make a textfield read only in grails? that "If you use disabled="true" the value will not actually be submitted in the form, so the <g:field/> tag should be used." which proves that disable attribute affects the value of the element.
How can I disable the select element and at the same time, still get its value correctly?
The problem is that in HTML the mere existence of the disabled attribute disables the tag. The value of the attribute (true/false) is ignored.
In such cases the solution is to use an <g:if> to create the tag with or without the disabled attribute according to a condition.
In your case, since you want the value even when the tag is disabled you can add a <g:hiddenField> with the same name and value as the disabled select.
So, I'm trying to select a polymer custom element(using paper_elements) in my view with querySelector. I'm able to select regular html elements just fine. In particular, I'm trying to select a specific paper-input element. I want to be able to query it's input element which is buried in it's second shadowroot.
I've tried the following:
querySelector('#my-paper-input::shadow #input')
querySelector('paper-input::shadow input')
and a bunch of other variations. However, no matter what I do, the query always returns null. It's driving me mad because I can style it in css. What do?
As far as I know you have to use several steps
querySelector('#my-paper-input').shadowRoot.querySelector('input');
but you should also be able to access the value using the attribute of the outer element like
querySelector('#my-paper-input').attributes['value'] or
querySelector('#my-paper-input').attributes['inputValue']
you could also use http://pub.dartlang.org/packages/angular_node_bind
but I wasn't able using Angular with paper-elements recently (see https://github.com/angular/angular.dart/issues/1227)
I've got an MVC app that gives the user textarea's to update some description fields. It's strongly-typed to a table object, and the fields are wrapped in a form with a Submit button.
Occaisionally they don't want any data in a field, but when they delete the text and try to save, the blanked-out field comes back with its original text (i.e. the table object passed to the Save action contains other edits, but attempts to blank out fields result in the original text staying in the field).
I'm assuming this is LINQ trying to determine which fields have been edited, but how do you tell it that it's blank on purpose?
UPDATE: It appears this may be a problem with the TinyMCE jQuery plugin. It adds rich-text functionality to textarea controls. If I turn it off, I can remove text with no problems.
UPDATE 2: It seems to be some kind of javascript bug or something. If I put another dummy field after the problem fields, they work. If I move them to another place in my code, they work. They just don't want to work where they are. Very peculiar.
I'm pretty sure that TinyMCE, by default, puts in <p></p> when the control is emptied.
So if you are checking for "" then you may be disapointed.
This initially caused me some issues but never with saving. I was checking if the field was "" and then doing something else. Once I realised that "" was never going to happen, I adapted my validation accordingly.
I just check that on a recent project using TinyMCE editor, but it indeed send "" for an empty input, and during the implementation we had no issues with that.
alt text http://diarioplus.com/files/pictures/tiny.PNG
The body property is the one with a tinyMCE editor on the client side.
I really think it will be something with the modelBinder or the way you set the values back to the model.