Add a :click-element command
This commit is contained in:
parent
28a6b3918c
commit
0cef4ac2db
@ -38,6 +38,7 @@ Added
|
||||
- New `prev-category` and `next-category` arguments to `:completion-item-focus`
|
||||
to focus the previous/next category in the completion (bound to `<Ctrl-Tab>`
|
||||
and `<Ctrl-Shift-Tab>` by default).
|
||||
- New `:click-element` command to fake a click on a element.
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
@ -1528,6 +1528,47 @@ class CommandDispatcher:
|
||||
this.dispatchEvent(event);
|
||||
""".format(javascript.string_escape(text)))
|
||||
|
||||
@cmdutils.register(instance='command-dispatcher', scope='window',
|
||||
hide=True)
|
||||
@cmdutils.argument('filter_', choices=['id'])
|
||||
def click_element(self, filter_: str, value, *,
|
||||
target: usertypes.ClickTarget):
|
||||
"""Click the element matching the given filter.
|
||||
|
||||
The given filter needs to result in exactly one element, otherwise, an
|
||||
error is shown.
|
||||
|
||||
Args:
|
||||
filter: How to filter the elements.
|
||||
id: Get an element based on its ID.
|
||||
value: The value to filter for.
|
||||
"""
|
||||
tab = self._current_widget()
|
||||
|
||||
def single_cb(elem):
|
||||
"""Click a single element."""
|
||||
if elem is None:
|
||||
message.error(self._win_id, "No element found!")
|
||||
return
|
||||
elem.click(target)
|
||||
|
||||
# def multiple_cb(elems):
|
||||
# """Click multiple elements (with only one expected)."""
|
||||
# if not elems:
|
||||
# message.error(self._win_id, "No element found!")
|
||||
# return
|
||||
# elif len(elems) != 1:
|
||||
# message.error(self._win_id, "{} elements found!".format(
|
||||
# len(elems)))
|
||||
# return
|
||||
# elems[0].click(target)
|
||||
|
||||
handlers = {
|
||||
'id': (tab.elements.find_id, single_cb),
|
||||
}
|
||||
handler, callback = handlers[filter_]
|
||||
handler(value, callback)
|
||||
|
||||
def _search_cb(self, found, *, tab, old_scroll_pos, options, text, prev):
|
||||
"""Callback called from search/search_next/search_prev.
|
||||
|
||||
|
@ -513,7 +513,12 @@ class WebKitElements(browsertab.AbstractElements):
|
||||
callback(elems)
|
||||
|
||||
def find_id(self, elem_id, callback):
|
||||
self.find_css('#' + elem_id, callback)
|
||||
def find_id_cb(elems):
|
||||
if not elems:
|
||||
callback(None)
|
||||
else:
|
||||
callback(elems[0])
|
||||
self.find_css('#' + elem_id, find_id_cb)
|
||||
|
||||
def find_focused(self, callback):
|
||||
frame = self._widget.page().currentFrame()
|
||||
|
@ -7,5 +7,6 @@
|
||||
<span onclick='console.log("click_element special chars")'>"Don't", he shouted</span>
|
||||
<span>Duplicate</span>
|
||||
<span>Duplicate</span>
|
||||
<form><input id='qute-input'></input></form>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -559,3 +559,15 @@ Feature: Various utility commands.
|
||||
And I put "{url}" into the clipboard
|
||||
And I run :message-info {clipboard}bar{url}
|
||||
Then the message "{url}barhttp://localhost:*/hello.txt" should be shown
|
||||
|
||||
## :click-element
|
||||
|
||||
Scenario: Clicking an element with unknown ID
|
||||
When I open data/click_element.html
|
||||
And I run :click-element id blah
|
||||
Then the error "No element found!" should be shown
|
||||
|
||||
Scenario: Clicking an element by ID
|
||||
When I open data/click_element.html
|
||||
And I run :click-element id qute-input
|
||||
Then "Clicked editable element!" should be logged
|
||||
|
@ -548,21 +548,6 @@ class QuteProc(testprocess.Process):
|
||||
raise ValueError('Invalid response from qutebrowser: {}'
|
||||
.format(message))
|
||||
|
||||
def click_element_by_id(self, elem_id):
|
||||
"""Click the element with the given ID."""
|
||||
script = (
|
||||
'var _elem = document.getElementById("{elem_id}"); '
|
||||
'if (_elem === null) {{ console.log("qute:no elem"); }} '
|
||||
'else {{ console.log("qute:okay"); _elem.click(); }}'
|
||||
).format(elem_id=javascript.string_escape(elem_id))
|
||||
self.send_cmd(':jseval ' + script, escape=False)
|
||||
message = self.wait_for_js('qute:*').message
|
||||
if message.endswith('qute:no elem'):
|
||||
raise ValueError('No element with ID {!r} found'.format(elem_id))
|
||||
elif not message.endswith('qute:okay'):
|
||||
raise ValueError('Invalid response from qutebrowser: {}'
|
||||
.format(message))
|
||||
|
||||
def compare_session(self, expected):
|
||||
"""Compare the current sessions against the given template.
|
||||
|
||||
|
@ -265,22 +265,6 @@ class TestClickElementByText:
|
||||
assert 'No element' in str(excinfo.value)
|
||||
|
||||
|
||||
class TestClickElementById:
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def open_page(self, quteproc):
|
||||
quteproc.open_path('data/click_element.html')
|
||||
|
||||
def test_click_element(self, quteproc):
|
||||
quteproc.click_element_by_id('test')
|
||||
quteproc.wait_for_js('click_element clicked')
|
||||
|
||||
def test_nonexistent(self, quteproc):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
quteproc.click_element_by_id('blah')
|
||||
assert 'No element' in str(excinfo.value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('string, expected', [
|
||||
('Test', "'Test'"),
|
||||
("Don't", '"Don\'t"'),
|
||||
|
Loading…
Reference in New Issue
Block a user