Skip to content

Developer Interface

This part of the documentation describes the interfaces for using pomcorn.

WebView

WebView

Class for storing basic shortcuts for interacting with the browser.

Source code in pomcorn/web_view.py
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
class WebView:
    """Class for storing basic shortcuts for interacting with the browser."""

    def __init__(
        self,
        webdriver: WebDriver,
        *,
        app_root: str,
        wait_timeout: float,
        poll_frequency: float = 0,
    ):
        """Initialize webview.

        Args:
            webdriver: Instance of a class for managing the browser.
            app_root: The URL of browser.
            wait_timeout: Number of seconds before timing out.
            poll_frequency: Time between checks of `wait` condition, lower
                interval - faster checks. This allows to improve overall tests
                speed.

        """
        self.webdriver = webdriver
        self.app_root = app_root
        self.wait_timeout = wait_timeout
        self.poll_frequency = poll_frequency
        self.wait = self.get_wait(self.wait_timeout)

    def init_element(
        self,
        locator: TInitLocator,
    ) -> PomcornElement[TInitLocator]:
        """Shortcut for initializing Element instances.

        Note: To be consistent with the method of the same name in
        ``Component``, try to use keyword when specifying the ``locator``
        argument whenever possible.

        Args:
            locator: Instance of a class to locate the element in the browser.

        """
        return PomcornElement(web_view=self, locator=locator)

    def init_elements(
        self,
        locator: locators.XPathLocator,
    ) -> list[XPathElement]:
        """Shortcut for initializing many Element instances via single locator.

        Note: Only supports Xpath locators.

        Note: To be consistent with the method of the same name in
        ``Component``, try to use keyword when specifying the ``locator``
        argument whenever possible.

        Args:
            locator: Instance of a class to locate the element in the browser.

        """
        assert isinstance(
            locator,
            locators.XPathLocator,
        ), "Only supports Xpath locators!"
        elements_count = len(self._get_elements(locator=locator))
        return [
            self.init_element(
                locator=locators.XPathLocator(
                    query=f"({locator.query})[{index + 1}]",
                ),
            )
            for index in range(elements_count)
        ]

    def iter_locators(
        self,
        locator: locators.XPathLocator,
        only_visible: bool = False,
    ) -> list[locators.XPathLocator]:
        """Get the list of the locators where each of them match an element.

        For example, there are multiple elements on the page that matches
        `XPathLocator("//a")`.

        This method return the set of locators like:
        * `XPathLocator("(//a)[1]")`
        * `XPathLocator("(//a)[2]")`

        Args:
            locator: Instance of a class to locate the element in the browser.
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements,
                otherwise all the elements (including not visible) will be
                counted.

        """
        elements_count = len(
            self._get_elements(locator=locator, only_visible=only_visible),
        )
        # Need to wrap it into parentheses to iterate by index when locator
        # is complex: https://sqa.stackexchange.com/a/39465
        return [
            locators.XPathLocator(query=f"({locator.query})[{index}]")
            for index in range(1, elements_count + 1)
        ]

    def get_wait(
        self,
        timeout: float | None = None,
    ) -> WebDriverWait[WebDriver]:
        """Get `WebDriverWait` instance.

        If no arguments are provided, returns the default wait instance.

        """
        if not timeout:
            return self.wait

        return WebDriverWait(
            driver=self.webdriver,
            timeout=timeout,
            poll_frequency=self.poll_frequency,
        )

    @property
    def current_url(self) -> str:
        """Return the current webdriver URL."""
        return self.webdriver.current_url

    def _get_element(
        self,
        locator: locators.Locator,
        only_visible: bool = True,
    ) -> WebElement:
        """Get WebElement from page by using locator.

        Args:
            locator: Instance of a class to locate the element in the browser.
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements,
                otherwise all the elements (including not visible) will be
                counted.

        """
        if only_visible:
            self.wait_until_locator_visible(locator=locator)
        return self.webdriver.find_element(*locator)

    def _get_elements(
        self,
        locator: locators.Locator,
        only_visible: bool = False,
    ) -> list[WebElement]:
        """Get WebElements from page by using locator.

        Args:
            locator: Instance of a class to locate the element in the browser.
            only_visible: Flag for viewing visible elements. If this is `True`,
                then this method will only get visible elements, otherwise
                all (default) the elements (including not visible) will be
                counted.

        """
        if only_visible:
            self.wait_until_locator_visible(locator=locator)
        return self.webdriver.find_elements(*locator)

    def wait_until_url_contains(
        self,
        url: str,
        timeout: float | None = None,
    ) -> None:
        """Wait until browser's url contains input url.

        By default, method waits for `self.wait_timeout` seconds.
        If you need to change timeout, you can specify it in `timeout`
        argument.

        Raises:
            TimeoutException: If after `self.wait._timeout` seconds the wait
                has not ended.

        """
        wait = self.get_wait(timeout)
        wait.until(
            method=expected_conditions.url_contains(url),
            message=(
                f"Url doesn't contain `{url}` in {wait._timeout} "
                f"seconds! The current URL is `{self.current_url}`."
            ),
        )

    def wait_until_url_not_contains(
        self,
        url: str,
        timeout: float | None = None,
    ) -> None:
        """Wait until browser's url doesn't not contains input url.

        By default, method waits for `self.wait_timeout` seconds.
        If you need to change timeout, you can specify it in `timeout`
        argument.

        Raises:
            TimeoutException: If after `self.wait._timeout` seconds the wait
                has not ended.

        """
        wait = self.get_wait(timeout)
        wait.until(
            method=waits_conditions.url_not_matches(url),
            message=(
                f"Url does contain `{url}` in {wait._timeout} seconds! "
                f"The current URL is `{self.current_url}`."
            ),
        )

    def wait_until_url_changes(
        self,
        url: str | None = None,
        timeout: float | None = None,
    ) -> None:
        """Wait until url changes.

        Args:
            url: Browser URL which should be changed. If the argument is not
                input, will be used `self.current_url`.
            timeout: Number of seconds to wait until timing out. By default,
                method waits for `self.wait_timeout` seconds.

        Raises:
            TimeoutException: If after `self.wait._timeout` seconds the wait
                has not ended.

        """
        url = url or self.current_url
        wait = self.get_wait(timeout)
        wait.until(
            method=expected_conditions.url_changes(url),
            message=(
                f"Url didn't changed from {url} in {wait._timeout} "
                f"seconds! The current URL is `{self.current_url}`."
            ),
        )

    def wait_until_locator_visible(
        self,
        locator: locators.Locator,
        timeout: float | None = None,
    ) -> None:
        """Wait until element matching locator becomes visible.

        Args:
            locator: Instance of a class to locate the element in the browser.
            timeout: Number of seconds to wait until timing out. By default,
                method waits for `self.wait_timeout` seconds.

        Raises:
            TimeoutException: If after `self.wait._timeout` seconds the wait
                has not ended.

        """
        wait = self.get_wait(timeout)
        wait.until(
            method=expected_conditions.visibility_of_element_located(
                locator=(locator.by, locator.query),
            ),
            message=(
                f"Unable to locate {locator} in {wait._timeout} seconds!"
            ),
        )

    def wait_until_locator_invisible(
        self,
        locator: locators.Locator,
        timeout: float | None = None,
    ) -> None:
        """Wait until element matching locator becomes invisible.

        Args:
            locator: Instance of a class to locate the element in the browser.
            timeout: Number of seconds to wait until timing out. By default,
                method waits for `self.wait_timeout` seconds.

        Raises:
            TimeoutException: If after `self.wait._timeout` seconds the wait
                has not ended.

        """
        wait = self.get_wait(timeout)
        wait.until(
            method=expected_conditions.invisibility_of_element_located(
                locator=(locator.by, locator.query),
            ),
            message=(
                f"{locator} is still visible in {wait._timeout} seconds!"
            ),
        )

    def wait_until_clickable(
        self,
        locator: locators.Locator,
        timeout: float | None = None,
    ) -> None:
        """Wait until element matching locator becomes clickable.

        Args:
            locator: Instance of a class to locate the element in the browser.
            timeout: Number of seconds to wait until timing out. By default,
                method waits for `self.wait_timeout` seconds.

        Raises:
            TimeoutException: If after `self.wait._timeout` seconds the wait
                has not ended.

        """
        wait = self.get_wait(timeout)
        wait.until(
            method=expected_conditions.element_to_be_clickable(
                mark=(locator.by, locator.query),
            ),
            message=(
                f"{locator} isn't clickable after {wait._timeout} seconds!"
            ),
        )

    def wait_until_text_is_in_element(
        self,
        text: str,
        locator: locators.Locator,
        timeout: float | None = None,
    ) -> None:
        """Wait until text is present in the specified element by locator.

        Args:
            locator: Instance of a class to locate the element in the browser.
            text: Text that should be presented in element.
            timeout: Number of seconds to wait until timing out. By default,
                method waits for `self.wait_timeout` seconds.

        Raises:
            TimeoutException: If after `self.wait._timeout` seconds the wait
                has not ended.

        """
        wait = self.get_wait(timeout)
        wait.until(
            method=expected_conditions.text_to_be_present_in_element(
                locator=(locator.by, locator.query),
                text_=text,
            ),
            message=(
                f"{locator} doesn't have `{text}` after {wait._timeout} "
                "seconds!"
            ),
        )

    def wait_until_not_exists_in_dom(
        self,
        element: PomcornElement[locators.TLocator_co] | locators.TLocator_co,
        timeout: float | None = None,
    ):
        """Wait until element ceases to exist in DOM.

        Args:
            element: Instance of a class to locate the element in the browser
                or instance of element.
            timeout: Number of seconds to wait until timing out. By default,
                method waits for `self.wait_timeout` seconds.

        Raises:
            TimeoutException: If after `self.wait._timeout` seconds the wait
                has not ended.

        """
        wait = self.get_wait(timeout)
        wait.until(
            method=waits_conditions.element_not_exists_in_dom(element),
            message=(
                f"{element} is still exists in DOM after {wait._timeout} "
                "seconds!"
            ),
        )

    def drag_and_drop(self, source: WebElement, target: WebElement):
        """Perform drag and drop.

        Args:
            source: The web element instance to drag.
            target: The web element instance to drag into.

        """
        ActionChains(self.webdriver).drag_and_drop(source, target).perform()

    def scroll_to(self, target: WebElement):
        """Scroll page to target.

        Scroll to the center of target vertically and to the center of target
        horizontally.

        Args:
            target: The web element instance to scroll to.

        """
        # behavior="instant" - to scroll without animation
        # block="center" - vertical scrolling up to center
        # inline="center"- horizontal scrolling up to center
        script = (
            "arguments[0].scrollIntoView("
            "{behavior: 'instant', block: 'center', inline: 'center'}"
            ");"
        )
        self.webdriver.execute_script(script, target)

    def scroll_to_top(self):
        """Scroll browser to top."""
        self.webdriver.execute_script(
            script="window.scrollBy(0, -document.body.scrollHeight)",
        )

    def scroll_to_bottom(self):
        """Scroll browser to bottom."""
        self.webdriver.execute_script(
            script="window.scrollBy(0, document.body.scrollHeight)",
        )

    def get_input_value(self, label: str) -> str:
        """Find input element by label and get it's value."""
        return self.init_element(
            locator=locators.InputByLabelLocator(label=label),
        ).get_value()

    def execute_javascript(self, script: str, *args):
        """Execute simple javascript.

        Args:
            script: JavaScript code as a string object.
            *args: Any applicable arguments for your JavaScript.

        """
        self.webdriver.execute_script(script, *args)

    def switch_to_default(self):
        """Switch webdriver's focus to default content."""
        self.webdriver.switch_to.default_content()

    def switch_to_iframe(self, locator: locators.Locator):
        """Switch webdriver's focus to iframe.

        Args:
            locator: Instance of a class to locate the element in the browser.

        """
        self.webdriver.switch_to.frame(self._get_element(locator))

    @contextmanager
    def iframe_switcher_manager(self, locator: locators.Locator):
        """Context manager for interacting with iframes.

        Args:
            locator: Instance of a class to locate the element in the browser.

        """
        self.switch_to_iframe(locator=locator)
        yield
        self.switch_to_default()

current_url property

Return the current webdriver URL.

__init__(webdriver, *, app_root, wait_timeout, poll_frequency=0)

Initialize webview.

Parameters:

Name Type Description Default
webdriver WebDriver

Instance of a class for managing the browser.

required
app_root str

The URL of browser.

required
wait_timeout float

Number of seconds before timing out.

required
poll_frequency float

Time between checks of wait condition, lower interval - faster checks. This allows to improve overall tests speed.

0
Source code in pomcorn/web_view.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def __init__(
    self,
    webdriver: WebDriver,
    *,
    app_root: str,
    wait_timeout: float,
    poll_frequency: float = 0,
):
    """Initialize webview.

    Args:
        webdriver: Instance of a class for managing the browser.
        app_root: The URL of browser.
        wait_timeout: Number of seconds before timing out.
        poll_frequency: Time between checks of `wait` condition, lower
            interval - faster checks. This allows to improve overall tests
            speed.

    """
    self.webdriver = webdriver
    self.app_root = app_root
    self.wait_timeout = wait_timeout
    self.poll_frequency = poll_frequency
    self.wait = self.get_wait(self.wait_timeout)

drag_and_drop(source, target)

Perform drag and drop.

Parameters:

Name Type Description Default
source WebElement

The web element instance to drag.

required
target WebElement

The web element instance to drag into.

required
Source code in pomcorn/web_view.py
399
400
401
402
403
404
405
406
407
def drag_and_drop(self, source: WebElement, target: WebElement):
    """Perform drag and drop.

    Args:
        source: The web element instance to drag.
        target: The web element instance to drag into.

    """
    ActionChains(self.webdriver).drag_and_drop(source, target).perform()

execute_javascript(script, *args)

Execute simple javascript.

Parameters:

Name Type Description Default
script str

JavaScript code as a string object.

required
*args

Any applicable arguments for your JavaScript.

()
Source code in pomcorn/web_view.py
447
448
449
450
451
452
453
454
455
def execute_javascript(self, script: str, *args):
    """Execute simple javascript.

    Args:
        script: JavaScript code as a string object.
        *args: Any applicable arguments for your JavaScript.

    """
    self.webdriver.execute_script(script, *args)

get_input_value(label)

Find input element by label and get it's value.

Source code in pomcorn/web_view.py
441
442
443
444
445
def get_input_value(self, label: str) -> str:
    """Find input element by label and get it's value."""
    return self.init_element(
        locator=locators.InputByLabelLocator(label=label),
    ).get_value()

get_wait(timeout=None)

Get WebDriverWait instance.

If no arguments are provided, returns the default wait instance.

Source code in pomcorn/web_view.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
def get_wait(
    self,
    timeout: float | None = None,
) -> WebDriverWait[WebDriver]:
    """Get `WebDriverWait` instance.

    If no arguments are provided, returns the default wait instance.

    """
    if not timeout:
        return self.wait

    return WebDriverWait(
        driver=self.webdriver,
        timeout=timeout,
        poll_frequency=self.poll_frequency,
    )

iframe_switcher_manager(locator)

Context manager for interacting with iframes.

Parameters:

Name Type Description Default
locator Locator

Instance of a class to locate the element in the browser.

required
Source code in pomcorn/web_view.py
470
471
472
473
474
475
476
477
478
479
480
@contextmanager
def iframe_switcher_manager(self, locator: locators.Locator):
    """Context manager for interacting with iframes.

    Args:
        locator: Instance of a class to locate the element in the browser.

    """
    self.switch_to_iframe(locator=locator)
    yield
    self.switch_to_default()

init_element(locator)

Shortcut for initializing Element instances.

Note: To be consistent with the method of the same name in Component, try to use keyword when specifying the locator argument whenever possible.

Parameters:

Name Type Description Default
locator TInitLocator

Instance of a class to locate the element in the browser.

required
Source code in pomcorn/web_view.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def init_element(
    self,
    locator: TInitLocator,
) -> PomcornElement[TInitLocator]:
    """Shortcut for initializing Element instances.

    Note: To be consistent with the method of the same name in
    ``Component``, try to use keyword when specifying the ``locator``
    argument whenever possible.

    Args:
        locator: Instance of a class to locate the element in the browser.

    """
    return PomcornElement(web_view=self, locator=locator)

init_elements(locator)

Shortcut for initializing many Element instances via single locator.

Note: Only supports Xpath locators.

Note: To be consistent with the method of the same name in Component, try to use keyword when specifying the locator argument whenever possible.

Parameters:

Name Type Description Default
locator XPathLocator

Instance of a class to locate the element in the browser.

required
Source code in pomcorn/web_view.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
def init_elements(
    self,
    locator: locators.XPathLocator,
) -> list[XPathElement]:
    """Shortcut for initializing many Element instances via single locator.

    Note: Only supports Xpath locators.

    Note: To be consistent with the method of the same name in
    ``Component``, try to use keyword when specifying the ``locator``
    argument whenever possible.

    Args:
        locator: Instance of a class to locate the element in the browser.

    """
    assert isinstance(
        locator,
        locators.XPathLocator,
    ), "Only supports Xpath locators!"
    elements_count = len(self._get_elements(locator=locator))
    return [
        self.init_element(
            locator=locators.XPathLocator(
                query=f"({locator.query})[{index + 1}]",
            ),
        )
        for index in range(elements_count)
    ]

iter_locators(locator, only_visible=False)

Get the list of the locators where each of them match an element.

For example, there are multiple elements on the page that matches XPathLocator("//a").

This method return the set of locators like: * XPathLocator("(//a)[1]") * XPathLocator("(//a)[2]")

Parameters:

Name Type Description Default
locator XPathLocator

Instance of a class to locate the element in the browser.

required
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements, otherwise all the elements (including not visible) will be counted.

False
Source code in pomcorn/web_view.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
def iter_locators(
    self,
    locator: locators.XPathLocator,
    only_visible: bool = False,
) -> list[locators.XPathLocator]:
    """Get the list of the locators where each of them match an element.

    For example, there are multiple elements on the page that matches
    `XPathLocator("//a")`.

    This method return the set of locators like:
    * `XPathLocator("(//a)[1]")`
    * `XPathLocator("(//a)[2]")`

    Args:
        locator: Instance of a class to locate the element in the browser.
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements,
            otherwise all the elements (including not visible) will be
            counted.

    """
    elements_count = len(
        self._get_elements(locator=locator, only_visible=only_visible),
    )
    # Need to wrap it into parentheses to iterate by index when locator
    # is complex: https://sqa.stackexchange.com/a/39465
    return [
        locators.XPathLocator(query=f"({locator.query})[{index}]")
        for index in range(1, elements_count + 1)
    ]

scroll_to(target)

Scroll page to target.

Scroll to the center of target vertically and to the center of target horizontally.

Parameters:

Name Type Description Default
target WebElement

The web element instance to scroll to.

required
Source code in pomcorn/web_view.py
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
def scroll_to(self, target: WebElement):
    """Scroll page to target.

    Scroll to the center of target vertically and to the center of target
    horizontally.

    Args:
        target: The web element instance to scroll to.

    """
    # behavior="instant" - to scroll without animation
    # block="center" - vertical scrolling up to center
    # inline="center"- horizontal scrolling up to center
    script = (
        "arguments[0].scrollIntoView("
        "{behavior: 'instant', block: 'center', inline: 'center'}"
        ");"
    )
    self.webdriver.execute_script(script, target)

scroll_to_bottom()

Scroll browser to bottom.

Source code in pomcorn/web_view.py
435
436
437
438
439
def scroll_to_bottom(self):
    """Scroll browser to bottom."""
    self.webdriver.execute_script(
        script="window.scrollBy(0, document.body.scrollHeight)",
    )

scroll_to_top()

Scroll browser to top.

Source code in pomcorn/web_view.py
429
430
431
432
433
def scroll_to_top(self):
    """Scroll browser to top."""
    self.webdriver.execute_script(
        script="window.scrollBy(0, -document.body.scrollHeight)",
    )

switch_to_default()

Switch webdriver's focus to default content.

Source code in pomcorn/web_view.py
457
458
459
def switch_to_default(self):
    """Switch webdriver's focus to default content."""
    self.webdriver.switch_to.default_content()

switch_to_iframe(locator)

Switch webdriver's focus to iframe.

Parameters:

Name Type Description Default
locator Locator

Instance of a class to locate the element in the browser.

required
Source code in pomcorn/web_view.py
461
462
463
464
465
466
467
468
def switch_to_iframe(self, locator: locators.Locator):
    """Switch webdriver's focus to iframe.

    Args:
        locator: Instance of a class to locate the element in the browser.

    """
    self.webdriver.switch_to.frame(self._get_element(locator))

wait_until_clickable(locator, timeout=None)

Wait until element matching locator becomes clickable.

Parameters:

Name Type Description Default
locator Locator

Instance of a class to locate the element in the browser.

required
timeout float | None

Number of seconds to wait until timing out. By default, method waits for self.wait_timeout seconds.

None

Raises:

Type Description
TimeoutException

If after self.wait._timeout seconds the wait has not ended.

Source code in pomcorn/web_view.py
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
def wait_until_clickable(
    self,
    locator: locators.Locator,
    timeout: float | None = None,
) -> None:
    """Wait until element matching locator becomes clickable.

    Args:
        locator: Instance of a class to locate the element in the browser.
        timeout: Number of seconds to wait until timing out. By default,
            method waits for `self.wait_timeout` seconds.

    Raises:
        TimeoutException: If after `self.wait._timeout` seconds the wait
            has not ended.

    """
    wait = self.get_wait(timeout)
    wait.until(
        method=expected_conditions.element_to_be_clickable(
            mark=(locator.by, locator.query),
        ),
        message=(
            f"{locator} isn't clickable after {wait._timeout} seconds!"
        ),
    )

wait_until_locator_invisible(locator, timeout=None)

Wait until element matching locator becomes invisible.

Parameters:

Name Type Description Default
locator Locator

Instance of a class to locate the element in the browser.

required
timeout float | None

Number of seconds to wait until timing out. By default, method waits for self.wait_timeout seconds.

None

Raises:

Type Description
TimeoutException

If after self.wait._timeout seconds the wait has not ended.

Source code in pomcorn/web_view.py
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
def wait_until_locator_invisible(
    self,
    locator: locators.Locator,
    timeout: float | None = None,
) -> None:
    """Wait until element matching locator becomes invisible.

    Args:
        locator: Instance of a class to locate the element in the browser.
        timeout: Number of seconds to wait until timing out. By default,
            method waits for `self.wait_timeout` seconds.

    Raises:
        TimeoutException: If after `self.wait._timeout` seconds the wait
            has not ended.

    """
    wait = self.get_wait(timeout)
    wait.until(
        method=expected_conditions.invisibility_of_element_located(
            locator=(locator.by, locator.query),
        ),
        message=(
            f"{locator} is still visible in {wait._timeout} seconds!"
        ),
    )

wait_until_locator_visible(locator, timeout=None)

Wait until element matching locator becomes visible.

Parameters:

Name Type Description Default
locator Locator

Instance of a class to locate the element in the browser.

required
timeout float | None

Number of seconds to wait until timing out. By default, method waits for self.wait_timeout seconds.

None

Raises:

Type Description
TimeoutException

If after self.wait._timeout seconds the wait has not ended.

Source code in pomcorn/web_view.py
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
def wait_until_locator_visible(
    self,
    locator: locators.Locator,
    timeout: float | None = None,
) -> None:
    """Wait until element matching locator becomes visible.

    Args:
        locator: Instance of a class to locate the element in the browser.
        timeout: Number of seconds to wait until timing out. By default,
            method waits for `self.wait_timeout` seconds.

    Raises:
        TimeoutException: If after `self.wait._timeout` seconds the wait
            has not ended.

    """
    wait = self.get_wait(timeout)
    wait.until(
        method=expected_conditions.visibility_of_element_located(
            locator=(locator.by, locator.query),
        ),
        message=(
            f"Unable to locate {locator} in {wait._timeout} seconds!"
        ),
    )

wait_until_not_exists_in_dom(element, timeout=None)

Wait until element ceases to exist in DOM.

Parameters:

Name Type Description Default
element PomcornElement[TLocator_co] | TLocator_co

Instance of a class to locate the element in the browser or instance of element.

required
timeout float | None

Number of seconds to wait until timing out. By default, method waits for self.wait_timeout seconds.

None

Raises:

Type Description
TimeoutException

If after self.wait._timeout seconds the wait has not ended.

Source code in pomcorn/web_view.py
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
def wait_until_not_exists_in_dom(
    self,
    element: PomcornElement[locators.TLocator_co] | locators.TLocator_co,
    timeout: float | None = None,
):
    """Wait until element ceases to exist in DOM.

    Args:
        element: Instance of a class to locate the element in the browser
            or instance of element.
        timeout: Number of seconds to wait until timing out. By default,
            method waits for `self.wait_timeout` seconds.

    Raises:
        TimeoutException: If after `self.wait._timeout` seconds the wait
            has not ended.

    """
    wait = self.get_wait(timeout)
    wait.until(
        method=waits_conditions.element_not_exists_in_dom(element),
        message=(
            f"{element} is still exists in DOM after {wait._timeout} "
            "seconds!"
        ),
    )

wait_until_text_is_in_element(text, locator, timeout=None)

Wait until text is present in the specified element by locator.

Parameters:

Name Type Description Default
locator Locator

Instance of a class to locate the element in the browser.

required
text str

Text that should be presented in element.

required
timeout float | None

Number of seconds to wait until timing out. By default, method waits for self.wait_timeout seconds.

None

Raises:

Type Description
TimeoutException

If after self.wait._timeout seconds the wait has not ended.

Source code in pomcorn/web_view.py
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
def wait_until_text_is_in_element(
    self,
    text: str,
    locator: locators.Locator,
    timeout: float | None = None,
) -> None:
    """Wait until text is present in the specified element by locator.

    Args:
        locator: Instance of a class to locate the element in the browser.
        text: Text that should be presented in element.
        timeout: Number of seconds to wait until timing out. By default,
            method waits for `self.wait_timeout` seconds.

    Raises:
        TimeoutException: If after `self.wait._timeout` seconds the wait
            has not ended.

    """
    wait = self.get_wait(timeout)
    wait.until(
        method=expected_conditions.text_to_be_present_in_element(
            locator=(locator.by, locator.query),
            text_=text,
        ),
        message=(
            f"{locator} doesn't have `{text}` after {wait._timeout} "
            "seconds!"
        ),
    )

wait_until_url_changes(url=None, timeout=None)

Wait until url changes.

Parameters:

Name Type Description Default
url str | None

Browser URL which should be changed. If the argument is not input, will be used self.current_url.

None
timeout float | None

Number of seconds to wait until timing out. By default, method waits for self.wait_timeout seconds.

None

Raises:

Type Description
TimeoutException

If after self.wait._timeout seconds the wait has not ended.

Source code in pomcorn/web_view.py
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
def wait_until_url_changes(
    self,
    url: str | None = None,
    timeout: float | None = None,
) -> None:
    """Wait until url changes.

    Args:
        url: Browser URL which should be changed. If the argument is not
            input, will be used `self.current_url`.
        timeout: Number of seconds to wait until timing out. By default,
            method waits for `self.wait_timeout` seconds.

    Raises:
        TimeoutException: If after `self.wait._timeout` seconds the wait
            has not ended.

    """
    url = url or self.current_url
    wait = self.get_wait(timeout)
    wait.until(
        method=expected_conditions.url_changes(url),
        message=(
            f"Url didn't changed from {url} in {wait._timeout} "
            f"seconds! The current URL is `{self.current_url}`."
        ),
    )

wait_until_url_contains(url, timeout=None)

Wait until browser's url contains input url.

By default, method waits for self.wait_timeout seconds. If you need to change timeout, you can specify it in timeout argument.

Raises:

Type Description
TimeoutException

If after self.wait._timeout seconds the wait has not ended.

Source code in pomcorn/web_view.py
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
def wait_until_url_contains(
    self,
    url: str,
    timeout: float | None = None,
) -> None:
    """Wait until browser's url contains input url.

    By default, method waits for `self.wait_timeout` seconds.
    If you need to change timeout, you can specify it in `timeout`
    argument.

    Raises:
        TimeoutException: If after `self.wait._timeout` seconds the wait
            has not ended.

    """
    wait = self.get_wait(timeout)
    wait.until(
        method=expected_conditions.url_contains(url),
        message=(
            f"Url doesn't contain `{url}` in {wait._timeout} "
            f"seconds! The current URL is `{self.current_url}`."
        ),
    )

wait_until_url_not_contains(url, timeout=None)

Wait until browser's url doesn't not contains input url.

By default, method waits for self.wait_timeout seconds. If you need to change timeout, you can specify it in timeout argument.

Raises:

Type Description
TimeoutException

If after self.wait._timeout seconds the wait has not ended.

Source code in pomcorn/web_view.py
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
def wait_until_url_not_contains(
    self,
    url: str,
    timeout: float | None = None,
) -> None:
    """Wait until browser's url doesn't not contains input url.

    By default, method waits for `self.wait_timeout` seconds.
    If you need to change timeout, you can specify it in `timeout`
    argument.

    Raises:
        TimeoutException: If after `self.wait._timeout` seconds the wait
            has not ended.

    """
    wait = self.get_wait(timeout)
    wait.until(
        method=waits_conditions.url_not_matches(url),
        message=(
            f"Url does contain `{url}` in {wait._timeout} seconds! "
            f"The current URL is `{self.current_url}`."
        ),
    )

Page

Page

Bases: WebView

The class for representing a web page.

It contains the element and components of the page and utils methods for page manipulation.

Source code in pomcorn/page.py
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
class Page(WebView):
    """The class for representing a web page.

    It contains the element and components of the page and utils methods for
    page manipulation.

    """

    APP_ROOT: str

    def __init__(
        self,
        webdriver: WebDriver,
        *,
        app_root: str | None = None,
        wait_timeout: float = 5.0,
        poll_frequency: float = 0.01,
    ):
        """Initialize page.

        Call `wait_until_loaded` method after initialization.

        Args:
            webdriver: Instance of a class for managing the browser.
            app_root: The URL of base page, by default the value of `APP_ROOT`
                attribute is used.
            wait_timeout: Number of seconds before timing out.
            poll_frequency: Time between checks of `wait` condition, lower
                interval - faster checks. This allows to improve overall tests
                speed.

        """
        super().__init__(
            webdriver,
            app_root=app_root or self.APP_ROOT,
            wait_timeout=wait_timeout,
            poll_frequency=poll_frequency,
        )
        self.wait_until_loaded()

    def check_page_is_loaded(self) -> bool:
        """Return result of check that the page is loaded.

        Some pages can be slow to load and cause problems checking for unloaded
        items. To be sure the page is loaded, this property should return the
        result of checking for the slowest parts of the page.

        """
        return True

    @classmethod
    def open(
        cls,
        webdriver: WebDriver,
        *,
        app_root: str | None = None,
    ) -> Self:
        """Open page and initialize page object.

        Args:
            webdriver: Instance of a WebDriver class for managing the browser.
            app_root: The URL of page, by default the value of `APP_ROOT`
                attribute is used.

        """
        webdriver.get(url=f"{app_root or cls.APP_ROOT}")
        # hack to not specify app_root in each page init method
        kwargs = {}
        if app_root:
            kwargs = {"app_root": app_root}

        # Mypy raise error on unpacking `kwargs`:
        # "Page" has incompatible type "**dict[str, str]"; expected "int"
        # "Page" has incompatible type "**dict[str, str]"; expected "float"
        return cls(webdriver, **kwargs)  # type: ignore

    @classmethod
    def open_from_url(
        cls,
        webdriver: WebDriver,
        *,
        path: str,
        app_root: str | None = None,
        **kwargs,
    ) -> Self:
        """Open page from relative path and initialize page object.

        Add `path` to `app_root` in browser URL.

        Args:
            webdriver: Instance of a WebDriver class for managing the browser.
            app_root: The URL of page, by default the value of `APP_ROOT`
                attribute is used.
            path: Relative URL.
            **kwargs: Additional arguments passed to the
                page object initialization.

        """
        # hack to not specify app_root in each page init method
        if app_root:
            kwargs["app_root"] = app_root

        # We don't use `page.navigate_relative` here because we need to
        # navigate to relative url before page is initialized, since otherwise
        # `wait_until_loaded` method in page `__init__` method might fail.
        webdriver.get(
            url=cls._get_full_relative_url(app_root or cls.APP_ROOT, path),
        )

        page = cls(webdriver, **kwargs)
        return page

    def refresh(self) -> None:
        """Refresh web page and wait until it is loaded."""
        self.webdriver.refresh()
        self.wait_until_loaded()

    def wait_until_loaded(self, timeout: float | None = None) -> None:
        """Wait until page is loaded."""
        wait = self.get_wait(timeout)
        wait.until(
            method=lambda _: self.check_page_is_loaded(),
            message=(
                f"Page `{self.__class__}` didn't loaded in "
                f"{wait._timeout} seconds! Didn't wait for `True` from "
                "`check_page_is_loaded` method."
            ),
        )

    def navigate(self, url: str) -> None:
        """Navigate absolute URL.

        Replace the browser URL with the entered one.

        """
        self.webdriver.get(url)

    def navigate_relative(self, relative_url: str = "/") -> None:
        """Navigate to URL relative to application root.

        Args:
            relative_url (str): Relative URL

        """
        self.webdriver.get(
            self._get_full_relative_url(self.app_root, relative_url),
        )

    def click_on_page(self) -> None:
        """Click on (1, 1) coordinates of page (left upper corner).

        Allows you to move focus away from an element, for example, if it
        is currently unavailable for interaction.

        """
        from selenium.webdriver.common.actions.action_builder import (
            ActionBuilder,
        )

        action = ActionBuilder(self.webdriver)
        action.pointer_action.move_to_location(1, 1).click()
        action.perform()

    @staticmethod
    def _get_full_relative_url(app_root: str, relative_url: str) -> str:
        """Add relative URL to application root URL.

        Args:
            app_root: The URL of page, by default the value of `APP_ROOT`
                attribute is used.
            relative_url (str): Relative URL

        """
        # https://www.youtube.com/ -> https://www.youtube.com
        app_root = app_root.removesuffix("/")
        # /watch_list -> watch_list
        relative_url = relative_url.removeprefix("/")

        return f"{app_root}/{relative_url}"

__init__(webdriver, *, app_root=None, wait_timeout=5.0, poll_frequency=0.01)

Initialize page.

Call wait_until_loaded method after initialization.

Parameters:

Name Type Description Default
webdriver WebDriver

Instance of a class for managing the browser.

required
app_root str | None

The URL of base page, by default the value of APP_ROOT attribute is used.

None
wait_timeout float

Number of seconds before timing out.

5.0
poll_frequency float

Time between checks of wait condition, lower interval - faster checks. This allows to improve overall tests speed.

0.01
Source code in pomcorn/page.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
def __init__(
    self,
    webdriver: WebDriver,
    *,
    app_root: str | None = None,
    wait_timeout: float = 5.0,
    poll_frequency: float = 0.01,
):
    """Initialize page.

    Call `wait_until_loaded` method after initialization.

    Args:
        webdriver: Instance of a class for managing the browser.
        app_root: The URL of base page, by default the value of `APP_ROOT`
            attribute is used.
        wait_timeout: Number of seconds before timing out.
        poll_frequency: Time between checks of `wait` condition, lower
            interval - faster checks. This allows to improve overall tests
            speed.

    """
    super().__init__(
        webdriver,
        app_root=app_root or self.APP_ROOT,
        wait_timeout=wait_timeout,
        poll_frequency=poll_frequency,
    )
    self.wait_until_loaded()

check_page_is_loaded()

Return result of check that the page is loaded.

Some pages can be slow to load and cause problems checking for unloaded items. To be sure the page is loaded, this property should return the result of checking for the slowest parts of the page.

Source code in pomcorn/page.py
48
49
50
51
52
53
54
55
56
def check_page_is_loaded(self) -> bool:
    """Return result of check that the page is loaded.

    Some pages can be slow to load and cause problems checking for unloaded
    items. To be sure the page is loaded, this property should return the
    result of checking for the slowest parts of the page.

    """
    return True

click_on_page()

Click on (1, 1) coordinates of page (left upper corner).

Allows you to move focus away from an element, for example, if it is currently unavailable for interaction.

Source code in pomcorn/page.py
156
157
158
159
160
161
162
163
164
165
166
167
168
169
def click_on_page(self) -> None:
    """Click on (1, 1) coordinates of page (left upper corner).

    Allows you to move focus away from an element, for example, if it
    is currently unavailable for interaction.

    """
    from selenium.webdriver.common.actions.action_builder import (
        ActionBuilder,
    )

    action = ActionBuilder(self.webdriver)
    action.pointer_action.move_to_location(1, 1).click()
    action.perform()

navigate(url)

Navigate absolute URL.

Replace the browser URL with the entered one.

Source code in pomcorn/page.py
137
138
139
140
141
142
143
def navigate(self, url: str) -> None:
    """Navigate absolute URL.

    Replace the browser URL with the entered one.

    """
    self.webdriver.get(url)

navigate_relative(relative_url='/')

Navigate to URL relative to application root.

Parameters:

Name Type Description Default
relative_url str

Relative URL

'/'
Source code in pomcorn/page.py
145
146
147
148
149
150
151
152
153
154
def navigate_relative(self, relative_url: str = "/") -> None:
    """Navigate to URL relative to application root.

    Args:
        relative_url (str): Relative URL

    """
    self.webdriver.get(
        self._get_full_relative_url(self.app_root, relative_url),
    )

open(webdriver, *, app_root=None) classmethod

Open page and initialize page object.

Parameters:

Name Type Description Default
webdriver WebDriver

Instance of a WebDriver class for managing the browser.

required
app_root str | None

The URL of page, by default the value of APP_ROOT attribute is used.

None
Source code in pomcorn/page.py
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
@classmethod
def open(
    cls,
    webdriver: WebDriver,
    *,
    app_root: str | None = None,
) -> Self:
    """Open page and initialize page object.

    Args:
        webdriver: Instance of a WebDriver class for managing the browser.
        app_root: The URL of page, by default the value of `APP_ROOT`
            attribute is used.

    """
    webdriver.get(url=f"{app_root or cls.APP_ROOT}")
    # hack to not specify app_root in each page init method
    kwargs = {}
    if app_root:
        kwargs = {"app_root": app_root}

    # Mypy raise error on unpacking `kwargs`:
    # "Page" has incompatible type "**dict[str, str]"; expected "int"
    # "Page" has incompatible type "**dict[str, str]"; expected "float"
    return cls(webdriver, **kwargs)  # type: ignore

open_from_url(webdriver, *, path, app_root=None, **kwargs) classmethod

Open page from relative path and initialize page object.

Add path to app_root in browser URL.

Parameters:

Name Type Description Default
webdriver WebDriver

Instance of a WebDriver class for managing the browser.

required
app_root str | None

The URL of page, by default the value of APP_ROOT attribute is used.

None
path str

Relative URL.

required
**kwargs

Additional arguments passed to the page object initialization.

{}
Source code in pomcorn/page.py
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
@classmethod
def open_from_url(
    cls,
    webdriver: WebDriver,
    *,
    path: str,
    app_root: str | None = None,
    **kwargs,
) -> Self:
    """Open page from relative path and initialize page object.

    Add `path` to `app_root` in browser URL.

    Args:
        webdriver: Instance of a WebDriver class for managing the browser.
        app_root: The URL of page, by default the value of `APP_ROOT`
            attribute is used.
        path: Relative URL.
        **kwargs: Additional arguments passed to the
            page object initialization.

    """
    # hack to not specify app_root in each page init method
    if app_root:
        kwargs["app_root"] = app_root

    # We don't use `page.navigate_relative` here because we need to
    # navigate to relative url before page is initialized, since otherwise
    # `wait_until_loaded` method in page `__init__` method might fail.
    webdriver.get(
        url=cls._get_full_relative_url(app_root or cls.APP_ROOT, path),
    )

    page = cls(webdriver, **kwargs)
    return page

refresh()

Refresh web page and wait until it is loaded.

Source code in pomcorn/page.py
120
121
122
123
def refresh(self) -> None:
    """Refresh web page and wait until it is loaded."""
    self.webdriver.refresh()
    self.wait_until_loaded()

wait_until_loaded(timeout=None)

Wait until page is loaded.

Source code in pomcorn/page.py
125
126
127
128
129
130
131
132
133
134
135
def wait_until_loaded(self, timeout: float | None = None) -> None:
    """Wait until page is loaded."""
    wait = self.get_wait(timeout)
    wait.until(
        method=lambda _: self.check_page_is_loaded(),
        message=(
            f"Page `{self.__class__}` didn't loaded in "
            f"{wait._timeout} seconds! Didn't wait for `True` from "
            "`check_page_is_loaded` method."
        ),
    )

Components

Component

Bases: WebView, Generic[TPage]

The class to represent a page component that depends on base locator.

It contains page elements, components and utils methods for page manipulation, but as a separate entity that can be reused for different pages with common elements.

Implement wait methods until the component becomes visible or invisible.

Source code in pomcorn/component.py
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
class Component(WebView, Generic[TPage]):
    """The class to represent a page component that depends on base locator.

    It contains page elements, components and utils methods for page
    manipulation, but as a separate entity that can be reused for different
    pages with common elements.

    Implement wait methods until the component becomes visible or invisible.

    """

    base_locator: locators.XPathLocator

    def __init__(
        self,
        page: TPage,
        base_locator: locators.XPathLocator | None = None,
        wait_until_visible: bool = True,
    ):
        """Initialize component.

        Args:
            page: An instance of the page that uses this component.
            base_locator: Instance of a class to locate the component in the
                browser. Used in relative element initialization methods and
                visibility waits. You also can specify it as attribute.
            wait_until_visible: Whether to wait for the component to become
                visible before completing initialization or not.

        """
        super().__init__(
            page.webdriver,
            app_root=page.app_root,
            wait_timeout=page.wait._timeout,
        )
        self.page = page
        self.base_locator = base_locator or self.base_locator
        self.body = self.init_element(locator=self.base_locator)

        if wait_until_visible:
            self.wait_until_visible()

    @overload  # type: ignore
    def init_element(
        self,
        *,
        locator: locators.XPathLocator,
    ) -> XPathElement: ...

    @overload  # type: ignore
    def init_element(
        self,
        *,
        relative_locator: locators.XPathLocator,
    ) -> XPathElement: ...

    def init_element(
        self,
        *,
        relative_locator: locators.XPathLocator | None = None,
        locator: locators.XPathLocator | None = None,
    ) -> XPathElement:
        """Initialize element including base locator.

        Use `relative_locator` if you need to include `base_locator`, otherwise
        use `locator`.

        Raises:
            ValueError: If both arguments were passed or neither.

        """
        return self.page.init_element(
            locator=self._prepare_locator(
                locator=locator,
                relative_locator=relative_locator,
            ),
        )

    @overload  # type: ignore
    def init_elements(
        self,
        *,
        locator: locators.XPathLocator | None = None,
    ) -> list[XPathElement]: ...

    @overload  # type: ignore
    def init_elements(
        self,
        *,
        relative_locator: locators.XPathLocator | None = None,
    ) -> list[XPathElement]: ...

    def init_elements(
        self,
        *,
        relative_locator: locators.XPathLocator | None = None,
        locator: locators.XPathLocator | None = None,
    ) -> list[XPathElement]:
        """Initialize list of elements including base locator.

        Use `relative_locator` if you need to include `base_locator`, otherwise
        use `locator`.

        Raises:
            ValueError: If both arguments were passed or neither.

        """
        return self.page.init_elements(
            locator=self._prepare_locator(
                locator=locator,
                relative_locator=relative_locator,
            ),
        )

    def _prepare_locator(
        self,
        *,
        relative_locator: locators.XPathLocator | None = None,
        locator: locators.XPathLocator | None = None,
    ) -> locators.XPathLocator:
        """Prepare a locator by arguments.

        Check that only one locator argument is passed, or none.
        If only `relative_locator` was passed, `base_locator` will be added to
        it. If only `locator` was passed, it will return itself.

        Raises:
            ValueError: If both arguments were passed or neither.

        """
        if relative_locator and locator:
            raise ValueError(
                "You need to pass only one of the arguments: "
                "`locator` or `relative_locator`.",
            )

        if not relative_locator:
            if not locator:
                raise ValueError(
                    "You need to pass one of the arguments: "
                    "`locator` or `relative_locator`.",
                )
            return locator
        return self.base_locator // relative_locator

    def wait_until_visible(self, timeout: float | None = None, **kwargs):
        """Wait until component becomes visible.

        By default, method waits for `self.wait._timeout` seconds.
        If you need to change timeout, you can specify it in `timeout`
        argument.

        """
        self.body.wait_until_visible(timeout)

    def wait_until_invisible(self, timeout: float | None = None, **kwargs):
        """Wait until component becomes invisible.

        By default, method waits for `self.wait._timeout` seconds.
        If you need to change timeout, you can specify it in `timeout`
        argument.

        """
        self.body.wait_until_invisible(timeout)

__init__(page, base_locator=None, wait_until_visible=True)

Initialize component.

Parameters:

Name Type Description Default
page TPage

An instance of the page that uses this component.

required
base_locator XPathLocator | None

Instance of a class to locate the component in the browser. Used in relative element initialization methods and visibility waits. You also can specify it as attribute.

None
wait_until_visible bool

Whether to wait for the component to become visible before completing initialization or not.

True
Source code in pomcorn/component.py
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
def __init__(
    self,
    page: TPage,
    base_locator: locators.XPathLocator | None = None,
    wait_until_visible: bool = True,
):
    """Initialize component.

    Args:
        page: An instance of the page that uses this component.
        base_locator: Instance of a class to locate the component in the
            browser. Used in relative element initialization methods and
            visibility waits. You also can specify it as attribute.
        wait_until_visible: Whether to wait for the component to become
            visible before completing initialization or not.

    """
    super().__init__(
        page.webdriver,
        app_root=page.app_root,
        wait_timeout=page.wait._timeout,
    )
    self.page = page
    self.base_locator = base_locator or self.base_locator
    self.body = self.init_element(locator=self.base_locator)

    if wait_until_visible:
        self.wait_until_visible()

init_element(*, relative_locator=None, locator=None)

init_element(*, locator: locators.XPathLocator) -> XPathElement
init_element(*, relative_locator: locators.XPathLocator) -> XPathElement

Initialize element including base locator.

Use relative_locator if you need to include base_locator, otherwise use locator.

Raises:

Type Description
ValueError

If both arguments were passed or neither.

Source code in pomcorn/component.py
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
def init_element(
    self,
    *,
    relative_locator: locators.XPathLocator | None = None,
    locator: locators.XPathLocator | None = None,
) -> XPathElement:
    """Initialize element including base locator.

    Use `relative_locator` if you need to include `base_locator`, otherwise
    use `locator`.

    Raises:
        ValueError: If both arguments were passed or neither.

    """
    return self.page.init_element(
        locator=self._prepare_locator(
            locator=locator,
            relative_locator=relative_locator,
        ),
    )

init_elements(*, relative_locator=None, locator=None)

init_elements(*, locator: locators.XPathLocator | None = None) -> list[XPathElement]
init_elements(*, relative_locator: locators.XPathLocator | None = None) -> list[XPathElement]

Initialize list of elements including base locator.

Use relative_locator if you need to include base_locator, otherwise use locator.

Raises:

Type Description
ValueError

If both arguments were passed or neither.

Source code in pomcorn/component.py
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
def init_elements(
    self,
    *,
    relative_locator: locators.XPathLocator | None = None,
    locator: locators.XPathLocator | None = None,
) -> list[XPathElement]:
    """Initialize list of elements including base locator.

    Use `relative_locator` if you need to include `base_locator`, otherwise
    use `locator`.

    Raises:
        ValueError: If both arguments were passed or neither.

    """
    return self.page.init_elements(
        locator=self._prepare_locator(
            locator=locator,
            relative_locator=relative_locator,
        ),
    )

wait_until_invisible(timeout=None, **kwargs)

Wait until component becomes invisible.

By default, method waits for self.wait._timeout seconds. If you need to change timeout, you can specify it in timeout argument.

Source code in pomcorn/component.py
187
188
189
190
191
192
193
194
195
def wait_until_invisible(self, timeout: float | None = None, **kwargs):
    """Wait until component becomes invisible.

    By default, method waits for `self.wait._timeout` seconds.
    If you need to change timeout, you can specify it in `timeout`
    argument.

    """
    self.body.wait_until_invisible(timeout)

wait_until_visible(timeout=None, **kwargs)

Wait until component becomes visible.

By default, method waits for self.wait._timeout seconds. If you need to change timeout, you can specify it in timeout argument.

Source code in pomcorn/component.py
177
178
179
180
181
182
183
184
185
def wait_until_visible(self, timeout: float | None = None, **kwargs):
    """Wait until component becomes visible.

    By default, method waits for `self.wait._timeout` seconds.
    If you need to change timeout, you can specify it in `timeout`
    argument.

    """
    self.body.wait_until_visible(timeout)

ListComponent

Bases: Component[TPage], Generic[ListItemType, TPage]

Class to represent a list-like component.

It contains standard properties and methods for working with list-like components:

  • count
  • all
  • get_item_by_text()

Waits for base_item_locator property to be overridden or one of the attributes (item_locator or relative_item_locator) to be specified.

Source code in pomcorn/component.py
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
class ListComponent(Component[TPage], Generic[ListItemType, TPage]):
    """Class to represent a list-like component.

    It contains standard properties and methods for working with list-like
    components:

    * count
    * all
    * get_item_by_text()

    Waits for `base_item_locator` property  to be overridden or one of the
    attributes (`item_locator` or `relative_item_locator`) to be specified.

    """

    _item_class: type[ListItemType] = EmptyValue

    item_locator: locators.XPathLocator | None = None
    relative_item_locator: locators.XPathLocator | None = None

    def __class_getitem__(cls, item: tuple[type, ...]) -> Any:
        """Create parameterized versions of generic classes.

        This method is called when the class is used as a parameterized type,
        such as MyGeneric[int] or MyGeneric[List[str]].

        We override this method to store values passed in generic parameters.

        Args:
            cls: The generic class itself.
            item: The type used for parameterization.

        Returns:
            type: A parameterized version of the class with the specified type.

        """
        list_cls = super().__class_getitem__(item)  # type: ignore
        cls.__generic_parameters__ = item  # type: ignore
        return list_cls

    def __init__(
        self,
        page: TPage,
        base_locator: locators.XPathLocator | None = None,
        wait_until_visible: bool = True,
    ) -> None:
        # If `_item_class` was not specified in `__init_subclass__`, this means
        # that `ListComponent` is used as a parameterized type
        # (e.g., `List[ItemClass, Page]`).
        if isinstance(self._item_class, _EmptyValue):
            # In this way we check the stored generic parameters and, if first
            # from them is valid, set it as `_item_class`
            first_generic_param = self.__generic_parameters__[0]
            if self.is_valid_item_class(first_generic_param):
                self._item_class = first_generic_param
        super().__init__(page, base_locator, wait_until_visible)

    def __init_subclass__(cls) -> None:
        """Run logic for getting/overriding item_class attr for subclasses."""
        super().__init_subclass__()

        # If class has valid `_item_class` attribute from a parent class
        if cls.is_valid_item_class(cls._item_class):
            # We leave using of parent `item_class`
            return

        # Try to get `item_class` from first generic variable
        list_item_class = cls.get_list_item_class()

        if not list_item_class:
            # If `item_class` is not specified in generic we leave it empty
            # because it maybe not specified in base class but will be
            # specified in child
            return

        cls._item_class = list_item_class

    @property
    def base_item_locator(self) -> locators.XPathLocator:
        """Get the base locator of list item.

        Raises:
            ValueError: If both attributes are specified.
            NotImplementedError: If no attribute has been specified,

        """
        if self.relative_item_locator and self.item_locator:
            raise ValueError(
                "You only need to specify one of the attributes: "
                "`relative_item_locator` - if you want locator nested within "
                "`base_locator`, `item_locator` - otherwise. "
                "Or override `base_item_locator` property.",
            )
        if not self.relative_item_locator:
            if not self.item_locator:
                raise NotImplementedError(
                    "You need to specify one of the arguments: "
                    "`relative_item_locator` - if you want locator nested "
                    "within `base_locator`, `item_locator` - otherwise. "
                    "Or override `base_item_locator` property.",
                )
            return self.item_locator
        return self.base_locator // self.relative_item_locator

    @property
    def count(self) -> int:
        """Get count of list items."""
        return len(self._get_elements(self.base_item_locator))

    @property
    def all(self) -> list[ListItemType]:
        """Get all items of list."""
        # Sometimes `base_item_locator` exists in dom but is not visible
        # and method returns an empty list. That's why we add waiting for this
        if (
            base_item := self.init_element(locator=self.base_item_locator)
        ).exists_in_dom:
            base_item.wait_until_visible()

        return [
            self._item_class(page=self.page, base_locator=locator)
            for locator in self.iter_locators(self.base_item_locator)
        ]

    @classmethod
    def get_list_item_class(cls) -> type[ListItemType] | None:
        """Return class passed in `Generic[ListItemType]`."""
        base_class = next(
            _class
            for _class in cls.__orig_bases__  # type: ignore
            if isclass(get_origin(_class))
            and issubclass(get_origin(_class), ListComponent)
        )

        # Get first generic variable and return it if it is valid item class
        item_class = get_args(base_class)[0]
        if cls.is_valid_item_class(item_class):
            return item_class

        return None

    @classmethod
    def is_valid_item_class(cls, item_class: Any) -> bool:
        """Check that specified ``item_class`` is valid.

        Valid ``item_class`` should be
        * a class and subclass of ``Component``
        * or TypeAlias based on ``Component``

        """
        if isclass(item_class) and issubclass(item_class, Component):
            return True

        if isinstance(item_class, typing._GenericAlias):  # type: ignore
            type_alias = item_class.__origin__  # type: ignore
            return isclass(type_alias) and issubclass(type_alias, Component)

        return False

    def get_item_by_text(self, text: str, exact: bool = False) -> ListItemType:
        """Get list item by text."""
        locator = self.base_item_locator.contains(
            text=text,
            exact=exact,
        )
        return self._item_class(page=self.page, base_locator=locator)

    def __repr__(self) -> str:
        return (
            "ListComponent("
            f"component={self.__class__}, "
            f"item_class={self._item_class}, "
            f"base_item_locator={self.base_item_locator}, "
            f"count={self.count}, "
            f"items={self.all}, "
            f"page={self.page}"
            ")"
        )

    def __str__(self) -> str:
        return f"{self.all}"

all property

Get all items of list.

base_item_locator property

Get the base locator of list item.

Raises:

Type Description
ValueError

If both attributes are specified.

NotImplementedError

If no attribute has been specified,

count property

Get count of list items.

__class_getitem__(item)

Create parameterized versions of generic classes.

This method is called when the class is used as a parameterized type, such as MyGeneric[int] or MyGeneric[List[str]].

We override this method to store values passed in generic parameters.

Parameters:

Name Type Description Default
cls

The generic class itself.

required
item tuple[type, ...]

The type used for parameterization.

required

Returns:

Name Type Description
type Any

A parameterized version of the class with the specified type.

Source code in pomcorn/component.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
def __class_getitem__(cls, item: tuple[type, ...]) -> Any:
    """Create parameterized versions of generic classes.

    This method is called when the class is used as a parameterized type,
    such as MyGeneric[int] or MyGeneric[List[str]].

    We override this method to store values passed in generic parameters.

    Args:
        cls: The generic class itself.
        item: The type used for parameterization.

    Returns:
        type: A parameterized version of the class with the specified type.

    """
    list_cls = super().__class_getitem__(item)  # type: ignore
    cls.__generic_parameters__ = item  # type: ignore
    return list_cls

__init_subclass__()

Run logic for getting/overriding item_class attr for subclasses.

Source code in pomcorn/component.py
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
def __init_subclass__(cls) -> None:
    """Run logic for getting/overriding item_class attr for subclasses."""
    super().__init_subclass__()

    # If class has valid `_item_class` attribute from a parent class
    if cls.is_valid_item_class(cls._item_class):
        # We leave using of parent `item_class`
        return

    # Try to get `item_class` from first generic variable
    list_item_class = cls.get_list_item_class()

    if not list_item_class:
        # If `item_class` is not specified in generic we leave it empty
        # because it maybe not specified in base class but will be
        # specified in child
        return

    cls._item_class = list_item_class

get_item_by_text(text, exact=False)

Get list item by text.

Source code in pomcorn/component.py
362
363
364
365
366
367
368
def get_item_by_text(self, text: str, exact: bool = False) -> ListItemType:
    """Get list item by text."""
    locator = self.base_item_locator.contains(
        text=text,
        exact=exact,
    )
    return self._item_class(page=self.page, base_locator=locator)

get_list_item_class() classmethod

Return class passed in Generic[ListItemType].

Source code in pomcorn/component.py
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
@classmethod
def get_list_item_class(cls) -> type[ListItemType] | None:
    """Return class passed in `Generic[ListItemType]`."""
    base_class = next(
        _class
        for _class in cls.__orig_bases__  # type: ignore
        if isclass(get_origin(_class))
        and issubclass(get_origin(_class), ListComponent)
    )

    # Get first generic variable and return it if it is valid item class
    item_class = get_args(base_class)[0]
    if cls.is_valid_item_class(item_class):
        return item_class

    return None

is_valid_item_class(item_class) classmethod

Check that specified item_class is valid.

Valid item_class should be * a class and subclass of Component * or TypeAlias based on Component

Source code in pomcorn/component.py
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
@classmethod
def is_valid_item_class(cls, item_class: Any) -> bool:
    """Check that specified ``item_class`` is valid.

    Valid ``item_class`` should be
    * a class and subclass of ``Component``
    * or TypeAlias based on ``Component``

    """
    if isclass(item_class) and issubclass(item_class, Component):
        return True

    if isinstance(item_class, typing._GenericAlias):  # type: ignore
        type_alias = item_class.__origin__  # type: ignore
        return isclass(type_alias) and issubclass(type_alias, Component)

    return False

PomcornElement

Note

This class is returned when the Element descriptor or the init_element/init_elements methods of the page or components are used.

PomcornElement

Bases: Generic[TLocator_co]

The class to represent a simple element (tag) on the page.

Contains methods for the interaction with an element on the browser page.

Source code in pomcorn/element.py
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
class PomcornElement(Generic[locators.TLocator_co]):
    """The class to represent a simple element (tag) on the page.

    Contains methods for the interaction with an element on the browser page.

    """

    def __init__(self, web_view: WebView, locator: locators.TLocator_co):
        """Init page element.

        Args:
            web_view: Instance of a webview.
            locator: Instance of a class to locate the element in the browser.

        """
        self.web_view = web_view
        self.locator = locator

    def wait_until_visible(self, timeout: float | None = None):
        """Wait until element becomes visible.

        By default, method waits for `self.web_view.wait_timeout` seconds.
        If you need to change timeout, you can specify it in `timeout`
        argument.

        Raises:
            TimeoutException: If after `self.web_view.wait_timeout` seconds
                the wait has not ended.

        """
        self.web_view.wait_until_locator_visible(
            locator=self.locator,
            timeout=timeout,
        )

    def wait_until_invisible(
        self,
        timeout: float | None = None,
    ):
        """Wait until element becomes invisible.

        By default, method waits for `self.web_view.wait_timeout` seconds.
        If you need to change timeout, you can specify it in `timeout`
        argument.

        Raises:
            TimeoutException: If after `self.web_view.wait_timeout` seconds
                the wait has not ended.

        """
        self.web_view.wait_until_locator_invisible(
            locator=self.locator,
            timeout=timeout,
        )

    def wait_until_clickable(
        self,
        timeout: float | None = None,
    ):
        """Wait until element becomes clickable.

        By default, method waits for `self.web_view.wait_timeout` seconds.
        If you need to change timeout, you can specify it in `timeout`
        argument.

        Raises:
            TimeoutException: If after `self.web_view.wait_timeout` seconds
                the wait has not ended.

        """
        self.web_view.wait_until_clickable(
            locator=self.locator,
            timeout=timeout,
        )

    def wait_until_text_is_in_element(
        self,
        text: str,
        timeout: float | None = None,
    ):
        """Wait until text is present in element.

        By default, method waits for `self.web_view.wait_timeout` seconds.
        If you need to change timeout, you can specify it in `timeout`
        argument.

        Raises:
            TimeoutException: If after `self.web_view.wait_timeout` seconds
                the wait has not ended.

        """
        self.web_view.wait_until_text_is_in_element(
            text=text,
            locator=self.locator,
            timeout=timeout,
        )

    def wait_until_not_exists_in_dom(self, timeout: float | None = None):
        """Wait until element ceases to exist in DOM.

        By default, method waits for `self.web_view.wait_timeout` seconds.
        If you need to change timeout, you can specify it in `timeout`
        argument.

        Raises:
            TimeoutException: If after `self.web_view.wait_timeout` seconds
                the wait has not ended.

        """
        self.web_view.wait_until_not_exists_in_dom(
            element=self.locator,
            timeout=timeout,
        )

    def get_element(self, only_visible: bool = True) -> WebElement:
        """Get selenium instance(WebElement) of element.

        Args:
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements,
                otherwise all the elements (including not visible) will be
                counted.

        """
        return self.web_view._get_element(
            locator=self.locator,
            only_visible=only_visible,
        )

    @property
    def exists_in_dom(self) -> bool:
        """Check if element is present in html, can be not visible."""
        return len(self.web_view._get_elements(locator=self.locator)) != 0

    @property
    def is_displayed(self) -> bool:
        """Check if element is displayed.

        If element is not present in the html, return `False`.

        """
        elements = self.web_view._get_elements(locator=self.locator)
        if not elements:
            return False

        try:
            return elements[0].is_displayed()
        except StaleElementReferenceException:
            # Sometimes an element may disappear before we check its visibility
            return False

    @property
    def is_enabled(self) -> bool:
        """Check if element is enabled.

        It is primarily used with buttons.

        """
        return self.get_element().is_enabled()

    @property
    def is_selected(self) -> bool:
        """Check if element is selected.

        It is predominantly used with radio buttons, dropdowns and checkboxes.

        """
        return self.get_element().is_selected()

    def fill(
        self,
        text: str,
        only_visible: bool = True,
        clear: bool = True,
    ):
        """Fill element with text.

        Args:
            text: The text that will be sent to the element to be filled.
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements,
                otherwise all elements (including not visible) will be counted.
            clear: Whether the element needs to be cleared before filling it
                or not (default `True`).

        """
        if clear:
            self.clear(only_visible=only_visible)
        self.send_keys(str(text), only_visible=only_visible)

    def clear(self, only_visible: bool = True):
        """Clear element (input) and it's value.

        Args:
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements,
                otherwise all the elements (including not visible) will be
                counted.

        """
        cmd_ctrl = Keys.CONTROL
        if sys.platform.lower() == "darwin":
            cmd_ctrl = Keys.COMMAND

        self.send_keys(cmd_ctrl + "a", only_visible=only_visible)
        self.send_keys(Keys.BACK_SPACE, only_visible=only_visible)

    def send_keys(self, keys: str, only_visible: bool = True):
        """Send keys to element.

        Simulate user keystrokes.

        Args:
            keys: The names of the keys in the form of a single string.
                More keys: https://www.selenium.dev/selenium/docs/api/py/webdriver/selenium.webdriver.common.keys.html
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements,
                otherwise all the elements (including not visible) will be
                counted.

        """
        self.get_element(only_visible=only_visible).send_keys(*keys)

    def get_text(self, only_visible: bool = True) -> str:
        """Get text from element.

        Args:
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements,
                otherwise all the elements (including not visible) will be
                counted.

        """
        return self.get_element(only_visible=only_visible).text

    def get_attribute(
        self,
        attribute_name: str,
        only_visible: bool = True,
    ) -> str:
        """Get value of attribute from element.

        If attribute is not found, return empty string.

        Args:
            attribute_name: Element attribute name..
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements,
                otherwise all the elements (including not visible) will be
                counted.

        """
        return (
            self.get_element(only_visible=only_visible).get_attribute(
                name=attribute_name,
            )
            or ""
        )

    def set_attribute(
        self,
        attribute_name: str,
        value: str,
        only_visible: bool = True,
    ):
        """Set value to element attribute.

        Args:
            attribute_name: Element attribute name.
            value: New value for attribute.
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements,
                otherwise all the elements (including not visible) will be
                counted.

        """
        element = self.get_element(only_visible=only_visible)
        self.web_view.execute_javascript(
            f"arguments[0].setAttribute('{attribute_name}',arguments[1])",
            element,
            value,
        )

    def get_value(self, only_visible: bool = True):
        """Get value of `value` attribute from element.

        Args:
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements,
                otherwise all the elements (including not visible) will be
                counted.

        """
        return self.get_attribute(
            attribute_name="value",
            only_visible=only_visible,
        )

    def select(self, value: str, only_visible: bool = True):
        """Perform select on element.

        Args:
            value: Value for selecting an element based on visible text.
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements.

        """
        Select(self.get_element(only_visible)).select_by_visible_text(value)

    def click(
        self,
        only_visible: bool = True,
        wait_until_clickable: bool = True,
        center_element: bool = False,
    ):
        """Click on element.

        Args:
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements.
            wait_until_clickable: Wait until the element is clickable before
                clicking, or not (default `True`).
            center_element: Scroll the page until the element is in
                the center, or not scroll (default `False`).

        By default, webdriver scrolls to the element before clicking if the
        element is not in viewport or is behind overlays (header/footer tags).
        If the element is in viewport but overlapped, set center_element
        to True to scroll until element is in the center of the screen.

        """
        if wait_until_clickable:
            self.wait_until_clickable()
        if center_element:
            self.scroll_to(only_visible=only_visible)
        self.get_element(only_visible=only_visible).click()

    def drag_and_drop(
        self,
        target: PomcornElement[locators.TLocator_co],
        only_visible: bool = True,
    ):
        """Drag and drop page object on target object.

        Args:
            target: The element instance to drag into.
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements.

        """
        self.web_view.drag_and_drop(
            source=self.get_element(only_visible=only_visible),
            target=target.get_element(only_visible=only_visible),
        )

    def scroll_to(self, only_visible: bool = True):
        """Scroll page until element is visible.

        Args:
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements.

        """
        self.web_view.scroll_to(self.get_element(only_visible=only_visible))

    def hover_to(self, only_visible: bool = True):
        """Hover cursor to element.

        Args:
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements.

        """
        action = ActionChains(self.web_view.webdriver).move_to_element(
            to_element=self.get_element(only_visible=only_visible),
        )
        action.perform()

    def get_value_of_css_property(
        self,
        property_name: str,
        only_visible: bool = True,
    ) -> str:
        """Return value of a CSS property.

        Args:
            property_name: Name of CSS property.
            only_visible: Flag for viewing visible elements. If this is `True`
                (default), then this method will only get visible elements.

        """
        return self.get_element(only_visible).value_of_css_property(
            property_name=property_name,
        )

    def add_debug_mark(self):
        """Set element background to red.

        Should be used only for debugging.

        """
        current_style = self.get_attribute("style")
        self.set_attribute("style", f"{current_style} background: red;")

    def remove_debug_mark(self):
        """Remove debug mark."""
        current_style = self.get_attribute("style")
        self.set_attribute(
            attribute_name="style",
            value=current_style.replace("background: red;", ""),
        )

exists_in_dom property

Check if element is present in html, can be not visible.

is_displayed property

Check if element is displayed.

If element is not present in the html, return False.

is_enabled property

Check if element is enabled.

It is primarily used with buttons.

is_selected property

Check if element is selected.

It is predominantly used with radio buttons, dropdowns and checkboxes.

__init__(web_view, locator)

Init page element.

Parameters:

Name Type Description Default
web_view WebView

Instance of a webview.

required
locator TLocator_co

Instance of a class to locate the element in the browser.

required
Source code in pomcorn/element.py
25
26
27
28
29
30
31
32
33
34
def __init__(self, web_view: WebView, locator: locators.TLocator_co):
    """Init page element.

    Args:
        web_view: Instance of a webview.
        locator: Instance of a class to locate the element in the browser.

    """
    self.web_view = web_view
    self.locator = locator

add_debug_mark()

Set element background to red.

Should be used only for debugging.

Source code in pomcorn/element.py
413
414
415
416
417
418
419
420
def add_debug_mark(self):
    """Set element background to red.

    Should be used only for debugging.

    """
    current_style = self.get_attribute("style")
    self.set_attribute("style", f"{current_style} background: red;")

clear(only_visible=True)

Clear element (input) and it's value.

Parameters:

Name Type Description Default
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements, otherwise all the elements (including not visible) will be counted.

True
Source code in pomcorn/element.py
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
def clear(self, only_visible: bool = True):
    """Clear element (input) and it's value.

    Args:
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements,
            otherwise all the elements (including not visible) will be
            counted.

    """
    cmd_ctrl = Keys.CONTROL
    if sys.platform.lower() == "darwin":
        cmd_ctrl = Keys.COMMAND

    self.send_keys(cmd_ctrl + "a", only_visible=only_visible)
    self.send_keys(Keys.BACK_SPACE, only_visible=only_visible)

click(only_visible=True, wait_until_clickable=True, center_element=False)

Click on element.

Parameters:

Name Type Description Default
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements.

True
wait_until_clickable bool

Wait until the element is clickable before clicking, or not (default True).

True
center_element bool

Scroll the page until the element is in the center, or not scroll (default False).

False

By default, webdriver scrolls to the element before clicking if the element is not in viewport or is behind overlays (header/footer tags). If the element is in viewport but overlapped, set center_element to True to scroll until element is in the center of the screen.

Source code in pomcorn/element.py
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
def click(
    self,
    only_visible: bool = True,
    wait_until_clickable: bool = True,
    center_element: bool = False,
):
    """Click on element.

    Args:
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements.
        wait_until_clickable: Wait until the element is clickable before
            clicking, or not (default `True`).
        center_element: Scroll the page until the element is in
            the center, or not scroll (default `False`).

    By default, webdriver scrolls to the element before clicking if the
    element is not in viewport or is behind overlays (header/footer tags).
    If the element is in viewport but overlapped, set center_element
    to True to scroll until element is in the center of the screen.

    """
    if wait_until_clickable:
        self.wait_until_clickable()
    if center_element:
        self.scroll_to(only_visible=only_visible)
    self.get_element(only_visible=only_visible).click()

drag_and_drop(target, only_visible=True)

Drag and drop page object on target object.

Parameters:

Name Type Description Default
target PomcornElement[TLocator_co]

The element instance to drag into.

required
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements.

True
Source code in pomcorn/element.py
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
def drag_and_drop(
    self,
    target: PomcornElement[locators.TLocator_co],
    only_visible: bool = True,
):
    """Drag and drop page object on target object.

    Args:
        target: The element instance to drag into.
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements.

    """
    self.web_view.drag_and_drop(
        source=self.get_element(only_visible=only_visible),
        target=target.get_element(only_visible=only_visible),
    )

fill(text, only_visible=True, clear=True)

Fill element with text.

Parameters:

Name Type Description Default
text str

The text that will be sent to the element to be filled.

required
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements, otherwise all elements (including not visible) will be counted.

True
clear bool

Whether the element needs to be cleared before filling it or not (default True).

True
Source code in pomcorn/element.py
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
def fill(
    self,
    text: str,
    only_visible: bool = True,
    clear: bool = True,
):
    """Fill element with text.

    Args:
        text: The text that will be sent to the element to be filled.
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements,
            otherwise all elements (including not visible) will be counted.
        clear: Whether the element needs to be cleared before filling it
            or not (default `True`).

    """
    if clear:
        self.clear(only_visible=only_visible)
    self.send_keys(str(text), only_visible=only_visible)

get_attribute(attribute_name, only_visible=True)

Get value of attribute from element.

If attribute is not found, return empty string.

Parameters:

Name Type Description Default
attribute_name str

Element attribute name..

required
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements, otherwise all the elements (including not visible) will be counted.

True
Source code in pomcorn/element.py
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
def get_attribute(
    self,
    attribute_name: str,
    only_visible: bool = True,
) -> str:
    """Get value of attribute from element.

    If attribute is not found, return empty string.

    Args:
        attribute_name: Element attribute name..
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements,
            otherwise all the elements (including not visible) will be
            counted.

    """
    return (
        self.get_element(only_visible=only_visible).get_attribute(
            name=attribute_name,
        )
        or ""
    )

get_element(only_visible=True)

Get selenium instance(WebElement) of element.

Parameters:

Name Type Description Default
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements, otherwise all the elements (including not visible) will be counted.

True
Source code in pomcorn/element.py
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def get_element(self, only_visible: bool = True) -> WebElement:
    """Get selenium instance(WebElement) of element.

    Args:
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements,
            otherwise all the elements (including not visible) will be
            counted.

    """
    return self.web_view._get_element(
        locator=self.locator,
        only_visible=only_visible,
    )

get_text(only_visible=True)

Get text from element.

Parameters:

Name Type Description Default
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements, otherwise all the elements (including not visible) will be counted.

True
Source code in pomcorn/element.py
241
242
243
244
245
246
247
248
249
250
251
def get_text(self, only_visible: bool = True) -> str:
    """Get text from element.

    Args:
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements,
            otherwise all the elements (including not visible) will be
            counted.

    """
    return self.get_element(only_visible=only_visible).text

get_value(only_visible=True)

Get value of value attribute from element.

Parameters:

Name Type Description Default
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements, otherwise all the elements (including not visible) will be counted.

True
Source code in pomcorn/element.py
301
302
303
304
305
306
307
308
309
310
311
312
313
314
def get_value(self, only_visible: bool = True):
    """Get value of `value` attribute from element.

    Args:
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements,
            otherwise all the elements (including not visible) will be
            counted.

    """
    return self.get_attribute(
        attribute_name="value",
        only_visible=only_visible,
    )

get_value_of_css_property(property_name, only_visible=True)

Return value of a CSS property.

Parameters:

Name Type Description Default
property_name str

Name of CSS property.

required
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements.

True
Source code in pomcorn/element.py
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
def get_value_of_css_property(
    self,
    property_name: str,
    only_visible: bool = True,
) -> str:
    """Return value of a CSS property.

    Args:
        property_name: Name of CSS property.
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements.

    """
    return self.get_element(only_visible).value_of_css_property(
        property_name=property_name,
    )

hover_to(only_visible=True)

Hover cursor to element.

Parameters:

Name Type Description Default
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements.

True
Source code in pomcorn/element.py
383
384
385
386
387
388
389
390
391
392
393
394
def hover_to(self, only_visible: bool = True):
    """Hover cursor to element.

    Args:
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements.

    """
    action = ActionChains(self.web_view.webdriver).move_to_element(
        to_element=self.get_element(only_visible=only_visible),
    )
    action.perform()

remove_debug_mark()

Remove debug mark.

Source code in pomcorn/element.py
422
423
424
425
426
427
428
def remove_debug_mark(self):
    """Remove debug mark."""
    current_style = self.get_attribute("style")
    self.set_attribute(
        attribute_name="style",
        value=current_style.replace("background: red;", ""),
    )

scroll_to(only_visible=True)

Scroll page until element is visible.

Parameters:

Name Type Description Default
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements.

True
Source code in pomcorn/element.py
373
374
375
376
377
378
379
380
381
def scroll_to(self, only_visible: bool = True):
    """Scroll page until element is visible.

    Args:
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements.

    """
    self.web_view.scroll_to(self.get_element(only_visible=only_visible))

select(value, only_visible=True)

Perform select on element.

Parameters:

Name Type Description Default
value str

Value for selecting an element based on visible text.

required
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements.

True
Source code in pomcorn/element.py
316
317
318
319
320
321
322
323
324
325
def select(self, value: str, only_visible: bool = True):
    """Perform select on element.

    Args:
        value: Value for selecting an element based on visible text.
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements.

    """
    Select(self.get_element(only_visible)).select_by_visible_text(value)

send_keys(keys, only_visible=True)

Send keys to element.

Simulate user keystrokes.

Parameters:

Name Type Description Default
keys str

The names of the keys in the form of a single string. More keys: https://www.selenium.dev/selenium/docs/api/py/webdriver/selenium.webdriver.common.keys.html

required
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements, otherwise all the elements (including not visible) will be counted.

True
Source code in pomcorn/element.py
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
def send_keys(self, keys: str, only_visible: bool = True):
    """Send keys to element.

    Simulate user keystrokes.

    Args:
        keys: The names of the keys in the form of a single string.
            More keys: https://www.selenium.dev/selenium/docs/api/py/webdriver/selenium.webdriver.common.keys.html
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements,
            otherwise all the elements (including not visible) will be
            counted.

    """
    self.get_element(only_visible=only_visible).send_keys(*keys)

set_attribute(attribute_name, value, only_visible=True)

Set value to element attribute.

Parameters:

Name Type Description Default
attribute_name str

Element attribute name.

required
value str

New value for attribute.

required
only_visible bool

Flag for viewing visible elements. If this is True (default), then this method will only get visible elements, otherwise all the elements (including not visible) will be counted.

True
Source code in pomcorn/element.py
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
def set_attribute(
    self,
    attribute_name: str,
    value: str,
    only_visible: bool = True,
):
    """Set value to element attribute.

    Args:
        attribute_name: Element attribute name.
        value: New value for attribute.
        only_visible: Flag for viewing visible elements. If this is `True`
            (default), then this method will only get visible elements,
            otherwise all the elements (including not visible) will be
            counted.

    """
    element = self.get_element(only_visible=only_visible)
    self.web_view.execute_javascript(
        f"arguments[0].setAttribute('{attribute_name}',arguments[1])",
        element,
        value,
    )

wait_until_clickable(timeout=None)

Wait until element becomes clickable.

By default, method waits for self.web_view.wait_timeout seconds. If you need to change timeout, you can specify it in timeout argument.

Raises:

Type Description
TimeoutException

If after self.web_view.wait_timeout seconds the wait has not ended.

Source code in pomcorn/element.py
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def wait_until_clickable(
    self,
    timeout: float | None = None,
):
    """Wait until element becomes clickable.

    By default, method waits for `self.web_view.wait_timeout` seconds.
    If you need to change timeout, you can specify it in `timeout`
    argument.

    Raises:
        TimeoutException: If after `self.web_view.wait_timeout` seconds
            the wait has not ended.

    """
    self.web_view.wait_until_clickable(
        locator=self.locator,
        timeout=timeout,
    )

wait_until_invisible(timeout=None)

Wait until element becomes invisible.

By default, method waits for self.web_view.wait_timeout seconds. If you need to change timeout, you can specify it in timeout argument.

Raises:

Type Description
TimeoutException

If after self.web_view.wait_timeout seconds the wait has not ended.

Source code in pomcorn/element.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
def wait_until_invisible(
    self,
    timeout: float | None = None,
):
    """Wait until element becomes invisible.

    By default, method waits for `self.web_view.wait_timeout` seconds.
    If you need to change timeout, you can specify it in `timeout`
    argument.

    Raises:
        TimeoutException: If after `self.web_view.wait_timeout` seconds
            the wait has not ended.

    """
    self.web_view.wait_until_locator_invisible(
        locator=self.locator,
        timeout=timeout,
    )

wait_until_not_exists_in_dom(timeout=None)

Wait until element ceases to exist in DOM.

By default, method waits for self.web_view.wait_timeout seconds. If you need to change timeout, you can specify it in timeout argument.

Raises:

Type Description
TimeoutException

If after self.web_view.wait_timeout seconds the wait has not ended.

Source code in pomcorn/element.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
def wait_until_not_exists_in_dom(self, timeout: float | None = None):
    """Wait until element ceases to exist in DOM.

    By default, method waits for `self.web_view.wait_timeout` seconds.
    If you need to change timeout, you can specify it in `timeout`
    argument.

    Raises:
        TimeoutException: If after `self.web_view.wait_timeout` seconds
            the wait has not ended.

    """
    self.web_view.wait_until_not_exists_in_dom(
        element=self.locator,
        timeout=timeout,
    )

wait_until_text_is_in_element(text, timeout=None)

Wait until text is present in element.

By default, method waits for self.web_view.wait_timeout seconds. If you need to change timeout, you can specify it in timeout argument.

Raises:

Type Description
TimeoutException

If after self.web_view.wait_timeout seconds the wait has not ended.

Source code in pomcorn/element.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def wait_until_text_is_in_element(
    self,
    text: str,
    timeout: float | None = None,
):
    """Wait until text is present in element.

    By default, method waits for `self.web_view.wait_timeout` seconds.
    If you need to change timeout, you can specify it in `timeout`
    argument.

    Raises:
        TimeoutException: If after `self.web_view.wait_timeout` seconds
            the wait has not ended.

    """
    self.web_view.wait_until_text_is_in_element(
        text=text,
        locator=self.locator,
        timeout=timeout,
    )

wait_until_visible(timeout=None)

Wait until element becomes visible.

By default, method waits for self.web_view.wait_timeout seconds. If you need to change timeout, you can specify it in timeout argument.

Raises:

Type Description
TimeoutException

If after self.web_view.wait_timeout seconds the wait has not ended.

Source code in pomcorn/element.py
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def wait_until_visible(self, timeout: float | None = None):
    """Wait until element becomes visible.

    By default, method waits for `self.web_view.wait_timeout` seconds.
    If you need to change timeout, you can specify it in `timeout`
    argument.

    Raises:
        TimeoutException: If after `self.web_view.wait_timeout` seconds
            the wait has not ended.

    """
    self.web_view.wait_until_locator_visible(
        locator=self.locator,
        timeout=timeout,
    )