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