Get the actual value of a boolean attribute - ruby

I have the span:
<span disabled="disabled">Edit Member</span>
When I try to get the value of the disabled attribute:
page.in_iframe(:id => 'MembersAreaFrame') do |frame|
expect(page.span_element(:xpath => "//span[text()='Edit Member']", :frame => frame).attribute('disabled')).to eq("disabled")
end
I get:
expected: "disabled"
got: "true"
How do I get the value of specified attribute instead of a boolean value?

The Page-Object gem's attribute method does not do any formatting of the attribute value. It simply returns what is returned from Selenium-WebDriver (or Watir-Webdriver).
In the case of boolean attributes, this means that true or false will be returned. From the Selenium-WebDriver#attribute documentation:
The following are deemed to be “boolean” attributes, and will return
either “true” or “false”:
async, autofocus, autoplay, checked, compact, complete, controls,
declare, defaultchecked, defaultselected, defer, disabled, draggable,
ended, formnovalidate, hidden, indeterminate, iscontenteditable,
ismap, itemscope, loop, multiple, muted, nohref, noresize, noshade,
novalidate, nowrap, open, paused, pubdate, readonly, required,
reversed, scoped, seamless, seeking, selected, spellcheck, truespeed,
willvalidate
As you can see, the "disabled" attribute is included in this list and thus returns a boolean.
If you really want to check the actual attribute value, you will have to parse the HTML. Unless the HTML is simple, I would suggest using Nokogiri (or other HTML parser) rather than writing your own. In Nokogiri:
require 'nokogiri'
# Get the HTML of the span
span_html = page.in_iframe(:id => 'MembersAreaFrame') do |frame|
page.span_element(:xpath => "//span[text()='Edit Member']", :frame => frame).html
end
# Parse the span
doc = Nokogiri::HTML.fragment(span_html)
root_element = doc.at_css('*')
# Check the disabled attribute of the root element (ie the span)
expect(root_element['disabled']).to eq("disabled")

Related

How to query data-attribute for a whitespace-separated value in Cypress component tests?

When testing a complex component, I want to assign multiple whitespace-separated values to data-cy attribute, for example
<div data-cy="my-component disabled" />
and use the ~= attribute selector to query for the element:
cy.get('[data-cy~="my-component"]')
Now, having already queried for my-component, how can I further assert that it:
does contain "disabled" in data-cy
does not contain "disabled" in data-cy
in broader sense, does or does not satisfy a css selector?
I know I can explicitly re-query with all parameters for each assertion, eg.:
cy.get('[data-cy~="my-component"]:not([data-cy~="disabled"])').should('exist')
but this feels overly complicated and doesn't read very well - I want to query the element first, and further assert against it in a later step - for example:
cy.get('...').should(el => {
// assert here
})
The approach seems like a good one. If you used individual attributes, likely they would clash with other "native" attributes.
For example if data-cy="disabled" means the "Person" has a disability, but used unwrapped the browser would disable the element.
Ref Using data attributes
data-* attributes allow us to store extra information on standard, semantic HTML elements without other hacks such as non-standard attributes, or extra properties on DOM.
Also some frameworks (React) are fussy about the attributes allowed on an element.
You might be looking for a function to provide the selector for the test.
const asDataCy = (attrs) => {
return attrs.split(' ').map(attr => {
let op = '~'
if (item.charAt(0) === '!') {
op = '!'
attr = attr.slice(1)
}
return `[data-cy${op}="${attr}"]`
).join('')
}
cy.get(asDataCy('my-component !disabled'))
// [data-cy~="my-component"][data-cy!="disabled"])
The Chai-jQuery assertion expect($el).match(selector) does exactly that!
// should form
cy.get('[data-cy~="my-component"]')
.should('match', '[data-cy~="some-value"]')
.should('match', ':not([data-cy~="something-else"])')
// expect form
cy.get('[data-cy~="my-component"]')
.then(el => expect(el).to.match('[data-cy~="some-value"]'))
.then(el => expect(el).to.match(':not([data-cy~="something-else"])'))

chef attributes value not getting parsed in another attribute

I am setting attributes in default.rb as
default[:my_app] = {
:vol => "data02",
:commitlog => "/foo/bar/node[:vol]/commitlog",
}
But :vol value is not getting parsed in commitlog attribute and I am getting following error.
mError executing action `create` on resource 'directory[/foo/bar/node[:vol]/comitlog]'[0m
You're missing the String interpolation syntax, e.g. y = "The value of X is #{X}." You probably want:
default[:my_app] = {
:vol => "data02",
:commitlog => "/foo/bar/#{node[:vol]}/commitlog",
}
Also, keep in mind that if you make one attribute depend on the value of another, you might override node[:my_app][:vol] later and expect the value of node[:my_app][:commitlog] to change with it, and it may not. The attributes will be parsed together, potentially before your override affects the first one.
Even after I am using the interpolation syntax, and when I am using node[:my_app][:commitlog] in recipe it shows /foo/bar//commitlog

getting the value of text field using rspec selenium

How do we use selenium webdriver + ruby to check to see if the value of a text field is equal to a certain value?
I was doing:
#tester.browser.find_element(:id => "id_of_text_field").text.should == 'test value'
Why doesn't that work?
this test failed ... couldn't get the value of the text field.
Text fields do not have text. The value you see in the text field is actually the value of their value attribute.
You can get an element's value attribute by doing:
element['value']
Therefore, your test needs to do:
#tester.browser.find_element(:id => "id_of_text_field")['value'].should == 'test value'
Write as below using should eql(expected)
Passes if given and expected are of equal value, but not necessarily the same object.
# I write in below way, just for readability, you can write it in one line.
elem = #tester.browser.find_element(:id => "id_of_text_field")
elem.text.should eql('test value')

How do I read text from non visible elements with Watir (Ruby)?

There is a div on a page that is not visible but has some value I want to capture. Calling text on it returns me an empty string.
How do I get the value displayed without having to deal with the raw html? Can I force .text to return me the actual value regardless of the visiblity of the text in the browser?
irb(main):1341:0> d.first.visible?
=> false
irb(main):1344:0> d.first.html
=> "<div class=\"day\">7</div>"
irb(main):1345:0> d.first.text
=> ""
PS: There are many many divs (the page is caching response and display them accordingly). I considered changing all the display:none in the page or clicking to make them visible but I'd prefer to avoid this if possible.
If not possible a solution with changing all the display none would be the preferred work around.
PPS: Damned, I tried to overload the visible? method in the Watir::Element class to always return true, but that didn't do the trick.
irb(main):1502:0> d.first.visible?
=> true
irb(main):1504:0> d.first.text
=> ""
For the newer versions of Watir, there is now an Element#text_content method that does the below JavaScript work for you.
e = d.first
e.text_content
#=> "7"
For Old Versions of Watir (Original Answer):
You can use JavaScript to get this.
e = d.first
browser.execute_script('return arguments[0].textContent', e)
#=> "7"
Note that this would only work for Mozilla-like browsers. For IE-like browsers, you would need to use innerText. Though if you are using watir-classic it would simply be d.first.innerText (ie no execute_script required).
Using attribute_value:
Turns out you can make it simpler by using the attribute_value method. Seems it can get the same attribute values as javascript.
d.first.attribute_value('textContent')
#=> "7"
Using inner_html
If the element only includes text nodes (ie no elements), you can also use inner_html:
d.first.inner_html
#=> "7"
Try using the execute_script method do change the value of "visible" to visible. Something like document.getElementById('id').style.visibility = 'visible' assuming it has an ID. If it does not you can always ask the devs to put a test-id on the element (or just do it yourself).

Nokogiri Error: undefined method `radiobutton_with' - Why?

I try to access a form using mechanize (Ruby).
On my form I have a gorup of Radiobuttons.
So I want to check one of them.
I wrote:
target_form = (page/:form).find{ |elem| elem['id'] == 'formid'}
target_form.radiobutton_with(:name => "radiobuttonname")[2].check
In this line I want to check the radiobutton with the value of 2.
But in this line, I get an error:
: undefined method `radiobutton_with' for #<Nokogiri::XML::Element:0x9b86ea> (NoMethodError)
The problem occured because using a Mechanize page as a Nokogiri document (by calling the / method, or search, or xpath, etc.) returns Nokogiri elements, not Mechanize elements with their special methods.
As noted in the comments, you can be sure to get a Mechanize::Form by using the form_with method to find your form instead.
Sometimes, however, you can find the element you want with Nokogiri but not with Mechanize. For example, consider a page with a <select> element that is not inside a <form>. Since there is no form, you can't use the Mechanize field_with method to find the select and get a Mechanize::Form::SelectList instance.
If you have a Nokogiri element and you want the Mechanize equivalent, you can create it by passing the Nokogiri element to the constructor. For example:
sel = Mechanize::Form::SelectList.new( page.at_xpath('//select[#name="city"]') )
In your case where you had a Nokogiri::XML::Element and wanted a Mechanize::Form:
# Find the xml element
target_form = (page/:form).find{ |elem| elem['id'] == 'formid'}
target_form = Mechanize::Form.new( target_form )
P.S. The first line above is more simply achieved by target_form = page.at_css('#formid').

Resources