├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── feature_request.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── tests.yml ├── README.md ├── config.selenium-standalone-chrome.yaml ├── docker-compose.selenium-chrome.yaml ├── install.yaml └── tests └── test.bats /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🐞 Bug report or Support Request 2 | description: Create a report to help us improve. 3 | labels: [bug] 4 | body: 5 | - type: checkboxes 6 | attributes: 7 | label: Preliminary checklist 8 | description: Please complete the following checks before submitting an issue. 9 | options: 10 | - label: I am using the latest stable version of DDEV 11 | required: true 12 | - label: I am using the latest stable version of this add-on 13 | required: true 14 | - type: textarea 15 | attributes: 16 | label: Expected Behavior 17 | description: What did you expect to happen? 18 | validations: 19 | required: true 20 | - type: textarea 21 | attributes: 22 | label: Actual Behavior 23 | description: What actually happened instead? 24 | validations: 25 | required: true 26 | - type: textarea 27 | attributes: 28 | label: Steps To Reproduce 29 | description: Specific steps to reproduce the behavior. 30 | placeholder: | 31 | 1. In this environment... 32 | 2. With this config... 33 | 3. Run `...` 34 | 4. See error... 35 | validations: 36 | required: false 37 | - type: textarea 38 | attributes: 39 | label: Anything else? 40 | description: | 41 | Links? References? Screenshots? Anything that will give us more context about your issue! 42 | 43 | 💡 Attach images or log files by clicking this area to highlight it and dragging files in. 44 | validations: 45 | required: false 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Feature request 2 | description: Suggest an idea for this project. 3 | labels: [enhancement] 4 | body: 5 | - type: checkboxes 6 | attributes: 7 | label: Is there an existing issue for this? 8 | description: Please search existing issues to see if one already exists for your request. 9 | options: 10 | - label: I have searched the existing issues 11 | required: true 12 | - type: textarea 13 | attributes: 14 | label: Is your feature request related to a problem? 15 | description: Clearly and concisely describe the problem. (Ex. I'm always frustrated when...) 16 | validations: 17 | required: true 18 | - type: textarea 19 | attributes: 20 | label: Describe your solution 21 | description: Clearly and concisely describe what you want to happen. 22 | validations: 23 | required: true 24 | - type: textarea 25 | attributes: 26 | label: Describe alternatives 27 | description: Clearly and concisely describe any alternative solutions or features you've considered. 28 | validations: 29 | required: false 30 | - type: textarea 31 | attributes: 32 | label: Additional context 33 | description: Add any other context or screenshots about the feature request. 34 | validations: 35 | required: false 36 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## The Issue 2 | 3 | - # 4 | 5 | 6 | 7 | ## How This PR Solves The Issue 8 | 9 | ## Manual Testing Instructions 10 | 11 | ```bash 12 | ddev add-on get https://github.com///tarball/ 13 | ddev restart 14 | ``` 15 | 16 | ## Automated Testing Overview 17 | 18 | 19 | 20 | ## Release/Deployment Notes 21 | 22 | 23 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | on: 3 | pull_request: 4 | push: 5 | branches: [ main ] 6 | 7 | schedule: 8 | - cron: '25 08 * * *' 9 | 10 | workflow_dispatch: 11 | inputs: 12 | debug_enabled: 13 | type: boolean 14 | description: Debug with tmate 15 | required: false 16 | default: false 17 | 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | cancel-in-progress: true 21 | 22 | # This is required for "gautamkrishnar/keepalive-workflow", see "ddev/github-action-add-on-test" 23 | permissions: 24 | actions: write 25 | 26 | jobs: 27 | tests: 28 | strategy: 29 | matrix: 30 | ddev_version: [stable, HEAD] 31 | fail-fast: false 32 | 33 | runs-on: ubuntu-latest 34 | 35 | steps: 36 | - uses: ddev/github-action-add-on-test@v2 37 | with: 38 | ddev_version: ${{ matrix.ddev_version }} 39 | token: ${{ secrets.GITHUB_TOKEN }} 40 | debug_enabled: ${{ github.event.inputs.debug_enabled }} 41 | addon_repository: ${{ env.GITHUB_REPOSITORY }} 42 | addon_ref: ${{ env.GITHUB_REF }} 43 | 44 | - name: Archive browser_output 45 | uses: actions/upload-artifact@v4 46 | with: 47 | name: browser_output 48 | path: | 49 | web/sites/simpletest/browser_output 50 | 51 | - name: Archive junits 52 | uses: actions/upload-artifact@v4 53 | with: 54 | name: junits 55 | path: | 56 | *.junit.xml 57 | 58 | - name: Nightwatch reports 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: nightwatch 62 | path: | 63 | web/core/reports/nightwatch 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![add-on registry](https://img.shields.io/badge/DDEV-Add--on_Registry-blue)](https://addons.ddev.com) 2 | [![tests](https://github.com/ddev/ddev-selenium-standalone-chrome/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/ddev/ddev-selenium-standalone-chrome/actions/workflows/tests.yml?query=branch%3Amain) 3 | [![last commit](https://img.shields.io/github/last-commit/ddev/ddev-selenium-standalone-chrome)](https://github.com/ddev/ddev-selenium-standalone-chrome/commits) 4 | [![release](https://img.shields.io/github/v/release/ddev/ddev-selenium-standalone-chrome)](https://github.com/ddev/ddev-selenium-standalone-chrome/releases/latest) 5 | 6 | # DDEV Selenium Standalone Chrome 7 | 8 | ## Overview 9 | 10 | This service can be used with any project type. The examples below are Drupal-specific. Contributions for docs and tests that show this service working with other project types are appreciated. 11 | 12 | ## Installation 13 | 14 | ```bash 15 | ddev add-on get ddev/ddev-selenium-standalone-chrome 16 | ddev restart 17 | ``` 18 | 19 | > [!NOTE] 20 | > Run `ddev add-on get ddev/ddev-selenium-standalone-chrome` after changes to `name`, `additional_hostnames`, `additional_fqdns`, or `project_tld` in `.ddev/config.yaml` so that `.ddev/docker-compose.selenium-chrome_extras.yaml` is regenerated. 21 | 22 | After installation, make sure to commit the `.ddev` directory to version control. 23 | 24 | ### Optional steps 25 | 26 | 1. Update the provided `.ddev/config.selenium-standalone-chrome.yaml` as you see fit (and remove the #ddev-generated line). You can also just override lines in your `.ddev/config.yaml` 27 | 1. Check `config.selenium-standalone-chrome.yaml` and `docker-compose.selenium-chrome.yaml` into your source control. 28 | 1. Update by re-running `ddev add-on get ddev/ddev-selenium-standalone-chrome`. 29 | 30 | ## Usage 31 | 32 | - Your project is now ready to run FunctionalJavascript and [Nightwatch](https://www.drupal.org/docs/automated-testing/javascript-testing-using-nightwatch) tests from Drupal core, or [Drupal Test Traits](https://gitlab.com/weitzman/drupal-test-traits) (DTT). All these types are tested in this repo. Some examples to try: 33 | - FunctionalJavascript: 34 | - Ensure you have the `drupal/core-dev` Composer package or equivalent. 35 | - `ddev exec -d /var/www/html/web "../vendor/bin/phpunit -c ./core/phpunit.xml.dist ./core/modules/system/tests/src/FunctionalJavascript/FrameworkTest.php"` 36 | - Nightwatch 37 | - `ddev exec -d /var/www/html/web/core yarn install` (do this once) 38 | - `ddev exec -d /var/www/html/web/core touch .env` (do this once) 39 | - `ddev exec -d /var/www/html/web/core yarn test:nightwatch tests/Drupal/Nightwatch/Tests/exampleTest.js` 40 | - Drupal Test Traits 41 | - Ensure you have a working site that has the `weitzman/drupal-test-traits` Composer package. 42 | - `ddev exec -d /var/www/html/web "../vendor/bin/phpunit --bootstrap=../vendor/weitzman/drupal-test-traits/src/bootstrap-fast.php --printer '\Drupal\Tests\Listeners\HtmlOutputPrinter' ../vendor/weitzman/drupal-test-traits/tests/ExampleSelenium2DriverTest.php"` 43 | 44 | ## Watching the tests 45 | 46 | ### The easy way: Use noVNC (built-in) 47 | 48 | 1. Remove `--headless` from the `MINK_DRIVER_ARGS_WEBDRIVER` in your project's `.ddev/config.selenium-standalone-chrome.yaml`. Run `ddev restart`. 49 | 2. On your host, run `ddev launch :7900` or browse to `https://[DDEV SITE URL]:7900` to watch tests run with noVNC (neat!). 50 | 51 | By default noVNC connects without password, you can enable password by removing the `VNC_NO_PASSWORD=1` line in the file `docker-compose.selenium-chrome.yaml`, the default password will be `secret`, and you can set the custom one via `VNC_PASSWORD` environment variable. 52 | 53 | This enables you to quickly see what is going on with your tests. 54 | 55 | ### Use a local VNC client (try noVNC first!) 56 | 57 | If you are using something like behat and want to debug tests when they fail by manually navigating around your site in the Chromium browser included with this addon, you might want to use a VNC client installed on your machine, such as Screen Sharing on macOS (built-in) or TightVNC on Linux and Windows (must be downloaded and installed). This is because with noVNC, you are running a browser (Chromium) inside another browser (whatever browser you use on your local machine), which can be inconvenient-- for example, the keyboard shortcut to reload a page in Chromium will reload your local browser and kick you out of noVNC instead of reloading Chromium, and it may be hard to type a new url in the Chromium address bar due to how your local browser handles keyboard input. 58 | 59 | In other words, if you just want to watch the tests, use noVNC. 60 | 61 | If you want to use the browser provided by this addon to check out the test results by poking around your site, consider using a local VNC client. To do so, you need to open port 5900. 62 | 63 | #### How to open port 5900 for VNC access 64 | 65 | 1. Open `.ddev/docker-compose.selenium-chrome.yaml`. 66 | 2. Uncomment the two lines about `ports` and `5900:5900`. 67 | 3. Execute `ddev restart`. 68 | 69 | You can now connect to `[DDEV SITE URL]:5900` (password: `secret`) in your VNC client. 70 | 71 | Note that when using `ports`, only one project at a time can be running with port 5900. 72 | 73 | ### Behat config example 74 | 75 | If you use Behat as a test running, adjust your `behat.yml` 76 | 77 | ```yaml 78 | extensions: 79 | Behat\MinkExtension: 80 | base_url: http://web 81 | selenium2: 82 | wd_host: http://selenium-chrome:4444/wd/hub 83 | capabilities: 84 | chrome: 85 | switches: 86 | - "--disable-gpu" 87 | - "--headless" 88 | - "--no-sandbox" 89 | - "--disable-dev-shm-usage" 90 | ``` 91 | 92 | ## Contribute 93 | 94 | - Anyone is welcome to submit a PR to this repo. See README.md at https://github.com/ddev/ddev-addon-template, the parent of this repo. 95 | 96 | ## Credits 97 | 98 | **Contributed and maintained by [@weitzman](https://github.com/weitzman)** 99 | -------------------------------------------------------------------------------- /config.selenium-standalone-chrome.yaml: -------------------------------------------------------------------------------- 1 | #ddev-generated 2 | # Remove the line above if you don't want this file to be overwritten when you run 3 | # ddev get ddev/ddev-selenium-standalone-chrome 4 | # 5 | # This file comes from https://github.com/ddev/ddev-selenium-standalone-chrome 6 | # 7 | web_environment: 8 | - BROWSERTEST_OUTPUT_DIRECTORY=/tmp 9 | - BROWSERTEST_OUTPUT_BASE_URL=${DDEV_PRIMARY_URL} 10 | - SIMPLETEST_BASE_URL=http://web 11 | - SIMPLETEST_DB=mysql://db:db@db/db 12 | # Use disable-dev-shm-usage instead of setting shm_usage 13 | # https://developers.google.com/web/tools/puppeteer/troubleshooting#tips 14 | # The format of chromeOptions is defined at https://chromedriver.chromium.org/capabilities 15 | - MINK_DRIVER_ARGS_WEBDRIVER=[\"chrome\", {\"browserName\":\"chrome\",\"goog:chromeOptions\":{\"w3c\":false,\"args\":[\"--disable-gpu\",\"--headless\", \"--no-sandbox\", \"--disable-dev-shm-usage\"]}}, \"http://selenium-chrome:4444/wd/hub\"] 16 | # Nightwatch 17 | - DRUPAL_TEST_BASE_URL=http://web 18 | - DRUPAL_TEST_DB_URL=mysql://db:db@db/db 19 | - DRUPAL_TEST_WEBDRIVER_HOSTNAME=selenium-chrome 20 | - DRUPAL_TEST_WEBDRIVER_PORT=4444 21 | - DRUPAL_TEST_WEBDRIVER_PATH_PREFIX=/wd/hub 22 | - DRUPAL_TEST_WEBDRIVER_CHROME_ARGS=--disable-gpu --headless --no-sandbox --disable-dev-shm-usage 23 | - DRUPAL_TEST_CHROMEDRIVER_AUTOSTART=false 24 | - DRUPAL_NIGHTWATCH_SEARCH_DIRECTORY=../ 25 | - DRUPAL_NIGHTWATCH_IGNORE_DIRECTORIES=node_modules,vendor,.*,sites/*/files,sites/*/private,sites/simpletest 26 | - DRUPAL_NIGHTWATCH_OUTPUT=reports/nightwatch 27 | # DTT 28 | - DTT_BASE_URL=http://web 29 | - DTT_MINK_DRIVER_ARGS=[\"chrome\", {\"browserName\":\"chrome\",\"goog:chromeOptions\":{\"w3c\":false,\"args\":[\"--disable-gpu\",\"--headless\", \"--no-sandbox\", \"--disable-dev-shm-usage\"]}}, \"http://selenium-chrome:4444/wd/hub\"] 30 | -------------------------------------------------------------------------------- /docker-compose.selenium-chrome.yaml: -------------------------------------------------------------------------------- 1 | #ddev-generated 2 | # Remove the line above if you don't want this file to be overwritten when you run 3 | # ddev get ddev/ddev-selenium-standalone-chrome 4 | # 5 | # This file comes from https://github.com/ddev/ddev-selenium-standalone-chrome 6 | # 7 | services: 8 | selenium-chrome: 9 | image: seleniarm/standalone-chromium:4.1.4-20220429 10 | container_name: ddev-${DDEV_SITENAME}-selenium-chrome 11 | expose: 12 | # The internal noVNC port, which operates over HTTP so it can be exposed 13 | # through the router. 14 | - 7900 15 | environment: 16 | - VIRTUAL_HOST=$DDEV_HOSTNAME 17 | - HTTPS_EXPOSE=7900:7900 18 | - HTTP_EXPOSE=7910:7900 19 | - VNC_NO_PASSWORD=1 20 | # To enable VNC access for traditional VNC clients like macOS "Screen Sharing", 21 | # uncomment the following two lines. 22 | #ports: 23 | # - "5900:5900" 24 | labels: 25 | com.ddev.site-name: ${DDEV_SITENAME} 26 | com.ddev.approot: $DDEV_APPROOT 27 | volumes: 28 | - ".:/mnt/ddev_config" 29 | 30 | web: 31 | links: 32 | - selenium-chrome 33 | -------------------------------------------------------------------------------- /install.yaml: -------------------------------------------------------------------------------- 1 | name: ddev-selenium-standalone-chrome 2 | 3 | project_files: 4 | - docker-compose.selenium-chrome.yaml 5 | - config.selenium-standalone-chrome.yaml 6 | 7 | ddev_version_constraint: '>= v1.24.3' 8 | 9 | post_install_actions: 10 | - | 11 | #ddev-nodisplay 12 | #ddev-description:Checking docker-compose.selenium-chrome_extras.yaml for changes 13 | if [ -f docker-compose.selenium-chrome_extras.yaml ] && ! grep -q '#ddev-generated' docker-compose.selenium-chrome_extras.yaml; then 14 | echo "Existing docker-compose.selenium-chrome_extras.yaml does not have #ddev-generated, so can't be updated" 15 | exit 2 16 | fi 17 | - | 18 | #ddev-nodisplay 19 | #ddev-description:Adding all hostnames to the selenium-chrome container to make them available 20 | cat <<-END >docker-compose.selenium-chrome_extras.yaml 21 | #ddev-generated 22 | services: 23 | selenium-chrome: 24 | external_links: 25 | {{- $selenium_chrome_hostnames := splitList "," (env "DDEV_HOSTNAME") -}} 26 | {{- range $i, $n := $selenium_chrome_hostnames }} 27 | - "ddev-router:{{- replace (env "DDEV_TLD") "\\${DDEV_TLD}" (replace (env "DDEV_PROJECT") "\\${DDEV_PROJECT}" $n) -}}" 28 | {{- end }} 29 | END 30 | 31 | removal_actions: 32 | - | 33 | #ddev-nodisplay 34 | #ddev-description:Remove docker-compose.selenium-chrome_extras.yaml file 35 | if [ -f docker-compose.selenium-chrome_extras.yaml ]; then 36 | if grep -q '#ddev-generated' docker-compose.selenium-chrome_extras.yaml; then 37 | rm -f docker-compose.selenium-chrome_extras.yaml 38 | else 39 | echo "Unwilling to remove '$DDEV_APPROOT/.ddev/docker-compose.selenium-chrome_extras.yaml' because it does not have #ddev-generated in it; you can manually delete it if it is safe to delete." 40 | fi 41 | fi 42 | -------------------------------------------------------------------------------- /tests/test.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | # Bats is a testing framework for Bash 4 | # Documentation https://bats-core.readthedocs.io/en/stable/ 5 | # Bats libraries documentation https://github.com/ztombol/bats-docs 6 | 7 | # For local tests, install bats-core, bats-assert, bats-file, bats-support 8 | # And run this in the add-on root directory: 9 | # bats ./tests/test.bats 10 | # To exclude release tests: 11 | # bats ./tests/test.bats --filter-tags '!release' 12 | # For debugging: 13 | # bats ./tests/test.bats --show-output-of-passing-tests --verbose-run --print-output-on-failure 14 | 15 | setup() { 16 | set -eu -o pipefail 17 | 18 | # Override this variable for your add-on: 19 | export GITHUB_REPO=ddev/ddev-selenium-standalone-chrome 20 | 21 | TEST_BREW_PREFIX="$(brew --prefix 2>/dev/null || true)" 22 | export BATS_LIB_PATH="${BATS_LIB_PATH}:${TEST_BREW_PREFIX}/lib:/usr/lib/bats" 23 | bats_load_library bats-assert 24 | bats_load_library bats-file 25 | bats_load_library bats-support 26 | 27 | export DIR="$(cd "$(dirname "${BATS_TEST_FILENAME}")/.." >/dev/null 2>&1 && pwd)" 28 | export PROJNAME="test-$(basename "${GITHUB_REPO}")" 29 | mkdir -p ~/tmp 30 | export TESTDIR=$(mktemp -d ~/tmp/${PROJNAME}.XXXXXX) 31 | export DDEV_NONINTERACTIVE=true 32 | export DDEV_NO_INSTRUMENTATION=true 33 | ddev delete -Oy "${PROJNAME}" >/dev/null 2>&1 || true 34 | cd "${TESTDIR}" 35 | 36 | composer -n --no-install create-project 'drupal/recommended-project:^10' . 37 | composer -n config --no-plugins allow-plugins true 38 | composer -n require 'drupal/core-dev:^10' 'drush/drush:^12' 'phpspec/prophecy-phpunit:^2' 'weitzman/drupal-test-traits:^2' 39 | 40 | run ddev config --project-name=${PROJNAME} --project-tld=ddev.site --php-version=8.1 --web-environment-add=SYMFONY_DEPRECATIONS_HELPER=disabled 41 | assert_success 42 | run ddev start -y 43 | assert_success 44 | } 45 | 46 | health_checks() { 47 | run ddev exec curl -sfI selenium-chrome:4444/wd/hub/status 48 | assert_success 49 | assert_output --partial "HTTP/1.1 200 OK" 50 | 51 | run ddev exec curl -sf selenium-chrome:4444/wd/hub/status 52 | assert_success 53 | assert_output --partial "Selenium Grid ready." 54 | 55 | echo "Run a FunctionalJavascript test." >&3 56 | 57 | run ddev exec -d /var/www/html/web "../vendor/bin/phpunit -v -c ./core/phpunit.xml.dist ./core/modules/system/tests/src/FunctionalJavascript/FrameworkTest.php" 58 | assert_success 59 | 60 | echo "Run a Nightwatch test." >&3 61 | 62 | run ddev exec -d /var/www/html/web/core yarn install 63 | assert_success 64 | 65 | run ddev exec -d /var/www/html/web/core touch .env 66 | assert_success 67 | assert_file_exists web/core/.env 68 | 69 | run ddev exec -d /var/www/html/web/core yarn test:nightwatch tests/Drupal/Nightwatch/Tests/jsOnceTest.js 70 | assert_success 71 | 72 | echo "Run a Nightwatch test that logs into Drupal." >&3 73 | 74 | run ddev exec -d /var/www/html/web/core yarn test:nightwatch tests/Drupal/Nightwatch/Tests/loginTest.js 75 | assert_success 76 | 77 | echo "Install Drupal and run a DTT test." >&3 78 | 79 | run ddev exec -d /var/www/html/web "../vendor/bin/drush si -y --account-name=admin --account-pass=password standard" 80 | assert_success 81 | 82 | run ddev exec -d /var/www/html/web "../vendor/bin/phpunit --log-junit dtt.junit.xml --bootstrap=../vendor/weitzman/drupal-test-traits/src/bootstrap-fast.php --printer '\Drupal\Tests\Listeners\HtmlOutputPrinter' ../vendor/weitzman/drupal-test-traits/tests/ExampleSelenium2DriverTest.php" 83 | assert_success 84 | } 85 | 86 | teardown() { 87 | set -eu -o pipefail 88 | ddev delete -Oy ${PROJNAME} >/dev/null 2>&1 89 | [ "${TESTDIR}" != "" ] && rm -rf ${TESTDIR} 90 | } 91 | 92 | @test "install from directory" { 93 | set -eu -o pipefail 94 | echo "# ddev add-on get ${DIR} with project ${PROJNAME} in $(pwd)" >&3 95 | run ddev add-on get "${DIR}" 96 | assert_success 97 | run ddev restart -y 98 | assert_success 99 | health_checks 100 | } 101 | --------------------------------------------------------------------------------