Undefined method 'count' when using '.map' in Watir - ruby

I'm using Watir to load all apps in a directory with infinite scroll and count them:
grid = browser.divs(class: 'rows')[1]
app_urls = grid.map { |app| app.a(class: 'element Link clickable-element').href }
app_urls.count
but I'm getting the following error:
in `method_missing': undefined method `count' for #<Watir::Map: located: false; {:class=>"rows", :tag_name=>"div", :index=>1} --> {:tag_name=>"map"}> (NoMethodError)
Why can't I use .map in this case and how should I count the number of apps instead?

grid is a single Watr::Div element. This means that #map is actually the method for looking for a map element rather than the Enumerable one.
Assuming you're wanting to iterate over the divs with class "row", then it should be:
grid = browser.divs(class: 'rows')

Related

unable to click on checkbox within shadowroot

I am writing a test to go through a test flow of a monetary registration. The registration has Add-ons that appear in different steps that flow. My goal is to be able to select the checkboxes in the add-on shadow root, so I can get to the next step. The elements within the shadow root that I'm trying to focus on seem like they can be targeted, and they are Enumerators, Arrays, and Hashes.
What I need help with is clicking on the checkbox, but the .click method doesn't work for the elements that I'm targeting. I don't return an error for .select, but it doesn't seem to do anything either.
As I step through the code, I think that I am targeting the correct element(s) which is centered around a checkbox. But none of the elements I see seem to be classes that can be "clicked" or interacted with. What I've tried so far:
sales_channels_reg.execute_script("return arguments[0].shadowRoot", sales_channels_reg.regsaver_section.regsaver_testtest.find("#sales-channels-element", visible: false)).find(css: "label[for='addToCart--false']")
Returns:
#<Enumerator: {"shadow-6066-11e4-a52e-4f735466cecf"=>"416aad9c-c512-496d-93c3-91c17ec6e27d"}:find(css: label[for='addToCart--false'])>
- sales_channels_reg.execute_script("return arguments[0].shadowRoot", sales_channels_reg.regsaver_section.regsaver_testtest.find("#sales-channels-element", visible: false)).find(id: "addToCart--false")
Returns
#<Enumerator: {"shadow-6066-11e4-a52e-4f735466cecf"=>"416aad9c-c512-496d-93c3-91c17ec6e27d"}:find(id: addToCart--false)>
- sales_channels_reg.execute_script("return arguments[0].shadowRoot", sales_channels_reg.regsaver_section.regsaver_testtest.find("#sales-channels-element", visible: false))
Returns
{"shadow-6066-11e4-a52e-4f735466cecf"=>"416aad9c-c512-496d-93c3-91c17ec6e27d"}
sales_channels_reg.execute_script("return arguments[0].shadowRoot", sales_channels_reg.regsaver_section.regsaver_testtest.find("#sales-channels-element", visible: false)).class
Returns
Hash
sales_channels_reg.execute_script("return arguments[0].shadowRoot", sales_channels_reg.regsaver_section.regsaver_testtest.find("#sales-channels-element", visible: false)).find(id: "addToCart--false").each do |c| puts c, c.class end
Returns
shadow-6066-11e4-a52e-4f735466cecf
416aad9c-c512-496d-93c3-91c17ec6e27d
Array
*** NoMethodError Exception: undefined method `call' for {:id=>"addToCart--false"}:Hash
(byebug) sales_channels_reg.execute_script("return arguments[0].shadowRoot", sales_channels_reg.regsaver_section.regsaver_testtest.find("#sales-channels-element", visible: false)).find(id: "addToCart--false", :visible => false).click
*** NoMethodError Exception: undefined method `click' for #<Enumerator:0x00007fbeb9195558>
nil
Code for what I'm writing
-first file-
describe "Showing 4 max add-ons in reg flow", type: :feature, service: "sales_channels1" do
context "yadda yadda" do
subject(:sales_channels_reg) { SalesChannelsRegGenerals.new }
subject(:se_signup_page) { SELogin.new }
# subject(:gen_reg) { RegistrationHelper.new }
let(:form_number) { "848624247" }
it "in test flow does thing" do
couple of other steps first
byebug (where I'm at in the code now)
end
end
end
-different file-
require "./spec/page_models/sales_channels_ncsa_section.rb"
require "./spec/page_models/sales_channels_medsaver_section.rb"
require "./spec/page_models/sales_channels_regsaver_section.rb"
require "./spec/page_models/sales_channels_four_addons_section.rb"
class SalesChannelsRegGenerals < SitePrism::Page
set_url "https://zachpartyka#{SeleniumTest.ngin_site}/register/form/{/form_number}"
section :regsaver_section, RegSaverSection, "div#siteContainer2"
end
-different file-
class RegSaverSection < SitePrism::Section
element :regsaver_testtest, "#pageContentContainer"
end
None of those values should be Enumerators, Hashes, etc (unless site-prism is really screwing with Capybaras returns). I'm guessing the reason is that you're using execute_script when you should be using evaluate_script. execute_script shouldn't be used when you expect a return value, and won't unwrap results into element references, evaluate_script does.
sales_channels_reg.evaluate_script("arguments[0].shadowRoot", ...)

How to scrape the next page in ruby

I am trying to scrape the next page of the website called https://www.jobsatosu.com/postings/search. Because there are many jobs, there are many pages. Our team successfully scraped the first page like this:
def initialize
#agent_menu = Mechanize.new
#page = #agent_menu.get(PAGE_URL)
#form = #page.forms[0]
I am working on trying to scrape the next page. Also, we were told to use Nokogiri and Mechanize in Ruby. I just have to scrape the next page and do not have to parse it.
This is what I did:
def next_page
#page_num += 1
new_url = "https://www.jobsatosu.com/postings/search?page=#{#page_num}"
#new_page = #agent_menu.get(new_url)
#new_form = #new_page.forms[0]
end
I made one page_num for all to share. If someone calls the method, then it gets iterated by 1 and it gets the new URL, puts it in #new_page.
I haven't tested this out, but any thoughts on this code?
You need to initialize #page_num = 0 before use
In the first time #page_num is nil so #page_num += 1 raises execption
NoMethodError: undefined method '+' for nil:NilClass
Actually you don't describe variable before using but in this case, you need to do

Define variable by elements class even not displayed on current page

I'm using Ruby and Selenium to get some data from a page. I want to define variable with driver.find_element, but element is not currently visible on page.
next = driver.find_element(:class, 'right')
It returns Selenium::WebDriver::Error::NoSuchElementError
It works fine when element is present.
Any solutions?
Thank you!
Selenium works by executing Javascript commands. By using find_element it will search for the element on the DOM. If it cannot find it you will get the error you are getting. After all if an element is not on the DOM it cannot be found.
The real question is why do you want too find an element that is not currently present on the DOM? You can't do anything with somehing that doesn't exist.
All I could think of is that the element becomes present after the DOM has been loaded due to Javascript not being fully executed yet. If that is the case you can use a WebDriver::Wait to try and find the element for a certain amount of time.
A small example:
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
begin
element = wait.until { driver.find_element(:id => "some-dynamic-element") }
ensure
driver.quit
end
Edit to include try-catch example:
begin
next = driver.find_element(:class, 'right')
# Code for when element is found here
rescue NoSuchElementError
# Code for when element is not found here
end

Is it possible to get element by class in selenium webdriver ruby?

I have a class like this:
<div class="qa-share-message ng-isolate-scope ng-valid ta-root
ng-dirty focussed" ng-model="message" text-angular="">
I want to type in this field. i have tried this:
driver.find_elements(:class, "qa-share-message").send_keys("This is a test message")
After running the code it shows error:
undefined method `send_keys' for [#<Selenium::WebDriver::Element:0x65990040 id="33">]:Array
Is it possible to get element by class?
You obviously got elements by class. Look:
undefined method `send_keys' for [# Selenium::WebDriver::Element:0x65990040 id="33"]:Array
the error above clearly says: the call to find_elements succeeded and returned an Array instance, containing Elements. Everything you now need is to either send_keys to each found element:
driver.find_elements(:class, "qa-share-message").each do |e|
e.send_keys("This is a test message")
end
or to send it to one of them, e.g. to the very first one:
driver.find_elements(:class, "qa-share-message")
.first
.send_keys("This is a test message")

dashing job undefined map method error

I'm using the dashing dashboard to display some data. Part of my code for one of the jobs uses the map! function in ruby:
vars = arr.map! { |element| element.gsub(/.{3}$/, '' )}
and when I try to run the dashboard using dashing start, I get the following error :
scheduler caught exception:
undefined method map! for #<Hash: 0x......>
If I run the code on its own as a ruby program, I get the correct result.
The documentation for the JSON module indicates that the parse method will "...convert your string into a hash." See http://www.ruby-doc.org/stdlib-2.0.0/libdoc/json/rdoc/JSON.html#module-JSON-label-Parsing+JSON.
Try calling just map on your hash instead of calling map!:
vars = arr.map { |element| element.gsub(/.{3}$/, '' )}
The difference is that map will return a new array with the results of running your block once for every element in the Hash. Also, map is defined in the Enumerable module, which is included by Hash, but map! is not defined in Enumerable. See http://www.ruby-doc.org/core-2.0.0/Enumerable.html#method-i-map.

Resources