xref: /aosp_15_r20/external/angle/build/fuchsia/test/chrome_driver_wrapper.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1# Copyright 2024 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4"""Wrapper of ChromeDriver binary."""
5
6import os
7
8from contextlib import AbstractContextManager
9from typing import Tuple
10
11# From vpython wheel.
12# pylint: disable=import-error
13from selenium import webdriver
14from selenium.webdriver import ChromeOptions
15from selenium.webdriver.chrome.service import Service
16from selenium.webdriver.common.by import By
17# pylint: enable=import-error
18
19from common import get_free_local_port
20
21
22class ChromeDriverWrapper(AbstractContextManager):
23    """Manages chromedriver and communicates with the web-engine via
24    chromedriver on the device. This class expects the chromedriver exists at
25    clang_x64/stripped/chromedriver in output dir."""
26
27    def __init__(self, target: Tuple[str, int]):
28        # The device / target to run the commands webdriver against.
29        self._target = target
30        # The reference of the webdriver.Chrome instance.
31        self._driver = None
32        # The port which chromedriver is listening to.
33        self._port = 0
34
35    def __enter__(self):
36        """Starts the chromedriver, must be executed before other commands."""
37        self._port = get_free_local_port()
38        options = ChromeOptions()
39        options.debugger_address = f'{self._target[0]}:{str(self._target[1])}'
40        self._driver = webdriver.Chrome(options=options,
41                                        service=Service(
42                                            os.path.join(
43                                                'clang_x64', 'stripped',
44                                                'chromedriver'), self._port))
45        self._driver.__enter__()
46        return self
47
48    def __exit__(self, exc_type, exc_val, exc_tb) -> bool:
49        """Stops the chromedriver, cannot perform other commands afterward."""
50        return self._driver.__exit__(exc_type, exc_val, exc_tb)
51
52    def __getattr__(self, name):
53        """Forwards function calls to the underlying |_driver| instance."""
54        return getattr(self._driver, name)
55
56    # Explicitly override find_element_by_id to avoid importing selenium
57    # packages in the caller files.
58    # The find_element_by_id in webdriver.Chrome is deprecated.
59    #   DeprecationWarning: find_element_by_* commands are deprecated. Please
60    #   use find_element() instead
61    def find_element_by_id(self, id_str):
62        """Returns the element in the page with id |id_str|."""
63        return self._driver.find_element(By.ID, id_str)
64