nerodia
nerodia copied to clipboard
Locating drop down menu without unique identifier inside a div with an id
Need to see if there is a way to locate drop down menu choices within a div in able to select drop down choices, which do not have unique identifiers. In this case, div has an id which I can use to locate it, but the view box vega embed graph drop down menu does not have a unique identifier. See below:
<div class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-4" id="pa_graph_1">
<div class="vega-embed has-actions"><div class="chart-wrapper" role="graphics-document" aria-roledescription="visualization" aria-label="Vega visualization" style="cursor: default;"><canvas width="262" height="269" class="marks" style="width: 252px; height: 259px;"></canvas><form class="vega-bindings"></form></div><details title="Click to view actions">
<summary>
<svg viewBox="0 0 16 16" fill="currentColor" stroke="none" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
<circle r="2" cy="8" cx="2"></circle>
<circle r="2" cy="8" cx="8"></circle>
<circle r="2" cy="8" cx="14"></circle>
</svg></summary>
<div class="vega-actions">
<a href="#" target="_blank" download="visualization.svg">Save as SVG</a>
<a href="#" target="_blank" download="visualization.png">Save as PNG</a>
<a href="#">View Source</a>
<a href="#">View Compiled Vega</a>
<a href="#">Open in Vega Editor</a>
</div></details></div></div>
<div class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-4" id="pa_graph_2">
<div class="vega-embed has-actions"><div class="chart-wrapper" role="graphics-document" aria-roledescription="visualization" aria-label="Vega visualization" style="cursor: default;"><canvas width="265" height="290" class="marks" style="width: 255px; height: 279px;"></canvas><form class="vega-bindings"></form></div><details title="Click to view actions">
<summary>
<svg viewBox="0 0 16 16" fill="currentColor" stroke="none" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
<circle r="2" cy="8" cx="2"></circle>
<circle r="2" cy="8" cx="8"></circle>
<circle r="2" cy="8" cx="14"></circle>
</svg></summary>
<div class="vega-actions">
<a href="#" target="_blank" download="visualization.svg">Save as SVG</a>
<a href="#" target="_blank" download="visualization.png">Save as PNG</a>
<a href="#">View Source</a>
<a href="#">View Compiled Vega</a>
<a href="#">Open in Vega Editor</a>
</div></details></div></div>
Watir (& Nerodia) support many different ways to locate elements (http://watir.com/guides/locating/)
I'm not familiar with this type of drop down, though, what do you need to identify by and what do you need to click?
I need to click on
<a href="#">View Compiled Vega</a>
"in each div. (id=" id="pa_graph_1" and id="pa_graph_2")
So in Ruby it would look like:
browser.div(id: 'pa_graph_1').a(text: 'View Compiled Vega').click
you'd have to translate the equivalent in Python for Nerodia...
I've tried:
browser.div(id = 'pa_graph_1').a(text='View Compiled Vega').click() browser.div(id = 'pa_graph_1').link(text='View Compiled Vega').click()
Any other ideas?
are you getting an error, or is it not doing anything?
browser.div(id = 'pa_graph_1').a(text='View Compiled Vega').click()
Error: AttributeError: Element 'Div' has no attribute 'a'
So I tried:
browser.div(id = 'pa_graph_1').link(text='View Compiled Vega').click()
Error: nerodia.exception.UnknownObjectException: element located, but timed out after 30 seconds, waiting for #<Anchor: located: True; {'id': 'pa_graph_1', 'tag_name': 'div'} --> {'text': 'View Compiled Vega', 'tag_name': 'a'}> to be present
Right, so this means that it is in the DOM, but that Selenium has calculated that it is not visible to the end user. Is there something you need to click or hover over in order to make it visible?
These href 'View Compiled Vega' choice is part of a drop down list under svg:
<svg viewBox="0 0 16 16" fill="currentColor" stroke="none" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
<circle r="2" cy="8" cx="2"></circle>
<circle r="2" cy="8" cx="8"></circle>
<circle r="2" cy="8" cx="14"></circle>
</svg>
However, I don't have a 'name' or 'id' for svg, which I can potentially use to click on it. However, this svg drop box is part of the overall div, which does have an 'id'
Here is an example of the Vega embed dropdown menu (https://observablehq.com/@vega/hello-vega-embed), which is similar to what I am using without an overall div id.
I am trying to do as follows:
- click on the drop down menu for this vega embed graph drop down menu,
- click on 'View Compiled Vega'
- change focus to new window
- acquire json data on new window
- close new vega json window, and go back to original window.
I have good news and bad news. First, this is hidden inside an iframe, which is causing a problem.
Good news: This (Ruby) code works!
irb(main):220:0> browser = Watir::Browser.new :firefox
=> #<Watir::Browser:0x7eeaa404f092b38e url="about:blank" title="">
irb(main):221:0> browser.goto 'https://observablehq.com/@vega/hello-vega-embed'
=> "https://observablehq.com/@vega/hello-vega-embed"
irb(main):222:0> browser.iframe.div(class: 'vega-embed-wrapper').svg.click
=> nil
irb(main):223:0> browser.iframe.link(text: 'View Compiled Vega').click
=> nil
irb(main):224:0> browser.windows.last.use
=> #<Watir::Window:0x..fda6a7121231443ac located=true>
irb(main):227:0> JSON.parse browser.code.text
=> {"$schema"=>"https://vega.github.io/schema/vega/v5.json", "background"=>"white", "padding"=>5, "width"=>360, "height"=>200, "style"=>"cell", "data"=>[{"name"=>"a_store"}, {"name"=>"source", "values"=>[{"a"=>"A", "b"=>28}, {"a"=>"B", "b"=>55}, {"a"=>"C", "b"=>43}, {"a"=>"D", "b"=>91}, {"a"=>"E", "b"=>81}, {"a"=>"F", "b"=>53}, {"a"=>"G", "b"=>19}, {"a"=>"H", "b"=>87}, {"a"=>"I", "b"=>52}]}, {"name"=>"data_0", "source"=>"source", "transform"=>[{"type"=>"identifier", "as"=>"_vgsid_"}, {"type"=>"filter", "expr"=>"isValid(datum[\"b\"]) && isFinite(+datum[\"b\"])"}]}], "signals"=>[{"name"=>"unit", "value"=>{}, "on"=>[{"events"=>"mousemove", "update"=>"isTuple(group()) ? group() : unit"}]}, {"name"=>"a", "update"=>"vlSelectionResolve(\"a_store\", \"union\")"}, {"name"=>"a_tuple", "on"=>[{"events"=>[{"source"=>"scope", "type"=>"click"}], "update"=>"datum && item().mark.marktype !== 'group' ? {unit: \"\", fields: a_tuple_fields, values: [(item().isVoronoi ? datum.datum : datum)[\"_vgsid_\"]]} : null", "force"=>true}, {"events"=>[{"source"=>"scope", "type"=>"dblclick"}], "update"=>"null"}]}, {"name"=>"a_tuple_fields", "value"=>[{"type"=>"E", "field"=>"_vgsid_"}]}, {"name"=>"a_modify", "on"=>[{"events"=>{"signal"=>"a_tuple"}, "update"=>"modify(\"a_store\", a_tuple, true)"}]}], "marks"=>[{"name"=>"marks", "type"=>"rect", "style"=>["bar"], "interactive"=>true, "from"=>{"data"=>"data_0"}, "encode"=>{"update"=>{"fill"=>[{"test"=>"!(length(data(\"a_store\"))) || (vlSelectionTest(\"a_store\", datum))", "value"=>"steelblue"}, {"value"=>"grey"}], "tooltip"=>{"signal"=>"format(datum[\"b\"], \"\")"}, "ariaRoleDescription"=>{"value"=>"bar"}, "description"=>{"signal"=>"\"a: \" + (isValid(datum[\"a\"]) ? datum[\"a\"] : \"\"+datum[\"a\"]) + \"; b: \" + (format(datum[\"b\"], \"\"))"}, "x"=>{"scale"=>"x", "field"=>"a"}, "width"=>{"scale"=>"x", "band"=>1}, "y"=>{"scale"=>"y", "field"=>"b"}, "y2"=>{"scale"=>"y", "value"=>0}}}}], "scales"=>[{"name"=>"x", "type"=>"band", "domain"=>{"data"=>"data_0", "field"=>"a", "sort"=>true}, "range"=>[0, {"signal"=>"width"}], "paddingInner"=>0.1, "paddingOuter"=>0.05}, {"name"=>"y", "type"=>"linear", "domain"=>{"data"=>"data_0", "field"=>"b"}, "range"=>[{"signal"=>"height"}, 0], "nice"=>true, "zero"=>true}], "axes"=>[{"scale"=>"y", "orient"=>"left", "gridScale"=>"x", "grid"=>true, "tickCount"=>{"signal"=>"ceil(height/40)"}, "domain"=>false, "labels"=>false, "aria"=>false, "maxExtent"=>0, "minExtent"=>0, "ticks"=>false, "zindex"=>0}, {"scale"=>"x", "orient"=>"bottom", "grid"=>false, "title"=>"a", "labelAlign"=>"right", "labelAngle"=>270, "labelBaseline"=>"middle", "zindex"=>0}, {"scale"=>"y", "orient"=>"left", "grid"=>false, "title"=>"b", "labelOverlap"=>true, "tickCount"=>{"signal"=>"ceil(height/40)"}, "zindex"=>0}]}
irb(main):228:0>
Bad news: it doesn't work with Chrome for some reason. Some kind of bug trying to interact with elements on the second window, the driver just hangs...
It seems I get a bit further in chrome than firefox.
I tried the following in chrome, and this works:
div_a = self.browser.iframe().div(class_name = "vega-embed-wrapper")
div_a.scroll_into_view()
div_a.svg().click()
self.browser.iframe().link(text = 'View Compiled Vega').click()
# Print JSON data from 'Vega JSON Source' window
print(self.browser.text)
# Go back to original window
self.browser.window(title = 'Hello Vega-Embed / Vega / Observable').use()
# Print original browser text
print(self.browser.text)
self.browser.window(title = 'Vega JSON Source').use()
However, after ' self.browser.window(title = 'Vega JSON Source').use()', everything hangs as you mentioned.
The following doesn't work either in chrome:
self.browser.window(title = 'Vega JSON Source').close()
In regards to Firefox browser, I get an error just by trying:
self.browser.window(title = 'Hello Vega-Embed / Vega / Observable').use()
Error:
File "/home/imaltero/.local/lib/python3.6/site-packages/nerodia/window.py", line 284, in _matches
self.driver.switch_to.window(orig)
File "/home/imaltero/.local/lib/python3.6/site-packages/selenium/webdriver/remote/switch_to.py", line 112, in window
self._w3c_window(window_name)
File "/home/imaltero/.local/lib/python3.6/site-packages/selenium/webdriver/remote/switch_to.py", line 123, in _w3c_window
send_handle(window_name)
File "/home/imaltero/.local/lib/python3.6/site-packages/selenium/webdriver/remote/switch_to.py", line 119, in send_handle
self._driver.execute(Command.SWITCH_TO_WINDOW, {'handle': h})
File "/home/imaltero/.local/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/home/imaltero/.local/lib/python3.6/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.InvalidArgumentException: Message: Expected "handle" to be a string, got [object Undefined] undefined
I think you're just referencing the window incorrectly somehow. In chrome and Firefox the windows appear in order, so you can use the last one in the array.
I did have 'self.browser.window(index=1).close()" work as expected closing Vega JSON Source page, but 'self.browser.window(index=1).use()' still hangs in chrome, where index=0 is original window and index=1 is Vega JSON Source page.
However using the same code for Chrome, I am still having issues with Firefox just by simply using 'self.browser.window(index=0).use()' or 'self.browser.window(title = 'Hello Vega-Embed / Vega / Observable').use()' for example as well as close() function, which work fine in Chrome but not Firefox getting same error as above.
Oh weird, I can reproduce this bug in Ruby Watir. Some kind of infinite loop when trying to iterate over a window set with a single window by looking at title, I'll raise an issue on Watir. I'm thinking https://github.com/watir/watir/pull/849 might address the issue, or at least make it easier to switch back to the original window, but not sure when that will get added.
In the meantime, this should work:
irb(main):025:0> browser.windows.last.use
=> #<Watir::Window:0x65022af5bb8f248c located=true>
irb(main):026:0> browser.window.close
=> #<Watir::Window:0x65022af5bb8f248c located=true>
irb(main):027:0> browser.windows.first.use
=> #<Watir::Window:0x10eb7bc745bf5a98 located=true>
irb(main):028:0>
In regards to Chrome, I noticed that in order for me to interact and extract json data from the new Vega JSON Source page I need to be able to use the use() function to change focus to this new window I just opened. I see the issue may be related to how the new Vega JSON Source page itself (possibly url?).
If Instead of opening the Vega JSON Source option I open 'Open in Vega Editor' option page, I am able to change focus to this new Open in Vega Editor window using the use() function as expected. So I am wondering if there is a work around I could to interact with Vega JSON Source page given this new finding.
As far as Firefox browser, I still get an InvalidArgumentException Exception Error as mentioned above when trying to use 'browser.window(index=1).use()' or 'browser.window(title = 'Vega Editor').use()', which both functions work fine in Chrome browser.
@ialtero are you using geckodriver v0.28? @lmtierney any chance you can duplicate this in Firefox? (there's an actual bug in here for the Title stuff, but index works in Ruby, so I'm not sure what is different in Python?)
I am currently using geckodriver v0.24, and firefox v83
Ok, I just tried it with v0.28 and it works now. The only issue now in both browser is to interact/change focus to Vega JSON Source option page instead of Open in Vega Editor option page.