-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add Playwright Backend Support to Galaxy Browser Automation Framework #21102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
87fc298
Enable package-centric development.
jmchilton 160e153
FIxes for pyproject.toml files.
jmchilton e90db61
Drop now redundant test-requirements.txt files.
jmchilton afe46a7
Type fix for ... Python 3.13?
jmchilton 933ea89
Expand tooling docs for working with packages.
jmchilton 760fff8
More documentation and QOL improvements for package-centric dev.
jmchilton a8fb820
Add script to auto-generate package pyproject.toml files from setup.cfg.
jmchilton 72e3498
Fixes for uv packages structure.
jmchilton a410532
Delay import of optional dependency.
jmchilton fd10036
Drop sizzle selector support in galaxy-selenium.
jmchilton a47ca54
Bug fix in navigates_galaxy.
jmchilton 94f2ffa
Unit tests for Selenium has_driver.
jmchilton a50a3fa
Unit tests for smart_components.py.
jmchilton 7a5c654
Remove the seemingly unused wait_for_select from smart_components.
jmchilton 2ee0779
Refactor smart_components to not depend on naviagtes_galaxy.
jmchilton 5bbd5d1
Rework navigates_galaxy to use new abstraction for navigating to url.
jmchilton d74fe8d
Migrate direct JavaScript interaction in NavigatesGalaxy into abstrac…
jmchilton 947d09c
Migrate direct frame interactions in naviagets galaxy into has driver...
jmchilton ad0b050
Migrate a bunch more selenium interactions from naviagtes_galaxy to h…
jmchilton cc9b778
Establish helpers to decouple test_has_driver from Selenium internals.
jmchilton 1c85afe
Use has_driver abstractions to reduce test dependence on Selenium int…
jmchilton 9e13167
Migrate screenshot abstractions into HasDriver.
jmchilton cae2334
Abstract out find_element.
jmchilton 0d4b91e
Establish a Playwright implementation of our page interaction layer.
jmchilton a248596
Cookie and WebElement abstractions.
jmchilton dc2cb4e
Implement more has driver abstractions to decouple navigates_galaxy f…
jmchilton 1986b80
Cleanup abstraction use in navigates_galaxy.py.
jmchilton 086eac9
Update galaxy.selenium package to allow dispatching selenium or playw…
jmchilton 468efd6
Allow reading most GALAXY_TEST_SELENIUM_ environment variables from a…
jmchilton 21d8b5a
Add additional e2e testing abstractions used by selenium test case fr…
jmchilton 0849f7a
Update Selenium Test Case framework to allow new playwright backend.
jmchilton cd5c958
Sharper selectors for signout components.
jmchilton 75fce6a
Introduce select_by_value for uniform selection across browser automa…
jmchilton 6ac14d4
Decorators to distinguish selenium only and playwright only tests.
jmchilton c1ad85a
Adjust tests for Playwright compatibility.
jmchilton 8df6f68
Add component.wait_for_and_send_enter abstraction, fix test.
jmchilton 8e9d350
run_tests.sh updates for playwright.
jmchilton 8fcd393
Add GitHub Actions workflow for Playwright test execution
jmchilton 8aa043b
More debugging in navigates_galaxy.py.
jmchilton aa44af4
Mark all the untested tests as Selenium only - we love a checklist.
jmchilton 50a76ec
Implement css accessor for playwright element.
jmchilton 4f99774
Working alert abstraction across playwright/selenium.
jmchilton a3adeab
Update tests for new abstractions...
jmchilton cb7b408
Full README for galaxy-selenium package.
jmchilton c1cd222
Refactor galaxy.tool_util.verify.wait -> galaxy.util.wait.
jmchilton 5638ce8
Refactor browser availability caching to use lru_cache
jmchilton 701ac9a
Fix ConfiguredDriver.__init__ docstring to reflect actual parameters
jmchilton 4bd3a4c
Import and docstrings fixes from PR review.
jmchilton 7392f29
Fix custom wait on conditions across browser abstractions.
jmchilton 0202dc0
Implement distinction between quit/close in browser automation stuff.
jmchilton 90cf6f1
Better documentation of type hacks in has_driver.
jmchilton 277c414
Switch to main frame so we don't accessibility check the tool output.
jmchilton File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| name: Playwright tests | ||
| on: | ||
| push: | ||
| paths-ignore: | ||
| - 'doc/**' | ||
| - 'packages/**' | ||
| pull_request: | ||
| paths-ignore: | ||
| - 'doc/**' | ||
| - 'packages/**' | ||
| schedule: | ||
| # Run at midnight UTC every Tuesday | ||
| - cron: '0 0 * * 2' | ||
| env: | ||
| GALAXY_CONFIG_GALAXY_URL_PREFIX: '/galaxypf' | ||
| GALAXY_TEST_DBURI: 'postgresql://postgres:postgres@localhost:5432/galaxy?client_encoding=utf8' | ||
| GALAXY_TEST_RAISE_EXCEPTION_ON_HISTORYLESS_HDA: '1' | ||
| GALAXY_TEST_SELENIUM_RETRIES: 1 | ||
| GALAXY_TEST_SKIP_FLAKEY_TESTS_ON_ERROR: 1 | ||
| GALAXY_TEST_SELENIUM_HEADLESS: 1 | ||
| YARN_INSTALL_OPTS: --frozen-lockfile | ||
| GALAXY_CONFIG_SQLALCHEMY_WARN_20: '1' | ||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
| jobs: | ||
| build-client: | ||
| uses: ./.github/workflows/build_client.yaml | ||
| test: | ||
| name: Test | ||
| needs: [build-client] | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| python-version: ['3.9'] | ||
| chunk: [0, 1, 2] | ||
| services: | ||
| postgres: | ||
| image: postgres:17 | ||
| env: | ||
| POSTGRES_USER: postgres | ||
| POSTGRES_PASSWORD: postgres | ||
| POSTGRES_DB: postgres | ||
| ports: | ||
| - 5432:5432 | ||
| steps: | ||
| - if: github.event_name == 'schedule' | ||
| run: | | ||
| echo "GALAXY_CONFIG_OVERRIDE_METADATA_STRATEGY=extended" >> $GITHUB_ENV | ||
| echo "GALAXY_CONFIG_OVERRIDE_OUTPUTS_TO_WORKING_DIRECTORY=true" >> $GITHUB_ENV | ||
| - uses: actions/checkout@v5 | ||
| with: | ||
| path: 'galaxy root' | ||
| persist-credentials: false | ||
| - uses: actions/setup-python@v6 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
| cache: 'pip' | ||
| cache-dependency-path: 'galaxy root/requirements.txt' | ||
| - name: Get full Python version | ||
| id: full-python-version | ||
| shell: bash | ||
| run: echo "version=$(python -c 'import sys; print("-".join(str(v) for v in sys.version_info))')" >> $GITHUB_OUTPUT | ||
| - name: Cache galaxy venv | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: 'galaxy root/.venv' | ||
| key: gxy-venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('galaxy root/requirements.txt') }}-playwright | ||
| - name: Install Playwright | ||
| run: | | ||
| pip install playwright | ||
| playwright install chromium --with-deps | ||
| working-directory: 'galaxy root' | ||
| - name: Restore client cache | ||
| uses: actions/cache@v4 | ||
| with: | ||
| key: galaxy-static-${{ needs.build-client.outputs.commit-id }} | ||
| path: 'galaxy root/static' | ||
| - name: Run tests | ||
| run: ./run_tests.sh --coverage -playwright lib/galaxy_test/selenium -- --num-shards=3 --shard-id=${{ matrix.chunk }} | ||
| working-directory: 'galaxy root' | ||
| - uses: codecov/codecov-action@v5 | ||
| with: | ||
| flags: playwright | ||
| working-directory: 'galaxy root' | ||
| - uses: actions/upload-artifact@v4 | ||
| if: failure() | ||
| with: | ||
| name: Playwright test results (${{ matrix.python-version }}, ${{ matrix.chunk }}) | ||
| path: 'galaxy root/run_playwright_tests.html' | ||
| - uses: actions/upload-artifact@v4 | ||
| if: failure() | ||
| with: | ||
| name: Playwright debug info (${{ matrix.python-version }}, ${{ matrix.chunk }}) | ||
| path: 'galaxy root/database/test_errors' | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| """Browser availability checking utilities for Selenium and Playwright. | ||
|
|
||
| This module provides functions to check if browsers are available and properly | ||
| configured for automated testing. These functions are used for conditional test | ||
| skipping and diagnostic scripts. | ||
| """ | ||
|
|
||
| from functools import lru_cache | ||
|
|
||
| from playwright.sync_api import sync_playwright | ||
| from selenium import webdriver | ||
| from selenium.webdriver.chrome.options import Options as ChromeOptions | ||
|
|
||
| # Installation instruction constants | ||
| SELENIUM_INSTALL_INSTRUCTIONS = ( | ||
| "Install Chrome browser and chromedriver. See: https://chromedriver.chromium.org/getting-started" | ||
| ) | ||
|
|
||
| PLAYWRIGHT_INSTALL_INSTRUCTIONS = "Install with: playwright install chromium" | ||
|
|
||
| # Skip message constants for pytest | ||
| SELENIUM_BROWSER_NOT_AVAILABLE_MESSAGE = f"Selenium Chrome browser not available. {SELENIUM_INSTALL_INSTRUCTIONS}" | ||
|
|
||
| PLAYWRIGHT_BROWSER_NOT_AVAILABLE_MESSAGE = ( | ||
| f"Playwright Chromium browser not available. {PLAYWRIGHT_INSTALL_INSTRUCTIONS}" | ||
| ) | ||
|
|
||
|
|
||
| def is_selenium_browser_available() -> bool: | ||
| """ | ||
| Check if Selenium WebDriver can launch Chrome browser. | ||
|
|
||
| Returns: | ||
| bool: True if Chrome browser is available and can be launched, False otherwise | ||
| """ | ||
| try: | ||
| options = ChromeOptions() | ||
| options.add_argument("--headless=new") | ||
| options.add_argument("--no-sandbox") | ||
| options.add_argument("--disable-dev-shm-usage") | ||
| driver = webdriver.Chrome(options=options) | ||
| driver.quit() | ||
| return True | ||
| except Exception: | ||
| return False | ||
|
|
||
|
|
||
| def is_playwright_browser_available() -> bool: | ||
| """ | ||
| Check if Playwright Chromium browser is installed and available. | ||
|
|
||
| Returns: | ||
| bool: True if Playwright Chromium is installed, False otherwise | ||
| """ | ||
| try: | ||
| with sync_playwright() as p: | ||
| browser = p.chromium.launch(headless=True) | ||
| browser.close() | ||
| return True | ||
| except Exception: | ||
| return False | ||
|
|
||
|
|
||
| def get_selenium_availability_message() -> str: | ||
| """ | ||
| Get a descriptive message about Selenium browser availability. | ||
|
|
||
| Returns: | ||
| str: Status message indicating if Selenium is available or how to enable it | ||
| """ | ||
| if is_selenium_browser_available(): | ||
| return "Selenium Chrome browser is available" | ||
| else: | ||
| return SELENIUM_BROWSER_NOT_AVAILABLE_MESSAGE | ||
|
|
||
|
|
||
| def get_playwright_availability_message() -> str: | ||
| """ | ||
| Get a descriptive message about Playwright browser availability. | ||
|
|
||
| Returns: | ||
| str: Status message indicating if Playwright is available or how to enable it | ||
| """ | ||
| if is_playwright_browser_available(): | ||
| return "Playwright Chromium browser is available" | ||
| else: | ||
| return PLAYWRIGHT_BROWSER_NOT_AVAILABLE_MESSAGE | ||
|
|
||
|
|
||
| @lru_cache(maxsize=1) | ||
| def check_selenium_cached() -> bool: | ||
| """ | ||
| Check Selenium browser availability with caching. | ||
|
|
||
| This avoids repeatedly launching browsers during test collection. | ||
| Uses lru_cache with maxsize=1 to cache the result of the check. | ||
|
|
||
| Returns: | ||
| bool: True if Selenium Chrome browser is available | ||
| """ | ||
| return is_selenium_browser_available() | ||
|
|
||
|
|
||
| @lru_cache(maxsize=1) | ||
| def check_playwright_cached() -> bool: | ||
| """ | ||
| Check Playwright browser availability with caching. | ||
|
|
||
| This avoids repeatedly launching browsers during test collection. | ||
| Uses lru_cache with maxsize=1 to cache the result of the check. | ||
|
|
||
| Returns: | ||
| bool: True if Playwright Chromium browser is available | ||
| """ | ||
| return is_playwright_browser_available() | ||
|
|
||
|
|
||
| __all__ = ( | ||
| # Constants | ||
| "SELENIUM_INSTALL_INSTRUCTIONS", | ||
| "PLAYWRIGHT_INSTALL_INSTRUCTIONS", | ||
| "SELENIUM_BROWSER_NOT_AVAILABLE_MESSAGE", | ||
| "PLAYWRIGHT_BROWSER_NOT_AVAILABLE_MESSAGE", | ||
| # Functions | ||
| "is_selenium_browser_available", | ||
| "is_playwright_browser_available", | ||
| "get_selenium_availability_message", | ||
| "get_playwright_availability_message", | ||
| "check_selenium_cached", | ||
| "check_playwright_cached", | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really want to do that ?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This same line is in the selenium version of this file. I am happy to drop it though if you'd like.