UI тесты для WordPress (Codeception + WP Browser)

12 мин. 5 сек.
165
1

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

Теперь, при добавлении нового кода в репозиторий, автоматически запускаются приемочные тесты.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *