Библиотека тестирования браузера и сеть для PHP и Symfony
Panther -это удобная автономная библиотека для очистки веб-сайтов и запуска сквозных тестов с использованием реальных браузеров .
Пантера очень мощная. Он использует протокол W3C Webdriver для управления нативными веб -браузерами, такими как Google Chrome и Firefox.
Panther очень проста в использовании, потому что она реализует популярные API Symfony Browserkit и Domcrawler, и содержит все функции, необходимые для тестирования ваших приложений. Это будет звучать знакомо, если вы когда -либо создали функциональный тест для приложения Symfony: поскольку API точно такой же! Имейте в виду, что Panther можно использовать в каждом проекте PHP, так как это отдельная библиотека.
Panther автоматически находит вашу локальную установку Chrome или Firefox и запускает их, поэтому вам не нужно устанавливать что -либо еще на вашем компьютере, сервер Selenium не нужен!
В тестовом режиме Panther автоматически запускает ваше приложение, используя встроенный веб-сервер PHP. Вы можете сосредоточиться на написании своих тестов или сценария скрещивания в Интернете, и Panther позаботится обо всем остальном.
В отличие от библиотек тестирования и скребки веб -скребки, для которых вы привыкли, Panther:
Используйте композитор для установки Panther в свой проект. Вы можете использовать флаг --dev
, если вы хотите использовать Panther только для тестирования, а не для сети в производственной среде:
composer req symfony/panther
composer req --dev symfony/panther
Panther использует протокол Webdriver для управления браузером, используемым для ползания веб -сайтов.
Во всех системах вы можете использовать dbrekelmans/browser-driver-installer
для установки Chromedriver и Geckodriver локально:
composer require --dev dbrekelmans/bdi
vendor/bin/bdi detect drivers
Panther будет обнаружить и использовать автоматически драйверы, хранящиеся в drivers/
каталоге.
В качестве альтернативы, вы можете использовать диспетчер пакетов вашей операционной системы для их установки.
На Ubuntu, беги:
apt-get install chromium-chromedriver firefox-geckodriver
На Mac, используя Homebrew:
brew install chromedriver geckodriver
В окнах, используя шоколад:
choco install chromedriver selenium-gecko-driver
Наконец, вы можете скачать ручной хромидривер (для хрома или хрома) и геккодривер (для Firefox) и поместить их в любом месте вашего PATH
или в drivers/
каталог вашего проекта.
Если вы собираетесь использовать Panther для проверки вашего приложения, мы настоятельно рекомендуем зарегистрировать расширение Panther Phpunit. Несмотря на то, что это расширение, хотя и не является строго обязательным, значительно улучшает опыт тестирования, повышая производительность и позволяя использовать режим интерактивной отладки.
При использовании расширения в сочетании с переменной среды PANTHER_ERROR_SCREENSHOT_DIR
, тестирование с использованием клиента PANTHER, которые сбой или ошибки (после создания клиента) автоматически сделают скриншот для помощи отладки.
Чтобы зарегистрировать расширение Panther, добавьте следующие строки в phpunit.xml.dist
:
<!-- phpunit.xml.dist -->
< extensions >
< extension class = " SymfonyComponentPantherServerExtension " />
</ extensions >
Без расширения веб -сервер, используемый Panther для обслуживания тестируемого приложения, запускается по требованию и останавливается при вызове tearDownAfterClass()
. С другой стороны, когда расширение зарегистрировано, веб -сервер будет остановлен только после самого последнего теста.
<?php
use Symfony Component Panther Client ;
require __DIR__ . ' /vendor/autoload.php ' ; // Composer's autoloader
$ client = Client :: createChromeClient ();
// Or, if you care about the open web and prefer to use Firefox
$ client = Client :: createFirefoxClient ();
$ client -> request ( ' GET ' , ' https://api-platform.com ' ); // Yes, this website is 100% written in JavaScript
$ client -> clickLink ( ' Getting started ' );
// Wait for an element to be present in the DOM (even if hidden)
$ crawler = $ client -> waitFor ( ' #installing-the-framework ' );
// Alternatively, wait for an element to be visible
$ crawler = $ client -> waitForVisibility ( ' #installing-the-framework ' );
echo $ crawler -> filter ( ' #installing-the-framework ' )-> text ();
$ client -> takeScreenshot ( ' screen.png ' ); // Yeah, screenshot!
Класс PantherTestCase
позволяет легко записать тесты E2E. Он автоматически запускает ваше приложение, используя встроенный веб-сервер PHP и позволяет вам ползти с помощью Panther. Чтобы предоставить все инструменты тестирования, для которых вы использовали, он расширяет TestCase
Phpunit.
Если вы тестируете приложение Symfony, PantherTestCase
автоматически расширяет класс WebTestCase
. Это означает, что вы можете легко создавать функциональные тесты, которые могут напрямую выполнить ядро вашего приложения и получить доступ ко всем существующим службам. В этом случае вы можете использовать все утверждения тестирования Crawler, предоставленные Symfony с Panther.
<?php
namespace App Tests ;
use Symfony Component Panther PantherTestCase ;
class E2eTest extends PantherTestCase
{
public function testMyApp (): void
{
$ client = static :: createPantherClient (); // Your app is automatically started using the built-in web server
$ client -> request ( ' GET ' , ' /mypage ' );
// Use any PHPUnit assertion, including the ones provided by Symfony
$ this -> assertPageTitleContains ( ' My Title ' );
$ this -> assertSelectorTextContains ( ' #main ' , ' My body ' );
// Or the one provided by 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 ' );
// Use waitForX methods to wait until some asynchronous process finish
$ client -> waitFor ( ' .popin ' ); // wait for element to be attached to the DOM
$ client -> waitForStaleness ( ' .popin ' ); // wait for element to be removed from the DOM
$ client -> waitForVisibility ( ' .loader ' ); // wait for element of the DOM to become visible
$ client -> waitForInvisibility ( ' .loader ' ); // wait for element of the DOM to become hidden
$ client -> waitForElementToContain ( ' .total ' , ' 25 € ' ); // wait for text to be inserted in the element content
$ client -> waitForElementToNotContain ( ' .promotion ' , ' 5% ' ); // wait for text to be removed from the element content
$ client -> waitForEnabled ( ' [type="submit"] ' ); // wait for the button to become enabled
$ client -> waitForDisabled ( ' [type="submit"] ' ); // wait for the button to become disabled
$ client -> waitForAttributeToContain ( ' .price ' , ' data-old-price ' , ' 25 € ' ); // wait for the attribute to contain content
$ client -> waitForAttributeToNotContain ( ' .price ' , ' data-old-price ' , ' 25 € ' ); // wait for the attribute to not contain content
// Let's predict the future
$ this -> assertSelectorWillExist ( ' .popin ' ); // element will be attached to the DOM
$ this -> assertSelectorWillNotExist ( ' .popin ' ); // element will be removed from the DOM
$ this -> assertSelectorWillBeVisible ( ' .loader ' ); // element will be visible
$ this -> assertSelectorWillNotBeVisible ( ' .loader ' ); // element will not be visible
$ this -> assertSelectorWillContain ( ' .total ' , ' €25 ' ); // text will be inserted in the element content
$ this -> assertSelectorWillNotContain ( ' .promotion ' , ' 5% ' ); // text will be removed from the element content
$ this -> assertSelectorWillBeEnabled ( ' [type="submit"] ' ); // button will be enabled
$ this -> assertSelectorWillBeDisabled ( ' [type="submit"] ' ); // button will be disabled
$ this -> assertSelectorAttributeWillContain ( ' .price ' , ' data-old-price ' , ' €25 ' ); // attribute will contain content
$ this -> assertSelectorAttributeWillNotContain ( ' .price ' , ' data-old-price ' , ' €25 ' ); // attribute will not contain content
}
}
Чтобы запустить этот тест:
bin/phpunit tests/E2eTest.php
Panther также предоставляет вам мгновенный доступ к другим реализациям Client
и Crawler
на основе Browerkicit. В отличие от нативного клиента Panther, эти альтернативные клиенты не поддерживают JavaScript, CSS и снимки экрана, но они очень бывают !
Доступны два альтернативных клиента:
WebTestCase
. Это самый быстрый клиент, но он доступен только для приложений Symfony.Забавная часть заключается в том, что 3 клиента реализуют тот же API, поэтому вы можете переключаться с одного на другое, просто позвонив в соответствующий фабричный метод, что приведет к хорошему компромиссу для каждого отдельного тестового примера (нужен ли мне JavaScript? Нужно аутентифицировать с внешним сервером SSO?
Вот как получить экземпляры этих клиентов:
<?php
namespace App Tests ;
use Symfony Component Panther PantherTestCase ;
use Symfony Component Panther Client ;
class E2eTest extends PantherTestCase
{
public function testMyApp (): void
{
$ symfonyClient = static :: createClient (); // A cute kitty: Symfony's functional test tool
$ httpBrowserClient = static :: createHttpBrowserClient (); // An agile lynx: HttpBrowser
$ pantherClient = static :: createPantherClient (); // A majestic Panther
$ firefoxClient = static :: createPantherClient ([ ' browser ' => static :: FIREFOX ]); // A splendid Firefox
// Both HttpBrowser and Panther benefits from the built-in HTTP server
$ customChromeClient = Client :: createChromeClient ( null , null , [], ' https://example.com ' ); // Create a custom Chrome client
$ customFirefoxClient = Client :: createFirefoxClient ( null , null , [], ' https://example.com ' ); // Create a custom Firefox client
$ customSeleniumClient = Client :: createSeleniumClient ( ' http://127.0.0.1:4444/wd/hub ' , null , ' https://example.com ' ); // Create a custom Selenium client
// When initializing a custom client, the integrated web server IS NOT started automatically.
// Use PantherTestCase::startWebServer() or WebServerManager if you want to start it manually.
// enjoy the same API for the 3 felines
// $*client->request('GET', '...')
$ kernel = static :: createKernel (); // If you are testing a Symfony app, you also have access to the kernel
// ...
}
}
Panther предоставляет удобный способ тестирования приложений с возможностями в реальном времени, которые используют Mercure, WebSocket и аналогичные технологии.
PantherTestCase::createAdditionalPantherClient()
создает дополнительные изолированные браузеры, которые могут взаимодействовать друг с другом. Например, это может быть полезно для тестирования приложения чата, с тем, что несколько пользователей подключены одновременно:
<?php
use Symfony Component Panther PantherTestCase ;
class ChatTest extends PantherTestCase
{
public function testChat (): void
{
$ client1 = self :: createPantherClient ();
$ client1 -> request ( ' GET ' , ' /chat ' );
// Connect a 2nd user using an isolated browser and say hi!
$ client2 = self :: createAdditionalPantherClient ();
$ client2 -> request ( ' GET ' , ' /chat ' );
$ client2 -> submitForm ( ' Post message ' , [ ' message ' => ' Hi folks ? ' ]);
// Wait for the message to be received by the first client
$ client1 -> waitFor ( ' .message ' );
// Symfony Assertions are always executed in the **primary** browser
$ this -> assertSelectorTextContains ( ' .message ' , ' Hi folks ? ' );
}
}
При необходимости вы можете использовать Panther для доступа к содержанию консоли:
<?php
use Symfony Component Panther PantherTestCase ;
class ConsoleTest extends PantherTestCase
{
public function testConsole (): void
{
$ client = self :: createPantherClient (
[],
[],
[
' capabilities ' => [
' goog:loggingPrefs ' => [
' browser ' => ' ALL ' , // calls to console.* methods
' performance ' => ' ALL ' , // performance data
],
],
]
);
$ client -> request ( ' GET ' , ' / ' );
$ consoleLogs = $ client -> getWebDriver ()-> manage ()-> getLog ( ' browser ' ); // console logs
$ performanceLogs = $ client -> getWebDriver ()-> manage ()-> getLog ( ' performance ' ); // performance logs
}
}
При необходимости вы можете настроить аргументы, чтобы перейти к бинарному chromedriver
:
<?php
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 ' , ' / ' );
}
}
Используйте метод Client::ping()
, чтобы проверить, все еще активное соединение WebDriver (полезно для длительных задач).
Поскольку Panther реализует API популярных библиотек, она уже имеет обширную документацию:
Client
прочитайте документацию BrowserkitCrawler
прочитайте документацию DomcrawlerСледующие переменные среды могут быть настроены для изменения поведения некоторой пантеры:
PANTHER_NO_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
, передаваемой на веб -сервер, управляющий приложением PHPPANTHER_ERROR_SCREENSHOT_DIR
: чтобы установить базовый каталог для вашего сбоя/экрана ошибок (например, ./var/error-screenshots
)PANTHER_DEVTOOLS
: чтобы переключить инструменты Dev Browser (по умолчанию, enabled
, полезно для отладки)PANTHER_ERROR_SCREENSHOT_ATTACH
: чтобы добавить экранированные снимки, упомянутые выше, чтобы проверить выход в формате прикрепления Юнита Если вы хотите изменить хост и/или порт, используемый встроенным веб-сервером, передайте hostname
и port
в параметр $options
параметра метода createPantherClient()
:
// ...
$ client = self :: createPantherClient ([
' hostname ' => ' example.com ' , // Defaults to 127.0.0.1
' port ' => 8080 , // Defaults to 9080
]);
PANTHER_NO_SANDBOX
: чтобы отключить песочницу Chrome (небезопасно, но позволяет использовать Panther в контейнерах)PANTHER_CHROME_ARGUMENTS
: для настройки хромовых аргументов. Вам нужно установить PANTHER_NO_HEADLESS
для полной настройки.PANTHER_CHROME_BINARY
: использовать другой бинарник google-chrome
PANTHER_FIREFOX_ARGUMENTS
: для настройки аргументов Firefox. Вам нужно установить PANTHER_NO_HEADLESS
для полной настройки.PANTHER_FIREFOX_BINARY
: использовать другой бинар firefox
Согласно спецификации, реализации WebDriver возвращают только отображаемый текст по умолчанию. Когда вы фильтруете на head
(например, title
), метод text()
возвращает пустую строку. Используйте метод html()
чтобы получить полное содержимое тега, включая сам тег.
Panther может сделать паузу в ваших тестах после сбоя. Это время перерыва, которое действительно ценится за изучение проблемы через веб -браузер. Для включения этого режима вам нужна опция Phpunit --debug
без головы режима:
$ PANTHER_NO_HEADLESS=1 bin/phpunit --debug
Test 'AppAdminTest::testLogin' started
Error: something is wrong.
Press enter to continue...
Чтобы использовать интерактивный режим, расширение PHPUNIT должно быть зарегистрировано.
Иногда удобно повторно использовать существующую конфигурацию веб-сервера вместо запуска встроенной PHP One. Для этого установите опцию external_base_uri
:
<?php
namespace App Tests ;
use Symfony Component Panther PantherTestCase ;
class E2eTest extends PantherTestCase
{
public function testMyApp (): void
{
$ pantherClient = static :: createPantherClient ([ ' external_base_uri ' => ' https://localhost ' ]);
// the PHP integrated web server will not be started
}
}
Получается, что ваше приложение PHP/Symfony может служить нескольким доменным именам.
Поскольку Panther сохраняет клиент в памяти между тестами для улучшения выступлений, вам придется запустить ваши тесты в отдельных процессах, если вы напишите несколько тестов, используя Panther для различных доменных имен.
Для этого вы можете использовать нативную аннотацию @runInSeparateProcess
Phpunit.
ℹ Примечание. Действительно удобно использовать опцию external_base_uri
и запустить свой собственный веб -сервер в фоновом режиме, потому что Panther не придется запускать и останавливать ваш сервер при каждом тесте. Symfony CLI может быть быстрым и простым способом сделать это.
Вот пример с использованием параметра external_base_uri
для определения доменного имени, используемого клиентом:
<?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 ' ,
]);
// Your tests
}
}
<?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 ' ,
]);
// Your tests
}
}
Чтобы использовать прокси-сервер, установите следующую переменную среды: PANTHER_CHROME_ARGUMENTS='--proxy-server=socks://127.0.0.1:9050'
Чтобы заставить Chrome принять недопустимые и самоподнегированные сертификаты, установите следующую переменную среды: panther_chrome_arguments = ' PANTHER_CHROME_ARGUMENTS='--ignore-certificate-errors'
сканеры).
Для Firefox создайте экземпляр клиента так:
$ client = Client :: createFirefoxClient ( null , null , [ ' capabilities ' => [ ' acceptInsecureCerts ' => true ]]);
Вот минимальное изображение Docker, которое может работать с Chrome и Firefox:
FROM php:alpine
# Chromium and ChromeDriver
ENV PANTHER_NO_SANDBOX 1
# Not mandatory, but recommended
ENV PANTHER_CHROME_ARGUMENTS= '--disable-dev-shm-usage'
RUN apk add --no-cache chromium chromium-chromedriver
# Firefox and GeckoDriver (optional)
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
Постройте его с помощью docker build . -t myproject
Запустите его с docker run -it -v "$PWD":/srv/myproject -w /srv/myproject myproject bin/phpunit
Пантера работает из коробки с действиями GitHub. Вот минимальный файл .github/workflows/panther.yml
для запуска тестов Panther:
name : Run Panther tests
on : [ push, pull_request ]
jobs :
tests :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@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
Panther будет работать из коробки с Travis CI, если вы добавите аддон Chrome. Вот минимальный файл .travis.yml
для запуска тестов пантеры:
language : php
addons :
# If you don't use Chrome, or Firefox, remove the corresponding line
chrome : stable
firefox : latest
php :
- 8.0
script :
- bin/phpunit
Вот минимальный файл .gitlab-ci.yml
для запуска тестов Panther с Gitlab CI:
image : ubuntu
before_script :
- apt-get update
- apt-get install software-properties-common -y
- ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
- apt-get install curl wget php php-cli php7.4 php7.4-common php7.4-curl php7.4-intl php7.4-xml php7.4-opcache php7.4-mbstring php7.4-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
test :
script :
- bin/phpunit
Panther будет работать из коробки с Appveyor, пока Google Chrome будет установлен. Вот минимальный файл appveyor.yml
для запуска тестов Panther:
build : false
platform : x86
clone_folder : c:projectsmyproject
cache :
- ' %LOCALAPPDATA%Composerfiles '
install :
- ps : Set-Service wuauserv -StartupType Manual
- cinst -y php composer googlechrome chromedriver firfox selenium-gecko-driver
- refreshenv
- cd c:toolsphp80
- 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 --no-interaction --no-progress
test_script :
- cd %APPVEYOR_BUILD_FOLDER%
- php binphpunit
Если вы хотите использовать Panther с другими инструментами тестирования, такими как liipfunctionaltestbundle или если вам просто нужно использовать другой базовый класс, Panther вас покрыла. Он предоставляет вам SymfonyComponentPantherPantherTestCaseTrait
и вы можете использовать его для улучшения существующей испытательной инфраструктуры с некоторой удивительностью пантеры:
<?php
namespace App Tests Controller ;
use Liip FunctionalTestBundle Test WebTestCase ;
use Symfony Component Panther PantherTestCaseTrait ;
class DefaultControllerTest extends WebTestCase
{
use PantherTestCaseTrait ; // this is the magic. Panther is now available.
public function testWithFixtures (): void
{
$ this -> loadFixtures ([]); // load your fixtures
$ client = self :: createPantherClient (); // create your panther client
$ client -> request ( ' GET ' , ' / ' );
}
}
Следующие функции в настоящее время не поддерживаются:
DOMElement
(потому что эта библиотека использует WebDriverElement
внутренне)Приглашаем запросы на то, чтобы заполнить оставшиеся пробелы!
Если вы используете Bootstrap 5, то у вас может быть проблема с тестированием. Bootstrap 5 реализует эффект прокрутки, который имеет тенденцию вводить в заблуждение Пантеру.
Чтобы исправить это, мы советуем вам деактивировать этот эффект, установив переменную Bootstrap 5 $ Enable-Smooth-Scroll в False в вашем файле стиля.
$enable-smooth-scroll : false;
Многие из видов диких кошек испытывают большую угрозу. Если вам нравится это программное обеспечение, помогите сохранить (реальные) пантеры, пожертвовав организацию Panthera.
Создан Кевином Дангласом. Спонсируется Les-tilleuls.coop.
Пантера построена на вершине PHP Webdriver и нескольких других библиотеках FOSS. Он был вдохновлен Nightwatch.js, на основе WebDriver Testing Tool для JavaScript.