Сквозное тестирование

Дата обновления перевода 2024-07-29

Сквозное тестирование

Компонент Panther позволяет управлять реальным веб-браузером с помощью PHP для создания сквозных тестов.

Установка

1
$ composer require symfony/panther

Note

Если вы устанавливаете этот компонент вне приложения Symfony, вам нужно подключить файл vendor/autoload.php в вашем коде для включения механизма автозагрузки классов, предоставляемых Composer. Детальнее читайте в этой статье.

Вступление

Сквозные тесты - это особый тип тестов приложения, которые имитируют взаимодействие реального пользователя с вашим приложением. Они обычно используются для тестирования пользовательского интерфейса (UI) вашего приложения и эффектов этих взаимодействий (например, когда я нажимаю на эту кнопку, должно быть отправлено письмо). Разница с функциональными тестами, описанными выше, заключается в том. что сквозные тесты используют реальный браузер, а не симуляцию. Этот браузер может работать как в режиме headless (без графического интерфейса), так и без него. Первый вариант удобен для запуска тестов в системе непрерывной интеграции (CI), а второй - для отладки.

Именно для этого предназначен Panther, компонент, который предоставляет настоящий браузер для выполнения ваших тестов. Вот несколько вещей, которые делают Panther особенной по сравнению с другими инструментами тестирования, предоставляемыми Symfony:

  • Возможность делать скриншоты браузера в любое время во время тестирования.
  • Выполнение JavaScript-кода, содержащегося на веб-страницах
  • Panther поддерживает все, что реализовано в Chrome (или Firefox)
  • Удобный способ тестирования приложений в реальном времени (например, WebSockets, Server-Sent Events с Mercure и т. д.)

Установка веб-драйверов

Panther использует протокол WebDriver для управления браузером, используемым для сканирования веб-сайтов. Во всех системах вы можете использовать dbrekelmans/browser-driver-installer, чтобы установить ChromeDriver и geckodriver локально:

1
2
3
$ composer require --dev dbrekelmans/bdi

$ vendor/bin/bdi detect drivers

Panther автоматически обнаружит и использует драйверы, хранящиеся в каталоге drivers/. вашего проекта при установке их вручную. Вы можете скачать ChromeDriver для Chromium или Chrome и GeckoDriver для Firefox и поместить их в любое место в вашем PATH или в каталоге drivers/ вашего проекта.

Также вы можете использовать менеджер пакетов вашей операционной системы для их установки:

1
2
3
4
5
6
7
8
# Ubuntu
$ apt-get install chromium-chromedriver firefox-geckodriver

# MacOS, используя Homebrew
$ brew install chromedriver geckodriver

# Windows, исползуя Chocolatey
$ choco install chromedriver selenium-gecko-driver

Регистрация расширения PHPUnit

Если вы собираетесь использовать Panther для тестирования вашего приложения, настоятельно рекомендуется зарегистрировать расширение Panther PHPUnit. Хотя это и не является строго обязательным, это расширение значительно улучшает качество тестирования, повышая производительность и позволяет использовать интерактивный режим отладки .

При использовании расширения в сочетании с переменной окружения PANTHER_ERROR_SCREENSHOT_DIR, тесты, использующие клиент Panther, которые терпят неудачу или ошибку (после создания клиента), автоматически будет сделан снимок экрана для помощи в отладке.

Чтобы зарегистрировать расширение Panther, добавьте следующие строки в phpunit.xml.dist:

1
2
3
4
<!-- phpunit.xml.dist -->
<extensions>
    <extension class="Symfony\Component\Panther\ServerExtension"/>
</extensions>

Без этого расширения веб-сервер, используемый Panther для обслуживания тестируемого приложения, запускается по требованию и останавливается при вызове tearDownAfterClass(). С другой стороны, если расширение зарегистрировано, веб-сервер будет остановлен только после последнего теста.

Использование

Вот пример фрагмента, в котором Panther используется для тестирования приложения:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Symfony\Component\Panther\Client;

$client = Client::createChromeClient();
// в качестве альтернативы создайте клиент Firefox
$client = Client::createFirefoxClient();

$client->request('GET', 'https://api-platform.com');
$client->clickLink('Getting started');

// ожидать присутствия элемента в DOM, даже если он скрыт
$crawler = $client->waitFor('#installing-the-framework');
// вы также можете подождать, пока элемент станет видимым
$crawler = $client->waitForVisibility('#installing-the-framework');

// получить текст элемента благодаря синтаксису селектора запросов
echo $crawler->filter('#installing-the-framework')->text();
// сделать снимок экрана текущей страницы
$client->takeScreenshot('screen.png');

Note

Согласно спецификации, реализаций WebDriver по умолчанию возвращают только отображаемый текст по умолчанию. При фильтрации по тегу head (например, title), метод text() возвращает пустую строку. Используйте метод html() для получения полного содержания тега, включая сам тег.

Создание TestCase

Класс PantherTestCase позволяет писать сквозные тесты. Он автоматически запускает ваше приложение с помощью встроенного веб-сервера PHP и позволяет вам сканировать его с помощью Panther. Для обеспечения всех привычных инструментов тестирования он расширяет TestCase от PHPUnit.

Если вы тестируете приложение Symfony, PantherTestCase автоматически расширяет класс WebTestCase. Это означает, что вы можете создавать функциональные тесты, которые могут напрямую выполнять ядро вашего приложения и получать доступ ко всем существующим сервисам. В этом случае вы можете использовать все тестовые утверждения краулера , предоставляемые Symfony вместе с Panther.

Вот пример PantherTestCase:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
namespace App\Tests;

use Symfony\Component\Panther\PantherTestCase;

class HomepageTest extends PantherTestCase
{
    public function testMyApp(): void
    {
        // ваше приложение автоматически запускается с использованием встроенного веб-сервера
        $client = static::createPantherClient();
        $client->request('GET', '/home');

        // использовать любое утверждение PHPUnit, включая те, которые предоставлены Symfony...
        $this->assertPageTitleContains('My Title');
        $this->assertSelectorTextContains('#main', 'My body');

        // ... или предоставленное Panther
        $this->assertSelectorIsEnabled('.search');
        $this->assertSelectorIsDisabled('[type="submit"]');
        $this->assertSelectorIsVisible('.errors');
        $this->assertSelectorIsNotVisible('.loading');
        $this->assertSelectorAttributeContains('.price', 'data-old-price', '42');
        $this->assertSelectorAttributeNotContains('.price', 'data-old-price', '36');

        // ...
    }
}

Клиент Panther поставляется с методами, которые ждут, пока какой-либо асинхронный процесс завершается:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
namespace App\Tests;

use Symfony\Component\Panther\PantherTestCase;

class HomepageTest extends PantherTestCase
{
    public function testMyApp(): void
    {
        // ...

        // подождать, чтобы элемент был прикреплен к DOM
        $client->waitFor('.popin');

        // подождать, чтобы элемент был удален из DOM
        $client->waitForStaleness('.popin');

        // подождать, чтобы элемент DOM стал видимым
        $client->waitForVisibility('.loader');

        // подождать, чтобы элемент DOM стал невидимым
        $client->waitForInvisibility('.loader');

        // подождать, чтобы текст был вставлен в содержание элемента
        $client->waitForElementToContain('.total', '25 €');

        // подождать, чтобы текст был удален из содержания элемента
        $client->waitForElementToNotContain('.promotion', '5%');

        // подождать, чтобы кнопка стала активной
        $client->waitForEnabled('[type="submit"]');

        // подождать, чтобы кнопка стала неактивной
        $client->waitForDisabled('[type="submit"]');

        // подождать, чтобы атрибут включал в себя содержание
        $client->waitForAttributeToContain('.price', 'data-old-price', '25 €');

        // подождать, чтобы атрибут не включал в себя содержание
        $client->waitForAttributeToNotContain('.price', 'data-old-price', '25 €');
    }
}

Наконец, вы также можете делать утверждения о вещах, которые произойдут в будущем:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
namespace App\Tests;

use Symfony\Component\Panther\PantherTestCase;

class HomepageTest extends PantherTestCase
{
    public function testMyApp(): void
    {
        // ...

        // элемент будет прикреплен к DOM
        $this->assertSelectorWillExist('.popin');

        // элемент будет удален из DOM
        $this->assertSelectorWillNotExist('.popin');

        // элемент будет видимым
        $this->assertSelectorWillBeVisible('.loader');

        // элемент будет невидимым
        $this->assertSelectorWillNotBeVisible('.loader');

        // текст будет вставлен в содержание элемента
        $this->assertSelectorWillContain('.total', '€25');

        // текст будет удален из содержания элемента
        $this->assertSelectorWillNotContain('.promotion', '5%');

        // кнопка будет активной
        $this->assertSelectorWillBeEnabled('[type="submit"]');

        // кнопка будет неактивной
        $this->assertSelectorWillBeDisabled('[type="submit"]');

        // атрибут будет иметь содержание
        $this->assertSelectorAttributeWillContain('.price', 'data-old-price', '€25');

        // атрибут не будет иметь содержания
        $this->assertSelectorAttributeWillNotContain('.price', 'data-old-price', '€25');
    }
}

Затем вы можете запустить этот тест с помощью PHPUnit, как вы бы сделали это для любого другого теста:

1
$ ./vendor/bin/phpunit tests/HomepageTest.php

При написании сквозных тестов следует помнить, что они медленнее, чем другие тесты. Если вам нужно проверить, что соединение WebDriver остается активным во время длительного выполнения тестов, вы можете использовать метод Client::ping(), который возвращает булево число в зависимости от статуса соединения.

Продвинутое использование

Изменение имени хоста и порта веб-сервера

Если вы хотите изменить хост и/или порт, используемые встроенным веб-сервером, передайте hostname и port в параметр $options метода createPantherClient():

1
2
3
4
$client = self::createPantherClient([
    'hostname' => 'example.com', // defaults to 127.0.0.1
    'port' => 8080, // defaults to 9080
]);

Использование клиентов Browser-Kit

Panther также предоставляет доступ к другим реализациям на базе BrowserKit, таким как Client и Crawler. В отличие от встроенного клиента Panther, эти альтернативные клиенты не поддерживают JavaScript, CSS и захват скриншотов, но они намного быстрее. Доступны два альтернативных клиента:

  • Первый напрямую манипулирует ядром Symfony, предоставляемым WebTestCase. Это самый быстрый из доступных клиентов, но он доступен только для приложений Symfony.
  • Второй использует HttpBrowser. Он является промежуточным звеном между ядром Symfony и тестовыми клиентами Panther. HttpBrowser отправляет реальные HTTP-запросы, используя компонент HttpClient. Он работает быстро и способен просматривать любые веб-страницы, а не только те, что принадлежат тестируемому приложению. Однако HttpBrowser не поддерживает JavaScript и другие дополнительные функции, потому что он полностью написан на PHP. Его можно использовать в любом PHP приложении.

Поскольку все клиенты реализуют один и тот же API, вы можете переключаться с одного на другой просто вызвав соответствующий метод фабрики, в результате чего получается хороший компромисс для каждого отдельного случая тестирования: нужен ли JavaScript, нужна ли аутентификация по внешнему SSO и т. д.

Вот как получить экземпляры этих клиентов:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace App\Tests;

use Symfony\Component\Panther\Client;
use Symfony\Component\Panther\PantherTestCase;

class AppTest extends PantherTestCase
{
    public function testMyApp(): void
    {
        // извлечь существующего клиента
        $symfonyClient = static::createClient();
        $httpBrowserClient = static::createHttpBrowserClient();
        $pantherClient = static::createPantherClient();
        $firefoxClient = static::createPantherClient(['browser' => static::FIREFOX]);

        // создать пользовательского клиента
        $customChromeClient = Client::createChromeClient(null, null, [], 'https://example.com');
        $customFirefoxClient = Client::createFirefoxClient(null, null, [], 'https://example.com');
        $customSeleniumClient = Client::createSeleniumClient('http://127.0.0.1:4444/wd/hub', null, 'https://example.com');

        // если вы тестируете приложение Symfony, вы также имеете доступ к ядру
        $kernel = static::createKernel();

        // ...
    }
}

Note

При инициализации пользовательского клиента интегрированный веб-сервер не запускается автоматически. Используйте PantherTestCase::startWebServer() или класс WebServerManager, если вы хотите запустить его вручную.

Тестирование приложений в реальном времени

Panther предоставляет удобный способ тестирования приложений с возможностями реального времени, которые используют Mercure, WebSocket и похожие технологии.

Метод PantherTestCase::createAdditionalPantherClient() позволяет создать дополнительные, изолированные браузеры, которые могут взаимодействовать с другими браузерами. Например, это может быть полезно для тестирования чат-приложения с несколькими пользователями, подключенными одновременно:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use Symfony\Component\Panther\PantherTestCase;

class ChatTest extends PantherTestCase
{
    public function testChat(): void
    {
        $client1 = self::createPantherClient();
        $client1->request('GET', '/chat');

        // подсоединить 2го пользователя, используя изолированный браузер
        $client2 = self::createAdditionalPantherClient();
        $client2->request('GET', '/chat');
        $client2->submitForm('Post message', ['message' => 'Hi folks !']);

        // подождать, чтобы сообщение было получено первым клиентом
        $client1->waitFor('.message');

        // Утверждения Symfony *всегда* выполняются в основном браузере
        $this->assertSelectorTextContains('.message', 'Hi folks !');
    }
}

Доступ к логам консоли браузера

При необходимости вы можете использовать Panther для доступа к содержанию консоли:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use Symfony\Component\Panther\PantherTestCase;

class ConsoleTest extends PantherTestCase
{
    public function testConsole(): void
    {
        $client = self::createPantherClient(
            [],
            [],
            [
                'capabilities' => [
                    'goog:loggingPrefs' => [
                        'browser' => 'ALL', // вызов к методам console.*
                        'performance' => 'ALL', // данные производительности
                    ],
                ],
            ]
        );

        $client->request('GET', '/');

        $consoleLogs = $client->getWebDriver()->manage()->getLog('browser');
        $performanceLogs = $client->getWebDriver()->manage()->getLog('performance'); // performance logs
    }
}

Передача аргументов в ChromeDriver

При необходимости вы можете сконфгиурировать аргументы для передачи бинарному файлу chromedriver:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use Symfony\Component\Panther\PantherTestCase;

class MyTest extends PantherTestCase
{
    public function testLogging(): void
    {
        $client = self::createPantherClient(
            [],
            [],
            [
                'chromedriver_arguments' => [
                    '--log-path=myfile.log',
                    '--log-level=DEBUG'
                ],
            ]
        );

        $client->request('GET', '/');
    }
}

Использование прокси

Чтобы использовать прокси-сервер, необходимо установить PANTHER_CHROME_ARGUMENTS:

1
2
# .env.test
PANTHER_CHROME_ARGUMENTS='--proxy-server=socks://127.0.0.1:9050'

Принятие самоподписанных сертификатов SSL

Чтобы заставить Chrome принимать невалидные и самоподписанные сертификаты, вы можете установить следующую переменную окружения: PANTHER_CHROME_ARGUMENTS='--ignore-certificate-errors'.

Caution

Эта опция небезопасна, используйте ее только для тестирования в окружениях разработки, никогда в производстве (например, для веб-краулеров).

Для Firefox инстанцируйте клиент следующим образом, это можно сделать при создании клиента:

1
$client = Client::createFirefoxClient(null, null, ['capabilities' => ['acceptInsecureCerts' => true]]);

Использование внешнего веб-сервера

Бывает удобно использовать существующую конфигурацию веб-сервера вместо того, чтобы запускать встроенную конфигурацию PHP. Для этого установите опцию external_base_uri при создании клиента:

1
2
3
4
5
6
7
8
9
10
11
12
13
namespace App\Tests;

use Symfony\Component\Panther\PantherTestCase;

class E2eTest extends PantherTestCase
{
    public function testMyApp(): void
    {
        $pantherClient = static::createPantherClient(['external_base_uri' => 'https://localhost']);

        // ...
    }
}

Note

При использовании внешнего веб-сервера Panther не будет запускать встроенный PHP веб-сервер.

Приложение с несколькими доменами

Бывает так, что ваше приложение на PHP/Symfony может обслуживать несколько различных доменных имен. Поскольку Panther сохраняет клиента в памяти между тестами для повышения производительности, вам придется запускать свои тесты в отдельных процесах, если вы пишете несколько тестов с использованием Panther для разных доменных имен.

Для этого вы можете использовать встроенную аннотацию PHPUnit @runInSeparateProcess. Вот пример использования опции external_base_uri для определения доменного имени, используемого клиентом при использовании отдельных процессов:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// tests/FirstDomainTest.php
namespace App\Tests;

use Symfony\Component\Panther\PantherTestCase;

class FirstDomainTest extends PantherTestCase
{
    /**
     * @runInSeparateProcess
     */
    public function testMyApp(): void
    {
        $pantherClient = static::createPantherClient([
            'external_base_uri' => 'http://mydomain.localhost:8000',
        ]);

        // ...
    }
}

// tests/SecondDomainTest.php
namespace App\Tests;

use Symfony\Component\Panther\PantherTestCase;

class SecondDomainTest extends PantherTestCase
{
    /**
     * @runInSeparateProcess
     */
    public function testMyApp(): void
    {
        $pantherClient = static::createPantherClient([
            'external_base_uri' => 'http://anotherdomain.localhost:8000',
        ]);

        // ...
    }
}

Использование с другими инструментами тестирования

Если вы хотите использовать Panther с другими инструментами тестирования, такими как LiipFunctionalTestBundle. или если вам просто нужно использовать другой базовый класс, вы можете использовать Symfony\Component\Panther\PantherTestCaseTrait для расширения существующей тестовой инфраструктуры с некоторыми механизмами Panther:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespace App\Tests\Controller;

use Liip\FunctionalTestBundle\Test\WebTestCase;
use Symfony\Component\Panther\PantherTestCaseTrait;

class DefaultControllerTest extends WebTestCase
{
    use PantherTestCaseTrait;

    public function testWithFixtures(): void
    {
        $this->loadFixtures([]); // загрузить ваши фикстуры
        $client = self::createPantherClient(); // создать вашего клиента panther

        $client->request('GET', '/');

        // ...
    }
}

Конфигурирование Panther через переменные окружения

Следующие переменные окружения могут быть установлены для изменения некоторого поведения Panther:

PANTHER_NO_HEADLESS
Отключить headless-режим браузера (будет отображаться окно тестирования, полезное для отладки)
PANTHER_WEB_SERVER_DIR
Изменить корень документа проекта (по умолчанию ./public/, относительные пути должны начинаться с ./)
PANTHER_WEB_SERVER_PORT
Изменить порт веб-сервера (по умолчанию 9080)
PANTHER_WEB_SERVER_ROUTER
Использовать скрипт маршрутизатора веб-сервера, который запускается в начале каждого HTTP-запроса
PANTHER_EXTERNAL_BASE_URI
Использовать внешний веб-сервер (встроенный в PHP веб-сервер не будет запущен)
PANTHER_APP_ENV
Переопределить переменную APP_ENV, передаваемую веб-серверу, на котором запущено приложение PHP
PANTHER_ERROR_SCREENSHOT_DIR
Установить базовый каталог для скриншотов неудач/ошибок (например, ./var/error-screenshots)
PANTHER_DEVTOOLS
Переключать инструменты разработчика браузера (по умолчанию enabled, полезно для отладки)
PANTHER_ERROR_SCREENSHOT_ATTACH
Добавить скриншоты, упомянутые выше, в тестовый вывод в формате приложения junit

Переменные окружения, специфические для Chrome

PANTHER_NO_SANDBOX
Отключить песочницу Chrome (небезопасно, но позволяет использовать Panther в контейнерах)
PANTHER_CHROME_ARGUMENTS
Настройте аргументы Chrome. Для полной настройки необходимо установить PANTHER_NO_HEADLESS
PANTHER_CHROME_BINARY
Чтобы использовать другую бинарность google-chrome

Переменные окружения, специфические для Firefox

PANTHER_FIREFOX_ARGUMENTS
Настроить аргументы Firefox. Вам необходимо установить PANTHER_NO_HEADLESS, чтобы настроить полностью
PANTHER_FIREFOX_BINARY
Чтобы использовать другую бинарность firefox

Интерактивный режим

Panther может сделать паузу в ваших наборах тестов после ошибки. Благодаря этой паузе вы можете исследовать возникшую проблему через веб-браузер. Чтобы включить этот режим, вам понадобится опция --debug PHPUnit без режима headless:

1
2
3
4
5
6
$ PANTHER_NO_HEADLESS=1 bin/phpunit --debug

Test 'App\AdminTest::testLogin' started
Error: something is wrong.

Нажмите ввод, чтобы продолжить...

Чтобы использовать интерактивный режим, необходимо зарегистрировать расширение PHPUnit .

Интеграция Docker

Вот минимальный образ Docker, который позволяет запускать Panther с Chrome и Firefox:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FROM php:alpine

# Chromium и ChromeDriver
ENV PANTHER_NO_SANDBOX 1
# Не обязательно, но рекомендовано
ENV PANTHER_CHROME_ARGUMENTS='--disable-dev-shm-usage'
RUN apk add --no-cache chromium chromium-chromedriver

# Firefox и GeckoDriver (опционально)
ARG GECKODRIVER_VERSION=0.28.0
RUN apk add --no-cache firefox libzip-dev; \
    docker-php-ext-install zip
RUN wget -q https://github.com/mozilla/geckodriver/releases/download/v$GECKODRIVER_VERSION/geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz; \
    tar -zxf geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz -C /usr/bin; \
    rm geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz

Затем вы можете создать и запустить свой образ:

1
2
$ docker build . -t myproject
$ docker run -it -v "$PWD":/srv/myproject -w /srv/myproject myproject bin/phpunit

Интегрирование Panther в вашем CI

Действия Github

Panther работает сразу после установки с Действиями GitHub. Вот минимальный файл .github/workflows/panther.yaml для запуска тестов Panther:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
name: Run Panther tests

on: [ push, pull_request ]

jobs:
  tests:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - uses: "ramsey/composer-install@v2"

      - name: Install dependencies
        run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

      - name: Run test suite
        run: bin/phpunit

Travis CI

Panther будет работать с `Travis CI` сразу после установки, если вы добавите аддон Chrome. Вот минимальный файл .travis.yaml для запуска тестов Panther:

1
2
3
4
5
6
7
8
9
10
11
language: php
addons:
  # Если вы не используете Chrome или Firefox, удалите соответствующую строку
  chrome: stable
  firefox: latest

php:
  - 8.0

script:
  - bin/phpunit

Gitlab CI

Вот минимальный файл .gitlab-ci.yaml для запуска тестов Panther с помощью Gitlab CI:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
image: ubuntu

before_script:
  - apt-get update
  - apt-get install software-properties-common -y
  - ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime
  - apt-get install curl wget php php-cli php8.1 php8.1-common php8.1-curl php8.1-intl php8.1-xml php8.1-opcache php8.1-mbstring php8.1-zip libfontconfig1 fontconfig libxrender-dev libfreetype6 libxrender1 zlib1g-dev xvfb chromium-chromedriver firefox-geckodriver -y -qq
  - export PANTHER_NO_SANDBOX=1
  - export PANTHER_WEB_SERVER_PORT=9080
  - php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
  - php composer-setup.php --install-dir=/usr/local/bin --filename=composer
  - php -r "unlink('composer-setup.php');"
  - composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

test:
  script:
    - bin/phpunit

AppVeyor

Panther будет работать сразу после установки с AppVeyor при условии, что установлен Google Chrome. Вот минимальный файл appveyor.yaml для запуска тестов Panther:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
build: false
platform: x86
clone_folder: c:\projects\myproject

cache:
  - '%LOCALAPPDATA%\Composer\files'

install:
  - ps: Set-Service wuauserv -StartupType Manual
  - cinst -y php composer googlechrome chromedriver firfox selenium-gecko-driver
  - refreshenv
  - cd c:\tools\php80
  - copy php.ini-production php.ini /Y
  - echo date.timezone="UTC" >> php.ini
  - echo extension_dir=ext >> php.ini
  - echo extension=php_openssl.dll >> php.ini
  - echo extension=php_mbstring.dll >> php.ini
  - echo extension=php_curl.dll >> php.ini
  - echo memory_limit=3G >> php.ini
  - cd %APPVEYOR_BUILD_FOLDER%
  - composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist

test_script:
  - cd %APPVEYOR_BUILD_FOLDER%
  - php bin\phpunit

Известные ограничения и устранение неполадок

В настоящее время не поддерживаются следующие функции:

  • Сканирование XML-документов (поддерживается только HTML)
  • Обновление существующих документов (браузеры в основном используются для потребления данных, а не для создания веб-страниц)
  • Установка значений формы с использованием синтаксиса многомерных массивов PHP
  • Методы, возвращающие экземпляр \DOMElement (потому что эта библиотека внутренне использует WebDriverElement)
  • Выбор невалидных вариантов в select

Также известна проблема, если вы используете Bootstrap 5. В нем реализован эффект прокрутки, который может вводить Panther в заблуждение. Чтобы решить эту проблему, мы советуем вам отключить этот эффект, установив переменную Bootstrap 5 $enable-smooth-scroll как false в вашем файле стилей:

1
$enable-smooth-scroll: false;

Дополнительная документация

Поскольку Panther реализует API популярных библиотек, вы можете найти еще больше документации: