UI тесты для WordPress (Codeception + WP Browser)
UI (E2E, GUI) тесты полностью эмулируют поведение пользователей в браузере. Данные тесты относятся к приемочному (acceptance) виду тестирования.
Пишется пошаговый тест, как пользователь должен себя вести в вашем приложении: на какую страницу приложения он зайдет, какую информацию заполнит, какую кнопку нажмет и т.д. Чаще всего такие тесты пишут тестировщики, но иногда и разработчики в зависимости от требований компании. В дальнейшем эти тесты можно и даже нужно использовать как часть процесса CI (Continuous Integration).
Данный вид тестов дает 100% гарантию, что ваше приложение работает полностью начиная от сервера, бэкенда и заканчивая фронтендом. К тому же сами тесты мега-простые в написании. Звучит хорошо, но как всегда за это нужно чем-то пожертвовать. Итак, эти тесты не показывают проблемы в коде (за исключением скриншотов, при включенном дебаге) и они слишком долго выполняются, так как требуют ресурсов для запуска.
Так как это единственные тесты, которые дают 100% гарантию работы вашего приложения, они обязательно должны быть на любом продуктовом проекте. Даже 1 тест даст вам крутой результат, а там где 1, там и 10к тестов, которые будут запускаться несколько часов, но реальные люди все равно не смогут протестировать этот же объем вручную и без ошибок.
Установка и настройка Codeception
Установим библиотеку для PHP Codeception, через которую, можно запускать практически любые виды тестов. К нему нужно поставить дополнение WP Browser, которое поможет писать тесты для WordPress еще проще, хотя куда еще проще, эти тесты и так самые простые в написании.
composer require --dev codeception/codeception composer require --dev lucatume/wp-browser
Из-за того, что библиотека Codeception позволяет запускать различные виды тестов нам понадобиться два конфига: основной и для приемочных тестов. Итак, создаем в корне приложения файл codeception.yml
:
paths: tests: tests/php # директория с тестами output: codeception/_output # директория для вывода результатов запуска. В нее будут сохраняться скриншоты и HTML-страницы неудачных запусков, информация по покрытию и многое другое. data: codeception/_data # дополнительная директорию, куда мы разместим дамп базы данных в дальнейшем. support: codeception/_support # директория в которую вы можете добавить любые классы (соблюдая стандарт PSR-4), которые будут загружаться при запуске тестов. envs: codeception/_envs # директория для конфигураций среды разработки. actor_suffix: Tester # суффикс класса для тестеров. extensions: # можем подключить любые расширения. enabled: - Codeception\Extension\RunFailed # расширение для продолжения работы при неудачном тесте. params: - codeception/_config/params.php # добавляем путь к PHP-файлу, в котором мы пропишем константы для подключения к БД settings: # настройки запуска backup_globals: false # запрещаем PHPUnit выполнять резервное копирование глобальных переменных. colors: true # Делаем разноцветный вывод
Теперь создаем конфиг для приемочных тестов tests/acceptance.suite.yml
:
actor: AcceptanceTester extensions: enabled: - Codeception\Extension\RunProcess: 0: chromedriver --url-base=/wd/hub - Codeception\Extension\RunFailed commands: - Codeception\Command\GenerateWPUnit - Codeception\Command\GenerateWPRestApi - Codeception\Command\GenerateWPRestController - Codeception\Command\GenerateWPRestPostTypeController - Codeception\Command\GenerateWPAjax - Codeception\Command\GenerateWPCanonical - Codeception\Command\GenerateWPXMLRPC modules: enabled: - WPDb - WPWebDriver config: WPDb: dsn: 'mysql:host=%DB_HOST%;dbname=%DB_NAME%' user: '%DB_USER%' password: '%DB_PASSWORD%' #import the dump before the tests; this means the test site database will be repopulated before the tests. dump: 'codeception/_data/dump.sql' populate: true # re-import the dump between tests; this means the test site database will be repopulated between the tests. cleanup: true waitlock: 10 url: '%WP_URL%' urlReplacement: true tablePrefix: '%DB_TABLE_PREFIX%' WPWebDriver: url: '%WP_URL%' port: 9515 window_size: maximize browser: chrome host: localhost adminUsername: '%WP_ADMIN_USERNAME%' adminPassword: '%WP_ADMIN_PASSWORD%' adminPath: '%WP_ADMIN_PATH%' capabilities: "goog:chromeOptions": args: ["--user-agent=wp-browser"]
Выглядит страшно, но в целом интуитивно понятные настройки. Если есть желание, можете разобраться с настройками сами.
Создаем отдельную новую базу acceptance_db
, ставим чистую установку WordPress, активируем тестируемый плагин/тему и делаем экспорт базы в codeception/_data/dump.sql
. Можно сделать вручную или с помощью WP CLI:
wp config create --dbname="acceptance_db" --dbusroot" --dbpass="root" --dbhost="localhost" --dbprefix="wp_" wp core install --url="http://your-site.local" --title="Test" --admin_user="admin" --admin_password="pass" --admin_email="i@wp-punk.com" --skip-email wp rewrite structure '/%postname%/' --hard wp plugin activate --all mysqldump --host="localhost" --user="root" --password="root" acceptance_db > codeception/_data/dump.sql
Создаем конфиг для подключения к БД в codeception/_config/params.php
:
<?php return [ 'WP_URL' => 'http://your-site.local', 'WP_ADMIN_USERNAME' => 'admin', 'WP_ADMIN_PASSWORD' => 'pass', 'WP_ADMIN_PATH' => '/wp-admin', 'DB_HOST' => 'localhost', 'DB_NAME' => 'acceptance_db', 'DB_USER' => 'root', 'DB_PASSWORD' => 'root', 'DB_TABLE_PREFIX' => 'wp_', ];
Создаем тестера, который будет выполнять наши задачи в файле codeception/_support/AcceptanceTester.php
:
<?php use Codeception\Actor; class AcceptanceTester extends Actor { use _generated\AcceptanceTesterActions; }
Теперь обновим wp_config.php
, чтобы при запуске приемочных тестов они выполнялись на другой базе данных:
if ( isset( $_SERVER['HTTP_X_TESTING'] ) || ( isset( $_SERVER['HTTP_USER_AGENT'] ) && $_SERVER['HTTP_USER_AGENT'] === 'wp-browser' ) || getenv( 'WPBROWSER_HOST_REQUEST' ) ) { define( 'DB_NAME', 'codeception_db' ); } else { define( 'DB_NAME', 'local' ); }
С настройкой Codeception мы закончили, но… Но необходимо установить ChromeDriver:
- MacOS:
brew cask install chromedriver
. - Windows:
choco install chromedriver
Первый Acceptance Тест
Теперь создаем файл tests/acceptance/FirstCest.php
(Cest — суффикс по умолчанию для названия тестовых классов):
<?php class FirstCest { public function visitSettingsPage( AcceptanceTester $I ) { $I->loginAsAdmin(); $I->amOnPage( '/wp-admin/admin.php?page=plugin-name' ); $I->see( 'Plugin Name Settings' ); } }
Вот так выглядит простой тест, который можно понять и без навыков программирования. Пользователь(I) заходит какую-то страницу в админку и видит там надпись Plugin Name Settings.
Запуск тестов
vendor/bin/codecept run acceptance
При запуске, должно открыться новое окно Google Chrome, автоматически выполнить все действия, описанные в тестах и вывести результат в консоль:

Как видите, самое сложное — это настройка среды, сами тесты очень простые и понятные без особых навыков.
Запуск приемочных тестов в GitHub Actions
Для запуска тестов необходимо настроить локальный сервер. Для этого создаем конфиг для Apache .github/workflows/plugin-name.conf
:
<VirtualHost *:80> DocumentRoot /home/runner/work/WPPlugin/WPPlugin/wordpress ServerName plugin-name.test ErrorLog /home/runner/work/WPPlugin/WPPlugin/logs/error.log CustomLog /home/runner/work/WPPlugin/WPPlugin/logs/access.log combined DirectoryIndex index.php index.html /index.php <Directory /home/runner/work/WPPlugin/WPPlugin/wordpress> DirectoryIndex index.php index.html /index.php AllowOverride All Require all granted </Directory> </VirtualHost>
Теперь нужно как-то разделить локальный запуск и запуск во время выполнение CI в GitHub Actions. Поэтому меняем код в файле codeception/_config/params.php
:
<?php if ( in_array( 'github-actions', $argv, true ) && file_exists( $config ) ) { // Config for GH Actions. return [ 'WP_URL' => 'http://plugin-name.test', 'WP_ADMIN_USERNAME' => 'admin', 'WP_ADMIN_PASSWORD' => 'admin', 'WP_ADMIN_PATH' => '/wp-admin', 'DB_HOST' => '127.0.0.1', 'DB_NAME' => 'test_db', 'DB_USER' => 'user', 'DB_PASSWORD' => 'passw0rd', 'DB_TABLE_PREFIX' => 'wp_', ]; } return [ 'WP_URL' => 'http://your-site.local', 'WP_ADMIN_USERNAME' => 'admin', 'WP_ADMIN_PASSWORD' => 'pass', 'WP_ADMIN_PATH' => '/wp-admin', 'DB_HOST' => 'localhost', 'DB_NAME' => 'acceptance_db', 'DB_USER' => 'root', 'DB_PASSWORD' => 'root', 'DB_TABLE_PREFIX' => 'wp_', ];
Создаем конфиг для GH Actions .github/workflows/plugin-name.yml
:
name: PluginName GitHub Actions on: [push] jobs: build: strategy: matrix: php-versions: [7.4] runs-on: ubuntu-latest env: php-ext-cache-key: cache-v1 # can be any string, change to clear the extension cache. php-extensions: mysql php-ini-values: post_max_size=256M wp-directory: wordpress wp-plugins-directory: wordpress/wp-content/plugins DB_HOST: 127.0.0.1 DB_TABLE_PREFIX: wp_ DB_NAME: test_db DB_USER: user DB_PASSWORD: passw0rd WP_URL: http://plugin-name.test WP_DOMAIN: plugin-name.test WP_ADMIN_USERNAME: admin WP_ADMIN_PASSWORD: admin WP_ADMIN_EMAIL: admin@plugin-name.test services: mysql: image: mysql:5.6 env: MYSQL_USER: ${{ env.DB_USER }} MYSQL_PASSWORD: ${{ env.DB_PASSWORD }} MYSQL_DATABASE: ${{ env.DB_NAME }} MYSQL_ALLOW_EMPTY_PASSWORD: yes ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - name: Download Plugin uses: actions/checkout@v2 with: path: ${{ env.wp-plugins-directory }} - name: Install dependencies working-directory: ${{ env.wp-plugins-directory }} run: | composer install yarn install - name: Setup PHP uses: shivammathur/setup-php@v2 with: tools: pecl php-version: ${{ matrix.php-versions }} extensions: ${{ env.php-extensions }} ini-values: ${{ env.php-ini-values }} env: update: true - name: Install WP CLI run: | curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar chmod +x wp-cli.phar mkdir -p wp-cli sudo mv wp-cli.phar wp-cli/wp echo "::add-path::$GITHUB_WORKSPACE/wp-cli" echo -n "apache_modules:\n - mod_rewrite" > "${{ env.wp-directory }}/wp-cli.yml" - name: Install WP working-directory: ${{ env.wp-directory }} run: | wp core download --version=5.4 wp config create --dbname="${{ env.DB_NAME }}" --dbuser="${{ env.DB_USER }}" --dbpass="${{ env.DB_PASSWORD }}" --dbhost="${{ env.DB_HOST }}" --dbprefix="${{ env.DB_TABLE_PREFIX }}" wp core install --url="${{ env.WP_URL }}" --title="Test" --admin_user="${{ env.WP_ADMIN_USERNAME }}" --admin_password="${{ env.WP_ADMIN_PASSWORD }}" --admin_email="${{ env.WP_ADMIN_EMAIL }}" --skip-email wp rewrite structure '/%postname%/' --hard wp plugin activate --all - name: Make a DB dump for Codeception working-directory: ${{ env.wp-plugins-directory }} run: mysqldump --host="${{ env.DB_HOST }}" --user="${{ env.DB_USER }}" --password="${{ env.DB_PASSWORD }}" ${{ env.DB_NAME }} > codeception/_data/dump.sql - name: Setup hosts run: | echo ${{ env.DB_HOST }} ${{ env.WP_DOMAIN }} | sudo tee -a /etc/hosts cat /etc/hosts - name: Install & configure Apache run: | sudo add-apt-repository ppa:ondrej/php sudo apt-get update sudo apt-get install apache2 libapache2-mod-php7.4 mkdir -p logs sudo cp ${{ env.wp-plugins-directory }}/.github/workflows/plugin-name.conf /etc/apache2/sites-available/plugin-name.conf sudo a2enmod headers sudo a2enmod rewrite sudo a2ensite plugin-name sudo service apache2 restart - name: Setup Chromedriver uses: nanasess/setup-chromedriver@master - name: Run Chromedriver run: | export DISPLAY=:99 chromedriver --url-base=/wd/hub & sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional - name: Run Acceptance Tests working-directory: ${{ env.wp-plugins-directory }} run: .vendor/bin/composer acceptance -- --env github-actions - name: Archive Codeception output uses: actions/upload-artifact@v1 if: failure() with: name: codeception-output path: ${{ env.wp-plugins-directory }}/codeception/_output - name: Archive Apache Logs uses: actions/upload-artifact@v1 if: failure() with: name: apache-logs path: logs
Теперь, при добавлении нового кода в репозиторий, автоматически запускаются приемочные тесты.
Источник: WP Punk.