При регистрирации сервис провайдер Dusk вручную вам никогда не нужно добавлять его
в окружение продакшен-сервера, так как это может привести к тому,
что случайные пользователи смогут пройти аутентификацию для вашего приложение.
Тесты для браузера
Содержание:
- Введение
- Установка
- Начало
- Взаимодействие с элементами
- Доступные утверждения
- Страницы
- Компоненты
- Дальнейшая интеграция
Введение
Ларавел Dusk предлагает выразительное, легкое для использования автоматизация браузера и API тестирования. По умолчанию, Dusk не требует установки JDK или Selenium на вашу машину. Вместо этого, Dusk использует отдельный компонент ChromeDriver. Вы можете использовать любой другой совместивый с Selenium драйвер по вашему желанию.
Установка
Для начала, вам необходимо добавить зависимость Composer laravel/dusk
в ваш проект:
composer require --dev laravel/dusk
После установки компонента Dusk, выполните команду Artisan dusk:install
:
php artisan dusk:install
Директория Browser
будет создана внутри вашей директории tests
и будет содержать пример теста. Следующим шагом необходимо установить переменную окружения
APP_URL
в вашем файле .env
. Это значение должно соотвествовать
URL вашего приложения в браузере.
Для запуска ваших тестов, используйте команду Artisan dusk
.
Команда dusk
принимает любые аргументы, которые принимаются
командой phpunit
:
php artisan dusk
Если у вас были неудачи теста при последнем исопльзовании команды dusk
,
вы можете сэкономить время путём перезапуска проваленных тестов заново
используя команду dusk:fails
:
php artisan dusk:fails
Управление установкой ChromeDriver
Если вы хотите установить версию ChromeDriver, котороя отличает от включённой с Laravel Dusk,
вы можете использовать команду dusk:chrome-driver
:
# Install the latest version of ChromeDriver for your OS...
php artisan dusk:chrome-driver
# Install a given version of ChromeDriver for your OS...
php artisan dusk:chrome-driver 74
# Install a given version of ChromeDriver for all supported OSs...
php artisan dusk:chrome-driver --all
Использование других браузеров
По умолчанию, Dusk использует Google Chrome и отдельную установку ChromeDriver для выполнения тестов браузера. Однако, вы можете запустить ваш собвтвенный сервер Selenium и проводить ваши тесты для любого браузера.
Для начала, откройте ваш файл tests/DuskTestCase.php
, который является
базовым тестовым случаем Dusk для вашего приложения. Внутри файла вы можете убрать
вызов метод startChromeDriver
. Это приведет к тому, что Ларавел перестанет
автоматически запускать драйвер ChromeDriver:
/**
* Prepare for Dusk test execution.
*
* @beforeClass
* @return void
*/
public static function prepare()
{
// static::startChromeDriver();
}
Следующим шагом вы можете вносить изменения в метод driver
,
чтобы подсоединиться к URL и порту по вашему выбору.
Дополнительно вы можете модифицировать "желаемые возможности",
которые должны передаваться в драйвер:
/**
* Create the RemoteWebDriver instance.
*
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
*/
protected function driver()
{
return RemoteWebDriver::create(
'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()
);
}
Начало
Генерация тестов
Для генерации Dusk теста используйте команду Artisan dusk:make
.
Сгенерированный тест будет размещён в директории tests/Browser
:
php artisan dusk:make LoginTest
Запуск тестов
Для запуска ваших тестов браузера используйте команду Artisan dusk
:
php artisan dusk
Если у вас были неудачи тестов при выполнении команды dusk
,
можно сэкономить время путём перезапуска проваленных тестов используя команду dusk:fails
:
php artisan dusk:fails
dusk
принимает любые аргументы,
которые обычно принимаются исполнителем тестов PHPUnit,
что позволяет вам только выполнять тесты для данной
группы:
php artisan dusk --group=foo
Запуск ChromeDriver вручную
По умолчанию, Dusk будет автоматически пытаться запустить ChromeDriver.
Если это не работает в конкретно вашем случае, вы можете запустить драйвер ChromeDriver
до выполнения команды dusk
. Если вы выбрали запуск вручную, вам необходимо закомментировать
следующую линию для вашего файла tests/DuskTestCase.php
file:
/**
* Prepare for Dusk test execution.
*
* @beforeClass
* @return void
*/
public static function prepare()
{
// static::startChromeDriver();
}
Дополнительно, если вы запустили ChromeDriver через порт отличный от 9515,
необходимо внести изменения в метод driver
для класса с таким же названием:
/**
* Create the RemoteWebDriver instance.
*
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
*/
protected function driver()
{
return RemoteWebDriver::create(
'http://localhost:9515', DesiredCapabilities::chrome()
);
}
Настройка окружения
Чтобы заставить Dusk использовать собственное окружение при выполнении тестов,
создайте файл .env.dusk.{environment}
в корневой директории вашего проекта.
Например, если вы запустите команду dusk
из вашего local
окружения,
вам необходимо создать файл .env.dusk.local
.
При выполнении тестов, Dusk сделает копию файла .env
, а файл окружения Dusk
будет переименован в .env
. После выполнения тестов исходный файл
.env
будет восстановлен.
Создание браузеров
Для начала, давайте напишем тест, который проводит верификацию того,
что мы можем войти в наше приложение. После генерации теста, мы можем изменить его
и перенести страницу входа, ввести необходимые данные и нажать кнопку "войти".
Для создания экземпляра браузера, вызовите метод browse
:
<?php
namespace Tests\Browser;
use App\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Chrome;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
/**
* A basic browser test example.
*
* @return void
*/
public function testBasicExample()
{
$user = factory(User::class)->create([
'email' => 'taylor@laravel.com',
]);
$this->browse(function ($browser) use ($user) {
$browser->visit('/login')
->type('email', $user->email)
->type('password', 'password')
->press('Login')
->assertPathIs('/home');
});
}
}
Как можно увидеть в примере выше, метод browse
принимает обратную связь.
Экземпляр браузера будет автоматически передан в обратную связь и является основным объектом
для взаимодействия с приложением и выполнения утверждений.
Создание нескольких браузеров
Иногда может возникнуть ситуация, когда нужно использовать несколько браузеров
для корректного проведения тестов. Например, несколько бразуеров могет понадобиться
для тестирования чата, который взаимодействует с сокетами.
Для создания нескольких браузеров в подписи для метода browse
необходимо "запросить" требуемое количество:
$this->browse(function ($first, $second) {
$first->loginAs(User::find(1))
->visit('/home')
->waitForText('Message');
$second->loginAs(User::find(2))
->visit('/home')
->waitForText('Message')
->type('message', 'Hey Taylor')
->press('Send');
$first->waitForText('Hey Taylor')
->assertSee('Jeffrey Way');
});
Изменение размера окна браузера
Вы можете использовать метод resize
, чтобы утвердить размер окна браузера:
$browser->resize(1920, 1080);
Метод maximize
может быть использован, чтобы максимизировать размеры окна браузера.
$browser->maximize();
Макросы браузера
Если вы хотите определить пользовательский метод браузера, который можно было бы использовать
для ваших различных тестов, вы можете использовать метод macro
для класса Browser
.
Обычно, вам необходимо вызвать этот мето из метода boot
вашего сервис провайдера:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\Browser;
class DuskServiceProvider extends ServiceProvider
{
/**
* Register the Dusk's browser macros.
*
* @return void
*/
public function boot()
{
Browser::macro('scrollToElement', function ($element = null) {
$this->script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);");
return $this;
});
}
}
Функция macro
принимает имя в качестве первого аргумента,
и Замыкание в качестве второго. Макрос будет выполняться при обращении по имени в качестве метода
для реализации Browser
:
$this->browse(function ($browser) use ($user) {
$browser->visit('/pay')
->scrollToElement('#credit-card-details')
->assertSee('Enter Credit Card Details');
});
Аутинтификация
Часто вам будет необходимо тестировать страницы, которые требуют аутентификации.
Вы можете использовать метод Dusk loginAs
, чтобы избежать взаимодействия
с экраном входа для каждого теста. Метод loginAs
принимает ID пользователя
или экземпляр модели:
$this->browse(function ($first, $second) {
$first->loginAs(User::find(1))
->visit('/home');
});
Миграции базы данных
Когда ваши тесты требуют миграций, как в примере аутентификации выше,
вам никогда не стоит использовать трейт RefreshDatabase
.
Трейт RefreshDatabase
использует транзации базы данных,
которые будут неприменимы для HTTP запросов. Вместо этого, используйте
трейт DatabaseMigrations
:
<?php
namespace Tests\Browser;
use App\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Chrome;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
}
Взаимодействие с элементами
Селекторы Dusk
Выбор хороших CSS селекторов для взаимодействия с элементамя — это одна и сложнейших задач написания тестов Dusk. Проходит время, меняются подходы и это может привести к тому, что следующие тесты перестанут работать:
// HTML...
<button>Login</button>
// Test...
$browser->click('.login-page .container div > button');
Селекторы Dusk позволяют вам сфокусироваться на написании эффективных тестов,
а не попытках запомнить селекторы CSS. Для определения селектора,
добавьте атрибут dusk
в ваш HTML элемент. После, добавьте
@
, чтобы манипулировать добавленным элементов внутри теста Dusk:
// HTML...
<button dusk="login-button">Login</button>
// Test...
$browser->click('@login-button');
Переход по ссылкам
Чтобы кликнуть на ссылку, вы можете использовать метод clickLink
для экземпляра браузера. Метод clickLink
кликнет по ссылке,
у которой указанный текст:
$browser->clickLink($linkText);
Текст, значение, атрибуты
Получение и присвоение значений.
Dusk предлагает несколько методов для взаимодействия с текущим тестом, значением,
атрибутами элементов на странице. Например, чтобы получить значение элемента
с данным селектором, используйте метод value
:
// Retrieve the value...
$value = $browser->value('selector');
// Set the value...
$browser->value('selector', 'value');
Получение текста
Метод text
может быть использован для получения текста элемента
для данного селектора:
$text = $browser->text('selector');
Получение атрибутов
Наконец, метод attribute
может быть использован для получения атрибута элемента,
который соотвествует данному селектору:
$attribute = $browser->attribute('selector', 'value');
Использование форм
Вписывание значений
Dusk предоставляет набор методов ддя взаимодействия с формами и элементами ввода. Первое, давайте взглянем на пример вписывания текста в форму:
$browser->type('email', 'taylor@laravel.com');
Нужно заметить, что на не обязательно передавать селектор CSS в метод type
.
Если селектор не указан, Dusk будет искать поле ввода для атрибута name
.
Наконец, Dusk будет пытаться найти textarea
с данным атрибутом name
.
Чтобы дополнить текст в поле ввода без очистки текущего контента,
вы можете использовать метод append
:
$browser->type('tags', 'foo')
->append('tags', ', bar, baz');
Вы можете очистить значение ввода используя метод clear
:
$browser->clear('email');
Выпадающие списки
Чтобы выбрать значение из выпадающего списка, вы можете использовать метод select
.
Как и в случае с методом type
не требует полного указания селектора.
При передаче значения в метод select
, вам необходимо передать значение опции,
а не отображаемый текст:
$browser->select('size', 'Large');
Вы можете выбрать случайное значение просто пропустив второй параметр:
$browser->select('size');
Чекбоксов
Чтобы "отметить" поле чекбокса, вы можете использовать метод check
.
Как и для других методов, полный селектор CSS не требуется. Если нет точного соответствия,
Dusk будет искать чекбокс с таким атрибутом name
:
$browser->check('terms');
$browser->uncheck('terms');
Радиокнопки
Чтобы выделить радиокнопки, вы можете использовать метод radio
.
Как и для других методов работы с вводными данные, не требуется указывать полный CSS селектор
не требуется. Если точного соответсвия не удается найти, Dusk будет искать радиокнопку и
атрибутами name
и value
:
$browser->radio('version', 'php7');
Вложение файлов
Метод attach
может быть использован, чтобы прикрепить файл к элементу ввода file
.
Как и для других методов работы с вводом, указание полного селектора CSS не требуется.
Если точное соотвествие не удаётся найти, Dusk будет искать загрузчик файла соотвествующий
атрибуту name
:
$browser->attach('photo', __DIR__.'/photos/me.png');
Использование клавиатуры
Метод keys
предоставляет расширенные возможности
по сравнению с методом type
. Например, вы можете зажимать кнопки "модификаторы"
при вводе данных. В этом примере, кнопка shift
будет зажата во время набора
taylor
. После того как слово taylor
было напечатано,
слово otwell
будет написано без всяких модификаторов:
$browser->keys('selector', ['{shift}', 'taylor'], 'otwell');
Вы даже можете отправить "горячие клавиши" на основной селектор CSS, который и содержит ваше приложение:
$browser->keys('.app', ['{command}', 'j']);
Использование мыши
Кликать на элементы
Метод click
может быть использован для элемента,
который соответствует данному селектору:
$browser->click('.selector');
Наведение курсора Мыши
Метод mouseover
может быть использован, когда вам необходимо навести мышь на
определённый элемент, который соотвествует данному селектору:
$browser->mouseover('.selector');
Перетаскивание элементов
Метод drag
может быть использован, чтобы перетащить элемент соответсвующий данному
селектору к другому элементу:
$browser->drag('.from-selector', '.to-selector');
Или можно перетаскивать элемент в определённом направлении:
$browser->dragLeft('.selector', 10);
$browser->dragRight('.selector', 10);
$browser->dragUp('.selector', 10);
$browser->dragDown('.selector', 10);
Диалоги JavaScript
Dusk предоставляет набор методов на взаимодействия с диалогами JavaScript:
// Wait for a dialog to appear:
$browser->waitForDialog($seconds = null);
// Assert that a dialog has been displayed and that its message matches the given value:
$browser->assertDialogOpened('value');
// Type the given value in an open JavaScript prompt dialog:
$browser->typeInDialog('Hello World');
Используйте следующий подход, чтобы закрыть открытый диалог JavaScript, нажав на кнопку "OK":
$browser->acceptDialog();
Чтобы закрыть диалог JavaScript путём нажатия кнопки "Отмена" (только для диалога-потверждения):
$browser->dismissDialog();
Селекторы областей действия
Иногда вы можете захотеть выполнить несколько операций одновременно в рамках данного селектора.
Например, вы хотите утверждать, что текст существует только внутри таблицы и далее кликнуть
на кнопку внутри этой таблицы. Вы можете использовать метод with
для реализации
задуманного. Все операции внутри метода with
будут ограничены выбранным селектором:
$browser->with('.table', function ($table) {
$table->assertSee('Hello World')
->clickLink('Delete');
});
Ожидание элементов
При тестировании приложений, которые используют активно используют JavaScript,
часто может потребоваться ждать пока определённые элементы или данные будут доступны
до момента проведения теста. Dusk позволяет легко и просто реализовать задуманное.
Используя набор методов вы сможете ждать момента, когда элементы будут видимы на странице
или даже до момента, когда данное JavaScript выражение станет true
.
Ожидание
Если вам необходимо приостановить тест на определённое количество милисекунд,
используйте метод pause
:
$browser->pause(1000);
Ожидание селекторв
Метод waitFor
может быть использован для того, чтобы остановить выполнение теста
до тех пор, пока соответсвующий данному CSS элемент не будет показан на странице.
По умолчанию, можно остановить тест на время до 5 секунд до момента получения исключения.
При необходимости, вы можете передать пользовательское время таймаута в качестве второго
аргумента в метод:
// Wait a maximum of five seconds for the selector...
$browser->waitFor('.selector');
// Wait a maximum of one second for the selector...
$browser->waitFor('.selector', 1);
Вы можете также ждать момента, когда данный селектор пропадёт со страницы:
$browser->waitUntilMissing('.selector');
$browser->waitUntilMissing('.selector', 1);
Группа селекторов при доступности
Может так случится, что вам необходимо дождаться данного селектора и уже после
взаимодействовать с соответсвующим селектору элементом. Например, вы можете дождаться
пока модальное окно станет доступным и после нажать кнопку "OK" внутри окна.
Метод whenAvailable
может быть использован в этом случае.
Все операции элемента проводимые внутри будут будут привязаны к оригинальному селектору:
$browser->whenAvailable('.modal', function ($modal) {
$modal->assertSee('Hello World')
->press('OK');
});
Ождание текста
Метод waitForText
может быть использован, чтобы дождаться
пока данный текст не появится на странице:
// Wait a maximum of five seconds for the text...
$browser->waitForText('Hello World');
// Wait a maximum of one second for the text...
$browser->waitForText('Hello World', 1);
Ожидание ссылок
Метод waitForLink
может быть использован, чтобы дождаться
пока данный текст-ссылка не появится на странцие:
// Wait a maximum of five seconds for the link...
$browser->waitForLink('Create');
// Wait a maximum of one second for the link...
$browser->waitForLink('Create', 1);
Ожидание на странице
Создание утрвеждений маршрута, таких как $browser->assertPathIs('/home')
,
может закончится неудачей, если window.location.pathname
обновлялось
асинхронно. Вы можете использовать метод waitForLocation
,
чтобы дождаться, пока местоположение будет иметь заданное значение:
$browser->waitForLocation('/secret');
Вы также можете ожидать названный маршрут локации:
$browser->waitForRoute($routeName, $parameters);
Ожидание перезагрузок страницы
Если вам необходимо сделать утверждения после перезагрузки страницы,
используйте метод waitForReload
:
$browser->click('.some-action')
->waitForReload()
->assertSee('something');
Ожидание выражений JavaScript
Иногда вам может понадобиться остановить выполнение теста до момента, пока какое-либо выражение
не примет значение true
. Вы можете легко так сделать используя метод waitUntil
.
При передаче выражение в этот метод, у вас нет необходимости включать слово return
или точку с запятой в конце:
// Wait a maximum of five seconds for the expression to be true...
$browser->waitUntil('App.dataLoaded');
$browser->waitUntil('App.data.servers.length > 0');
// Wait a maximum of one second for the expression to be true...
$browser->waitUntil('App.data.servers.length > 0', 1);
Ожидание выражений Vue
Следующие методы могут быть использованы, чтобы дождаться, когда атрибут компонента Vue получат данное значение:
// Wait until the component attribute contains the given value...
$browser->waitUntilVue('user.name', 'Taylor', '@user');
// Wait until the component attribute doesn't contain the given value...
$browser->waitUntilVueIsNot('user.name', null, '@user');
Ожидание с обратной связью
Многие методы "ожидания" в Dusk опираются на метод waitUsing
.
Вы можете использовать данный метод напрямую, чтобы ждать обратной связи и вернуть true
.
Метод waitUsing
принимает число секунд для ожидания, интервал оценки замыкания,
само Замыкание и сообщение необязательное сообщение неудачи:
$browser->waitUsing(10, 1, function () use ($something) {
return $something->isReady();
}, "Something wasn't ready in time.");
Сделать утверждение Vue
Dusk даже позволяет вам делать утверждения для данных компонента Vue. Например, представим, что ваше приложение содержит следующий компанент Vue:
// HTML...
<profile dusk="profile-component"></profile>
// Component Definition...
Vue.component('profile', {
template: '<div>{{ user.name }}</div>',
data: function () {
return {
user: {
name: 'Taylor'
}
};
}
});
Вы можете делать утверждения для компонента Vue следующим образом:
/**
* A basic Vue test example.
*
* @return void
*/
public function testVue()
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertVue('user.name', 'Taylor', '@profile-component');
});
}
Доступные утверждения
Dusk предоставялет набор утверждений, которые вы можете делать для вашего приложения. Ниже представлены доступные утверждение и их описание:
assertTitle assertTitleContains assertUrlIs assertSchemeIs assertSchemeIsNot assertHostIs assertHostIsNot assertPortIs assertPortIsNot assertPathBeginsWith assertPathIs assertPathIsNot assertRouteIs assertQueryStringHas assertQueryStringMissing assertFragmentIs assertFragmentBeginsWith assertFragmentIsNot assertHasCookie assertCookieMissing assertCookieValue assertPlainCookieValue assertSee assertDontSee assertSeeIn assertDontSeeIn assertSourceHas assertSourceMissing assertSeeLink assertDontSeeLink assertInputValue assertInputValueIsNot assertChecked assertNotChecked assertRadioSelected assertRadioNotSelected assertSelected assertNotSelected assertSelectHasOptions assertSelectMissingOptions assertSelectHasOption assertValue assertVisible assertPresent assertMissing assertDialogOpened assertEnabled assertDisabled assertButtonEnabled assertButtonDisabled assertFocused assertNotFocused assertVue assertVueIsNot assertVueContains assertVueDoesNotContain
assertTitle
Утверждает, что заголовок страницы сотвествует данному тексту:
$browser->assertTitle($title);
assertTitleContains
Утверждает, что заголовок содержит данный текст:
$browser->assertTitleContains($title);
assertUrlIs
Утверждает, что данный URL (без строки запросов) соотвествует данной строке:
$browser->assertUrlIs($url);
assertSchemeIs
Утверждает, что текущая схема URL соответсвует данной схеме:
$browser->assertSchemeIs($scheme);
assertSchemeIsNot
Утверждает, что текущая схема URL не соотвествует данной схеме:
$browser->assertSchemeIsNot($scheme);
assertHostIs
Утверждает, что текущий URL-адрес хоста соответствует данному хосту:
$browser->assertHostIs($host);
assertHostIsNot
Утверждает, что текущий URL-адрес хоста не соответствует данному хосту:
$browser->assertHostIsNot($host);
assertPortIs
Утверждает, что текущий порт URL соотвествует данному порту:
$browser->assertPortIs($port);
assertPortIsNot
Утверждает, что текущнй порт URL не соотвествует данному порту:
$browser->assertPortIsNot($port);
assertPathBeginsWith
Утверждает, что текущий URL путь начинается с данного пути:
$browser->assertPathBeginsWith($path);
assertPathIs
Утверждает, что текущий маршрут соотвествует данному маршруту:
$browser->assertPathIs('/home');
assertPathIsNot
Утверждает, что текущий путь не соотвествует данному пути:
$browser->assertPathIsNot('/home');
assertRouteIs
Утверждает, что текущий URL соответствует данному имени маршрута URL:
$browser->assertRouteIs($name, $parameters);
assertQueryStringHas
Утверждает, что данные параметры запроса присутсвуют:
$browser->assertQueryStringHas($name);
Утверждает, что данный параметр запроса присуствует и имеет следующее значение:
$browser->assertQueryStringHas($name, $value);
assertQueryStringMissing
Утверждает, что данный параметр запроса отсутсвует:
$browser->assertQueryStringMissing($name);
assertFragmentIs
Утверждает, что текущний фрагмент соответсвует данному фрагменту:
$browser->assertFragmentIs('anchor');
assertFragmentBeginsWith
Утверждает, что текущий фрагмент начинается с данного фрагмента:
$browser->assertFragmentBeginsWith('anchor');
assertFragmentIsNot
Утверждает, что текущий фрагмент не соотвествует данному фрагменту:
$browser->assertFragmentIsNot('anchor');
assertHasCookie
Утверждает, что данные куки присутсвуют:
$browser->assertHasCookie($name);
assertCookieMissing
Утверждает, что данные куки не присутсвуют:
$browser->assertCookieMissing($name);
assertCookieValue
Утверждает, что у куки следующее значение:
$browser->assertCookieValue($name, $value);
assertPlainCookieValue
Утверждает, что незашифрованные куки имеют следующее значение:
$browser->assertPlainCookieValue($name, $value);
assertSee
Утверждает, что данный текст присутсвует на странице:
$browser->assertSee($text);
assertDontSee
Утверждает, что данный текст не присутсвует на странице:
$browser->assertDontSee($text);
assertSeeIn
Утверждает, что данный текст присуствует внутри селектора:
$browser->assertSeeIn($selector, $text);
assertDontSeeIn
Утверждает, что данный текст не присуствует внутри селектора:
$browser->assertDontSeeIn($selector, $text);
assertSourceHas
Утверждает, что данный код присуствует на странице:
$browser->assertSourceHas($code);
assertSourceMissing
Утверждает, что данный код не присутвует на странице:
$browser->assertSourceMissing($code);
assertSeeLink
Утверждает, что данная ссылка присутсвует на странице:
$browser->assertSeeLink($linkText);
assertDontSeeLink
Утверждает, что данная ссылка не присуствует на странице:
$browser->assertDontSeeLink($linkText);
assertInputValue
Утверждает, что данное поле ввода содержит следующий текст:
$browser->assertInputValue($field, $value);
assertInputValueIsNot
Утверждает, что данное поле ввода не имеет следующего значения:
$browser->assertInputValueIsNot($field, $value);
assertChecked
Утверждает, что данный чекбокс выбран:
$browser->assertChecked($field);
assertNotChecked
Утверждает, что данный чекбокс не выбран:
$browser->assertNotChecked($field);
assertRadioSelected
Утверждает, что данная радио-кнопка выбрана:
$browser->assertRadioSelected($field, $value);
assertRadioNotSelected
Утверждает, что данная радио-кнопка не выбрана:
$browser->assertRadioNotSelected($field, $value);
assertSelected
Утверждает, что у данного выпадающего списка выбрано следующее значение:
$browser->assertSelected($field, $value);
assertNotSelected
Утверждает, что у данного выпадающего списка не выбрано следующее значение:
$browser->assertNotSelected($field, $value);
assertSelectHasOptions
Утверждает, что данный массив значений доступен для выбора:
$browser->assertSelectHasOptions($field, $values);
assertSelectMissingOptions
Утверждает, что данный массив значение не доступен для выбора:
$browser->assertSelectMissingOptions($field, $values);
assertSelectHasOption
Утверждает, что данное значение доступно для выбора для данного поля:
$browser->assertSelectHasOption($field, $value);
assertValue
Утверждает, что элемент соответвующий данному селектору имеет следующее значение:
$browser->assertValue($selector, $value);
assertVisible
Утверждает, что элемент соотвествующий данному селектору виден.
$browser->assertVisible($selector);
assertPresent
Утверждает, что элемент соответсвующий данному селектору присутсвует:
$browser->assertPresent($selector);
assertMissing
Утверждает, что элемент соответсвующий данному селектору не виден:
$browser->assertMissing($selector);
assertDialogOpened
Утверждает, что диалоговое окно JavaScript с данным сообщение открыто:
$browser->assertDialogOpened($message);
assertEnabled
Утверждает, что данное поле включено:
$browser->assertEnabled($field);
assertDisabled
Утверждает, что данное поле выключено:
$browser->assertDisabled($field);
assertButtonEnabled
Утверждает, что данная кнопка включена:
$browser->assertButtonEnabled($button);
assertButtonDisabled
Утверждает, что данная кнопка выключена:
$browser->assertButtonDisabled($button);
assertFocused
Утверждает, что данное поле выбрано в фокус:
$browser->assertFocused($field);
assertNotFocused
Утверждает, что данное поле не выбрано в фокус:
$browser->assertNotFocused($field);
assertVue
Утверждает, что данные компнента Vue соответствуют данному значению:
$browser->assertVue($property, $value, $componentSelector = null);
assertVueIsNot
Утверждает, что указаныне данные свойства компонента Vue не соответсвуют данному значению:
$browser->assertVueIsNot($property, $value, $componentSelector = null);
assertVueContains
Утверждает, что данные свойства компонента Vue являются массивом и содержат данное значение:
$browser->assertVueContains($property, $value, $componentSelector = null);
assertVueDoesNotContain
Утверждает, что данные свойства компонента Vue являются массивом и не содержат данное значение:
$browser->assertVueDoesNotContain($property, $value, $componentSelector = null);
Страницы
Иногда, тесты требуют последовательного выполнения нескольких сложных действий. Такие моменты могут усложнить понимание и чтение ваших тестов. Страницы позволяют вам определить действия, которые после будут представлены на данной странице используя один метод. Страницы также позволяют вам определить короткий путь к общим селекторам для вашего приложения или страницы.
Генерация страниц
Для генерации объекта страницы, используйте команду Artisan dusk:page
.
Все объекты страниц будут размещены в директории tests/Browser/Pages
:
php artisan dusk:page Login
Конфигурация страниц
По умолчанию, у страниц есть 3 метода: url
, assert
и elements
.
Давайте обсудим методы url
и assert
сейчас. Метод elements
мы рассмотрим более подробно ниже.
Метод url
Метод url
должен вернуть маршрут от URL, который представляет данную страницу.
Dusk будет использовать этот URL при навигации на эту страницу в браузере:
/**
* Get the URL for the page.
*
* @return string
*/
public function url()
{
return '/login';
}
Метод assert
Метод assert
может сделать любое утверждение, необходимое для верификации того,
что браузер находится на данной странице. Заполнять этот метод необязательно; однако вы легко
можете сделать такие утверждения по желанию. Эти утверждения будут выполняться автоматически
при навигации на эту страницу:
/**
* Assert that the browser is on the page.
*
* @return void
*/
public function assert(Browser $browser)
{
$browser->assertPathIs($this->url());
}
Навигация страниц
После настройки конфигурации страницы, вы можете пользоваться навигацией страниц
используя метод visit
:
use Tests\Browser\Pages\Login;
$browser->visit(new Login);
Иногда вы можете уже быть на странице и вам лишь необходимо "загрузить"
селекторы страниц и методы в текущий контекст теста. Это частая ситуация при перенаправлении
на эту же страницу после нажатия кнопки без точного указания адреса навигации.
В этом случае вы можете использовать метод on
для загрузки страницы:
use Tests\Browser\Pages\CreatePlaylist;
$browser->visit('/dashboard')
->clickLink('Create Playlist')
->on(new CreatePlaylist)
->assertSee('@create');
Сокращенные селекторы
Метод elements
в контексте использования страниц позволяет вам быстрый,
простой для запоминания ярлык для любого CSS селектора на вашей странице.
Например, давайте определим ярлык для поля ввода "email" для страницы входа
вашего приложения:
/**
* Get the element shortcuts for the page.
*
* @return array
*/
public function elements()
{
return [
'@email' => 'input[name=email]',
];
}
Теперь вы можете использовать этот сокращенный селектор в любом месте, где бы вы обыкновенно хотели использовать полный CSS селектор:
$browser->type('@email', 'taylor@laravel.com');
Глобальные ярлыки селекторов.
После установки Dusk, базовый класс Page
будет размещен в директории
tests/Browser/Pages
. Этот класс содержит метод siteElements
,
который может быть использован для определения глобальных ярклыков селекторов,
которые должны быть доступны для каждой страницы вашего приложения:
/**
* Get the global element shortcuts for the site.
*
* @return array
*/
public static function siteElements()
{
return [
'@element' => '#selector',
];
}
Страничные методы
Дополнительно к базовым методам определённых на страницах, вы можете определить
дополнительные методы, которые могут быть использованы для любых ваших тестов.
Например, давайте представим ситуацию, когда необходимо построить приложение
по управлению музыкой. Общим действием для страницы приложение может быть создание
плейлиста. Вместо того, чтобы писать логику создания плейлиста в каждом тесте,
вы можете определить метод createPlaylist
в классе страниц:
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
class Dashboard extends Page
{
// Other page methods...
/**
* Create a new playlist.
*
* @param \Laravel\Dusk\Browser $browser
* @param string $name
* @return void
*/
public function createPlaylist(Browser $browser, $name)
{
$browser->type('name', $name)
->check('share')
->press('Create Playlist');
}
}
После определения метода, вы можете использовать его внутри любого теста, который использует данную страницу. Экземпляр браузера будет автоматически передан в метод страницы:
use Tests\Browser\Pages\Dashboard;
$browser->visit(new Dashboard)
->createPlaylist('My Playlist')
->assertSee('My Playlist');
Компоненты
Компоненты похожи на "объекты страниц" Dusk, но предназначены для частей пользовательского интерфейса и функциональности, которую можно повторить для всего вашего приложения такие как навигация или окно уведомлений. Кроме того, компоненты не привязаны к определённым страницам.
Генерация компонентов
Чтобы сгенерировать компонент используйте команду Artisan dusk:component
.
Новые компоненты размещены в директории test/Browser/Components
:
php artisan dusk:component DatePicker
Как показано выше, "выборщик даты" это пример компонента, который должен распростроняться на всё приложение и применяться для большого количества страниц. Это может быть очень обременительным писать вручную логику браузера для выбора даты для десятков тестов в наборе ваших тестов. Вместо этого мы можем определить компонент Dusk, который и будет представлять выборщика даты, что позволит избежать повторения, а всю логику поместить внутри компонента:
<?php
namespace Tests\Browser\Components;
use Laravel\Dusk\Browser;
use Laravel\Dusk\Component as BaseComponent;
class DatePicker extends BaseComponent
{
/**
* Get the root selector for the component.
*
* @return string
*/
public function selector()
{
return '.date-picker';
}
/**
* Assert that the browser page contains the component.
*
* @param Browser $browser
* @return void
*/
public function assert(Browser $browser)
{
$browser->assertVisible($this->selector());
}
/**
* Get the element shortcuts for the component.
*
* @return array
*/
public function elements()
{
return [
'@date-field' => 'input.datepicker-input',
'@month-list' => 'div > div.datepicker-months',
'@day-list' => 'div > div.datepicker-days',
];
}
/**
* Select the given date.
*
* @param \Laravel\Dusk\Browser $browser
* @param int $month
* @param int $day
* @return void
*/
public function selectDate($browser, $month, $day)
{
$browser->click('@date-field')
->within('@month-list', function ($browser) use ($month) {
$browser->click($month);
})
->within('@day-list', function ($browser) use ($day) {
$browser->click($day);
});
}
}
Использование компонентов
После определения компонента, мы можем легко выбрать дату из любого теста. Если необходимо внести изменения в логику, то можно обновить компонент:
<?php
namespace Tests\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\Browser\Components\DatePicker;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
/**
* A basic component test example.
*
* @return void
*/
public function testBasicExample()
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->within(new DatePicker, function ($browser) {
$browser->selectDate(1, 2018);
})
->assertSee('January');
});
}
}
Дальнейшая интеграция
CircleCI
Если вы используете CircleCI для выполнения ваших тестов Dusk, вы можете использовать
этот файл конфигурации в качестве отправной точки. Как и для TravisCI,
мы будем использовать команду php artisan serve
для запуска
встроенного веб-сервера PHP:
version: 2
jobs:
build:
steps:
- run: sudo apt-get install -y libsqlite3-dev
- run: cp .env.testing .env
- run: composer install -n --ignore-platform-reqs
- run: npm install
- run: npm run production
- run: vendor/bin/phpunit
- run:
name: Start Chrome Driver
command: ./vendor/laravel/dusk/bin/chromedriver-linux
background: true
- run:
name: Run Laravel Server
command: php artisan serve
background: true
- run:
name: Run Laravel Dusk Tests
command: php artisan dusk
- store_artifacts:
path: tests/Browser/screenshots
Codeship
Для выполнения тестов Dusk Codeship, добавьте следующие в ваш проект Codeship. Эти команды являются отправной точкой и вы можете легко добавлять команды по вашему желанию:
phpenv local 7.2
cp .env.testing .env
mkdir -p ./bootstrap/cache
composer install --no-interaction --prefer-dist
php artisan key:generate
nohup bash -c "php artisan serve 2>&1 &" && sleep 5
php artisan dusk
Heroku CI
Для выполнения тестов Dusk на Heroku CI,
добавьте следующие строки в ваш Heroku app.json
файл в соотвествующие разделы
(buildpack и scripts):
{
"environments": {
"test": {
"buildpacks": [
{ "url": "heroku/php" },
{ "url": "https://github.com/heroku/heroku-buildpack-google-chrome" }
],
"scripts": {
"test-setup": "cp .env.testing .env",
"test": "nohup bash -c './vendor/laravel/dusk/bin/chromedriver-linux > /dev/null 2>&1 &' && nohup bash -c 'php artisan serve > /dev/null 2>&1 &' && php artisan dusk"
}
}
}
}
Travis CI
Для выполнения ваших тестов Dusk на Travis CI,
используйте следующий файл конфигурации .travis.yml
. В силу того, что Travis CI
не является графической средой, нам потребуется сделать некоторые шаги для запуска
браузера Chrome. Дополнительно мы будем использовать команду php artisan serve
для запуска встроенного веб-сервера PHP:
language: php
php:
- 7.3
addons:
chrome: stable
install:
- cp .env.testing .env
- travis_retry composer install --no-interaction --prefer-dist --no-suggest
- php artisan key:generate
before_script:
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
- php artisan serve &
script:
- php artisan dusk
Действия GitHub
Если вы используете Github Actions
для запуска ваших Dusk тестов, вы можете использовать эти файлы конфигурации
как отправную точку. Как и для TravisCI, мы будем использовать команду php artisan serve
для запуска встроенного веб-сервера PHP:
name: CI
on: [push]
jobs:
dusk-php:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Prepare The Environment
run: cp .env.example .env
- name: Install Composer Dependencies
run: composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader
- name: Generate Application Key
run: php artisan key:generate
- name: Upgrade Chrome Driver
run: php artisan dusk:chrome-driver
- name: Start Chrome Driver
run: ./vendor/laravel/dusk/bin/chromedriver-linux > /dev/null 2>&1 &
- name: Run Laravel Server
run: php artisan serve > /dev/null 2>&1 &
- name: Run Dusk Tests
run: php artisan dusk
В вашем файле .env.testing
настройте значение APP_URL
:
APP_URL=http://127.0.0.1:8000