-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from HDE/chained-actions
Chained actions
- Loading branch information
Showing
17 changed files
with
717 additions
and
216 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,26 @@ | ||
FROM ubuntu:zesty | ||
|
||
RUN apt-get update | ||
ENV DEBIAN_FRONTEND=noninteractive | ||
|
||
RUN apt-get install -y xvfb python3.6 python3.6-venv python3.6-dev firefox build-essential | ||
RUN apt-get update && \ | ||
apt-get install -y software-properties-common && \ | ||
add-apt-repository ppa:mozillateam/firefox-next && \ | ||
apt-get update && \ | ||
apt-get install -y \ | ||
xvfb \ | ||
python3.6 \ | ||
python3.6-venv \ | ||
python3.6-dev \ | ||
build-essential \ | ||
wget \ | ||
firefox | ||
|
||
COPY geckodriver-v0.16.0-linux64.tar.gz geckodriver-v0.16.0-linux64.tar.gz | ||
ARG GECKODRIVER_VERSION=0.16.1 | ||
|
||
RUN tar xzvf geckodriver-v0.16.0-linux64.tar.gz | ||
|
||
RUN cp geckodriver /usr/local/bin/geckodriver | ||
|
||
RUN chmod +x /usr/local/bin/geckodriver | ||
RUN wget --no-verbose -O /tmp/geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/v$GECKODRIVER_VERSION/geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz \ | ||
&& rm -rf /opt/geckodriver \ | ||
&& tar -C /opt -zxf /tmp/geckodriver.tar.gz \ | ||
&& rm /tmp/geckodriver.tar.gz \ | ||
&& mv /opt/geckodriver /opt/geckodriver-$GECKODRIVER_VERSION \ | ||
&& chmod 755 /opt/geckodriver-$GECKODRIVER_VERSION \ | ||
&& ln -fs /opt/geckodriver-$GECKODRIVER_VERSION /usr/local/bin/geckodriver |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
from arsenic.actions import Mouse, chain | ||
from arsenic.session import Element, Session | ||
|
||
|
||
async def drag_and_drop(session: Session, source_element: Element, x_offset: int, y_offset: int): | ||
mouse = Mouse() | ||
actions = chain( | ||
mouse.move_to(source_element), | ||
mouse.down(), | ||
mouse.move_by(x_offset, y_offset), | ||
mouse.up(), | ||
) | ||
await session.perform_actions(actions) | ||
|
||
|
||
import asyncio | ||
from functools import wraps, partial | ||
|
||
from aiohttp.web import Response, Application | ||
|
||
from arsenic import get_session, browsers, services | ||
|
||
|
||
async def handle(request): | ||
return Response(status=200, content_type='text/html', body='''<html> | ||
<body> | ||
<input id="range" type="range" min="1" max="100" value="1" /> <span id="output" /> | ||
<script> | ||
const range = document.getElementById('range'); | ||
const output = document.getElementById('output'); | ||
output.textContent = range.value; | ||
range.addEventListener('change', event => output.textContent = event.target.value); | ||
window.INITIALIZED = true; | ||
</script> | ||
</body> | ||
</html>''') | ||
|
||
|
||
def build_app(): | ||
app = Application() | ||
app.router.add_get('/', handle) | ||
return app | ||
|
||
|
||
class RunApp: | ||
def __init__(self): | ||
self.app = build_app() | ||
self.server = None | ||
|
||
async def __aenter__(self): | ||
self.server = await asyncio.get_event_loop().create_server( | ||
self.app.make_handler(), | ||
'127.0.0.1', | ||
0 | ||
) | ||
for socket in self.server.sockets: | ||
host, port = socket.getsockname() | ||
return f'http://{host}:{port}' | ||
|
||
async def __aexit__(self, exc_type, exc_val, exc_tb): | ||
if self.server: | ||
self.server.close() | ||
|
||
|
||
def with_app_and_session(coro): | ||
@wraps(coro) | ||
async def wrapper(): | ||
gecko = services.Geckodriver() | ||
ff = browsers.Firefox() | ||
async with RunApp() as base_url, get_session(gecko, ff, base_url) as session: | ||
return await coro(session) | ||
return wrapper | ||
|
||
|
||
@with_app_and_session | ||
async def run_drag_and_drop(session): | ||
values = [] | ||
await session.get('/') | ||
await session.wait(5, partial(session.execute_script, 'return window.INITIALIZED;')) | ||
result = await session.get_element('#output') | ||
values.append(await result.get_text()) | ||
source = await session.get_element('#range') | ||
await drag_and_drop(session, source, 200, 0) | ||
values.append(await result.get_text()) | ||
return values | ||
|
||
|
||
def main(): | ||
loop = asyncio.get_event_loop() | ||
values = loop.run_until_complete(run_drag_and_drop()) | ||
print(f'{values[0]} -> {values[1]}') | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
Action Chains | ||
############# | ||
|
||
Arsenic supports action chains that allow you to define a sequence of mouse and/or | ||
keyboard actions to perform in sequence (and in parallel). | ||
|
||
.. note:: | ||
|
||
Action chains are only supported by a few browsers so far. For other browsers, | ||
arsenic will attempt to emulate them using older APIs, however it can only | ||
emulate a single mouse input. | ||
|
||
Drag and drop | ||
************* | ||
|
||
Drag and drop functionality can be implemented using :py:class:`arsenic.actions.Mouse` | ||
together with :py:func:`arsenic.actions.chain` and :py:meth:`arsenic.session.Session.preform_actions`. | ||
|
||
Here is an example helper function which moves the mouse to an element and drags | ||
it by a specified amount of pixels: | ||
|
||
.. literalinclude:: action_chains.py | ||
:lines: 1-13 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.