diff --git a/Browser/browser.py b/Browser/browser.py
old mode 100644
new mode 100755
index c89681cb8..1c13705d3
--- a/Browser/browser.py
+++ b/Browser/browser.py
@@ -38,50 +38,278 @@ class Browser(DynamicCore):
[https://www.mozilla.org/en-US/firefox/new/|Firefox]
and [https://webkit.org/|WebKit] with a single library.
+
== Table of contents ==
%TOC%
+ = Browser, Context and Page =
+
+ Browser library works with three different layers that build on each other:
+ *Browser*, *Context* and *Page*.
+
+
+ == Browsers ==
+
+ A *browser* can be started with one of the three
+ different engines Chromium, Firefox or Webkit.
+
+ === Supported Browsers ===
+ | Browser | Browser with this engine |
+ | ``chromium`` | Google Chrome, Microsoft Edge (since 2020), Opera |
+ | ``firefox`` | Mozilla Firefox |
+ | ``webkit`` | Apple Safari, Mail, AppStore on MacOS and iOS |
+
+ Since [https://github.com/microsoft/playwright|Playwright] comes with a pack of builtin
+ binaries for all browsers, no additional drivers e.g. geckodriver are needed.
+
+ All these browsers that cover more than 85% of the world wide used browsers,
+ can be tested on Windows, Linux and MacOS.
+ Theres is not need for dedicated machines anymore.
+
+ A browser process is started ``headless`` (without a GUI) by default.
+ Run `New Browser` with specified arguments if a browser with a GUI is requested
+ or if a proxy has to be configured.
+ A browser process can contain several contexts.
+
+
+ == Contexts ==
+
+ A *context* corresponds to several independent incognito browsers in Chrome
+ that do not share cookies, sessions or profile settings.
+ Compared to Selenium, these do *not* require their own browser process!
+ Therefore, to get a clean environment the tests shall just close the current
+ context and open a new context.
+ Due to this new independent browser sessions can be opened with
+ Robot Framework Browser about 10 times faster than with Selenium by
+ just opening a `New Context` within the opened browser.
+
+ The context layer is useful e.g. for testing different users sessions on the
+ same webpage without opening a whole new browser context.
+ Contexts can also have detailed configurations, such as geo-location, language settings,
+ the viewport size or color scheme.
+ Contexts do also support http credentials to be set, so that basic authentication
+ can also be tested. To be able to download files within the test,
+ the ``acceptDownloads`` argument must be set to ``True`` in `New Context` keyword.
+ A context can contain different pages.
+
+
+ == Pages ==
+
+ A *page* does contain the content of the loaded web site.
+ Pages and browser tabs are the same.
+
+ Typical usage could be:
+ | *** Test Cases ***
+ | Starting a browser with a page
+ | New Browser chromium headless=false
+ | New Context viewport={'width': 1920, 'height': 1080}
+ | New Page https://marketsquare.github.io/robotframework-browser/Browser.html
+ | Get Title == Browser
+
+ There are shortcuts to open new pages together with new browsers but the offer less control.
+
+ The `Open Browser` keyword opens a new browser, a new context and a new page.
+ This keyword is usefull for quick experiments or debugging sessions.
+
+ When a `New Page` is called without an open browser, `New Browser`
+ and `New Context` are executed with default values first.
+
+ If there is no browser opened in Suite Setup and `New Page` is executed in
+ Test Setup, the corresponding pages and context is closed automatically at the end of
+ the test. The browser process remains open and will be closed at the end of
+ execution.
+
+ Each Browser, Context and Page has a unique ID with which they can be adressed.
+ A full catalog of what is open can be recieved by `Get Browser Catalog` as dictionary.
+
+
+
= Finding elements =
All keywords in the library that need to interact with an element
on a web page take an argument typically named ``selector`` that specifies
how to find the element.
- == Selector syntax ==
+ Selector strategies that are supported by default are listed in the table
+ below.
- Browser library supports the same selector strategies as the underlying
- Playwright node module: xpath, css, id and text. The strategy can either
- be explicitly specified with a prefix or the strategy can be implicit.
+ | = Strategy = | = Match based on = | = Example = |
+ | ``css`` | CSS selector. | ``css=.class > #login_btn`` |
+ | ``xpath`` | XPath expression. | ``xpath=//input[@id="login_btn"]`` |
+ | ``text`` | Browser text engine. | ``text=Login`` |
+ | ``id`` | Element ID Attribute. | ``id=login_btn`` |
- === Implicit selector strategy ===
- The default selector strategy is `css`. If selector does not contain
- one of the know selector strategies, `css`, `xpath`, `id` or `text` it is
- assumed to contain css selector. Also `selectors` starting with `//`
- considered as xpath selectors.
+ == Explicit Selector Strategy ==
+
+ The explicit selector strategy is specified with a prefix using syntax
+ ``strategy=value``. Spaces around the separator are ignored, so
+ ``css=foo``, ``css= foo`` and ``css = foo`` are all equivalent.
+
+
+ == Implicit Selector Strategy ==
+
+ *The default selector strategy is `css`.*
+
+ If selector does not contain one of the know explicit selector strategies, it is
+ assumed to contain css selector.
+
+ Selectors that are starting with ``//`` or ``..`` are considered as xpath selectors.
+
+ Selectors that are in quotes are considered as text selectors.
Examples:
- | `Click` | span > button | # Use css selector strategy the element. |
- | `Click` | //span/button | # Use xpath selector strategy the element. |
+ | # CSS selectors are default.
+ | `Click` span > button.some_class # This is equivalent
+ | `Click` css=span > button.some_class # to this.
+ |
+ | # // or .. leads to xpath selector strategy
+ | `Click` //span/button[@class="some_class"]
+ | `Click` xpath=//span/button[@class="some_class"]
+ |
+ | # "text" in quotes leads to exact text selector strategy
+ | `Click` "Login"
+ | `Click` text="Login"
- === Explicit selector strategy ===
- The explicit selector strategy is specified with a prefix using syntax
- ``strategy=value``. Spaces around the separator are ignored, so
- ``css=foo``, ``css= foo`` and ``css = foo`` are all equivalent.
+ == CSS ==
+ As written before, the default selector strategy is `css`. See
+ [https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors | css selector]
+ for more information.
- Selector strategies that are supported by default are listed in the table
- below.
+ Any malformed selector not starting with ``//`` or ``..`` nor starting and ending
+ with a quote is assumed to be a css selector.
+
+ Example:
+ | `Click` span > button.some_class
+
+
+ == XPath ==
+
+ XPath engine is equivalent to [https://developer.mozilla.org/en/docs/Web/API/Document/evaluate|Document.evaluate].
+ Example: ``xpath=//html/body//span[text()="Hello World"]``.
+
+ Malformed selector starting with ``//`` or ``..`` is assumed to be an xpath selector.
+ For example, ``//html/body`` is converted to ``xpath=//html/body``. More
+ examples are displayed in `Examples`.
+
+ Note that xpath does not pierce [https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM|shadow_roots].
+
+
+ == Text ==
+
+ Text engine finds an element that contains a text node with the passed text.
+ For example, ``Click text=Login`` clicks on a login button, and
+ ``Wait For Elements State text="lazy loaded text"`` waits for the "lazy loaded text"
+ to appear in the page.
+
+ Malformed selector starting and ending with a quote (either ``"`` or ``'``) is assumed
+ to be a text selector. For example, ``Click "Login"`` is converted to ``Click text="Login"``.
+ Be aware that these leads to exact matches only!
+ More examples are displayed in `Examples`.
+
+
+ === insensitive match ===
+
+ By default, the match is case-insensitive, ignores leading/trailing whitespace and
+ searches for a substring. This means ``text= Login`` matches
+ ````.
+
+ === exact match ===
+
+ Text body can be escaped with single or double quotes for precise matching,
+ insisting on exact match, including specified whitespace and case.
+ This means ``text="Login "`` will only match ```` with exactly
+ one space after "Login". Quoted text follows the usual escaping rules, e.g.
+ use ``\\"`` to escape double quote in a double-quoted string: ``text="foo\\"bar"``.
+
+ === RegEx ===
+
+ Text body can also be a JavaScript-like regex wrapped in / symbols.
+ This means ``text=/^hello .*!$/i`` or ``text=/^Hello .*!$/`` will match ``Hello Peter Parker!``
+ with any name after ``Hello``, ending with ``!``.
+ The first one flagged with ``i`` for case-insensitive.
+ See [https://regex101.com/] for more information about RegEx.
+
+ === Button and Submit Values ===
- | = Strategy = | = Match based on = | = Example = |
- | css | CSS selector. | ``css=div#example`` |
- | xpath | XPath expression. | ``xpath=//div[@id="example"]`` |
- | text | Browser text engine. | ``text=Login`` |
+ Input elements of the type button and submit are rendered with their value as text,
+ and text engine finds them. For example, ``text=Login`` matches
+ ````.
- == Finding elements inside frames ==
+
+
+ == Cascaded selector syntax ==
+
+ Browser library supports the same selector strategies as the underlying
+ Playwright node module: xpath, css, id and text. The strategy can either
+ be explicitly specified with a prefix or the strategy can be implicit.
+
+ A major advantage of Browser is, that multiple selector engines can be used
+ within one selector. It is possible to mix XPath, CSS and Text selectors while
+ selecting a single element.
+
+ Selectors are strings that consists of one or more clauses separated by
+ ``>>`` token, e.g. ``clause1 >> clause2 >> clause3``. When multiple clauses
+ are present, next one is queried relative to the previous one's result.
+ Browser library supports concatination of different selectors seperated by ``>>``.
+
+ For example:
+ | `Highlight Elements` "Hello" >> ../.. >> .select_button
+ | `Highlight Elements` text=Hello >> xpath=../.. >> css=.select_button
+
+ Each clause contains a selector engine name and selector body, e.g.
+ ``engine=body``. Here ``engine`` is one of the supported engines (e.g. css or
+ a custom one). Selector ``body`` follows the format of the particular engine,
+ e.g. for css engine it should be a [https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors | css selector].
+ Body format is assumed to ignore leading and trailing white spaces,
+ so that extra whitespace can be added for readability. If selector
+ engine needs to include ``>>`` in the body, it should be escaped
+ inside a string to not be confused with clause separator,
+ e.g. ``text="some >> text"``.
+
+ Selector engine name can be prefixed with ``*`` to capture element that
+ matches the particular clause instead of the last one. For example,
+ ``css=article >> text=Hello`` captures the element with the text ``Hello``,
+ and ``*css=article >> text=Hello`` (note the *) captures the article element
+ that contains some element with the text Hello.
+
+ For convenience, selectors in the wrong format are heuristically converted
+ to the right format. See `Implicit Selector Strategy`
+
+ == Examples ==
+ | # queries 'div' css selector
+ | Get Element css=div
+ |
+ | # queries '//html/body/div' xpath selector
+ | Get Element //html/body/div
+ |
+ | # queries '"foo"' text selector
+ | Get Element text=foo
+ |
+ | # queries 'span' css selector inside the result of '//html/body/div' xpath selector
+ | Get Element xpath=//html/body/div >> css=span
+ |
+ | # converted to 'css=div'
+ | Get Element div
+ |
+ | # converted to 'xpath=//html/body/div'
+ | Get Element //html/body/div
+ |
+ | # converted to 'text="foo"'
+ | Get Element "foo"
+ |
+ | # queries the div element of every 2nd span element inside an element with the id foo
+ | Get Element \\#foo >> css=span:nth-child(2n+1) >> div
+ | Get Element id=foo >> css=span:nth-child(2n+1) >> div
+
+ Be aware that using ``#`` as a starting character in Robot Framework would be interpreted as comment.
+ Due to that fact a ``#id`` must be escaped as ``\\#id``.
+
+ == Frames ==
By default, selector chains do not cross frame boundaries. It means that a
simple CSS selector is not able to select and element located inside an iframe
@@ -90,12 +318,94 @@ class Browser(DynamicCore):
inside a frame.
Given this simple pseudo html snippet:
- ````,
- here's a keyword call that clicks the button inside the frame.
+ |
- | Click | iframe[name="iframe"] >>> #btn |
+ Here's a keyword call that clicks the button inside the frame.
+
+ | Click id=iframe >>> id=btn
The selectors on the left and right side of ``>>>`` can be any valid selectors.
+ The selector clause directly before the frame opener ``>>>`` must select the frame element.
+
+ == WebComponents and Shadow DOM ==
+
+ Playwright and so also Browser are able to do automatic piercing of Shadow DOMs
+ and therefore are the best automation technology when working with WebComponents.
+
+ Also other technologies claim that they can handle
+ [https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM|Shadow DOM and Web Components].
+ However, non of them do pierce shadow roots automatically,
+ which may be inconvenient when working with Shadow DOM and Web Components.
+
+ For that reason, css engine pierces shadow roots. More specifically, every
+ [https://developer.mozilla.org/en-US/docs/Web/CSS/Descendant_combinator|Descendant combinator]
+ pierces an arbitrary number of open shadow roots, including the implicit descendant combinator
+ at the start of the selector.
+
+ That means, it is not nessesary to select each shadow host, open its shadow root and
+ select the next shadow host until you reach the element that should be controlled.
+
+ === CSS:light ===
+
+ ``css:light`` engine is equivalent to [https://developer.mozilla.org/en/docs/Web/API/Document/querySelector | Document.querySelector]
+ and behaves according to the CSS spec.
+ However, it does not pierce shadow roots.
+
+ ``css`` engine first searches for elements in the light dom in the iteration order,
+ and then recursively inside open shadow roots in the iteration order. It does not
+ search inside closed shadow roots or iframes.
+
+ Examples:
+
+ |
+ |
In the light dom
+ |
In the light dom, but goes into the shadow slot
+ |
+ |
+ |
+ | In the shadow dom
+ |
+ |
Deep in the shadow
+ |
+ |
+ |
+ |
+ |
+ |
+
+ Note that ```` is not an html element, but rather a shadow root
+ created with ``element.attachShadow({mode: 'open'})``.
+
+ - Both ``"css=article div"`` and ``"css:light=article div"`` match the first ``
In the light dom
``.
+ - Both ``"css=article > div"`` and ``"css:light=article > div"`` match two ``div`` elements that are direct children of the ``article``.
+ - ``"css=article .in-the-shadow"`` matches the ``
``, piercing the shadow root, while ``"css:light=article .in-the-shadow"`` does not match anything.
+ - ``"css:light=article div > span"`` does not match anything, because both light-dom ``div`` elements do not contain a ``span``.
+ - ``"css=article div > span"`` matches the ````, piercing the shadow root.
+ - ``"css=article > .in-the-shadow"`` does not match anything, because ``
`` is not a direct child of ``article``
+ - ``"css:light=article > .in-the-shadow"`` does not match anything.
+ - ``"css=article li#target"`` matches the ``
Deep in the shadow
``, piercing two shadow roots.
+
+ === text:light ===
+
+ ``text`` engine open pierces shadow roots similarly to ``css``, while ``text:light`` does not.
+ Text engine first searches for elements in the light dom in the iteration order, and then
+ recursively inside open shadow roots in the iteration order. It does not search inside
+ closed shadow roots or iframes.
+
+ === id, data-testid, data-test-id, data-test and their :light counterparts ===
+
+ Attribute engines are selecting based on the corresponding attribute value.
+ For example: ``data-test-id=foo`` is equivalent to ``css=[data-test-id="foo"]``,
+ and ``id:light=foo`` is equivalent to ``css:light=[id="foo"]``.
== Element reference syntax ==
@@ -103,8 +413,8 @@ class Browser(DynamicCore):
reference can be used as a *first* part of a selector by using a special selector
syntax `element=` like this:
- | ${ref}= | Get Element | .some_class |
- | | Click | element=${ref} >> .some_child |
+ | ${ref}= Get Element .some_class
+ | Click element=${ref} >> .some_child
The `.some_child` selector in the example is relative to the element referenced by ${ref}.
@@ -145,12 +455,12 @@ class Browser(DynamicCore):
== Examples ==
- | Keyword | Selector | Key | Assertion Operator | Assertion Expected |
- | Get Title | | | equal | Page Title |
- | Get Style | //*[@id="div-element"] | width | > | 100 |
- | Get Title | | | matches | \\\\w+\\\\s\\\\w+ |
- | Get Title | | | validate | value == "Login Page" |
- | Get Title | | | evaluate | value if value == "some value" else "something else" |
+ | *Keyword* | *Selector* | *Key* | *Assertion Operator* | *Assertion Expected* |
+ | `Get Title` | | | equal | Page Title |
+ | `Get Style` | //*[@id="div-element"] | width | > | 100 |
+ | `Get Title` | | | matches | \\\\w+\\\\s\\\\w+ |
+ | `Get Title` | | | validate | value == "Login Page" |
+ | `Get Title` | | | evaluate | value if value == "some value" else "something else" |
= Automatic page and context closing =
diff --git a/Browser/keywords/browser_control.py b/Browser/keywords/browser_control.py
index dc8d1974c..f6120b68f 100644
--- a/Browser/keywords/browser_control.py
+++ b/Browser/keywords/browser_control.py
@@ -56,7 +56,7 @@ def _get_screenshot_path(self, filename: str) -> Path:
def take_screenshot(self, filename: str = "", selector: str = ""):
"""Takes a screenshot of the current window and saves it to ``path``. Saves it as a png.
- ``filename`` Filename into which to save. The file will be saved into the robot framework output directory.
+ ``filename`` Filename into which to save. The file will be saved into the robot framework output directory by default.
String ``{index}`` in path will be replaced with a rolling number. Use this to not override filenames.
``selector`` Take a screenshot of the element matched by selector.
diff --git a/Browser/keywords/cookie.py b/Browser/keywords/cookie.py
index 4b7b7fe5f..2c173950d 100644
--- a/Browser/keywords/cookie.py
+++ b/Browser/keywords/cookie.py
@@ -100,13 +100,13 @@ def add_cookie(
``secure`` Sets the secure token.
- ``samesite`` Sets the samesite mode.
+ ``samesite`` < ``Strict`` | ``Lax`` | ``None`` > Sets the samesite mode.
Example:
- | `Add Cookie` | foo | bar | http://address.com/path/to/site | | # Using url argument. |
- | `Add Cookie` | foo | bar | domain=example.com | path=/foo/bar | # Using domain and url arguments. |
- | `Add Cookie` | foo | bar | http://address.com/path/to/site | expiry=2027-09-28 16:21:35 | # Expiry as timestamp. |
- | `Add Cookie` | foo | bar | http://address.com/path/to/site | expiry=1822137695 | # Expiry as epoch seconds. |
+ | `Add Cookie` foo bar http://address.com/path/to/site # Using url argument.
+ | `Add Cookie` foo bar domain=example.com path=/foo/bar # Using domain and url arguments.
+ | `Add Cookie` foo bar http://address.com/path/to/site expiry=2027-09-28 16:21:35 # Expiry as timestamp.
+ | `Add Cookie` foo bar http://address.com/path/to/site expiry=1822137695 # Expiry as epoch seconds.
"""
params = locals_to_params(locals())
if expires:
@@ -152,6 +152,8 @@ def get_cookie(
) -> Union[DotDict, str]:
"""Returns information of cookie with ``name`` as a Robot Framework dot dictionary or a string.
+ ``cookie`` Name of the cookie to be retrieved.
+
If ``return_type`` is ``dictionary`` or ``dict`` then keyword returns a of Robot Framework
[https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#accessing-list-and-dictionary-items|dot dictionary]
The dictionary contains all possible key value pairs of the cookie. If ``return_type`` is ``string`` or ``str``,
@@ -161,7 +163,7 @@ def get_cookie(
If no cookie is found with ``name`` keyword fails. The cookie dictionary contains
details about the cookie. Keys available in the dictionary are documented in the table below.
- | Value | Explanation |
+ | *Value* | *Explanation* |
| name | The name of a cookie, mandatory. |
| value | Value of the cookie, mandatory. |
| url | Define the scope of the cookie, what URLs the cookies should be sent to. |
@@ -177,9 +179,9 @@ def get_cookie(
for details about each attribute.
Example:
- | ${cookie} = | Get Cookie | Foobar |
- | Should Be Equal | ${cookie.value} | Tidii |
- | Should Be Equal | ${cookie.expiry.year} | ${2020} |
+ | ${cookie}= Get Cookie Foobar
+ | Should Be Equal ${cookie.value} Tidii
+ | Should Be Equal ${cookie.expiry.year} ${2020}
"""
_, cookies = self._get_cookies()
for cookie_dict in cookies:
diff --git a/Browser/keywords/device_descriptors.py b/Browser/keywords/device_descriptors.py
index 709996279..19096c0f2 100644
--- a/Browser/keywords/device_descriptors.py
+++ b/Browser/keywords/device_descriptors.py
@@ -35,10 +35,10 @@ def get_device(self, name: str):
before using ensure your active page is on that context.
Usage:
- | ${device}= | Get Device | iPhone X
- | | New Context | &{device}
- | | New Page |
- | | Get Viewport Size | returns { "width": 375, "height": 812 }
+ | ${device}= Get Device iPhone X
+ | New Context &{device}
+ | New Page
+ | Get Viewport Size returns { "width": 375, "height": 812 }
"""
with self.playwright.grpc_channel() as stub:
response = stub.GetDevice(Request().Device(name=name))
diff --git a/Browser/keywords/evaluation.py b/Browser/keywords/evaluation.py
index efe75957c..77887a07f 100644
--- a/Browser/keywords/evaluation.py
+++ b/Browser/keywords/evaluation.py
@@ -47,7 +47,7 @@ def highlight_elements(
``width`` Sets the width of the higlight border. Defaults to 2px.
- ``style`` Sets the style of the border. Defaults to dotted.
+ ``style`` < ``solid`` | ``dotted`` | ``double`` | ``dashed`` > Sets the style of the border. Defaults to dotted.
``color`` Sets the color of the border. Valid colors i.e. are:
``red``, ``blue``, ``yellow``, ``pink``, ``black``
diff --git a/Browser/keywords/getters.py b/Browser/keywords/getters.py
index 3a374435a..5ff0f2eee 100644
--- a/Browser/keywords/getters.py
+++ b/Browser/keywords/getters.py
@@ -198,7 +198,7 @@ def get_selected_options(
``selector`` Selector from which the info is to be retrieved. **Required**
``option_attribute`` Which attribute shall be returned/verified.
- Allowed values are ``<"value"|"label"|"text"|"index">``. Defaults to label.
+ Allowed values are ``< ``value`` | ``label`` | ``text`` | ``index`` >``. Defaults to label.
``assertion_operator`` See `Assertions` for further details. Defaults to None.
@@ -209,13 +209,13 @@ def get_selected_options(
Example:
- | `Select Options By` | label | //select[2] | Email | Mobile | | |
- | ${selected_list} | `Get Selected Options` | //select[2] | | | | # getter |
- | `Get Selected Options` | //select[2] | label | `==` | Mobile | Mail | #assertion content |
- | `Select Options By` | label | select#names | 2 | 4 | | |
- | `Get Selected Options` | select#names | index | `==` | 2 | 4 | #assertion index |
- | `Get Selected Options` | select#names | label | *= | Mikko | | #assertion contains |
- | `Get Selected Options` | select#names | label | validate | len(value) == 3 | | #assertion length |
+ | `Select Options By` label //select[2] Email Mobile
+ | ${selected_list} `Get Selected Options` //select[2] # getter
+ | `Get Selected Options` //select[2] label `==` Mobile Mail #assertion content
+ | `Select Options By` label select#names 2 4
+ | `Get Selected Options` select#names index `==` 2 4 #assertion index
+ | `Get Selected Options` select#names label *= Mikko #assertion contain
+ | `Get Selected Options` select#names label validate len(value) == 3 #assertion length
"""
with self.playwright.grpc_channel() as stub:
@@ -296,8 +296,6 @@ def get_element_count(
``assertion_operator`` See `Assertions` for further details. Defaults to None.
``expected_value`` Expected value for the counting
-
-
"""
with self.playwright.grpc_channel() as stub:
response = stub.GetElementCount(
@@ -460,15 +458,13 @@ def get_boundingbox(
See `Assertions` for further details for the assertion arguments. Defaults to None.
Example use:
- | ${bounding_box}= Get BoundingBox id=element # unfiltered
- | Log ${bounding_box} # {'x': 559.09375, 'y': 75.5, 'width': 188.796875, 'height': 18}
- | ${x}= Get BoundingBox id=element x # filtered
- | Log X: ${x} # X: 559.09375
+ | ${bounding_box}= Get BoundingBox id=element # unfiltered
+ | Log ${bounding_box} # {'x': 559.09375, 'y': 75.5, 'width': 188.796875, 'height': 18}
+ | ${x}= Get BoundingBox id=element x # filtered
+ | Log X: ${x} # X: 559.09375
| # Assertions:
- | Get BoundingBox id=element width > 180
- | Get BoundingBox id=element ALL validate value['x'] > value['y']*2
-
-
+ | Get BoundingBox id=element width > 180
+ | Get BoundingBox id=element ALL validate value['x'] > value['y']*2
"""
with self.playwright.grpc_channel() as stub:
response = stub.GetBoundingBox(Request.ElementSelector(selector=selector))
diff --git a/Browser/keywords/interaction.py b/Browser/keywords/interaction.py
index 4c99822c7..a036366f9 100644
--- a/Browser/keywords/interaction.py
+++ b/Browser/keywords/interaction.py
@@ -1,478 +1,478 @@
-import json
-from pathlib import Path
-from typing import Dict, Optional
-
-from robotlibcore import keyword # type: ignore
-
-from ..base import LibraryComponent
-from ..generated.playwright_pb2 import Request
-from ..utils import logger
-from ..utils.data_types import (
- AlertAction,
- KeyAction,
- KeyboardInputAction,
- KeyboardModifier,
- MouseButton,
- MouseButtonAction,
- MouseOptionsDict,
- SelectAttribute,
-)
-from ..utils.time_conversion import timestr_to_millisecs
-
-
-class Interaction(LibraryComponent):
- @keyword(tags=["Setter", "PageContent"])
- def type_text(
- self, selector: str, text: str, delay: str = "0 ms", clear: bool = True
- ):
- """Types the given ``text`` into the text field found by ``selector``.
-
- Sends a ``keydown``, ``keypress/input``, and ``keyup`` event for each
- character in the text.
-
- ``selector`` Selector of the text field. **Required**
-
- ``text`` Text for the text field. **Required**
-
- ``delay`` Delay between the single key strokes. It may be either a
- number or a Robot Framework time string. Time strings are fully
- explained in an appendix of Robot Framework User Guide. Defaults to ``0 ms``.
- Example: ``50 ms``
-
- ``clear`` Set to false, if the field shall not be cleared before typing.
- Defaults to true.
-
- See `Fill Text` for direct filling of the full text at once.
- """
- self._type_text(selector, text, delay, clear)
-
- @keyword(tags=["Setter", "PageContent"])
- def fill_text(self, selector: str, text: str):
- """Clears and fills the given ``text`` into the text field found by ``selector``.
-
- This method waits for an element matching the ``selector`` to appear,
- waits for actionability checks, focuses the element, fills it and
- triggers an input event after filling.
-
- If the element matching selector is not an ,