Skip to content

Commit

Permalink
screenshots, get_rect
Browse files Browse the repository at this point in the history
  • Loading branch information
ojii committed Jul 15, 2017
1 parent e509db8 commit 6258128
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 19 deletions.
36 changes: 19 additions & 17 deletions docs/reference/index.rst
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
API Refrence
############

.. toctree::
:maxdepth: 2
:caption: APIs

services
browsers
session
keys
actions
errors
webdriver
connection
http
utils
API Reference
#############


Main APIs
Expand Down Expand Up @@ -55,3 +40,20 @@ Main APIs
:return: Nothing.


All APIs
********

.. toctree::
:maxdepth: 2

services
browsers
session
keys
actions
errors
webdriver
connection
http
utils

10 changes: 8 additions & 2 deletions docs/reference/session.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@

:param str value: Value of the option to select.

.. py:method:: get_rect()
Coroutine to get the location and size of the element.

:rtype: :py:class:`arsenic.utils.Rect`

.. py:method:: get_element(selector)
Coroutine to get a child element of this element via CSS selector.
Expand Down Expand Up @@ -213,11 +219,11 @@
Coroutine to perform a series of actions. Use :py:func:`arsenic.actions.chain`
to build the actions object.

.. py:method:: screenshot
.. py:method:: get_screenshot
Coroutine to take a screenshot of the top-level browsing context’s viewport.

:rtype: bytes
:rtype: :py:class:`io.BytesIO`

.. py:method:: close
Expand Down
8 changes: 8 additions & 0 deletions docs/reference/utils.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,11 @@
Returns a free port.

:rtype: int


.. py:class:: Rect
.. py:attribute:: x
.. py:attribute:: y
.. py:attribute:: width
.. py:attribute:: height
33 changes: 33 additions & 0 deletions src/arsenic/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from arsenic.connection import Connection, WEB_ELEMENT
from arsenic.errors import NoSuchElement, OperationNotSupported
from arsenic.utils import Rect, px_to_int

UNSET = object()

Expand Down Expand Up @@ -86,6 +87,12 @@ async def get_attribute(self, name: str) -> str:
method='GET'
)

async def get_css_value(self, name: str) -> str:
return await self.connection.request(
url=f'/css/{name}',
method='GET',
)

async def select_by_value(self, value: str):
value = escape_value(value)
option = await self.get_element(f'option[value={value}]')
Expand Down Expand Up @@ -113,6 +120,13 @@ async def get_elements(self, selector: str) -> List['Element']:
)
return [self.session.create_element(element_id) for element_id in element_ids]

async def get_rect(self):
data = await self.connection.request(
url='/rect',
method='GET',
)
return Rect(data['x'], data['y'], data['width'], data['height'])


TCallback = Callable[..., Awaitable[Any]]
TWaiter = Callable[[int, TCallback], Awaitable[Any]]
Expand Down Expand Up @@ -316,7 +330,20 @@ def create_element(self, element_id):
)


class CompatElement(Element):
async def get_rect(self):
location = await self.connection.request(
url='/location',
method='GET'
)
width = await self.get_css_value('width')
height = await self.get_css_value('height')
return Rect(location['x'], location['y'], px_to_int(width), px_to_int(height))


class CompatSession(Session):
element_class = CompatElement

async def set_window_size(self, width: int, height: int,
handle: str = 'current'):
return await self.connection.request(
Expand Down Expand Up @@ -352,6 +379,12 @@ async def perform_actions(self, actions: Dict[str, Any]):
data=data,
)

async def get_screenshot(self) -> BytesIO:
return BytesIO(base64.b64decode(await self.connection.request(
url='/screenshot',
method='GET'
)))


def _pointer_down(device, action):
del action['duration']
Expand Down
20 changes: 20 additions & 0 deletions src/arsenic/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
import socket

import attr


def free_port() -> int:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind(('0.0.0.0', 0))
sock.listen(5)
return sock.getsockname()[1]


def px_to_int(value: str) -> int:
original = value
if value.endswith('px'):
value = value[:-2]
if value.isdigit():
return int(value)
else:
raise ValueError(f'{original!r} is not an int or <int>px value')


@attr.s
class Rect:
x: float = attr.ib()
y: float = attr.ib()
width: float = attr.ib()
height: float = attr.ib()
1 change: 1 addition & 0 deletions tests/browser/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pytest
pytest-asyncio
jinja2
pillow
23 changes: 23 additions & 0 deletions tests/browser/test_real_browsers.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from contextlib import contextmanager

import pytest
from PIL import Image

from arsenic.actions import Mouse, chain, Keyboard
from arsenic.browsers import Firefox
from arsenic.errors import OperationNotSupported
from arsenic.services import Remote
from arsenic.session import CompatSession
from arsenic.utils import Rect


@contextmanager
Expand Down Expand Up @@ -127,3 +129,24 @@ async def check(actions, expected):
mouse.up()
)
await check(actions, '')


async def test_get_screenshot(session):
await session.get('/screenshot/')
rect = await session.wait_for_element(5, '#rect')
screenshot = await session.get_screenshot()
image = Image.open(screenshot)
info = await rect.get_rect()
rect_img = image.crop((info.x, info.y, info.x + info.height, info.y + info.width))
colors = rect_img.getcolors()
assert len(colors) == 1
count, color = colors[0]
assert count == int(info.width * info.height)
assert color == (254, 220, 186, 255)


async def test_get_rect(session):
await session.get('/screenshot/')
ele = await session.get_element('#rect')
rect = await ele.get_rect()
assert rect == Rect(0, 0, 100, 100)
1 change: 1 addition & 0 deletions tests/plugins/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def build_app() -> Application:
app.router.add_get('/js/', render_view(jinja, 'js.html'))
app.router.add_get('/cookie/', render_view(jinja, 'data.html', process_cookies))
app.router.add_get('/actions/', render_view(jinja, 'actions.html'))
app.router.add_get('/screenshot/', render_view(jinja, 'screenshot.html'))
return app


Expand Down
29 changes: 29 additions & 0 deletions tests/plugins/app/templates/screenshot.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<html>
<head>
<title>Screenshot</title>
<style>
#rect {
width: 100px;
height: 100px;
background-color: #fedcba;
padding: 0;
margin: 0;
top: 0;
left: 0;
display: block;
position: absolute;
z-index: 2;
}
#other {
width: 200px;
height: 200px;
background-color: #ff00ff;
z-index: 1;
}
</style>
</head>
<body>
<div id="rect"></div>
<div id="other"></div>
</body>
</html>

0 comments on commit 6258128

Please sign in to comment.