From 490c95417495ba01e5e747454b85a5dec42869df Mon Sep 17 00:00:00 2001 From: Dor-bl <59066376+Dor-bl@users.noreply.github.com> Date: Sun, 11 Oct 2026 08:00:18 +0000 Subject: [PATCH] refactor: simplify executable lookup using shutil.which Replace manual PATH lookup logic in find_executable with direct shutil.which calls in get_node and get_npm, and add unit test coverage. --- appium/webdriver/appium_service.py | 25 +++------------------- test/unit/webdriver/appium_service_test.py | 20 ++++++++++++++++- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/appium/webdriver/appium_service.py b/appium/webdriver/appium_service.py index fe34d869..26290883 100644 --- a/appium/webdriver/appium_service.py +++ b/appium/webdriver/appium_service.py @@ -14,6 +14,7 @@ import os import re +import shutil import subprocess as sp import sys import time @@ -224,33 +225,15 @@ def is_service_listening(url: str, timeout: float = 5, custom_validator: Callabl return False -def find_executable(executable: str) -> str | None: - path = os.environ['PATH'] - paths = path.split(os.pathsep) - _, ext = os.path.splitext(executable) - if sys.platform == 'win32' and not ext: - executable = executable + '.exe' - - if os.path.isfile(executable): - return executable - - for p in paths: - full_path = os.path.join(p, executable) - if os.path.isfile(full_path): - return full_path - - return None - - def get_node() -> str: - result = find_executable('node') + result = shutil.which('node') if result is None: raise AppiumServiceError('NodeJS main executable cannot be found. Make sure it is installed and present in PATH') return result def get_npm() -> str: - result = find_executable('npm.cmd' if sys.platform == 'win32' else 'npm') + result = shutil.which('npm') if result is None: raise AppiumServiceError( 'Node Package Manager executable cannot be found. Make sure it is installed and present in PATH' @@ -330,8 +313,6 @@ def _make_server_url(args: list[str]) -> str: if __name__ == '__main__': - assert find_executable('node') is not None - assert find_executable('npm') is not None service = AppiumService() service.start(args=['--address', '127.0.0.1', '-p', str(DEFAULT_PORT)]) # service.start(args=['--address', '127.0.0.1', '-p', '80'], timeout_ms=2000) diff --git a/test/unit/webdriver/appium_service_test.py b/test/unit/webdriver/appium_service_test.py index d0826c8f..4645d475 100644 --- a/test/unit/webdriver/appium_service_test.py +++ b/test/unit/webdriver/appium_service_test.py @@ -17,13 +17,31 @@ import pytest from appium.webdriver import appium_service -from appium.webdriver.appium_service import AppiumService +from appium.webdriver.appium_service import AppiumService, AppiumServiceError class TestAppiumService: def test_get_instance(self): assert AppiumService() + def test_get_node_found(self, monkeypatch): + monkeypatch.setattr(appium_service.shutil, 'which', lambda cmd: f'/usr/bin/{cmd}') + assert appium_service.get_node() == '/usr/bin/node' + + def test_get_node_not_found(self, monkeypatch): + monkeypatch.setattr(appium_service.shutil, 'which', lambda cmd: None) + with pytest.raises(AppiumServiceError, match='NodeJS main executable cannot be found'): + appium_service.get_node() + + def test_get_npm_found(self, monkeypatch): + monkeypatch.setattr(appium_service.shutil, 'which', lambda cmd: f'/usr/bin/{cmd}') + assert appium_service.get_npm() == '/usr/bin/npm' + + def test_get_npm_not_found(self, monkeypatch): + monkeypatch.setattr(appium_service.shutil, 'which', lambda cmd: None) + with pytest.raises(AppiumServiceError, match='Node Package Manager executable cannot be found'): + appium_service.get_npm() + @pytest.mark.parametrize( ('status', 'expected_result', 'expected_elapsed', 'expected_requests'), [(200, True, 0.0, 1), (503, False, 5.0, 10)],