Laravel Dusk
- Вступ
- Встановлення
- Початок роботи
- Основи браузера
- Взаємодія з елементами
- Доступні твердження
- Сторінки
- Компоненти
- Безперервна інтеграція
Вступ
Laravel Dusk надає виразний, простий у використанні API для автоматизації браузера та тестування. За замовчуванням Dusk не вимагає встановлення JDK або Selenium на вашому локальному комп'ютері. Натомість Dusk використовує автономну установку ChromeDriver. Однак ви можете використовувати будь-який інший драйвер, сумісний із Selenium, за вашим бажанням.
Встановлення
Щоб розпочати, вам слід встановити Google Chrome і додати залежність laravel/dusk компонувальника до вашого проекту:
composer require laravel/dusk --dev
Якщо ви вручну реєструєте сервіс-провайдер Dusk, ви повинні ніколи не реєструвати його в вашому виробничому середовищі, оскільки це може призвести до того, що довільні користувачі зможуть автентифікуватися у вашому застосунку.
Після встановлення пакету Dusk виконайте команду Artisan dusk:install. Команда dusk:install створить директорію tests/Browser, приклад тесту Dusk, а також встановить бінарний файл Chrome Driver для вашої операційної системи:
php artisan dusk:install
Далі, встановіть змінну середовища APP_URL у файлі .env вашого застосунку. Це значення має відповідати URL, який ви використовуєте для доступу до вашого застосунку в браузері.
Якщо ви використовуєте Laravel Sail для управління вашим локальним середовищем розробки, будь ласка, також зверніться до документації Sail щодо налаштування та запуску тестів Dusk.
Керування встановленнями ChromeDriver
Якщо ви хочете встановити іншу версію ChromeDriver, ніж та, що встановлюється Laravel Dusk за допомогою команди dusk:install, ви можете скористатися командою dusk:chrome-driver:
# Встановити останню версію ChromeDriver для вашої ОС... php artisan dusk:chrome-driver # Встановити вказану версію ChromeDriver для вашої ОС... php artisan dusk:chrome-driver 86 # Встановити вказану версію ChromeDriver для всіх підтримуваних ОС... php artisan dusk:chrome-driver --all # Встановити версію ChromeDriver, що відповідає виявленій версії Chrome / Chromium для вашої ОС... php artisan dusk:chrome-driver --detect
Dusk вимагає, щоб бінарні файли chromedriver були виконуваними. Якщо у вас виникають проблеми з запуском Dusk, ви повинні переконатися, що бінарні файли є виконуваними, використовуючи наступну команду: chmod -R 0755 vendor/laravel/dusk/bin/.
Використання інших браузерів
За замовчуванням Dusk використовує Google Chrome та окрему установку ChromeDriver для запуску тестів вашого браузера. Однак, ви можете запустити власний сервер Selenium і виконувати тести в будь-якому браузері за вашим бажанням.
Щоб почати, відкрийте ваш файл tests/DuskTestCase.php, який є базовим тестовим випадком Dusk для вашого застосунку. У цьому файлі ви можете видалити виклик методу startChromeDriver. Це зупинить Dusk від автоматичного запуску ChromeDriver:
/**
* Підготуйтеся до виконання тестів Dusk.
*
* @beforeClass
*/
public static function prepare(): void
{
// static::startChromeDriver();
}
Далі, ви можете змінити метод driver, щоб підключитися до URL-адреси та порту на ваш вибір. Крім того, ви можете змінити "бажані можливості", які повинні бути передані до WebDriver:
use Facebook\WebDriver\Remote\RemoteWebDriver;
/**
* Створіть екземпляр RemoteWebDriver.
*/
protected function driver(): RemoteWebDriver
{
return RemoteWebDriver::create(
'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()
);
}
Початок роботи
Генерація тестів
Щоб згенерувати тест Dusk, використовуйте команду Artisan dusk:make. Згенерований тест буде розміщено в директорії tests/Browser:
php artisan dusk:make LoginTest
Скидання бази даних після кожного тесту
Більшість тестів, які ви пишете, будуть взаємодіяти зі сторінками, що отримують дані з бази даних вашого застосунку; однак, ваші Dusk тести ніколи не повинні використовувати трейт RefreshDatabase. Трейт RefreshDatabase використовує транзакції бази даних, які не будуть застосовні або доступні через HTTP-запити. Натомість, у вас є два варіанти: трейт DatabaseMigrations і трейт DatabaseTruncation.
Використання міграцій бази даних
Трейт DatabaseMigrations виконуватиме ваші міграції бази даних перед кожним тестом. Однак, видалення та повторне створення таблиць бази даних для кожного тесту зазвичай повільніше, ніж очищення таблиць:
<?php
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
uses(DatabaseMigrations::class);
//
<?php
namespace Tests\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
//
}
SQLite бази даних в пам'яті не можуть бути використані при виконанні Dusk тестів. Оскільки браузер виконується в межах власного процесу, він не зможе отримати доступ до баз даних в пам'яті інших процесів.
Використання очищення бази даних (truncation)
Трейт DatabaseTruncation мігрує вашу базу даних під час першого тесту, щоб забезпечити правильне створення таблиць бази даних. Однак у наступних тестах таблиці бази даних просто будуть очищені - це забезпечує підвищення швидкості в порівнянні з повторним запуском усіх міграцій бази даних:
<?php use Illuminate\Foundation\Testing\DatabaseTruncation; use Laravel\Dusk\Browser; uses(DatabaseTruncation::class); //
<?php namespace Tests\Browser; use App\Models\User; use Illuminate\Foundation\Testing\DatabaseTruncation; use Laravel\Dusk\Browser; use Tests\DuskTestCase; class ExampleTest extends DuskTestCase { use DatabaseTruncation; // }
За замовчуванням ця властивість буде очищати всі таблиці, окрім таблиці migrations. Якщо ви хочете налаштувати таблиці, які повинні бути очищені, ви можете визначити властивість $tablesToTruncate у вашому тестовому класі:
Якщо ви використовуєте Pest, ви повинні визначити властивості або методи в базовому класі DuskTestCase або в будь-якому класі, який розширює ваш тестовий файл.
/**
* Вказує, які таблиці слід очистити.
*
* @var array
*/
protected $tablesToTruncate = ['users'];
Альтернативно, ви можете визначити властивість $exceptTables у вашому тестовому класі, щоб вказати, які таблиці слід виключити з усічення:
/**
* Вказує, які таблиці слід виключити з усічення.
*
* @var array
*/
protected $exceptTables = ['users'];
Щоб вказати з'єднання з базою даних, таблиці яких слід очистити, ви можете визначити властивість $connectionsToTruncate у вашому тестовому класі:
/**
* Вказує, які з'єднання повинні мати свої таблиці очищеними.
*
* @var array
*/
protected $connectionsToTruncate = ['mysql'];
Якщо ви хочете виконати код до або після виконання усічення бази даних, ви можете визначити методи beforeTruncatingDatabase або afterTruncatingDatabase у вашому тестовому класі:
/**
* Виконайте будь-яку роботу, яка повинна відбутися до того, як база даних почне очищення.
*/
protected function beforeTruncatingDatabase(): void
{
//
}
/**
* Виконайте будь-яку роботу, яка повинна відбутися після того, як база даних завершила очищення.
*/
protected function afterTruncatingDatabase(): void
{
//
}
Запуск тестів
Щоб запустити тести вашого браузера, виконайте команду Artisan dusk:
php artisan dusk
Якщо у вас були збої тестів під час останнього запуску команди dusk, ви можете заощадити час, спочатку повторно запустивши невдалі тести за допомогою команди dusk:fails:
php artisan dusk:fails
Команда dusk приймає будь-які аргументи, які зазвичай приймаються тестовим запуском Pest / PHPUnit, такі як можливість запускати тести лише для заданої групи:
php artisan dusk --group=foo
Якщо ви використовуєте Laravel Sail для управління вашим локальним середовищем розробки, будь ласка, зверніться до документації Sail щодо налаштування та запуску тестів Dusk.
Ручний запуск ChromeDriver
За замовчуванням Dusk автоматично намагатиметься запустити ChromeDriver. Якщо це не працює для вашої системи, ви можете вручну запустити ChromeDriver перед виконанням команди dusk. Якщо ви вирішите запускати ChromeDriver вручну, вам слід закоментувати наступний рядок у вашому файлі tests/DuskTestCase.php:
/**
* Підготуйтеся до виконання тестів Dusk.
*
* @beforeClass
*/
public static function prepare(): void
{
// static::startChromeDriver();
}
Крім того, якщо ви запускаєте ChromeDriver на порту, відмінному від 9515, вам слід змінити метод driver того ж класу, щоб відобразити правильний порт:
use Facebook\WebDriver\Remote\RemoteWebDriver;
/**
* Створіть екземпляр RemoteWebDriver.
*/
protected function driver(): RemoteWebDriver
{
return RemoteWebDriver::create(
'http://localhost:9515', DesiredCapabilities::chrome()
);
}
Обробка середовища
Щоб змусити Dusk використовувати власний файл середовища під час запуску тестів, створіть файл .env.dusk.{environment} у кореневій директорії вашого проекту. Наприклад, якщо ви будете запускати команду dusk з вашого local середовища, вам слід створити файл .env.dusk.local.
Під час запуску тестів Dusk створить резервну копію вашого файлу .env і перейменує ваше середовище Dusk на .env. Після завершення тестів ваш файл .env буде відновлено.
Основи браузера
Створення браузерів
Щоб почати, давайте напишемо тест, який перевіряє, що ми можемо увійти в наш застосунок. Після створення тесту, ми можемо змінити його, щоб перейти на сторінку входу, ввести деякі облікові дані та натиснути кнопку "Увійти". Щоб створити екземпляр браузера, ви можете викликати метод browse з вашого Dusk тесту:
<?php use App\Models\User; use Illuminate\Foundation\Testing\DatabaseMigrations; use Laravel\Dusk\Browser; uses(DatabaseMigrations::class); test('basic example', function () { $user = User::factory()->create([ 'email' => 'example@example.com', ]); $this->browse(function (Browser $browser) use ($user) { $browser->visit('/login') ->type('email', $user->email) ->type('password', 'password') ->press('Login') ->assertPathIs('/home'); }); });
<?php namespace Tests\Browser; use App\Models\User; use Illuminate\Foundation\Testing\DatabaseMigrations; use Laravel\Dusk\Browser; use Tests\DuskTestCase; class ExampleTest extends DuskTestCase { use DatabaseMigrations; /** * Приклад базового браузерного тесту. */ public function test_basic_example(): void { $user = User::factory()->create([ 'email' => 'example@example.com', ]); $this->browse(function (Browser $browser) use ($user) { $browser->visit('/login') ->type('email', $user->email) ->type('password', 'password') ->press('Login') ->assertPathIs('/home'); }); } }
Як ви можете бачити у наведеному вище прикладі, метод browse приймає замикання. Екземпляр браузера автоматично передається цьому замиканню Dusk і є основним об'єктом, який використовується для взаємодії з вашим застосунком та для перевірки тверджень щодо нього.
Створення кількох браузерів
Іноді вам може знадобитися кілька браузерів, щоб належним чином виконати тест. Наприклад, кілька браузерів можуть бути потрібні для тестування екрану чату, який взаємодіє з веб-сокетами. Щоб створити кілька браузерів, просто додайте більше аргументів браузера до сигнатури замикання, переданого методу browse:
$this->browse(function (Browser $first, Browser $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');
});
Навігація
Метод visit може бути використаний для переходу до заданого URI у вашому застосунку:
$browser->visit('/login');
Ви можете використовувати метод visitRoute для переходу до іменованого маршруту:
$browser->visitRoute($routeName, $parameters);
Ви можете переміщатися "назад" і "вперед", використовуючи методи back і forward:
$browser->back();
$browser->forward();
Ви можете використовувати метод refresh для оновлення сторінки:
$browser->refresh();
Зміна розміру вікон браузера
Ви можете використовувати метод resize для зміни розміру вікна браузера:
$browser->resize(1920, 1080);
Метод maximize може бути використаний для максимізації вікна браузера:
$browser->maximize();
Метод fitContent змінить розмір вікна браузера, щоб відповідати розміру його вмісту:
$browser->fitContent();
Коли тест не вдається, Dusk автоматично змінює розмір браузера, щоб він відповідав вмісту перед створенням знімка екрана. Ви можете вимкнути цю функцію, викликавши метод disableFitOnFailure у вашому тесті:
$browser->disableFitOnFailure();
Ви можете використовувати метод move, щоб перемістити вікно браузера в інше положення на вашому екрані:
$browser->move($x = 100, $y = 100);
Макроси браузера
Якщо ви хочете визначити власний метод браузера, який можна повторно використовувати в різних тестах, ви можете скористатися методом macro у класі Browser. Зазвичай, ви повинні викликати цей метод з методу boot Сервіс-провайдера:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\Browser;
class DuskServiceProvider extends ServiceProvider
{
/**
* Зареєструйте макроси браузера Dusk.
*/
public function boot(): void
{
Browser::macro('scrollToElement', function (string $element = null) {
$this->script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);");
return $this;
});
}
}
Функція macro приймає ім'я як свій перший аргумент, а замикання як другий. Замикання макросу буде виконано при виклику макросу як методу на екземплярі Browser:
$this->browse(function (Browser $browser) use ($user) {
$browser->visit('/pay')
->scrollToElement('#credit-card-details')
->assertSee('Enter Credit Card Details');
});
Аутентифікація
Часто ви будете тестувати сторінки, які вимагають автентифікації. Ви можете використовувати метод Dusk loginAs, щоб уникнути взаємодії з екраном входу вашого застосунку під час кожного тесту. Метод loginAs приймає первинний ключ, пов'язаний з вашою автентифікованою моделлю, або екземпляр автентифікованої моделі:
use App\Models\User;
use Laravel\Dusk\Browser;
$this->browse(function (Browser $browser) {
$browser->loginAs(User::find(1))
->visit('/home');
});
Після використання методу loginAs сесія користувача буде зберігатися для всіх тестів у файлі.
Cookies
Ви можете використовувати метод cookie для отримання або встановлення значення зашифрованого cookie. За замовчуванням усі cookie, створені Laravel, зашифровані:
$browser->cookie('name');
$browser->cookie('name', 'Taylor');
Ви можете використовувати метод plainCookie для отримання або встановлення значення незашифрованого cookie:
$browser->plainCookie('name');
$browser->plainCookie('name', 'Taylor');
Ви можете використовувати метод deleteCookie для видалення вказаного cookie:
$browser->deleteCookie('name');
Виконання JavaScript
Ви можете використовувати метод script для виконання довільних JavaScript інструкцій у браузері:
$browser->script('document.documentElement.scrollTop = 0');
$browser->script([
'document.body.scrollTop = 0',
'document.documentElement.scrollTop = 0',
]);
$output = $browser->script('return window.location.pathname');
Зняття скріншоту
Ви можете використовувати метод screenshot для зняття скріншоту та збереження його з вказаним ім'ям файлу. Усі скріншоти будуть зберігатися в каталозі tests/Browser/screenshots:
$browser->screenshot('filename');
Метод responsiveScreenshots може бути використаний для зняття серії скріншотів на різних точках зупинки:
$browser->responsiveScreenshots('filename');
Метод screenshotElement може бути використаний для зняття скріншоту конкретного елемента на сторінці:
$browser->screenshotElement('#selector', 'filename');
Збереження Виводу Консолі на Диск
Ви можете використовувати метод storeConsoleLog для запису виводу консолі поточного браузера на диск з вказаною назвою файлу. Вивід консолі буде збережено в директорії tests/Browser/console:
$browser->storeConsoleLog('filename');
Збереження Джерела Сторінки на Диск
Ви можете використовувати метод storeSource, щоб записати вихідний код поточної сторінки на диск з вказаною назвою файлу. Вихідний код сторінки буде збережено в каталозі tests/Browser/source:
$browser->storeSource('filename');
Взаємодія з елементами
Селектори Dusk
Вибір хороших CSS-селекторів для взаємодії з елементами є однією з найскладніших частин написання тестів Dusk. З часом зміни у фронтенді можуть призвести до того, що CSS-селектори, як-от наступні, зламають ваші тести:
// 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');
Якщо потрібно, ви можете налаштувати HTML-атрибут, який використовує селектор Dusk, за допомогою методу selectorHtmlAttribute. Зазвичай цей метод слід викликати з методу boot у AppServiceProvider вашого застосунку:
use Laravel\Dusk\Dusk;
Dusk::selectorHtmlAttribute('data-dusk');
Текст, Значення та Атрибути
Отримання та встановлення значень
Dusk надає кілька методів для взаємодії з поточним значенням, відображуваним текстом та атрибутами елементів на сторінці. Наприклад, щоб отримати "значення" елемента, який відповідає заданому CSS або Dusk селектору, використовуйте метод value:
// Отримати значення...
$value = $browser->value('selector');
// Встановіть значення...
$browser->value('selector', 'value');
Ви можете використовувати метод inputValue, щоб отримати "значення" елемента введення, який має задане ім'я поля:
$value = $browser->inputValue('field');
Отримання тексту
Метод text може бути використаний для отримання тексту відображення елемента, який відповідає заданому селектору:
$text = $browser->text('selector');
Отримання атрибутів
Нарешті, метод attribute може бути використаний для отримання значення атрибута елемента, що відповідає заданому селектору:
$attribute = $browser->attribute('selector', 'value');
Взаємодія з формами
Введення значень
Dusk надає різноманітні методи для взаємодії з формами та елементами введення. Спочатку давайте розглянемо приклад введення тексту в поле введення:
$browser->type('email', 'example@example.com');
Зверніть увагу, що, хоча метод приймає його за необхідності, ми не зобов'язані передавати CSS селектор у метод type. Якщо CSS селектор не надано, Dusk буде шукати поле input або textarea з вказаним атрибутом name.
Щоб додати текст до поля, не очищаючи його вміст, ви можете використовувати метод append:
$browser->type('tags', 'foo')
->append('tags', ', bar, baz');
Ви можете очистити значення поля вводу, використовуючи метод clear:
$browser->clear('email');
Ви можете вказати Dusk вводити повільно, використовуючи метод typeSlowly. За замовчуванням Dusk робить паузу на 100 мілісекунд між натисканнями клавіш. Щоб налаштувати кількість часу між натисканнями клавіш, ви можете передати відповідну кількість мілісекунд як третій аргумент методу:
$browser->typeSlowly('mobile', '+1 (202) 555-5555');
$browser->typeSlowly('mobile', '+1 (202) 555-5555', 300);
Ви можете використовувати метод appendSlowly для повільного додавання тексту:
$browser->type('tags', 'foo')
->appendSlowly('tags', ', bar, baz');
Випадаючі списки
Щоб вибрати значення, доступне в елементі select, ви можете використовувати метод select. Як і метод type, метод select не вимагає повного CSS селектора. При передачі значення методу select, ви повинні передати основне значення опції замість тексту, що відображається:
$browser->select('size', 'Large');
Ви можете вибрати випадковий варіант, опустивши другий аргумент:
$browser->select('size');
Надавши масив як другий аргумент методу select, ви можете вказати методу вибрати кілька опцій:
$browser->select('categories', ['Art', 'Music']);
Прапорці (Checkboxes)
Щоб "позначити" елемент введення checkbox, ви можете використовувати метод check. Як і багато інших методів, пов'язаних з введенням, повний CSS селектор не потрібен. Якщо відповідний CSS селектор не знайдено, Dusk шукатиме checkbox з відповідним атрибутом name:
$browser->check('terms');
Метод uncheck може бути використаний для зняття позначки з елемента введення типу "checkbox":
$browser->uncheck('terms');
Перемикачі (Radio Buttons)
Щоб "вибрати" опцію введення radio, ви можете використовувати метод radio. Як і багато інших методів, пов'язаних із введенням, повний CSS-селектор не потрібен. Якщо відповідний CSS-селектор не може бути знайдений, Dusk шукатиме введення radio з відповідними атрибутами name та value:
$browser->radio('size', 'large');
Прикріплення файлів
Метод attach може бути використаний для прикріплення файлу до елемента введення file. Як і багато інших методів, пов'язаних з введенням, повний CSS селектор не є обов'язковим. Якщо відповідний CSS селектор не може бути знайдений, Dusk буде шукати елемент введення file з відповідним атрибутом name:
$browser->attach('photo', __DIR__.'/photos/mountains.png');
Функція attach вимагає, щоб розширення PHP Zip було встановлено та увімкнено на вашому сервері.
Натискання кнопок
Метод press може бути використаний для натискання на елемент кнопки на сторінці. Аргумент, переданий методу press, може бути або текстом, що відображається на кнопці, або CSS / Dusk селектором:
$browser->press('Login');
Коли відправляються форми, багато застосунків вимикають кнопку відправки форми після її натискання, а потім знову вмикають кнопку, коли HTTP-запит відправки форми завершено. Щоб натиснути кнопку і чекати, поки кнопка знову стане активною, ви можете використовувати метод pressAndWaitFor:
// Натисніть кнопку і зачекайте максимум 5 секунд, щоб вона стала активною...
$browser->pressAndWaitFor('Save');
// Натисніть кнопку і зачекайте максимум 1 секунду, щоб вона стала активною...
$browser->pressAndWaitFor('Save', 1);
Натискання на посилання
Щоб натиснути на посилання, ви можете використовувати метод clickLink на екземплярі браузера. Метод clickLink натисне на посилання, яке має заданий текст для відображення:
$browser->clickLink($linkText);
Ви можете використовувати метод seeLink, щоб визначити, чи посилання з вказаним текстом відображення видно на сторінці:
if ($browser->seeLink($linkText)) {
// ...
}
Ці методи взаємодіють з jQuery. Якщо jQuery недоступний на сторінці, Dusk автоматично вбудує його на сторінку, щоб він був доступний протягом тривалості тесту.
Використання клавіатури
Метод keys дозволяє надавати більш складні послідовності введення для заданого елемента, ніж зазвичай дозволяє метод type. Наприклад, ви можете вказати Dusk утримувати клавіші-модифікатори під час введення значень. У цьому прикладі клавіша shift буде утримуватися, поки taylor вводиться в елемент, що відповідає заданому селектору. Після того, як taylor буде введено, swift буде введено без жодних клавіш-модифікаторів:
$browser->keys('selector', ['{shift}', 'taylor'], 'swift');
Ще один цінний випадок використання методу keys - це відправка комбінації "клавіатурного скорочення" до основного CSS-селектора для вашого застосунку:
$browser->keys('.app', ['{command}', 'j']);
Усі клавіші-модифікатори, такі як {command}, обгорнуті в символи {} і відповідають константам, визначеним у класі Facebook\WebDriver\WebDriverKeys, які можна знайти на GitHub.
Плавна взаємодія з клавіатурою
Dusk також надає метод withKeyboard, що дозволяє плавно виконувати складні взаємодії з клавіатурою через клас Laravel\Dusk\Keyboard. Клас Keyboard надає методи press, release, type та pause:
use Laravel\Dusk\Keyboard;
$browser->withKeyboard(function (Keyboard $keyboard) {
$keyboard->press('c')
->pause(1000)
->release('c')
->type(['c', 'e', 'o']);
});
Макроси клавіатури
Якщо ви хочете визначити власні взаємодії з клавіатурою, які ви можете легко повторно використовувати у всьому вашому наборі тестів, ви можете скористатися методом macro, наданим класом Keyboard. Зазвичай, ви повинні викликати цей метод з методу boot Сервіс-провайдера:
<?php
namespace App\Providers;
use Facebook\WebDriver\WebDriverKeys;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\Keyboard;
use Laravel\Dusk\OperatingSystem;
class DuskServiceProvider extends ServiceProvider
{
/**
* Зареєструйте макроси браузера Dusk.
*/
public function boot(): void
{
Keyboard::macro('copy', function (string $element = null) {
$this->type([
OperatingSystem::onMac() ? WebDriverKeys::META : WebDriverKeys::CONTROL, 'c',
]);
return $this;
});
Keyboard::macro('paste', function (string $element = null) {
$this->type([
OperatingSystem::onMac() ? WebDriverKeys::META : WebDriverKeys::CONTROL, 'v',
]);
return $this;
});
}
}
Функція macro приймає ім'я як свій перший аргумент і замикання як другий. Замикання макросу буде виконано при виклику макросу як методу на екземплярі Keyboard:
$browser->click('@textarea')
->withKeyboard(fn (Keyboard $keyboard) => $keyboard->copy())
->click('@another-textarea')
->withKeyboard(fn (Keyboard $keyboard) => $keyboard->paste());
Використання миші
Клік по елементах
Метод click може бути використаний для натискання на елемент, що відповідає заданому CSS або Dusk селектору:
$browser->click('.selector');
Метод clickAtXPath може бути використаний для натискання на елемент, що відповідає заданому XPath виразу:
$browser->clickAtXPath('//div[@class = "selector"]');
Метод clickAtPoint може бути використаний для натискання на верхній елемент у заданій парі координат відносно видимої області браузера:
$browser->clickAtPoint($x = 0, $y = 0);
Метод doubleClick може бути використаний для імітації подвійного кліку миші:
$browser->doubleClick();
$browser->doubleClick('.selector');
Метод rightClick може бути використаний для імітації правого кліку миші:
$browser->rightClick();
$browser->rightClick('.selector');
Метод clickAndHold може бути використаний для імітації натискання і утримання кнопки миші. Наступний виклик методу releaseMouse скасує цю поведінку і відпустить кнопку миші:
$browser->clickAndHold('.selector');
$browser->clickAndHold()
->pause(1000)
->releaseMouse();
Метод controlClick може бути використаний для симуляції події ctrl+click у браузері:
$browser->controlClick();
$browser->controlClick('.selector');
Наведення курсору
Метод mouseover може бути використаний, коли вам потрібно перемістити мишу на елемент, що відповідає заданому CSS або Dusk селектору:
$browser->mouseover('.selector');
Перетягування (Drag and Drop)
Метод drag може бути використаний для перетягування елемента, що відповідає заданому селектору, до іншого елемента:
$browser->drag('.from-selector', '.to-selector');
Або ви можете перетягнути елемент в одному напрямку:
$browser->dragLeft('.selector', $pixels = 10);
$browser->dragRight('.selector', $pixels = 10);
$browser->dragUp('.selector', $pixels = 10);
$browser->dragDown('.selector', $pixels = 10);
Нарешті, ви можете перетягнути елемент на задане зміщення:
$browser->dragOffset('.selector', $x = 10, $y = 10);
Діалоги JavaScript
Dusk надає різні методи для взаємодії з JavaScript діалогами. Наприклад, ви можете використовувати метод waitForDialog, щоб чекати появи JavaScript діалогу. Цей метод приймає необов'язковий аргумент, що вказує, скільки секунд чекати на появу діалогу:
$browser->waitForDialog($seconds = null);
Метод assertDialogOpened може бути використаний для перевірки того, що діалогове вікно було відображено і містить задане повідомлення:
$browser->assertDialogOpened('Dialog message');
Якщо JavaScript-діалог містить запит, ви можете використовувати метод typeInDialog, щоб ввести значення в запит:
$browser->typeInDialog('Hello World');
Щоб закрити відкритий JavaScript-діалог, натиснувши кнопку "OK", ви можете викликати метод acceptDialog:
$browser->acceptDialog();
Щоб закрити відкритий JavaScript-діалог, натиснувши кнопку "Скасувати", ви можете викликати метод dismissDialog:
$browser->dismissDialog();
Взаємодія з вбудованими фреймами
Якщо вам потрібно взаємодіяти з елементами всередині iframe, ви можете використовувати метод withinFrame. Всі взаємодії з елементами, які відбуваються в межах замикання, наданого методу withinFrame, будуть обмежені контекстом вказаного iframe:
$browser->withinFrame('#credit-card-details', function ($browser) {
$browser->type('input[name="cardnumber"]', '4242424242424242')
->type('input[name="exp-date"]', '1224')
->type('input[name="cvc"]', '123')
->press('Pay');
});
Вибір селекторів
Іноді ви можете захотіти виконати кілька операцій, обмежуючи всі операції в межах заданого селектора. Наприклад, ви можете захотіти перевірити, що певний текст існує лише в межах таблиці, а потім натиснути кнопку в цій таблиці. Ви можете використовувати метод with для досягнення цього. Усі операції, виконані в межах замикання, переданого методу with, будуть обмежені початковим селектором:
$browser->with('.table', function (Browser $table) {
$table->assertSee('Hello World')
->clickLink('Delete');
});
Ви можете час від часу виконувати твердження поза поточним контекстом. Ви можете використовувати методи elsewhere та elsewhereWhenAvailable для цього:
$browser->with('.table', function (Browser $table) {
// Поточна область - це `body .table`...
$browser->elsewhere('.page-title', function (Browser $title) {
// Поточна область - `body .page-title`...
$title->assertSee('Hello World');
});
$browser->elsewhereWhenAvailable('.page-title', function (Browser $title) {
// Поточна область - `body .page-title`...
$title->assertSee('Hello World');
});
});
Очікування елементів
Коли тестуєте застосунки, які інтенсивно використовують JavaScript, часто стає необхідним "очікувати", поки певні елементи або дані стануть доступними перед продовженням тесту. Dusk робить це дуже просто. Використовуючи різноманітні методи, ви можете очікувати, поки елементи стануть видимими на сторінці або навіть чекати, поки заданий JavaScript вираз не оціниться як true.
Очікування
Якщо вам потрібно призупинити тест на певну кількість мілісекунд, використовуйте метод pause:
$browser->pause(1000);
Якщо вам потрібно призупинити тест лише за умови, що задана умова є true, використовуйте метод pauseIf:
$browser->pauseIf(App::environment('production'), 1000);
Аналогічно, якщо вам потрібно призупинити тест, якщо задана умова не є true, ви можете використовувати метод pauseUnless:
$browser->pauseUnless(App::environment('testing'), 1000);
Очікування селекторів
Метод waitFor може бути використаний для призупинення виконання тесту, доки елемент, що відповідає заданому CSS або Dusk селектору, не буде відображено на сторінці. За замовчуванням, це призупинить тест на максимум п'ять секунд перед генерацією винятку. За необхідності, ви можете передати власний поріг тайм-ауту як другий аргумент до методу:
// Зачекайте максимум п'ять секунд для селектора...
$browser->waitFor('.selector');
// Очікуйте максимум одну секунду для селектора...
$browser->waitFor('.selector', 1);
Ви також можете зачекати, поки елемент, що відповідає вказаному селектору, міститиме вказаний текст:
// Зачекайте максимум п'ять секунд, щоб селектор містив заданий текст...
$browser->waitForTextIn('.selector', 'Hello World');
// Зачекайте максимум одну секунду, щоб селектор містив вказаний текст...
$browser->waitForTextIn('.selector', 'Hello World', 1);
Ви також можете зачекати, поки елемент, що відповідає заданому селектору, зникне зі сторінки:
// Зачекайте максимум п'ять секунд, поки селектор не зникне...
$browser->waitUntilMissing('.selector');
// Зачекайте максимум одну секунду, поки селектор не зникне...
$browser->waitUntilMissing('.selector', 1);
Або ви можете зачекати, поки елемент, що відповідає заданому селектору, буде увімкнено або вимкнено:
// Зачекайте максимум п'ять секунд, поки селектор не буде увімкнено...
$browser->waitUntilEnabled('.selector');
// Зачекайте максимум одну секунду, поки селектор не буде увімкнено...
$browser->waitUntilEnabled('.selector', 1);
// Зачекайте максимум п'ять секунд, поки селектор не буде вимкнено...
$browser->waitUntilDisabled('.selector');
// Зачекайте максимум одну секунду, поки селектор не буде вимкнено...
$browser->waitUntilDisabled('.selector', 1);
Обмеження селекторів, коли доступно
Іноді ви можете захотіти почекати, поки з'явиться елемент, що відповідає заданому селектору, а потім взаємодіяти з цим елементом. Наприклад, ви можете захотіти почекати, поки модальне вікно стане доступним, а потім натиснути кнопку "OK" у цьому модальному вікні. Метод whenAvailable може бути використаний для досягнення цього. Усі операції з елементами, виконані в межах заданого замикання, будуть обмежені початковим селектором:
$browser->whenAvailable('.modal', function (Browser $modal) {
$modal->assertSee('Hello World')
->press('OK');
});
Очікування тексту
Метод waitForText може бути використаний для очікування, поки вказаний текст не буде відображено на сторінці:
// Зачекайте максимум п'ять секунд на текст...
$browser->waitForText('Hello World');
// Очікуйте максимум одну секунду для тексту...
$browser->waitForText('Hello World', 1);
Ви можете використовувати метод waitUntilMissingText, щоб чекати, поки відображуваний текст не буде видалено зі сторінки:
// Зачекайте максимум п'ять секунд, щоб текст було видалено...
$browser->waitUntilMissingText('Hello World');
// Зачекайте максимум одну секунду, щоб текст було видалено...
$browser->waitUntilMissingText('Hello World', 1);
Очікування посилань
Метод waitForLink може бути використаний для очікування, поки вказаний текст посилання не буде відображено на сторінці:
// Зачекайте максимум п'ять секунд на посилання...
$browser->waitForLink('Create');
// Зачекайте максимум одну секунду на посилання...
$browser->waitForLink('Create', 1);
Очікування на введення даних
Метод waitForInput може бути використаний для очікування, поки вказане поле введення не стане видимим на сторінці:
// Очікуйте максимум п'ять секунд на введення...
$browser->waitForInput($field);
// Зачекайте максимум одну секунду на введення...
$browser->waitForInput($field, 1);
Очікування на розташування сторінки
Коли ви робите перевірку шляху, таку як $browser->assertPathIs('/home'), перевірка може зазнати невдачі, якщо window.location.pathname оновлюється асинхронно. Ви можете використовувати метод waitForLocation, щоб дочекатися, поки місцезнаходження не стане заданим значенням:
$browser->waitForLocation('/secret');
Метод waitForLocation також можна використовувати для очікування, поки поточне розташування вікна не стане повністю кваліфікованим URL:
$browser->waitForLocation('https://example.com/path');
Ви також можете зачекати на розташування іменованого маршруту:
$browser->waitForRoute($routeName, $parameters);
Очікування перезавантаження сторінки
Якщо вам потрібно зачекати, поки сторінка перезавантажиться після виконання дії, використовуйте метод waitForReload:
use Laravel\Dusk\Browser;
$browser->waitForReload(function (Browser $browser) {
$browser->press('Submit');
})
->assertSee('Success!');
Оскільки необхідність чекати на перезавантаження сторінки зазвичай виникає після натискання кнопки, ви можете використовувати метод clickAndWaitForReload для зручності:
$browser->clickAndWaitForReload('.selector')
->assertSee('something');
Очікування на вирази JavaScript
Іноді ви можете захотіти призупинити виконання тесту, поки заданий вираз JavaScript не оціниться як true. Ви можете легко досягти цього, використовуючи метод waitUntil. Передаючи вираз цьому методу, вам не потрібно включати ключове слово return або кінцеву крапку з комою:
// Зачекайте максимум п'ять секунд, щоб вираз став істинним...
$browser->waitUntil('App.data.servers.length > 0');
// Зачекайте максимум одну секунду, щоб вираз став істинним...
$browser->waitUntil('App.data.servers.length > 0', 1);
Очікування на вирази Vue
Методи waitUntilVue та waitUntilVueIsNot можуть бути використані для очікування, поки атрибут Vue компонента не матиме заданого значення:
// Зачекайте, поки атрибут компонента міститиме задане значення...
$browser->waitUntilVue('user.name', 'Taylor', '@user');
// Зачекайте, поки атрибут компонента не міститиме задане значення...
$browser->waitUntilVueIsNot('user.name', null, '@user');
Очікування подій JavaScript
Метод waitForEvent може бути використаний для призупинення виконання тесту до виникнення події JavaScript:
$browser->waitForEvent('load');
Слухач подій прикріплений до поточної області, якою за замовчуванням є елемент body. При використанні селектора з обмеженою областю, слухач подій буде прикріплений до відповідного елемента:
$browser->with('iframe', function (Browser $iframe) {
// Зачекайте на подію завантаження iframe...
$iframe->waitForEvent('load');
});
Ви також можете надати селектор як другий аргумент методу waitForEvent, щоб прикріпити слухач подій до конкретного елемента:
$browser->waitForEvent('load', '.selector');
Ви також можете чекати на події на об'єктах document та window:
// Зачекайте, поки документ буде прокручено...
$browser->waitForEvent('scroll', 'document');
// Зачекайте максимум п'ять секунд, поки вікно не буде змінено в розмірі...
$browser->waitForEvent('resize', 'window', 5);
Очікування з зворотним викликом
Багато методів "wait" у Dusk покладаються на базовий метод waitUsing. Ви можете використовувати цей метод безпосередньо, щоб чекати, поки задане замикання не поверне true. Метод waitUsing приймає максимальну кількість секунд для очікування, інтервал, з яким слід оцінювати замикання, саме замикання та необов'язкове повідомлення про помилку:
$browser->waitUsing(10, 1, function () use ($something) {
return $something->isReady();
}, "Something wasn't ready in time.");
Прокручування елемента в представлення
Іноді ви можете не мати можливості натиснути на елемент, оскільки він знаходиться за межами видимої області браузера. Метод scrollIntoView прокрутить вікно браузера, поки елемент за вказаним селектором не опиниться в межах представлення:
$browser->scrollIntoView('.selector')
->click('.selector');
Доступні Твердження
Dusk надає різноманітні твердження, які ви можете використовувати проти вашого застосунку. Усі доступні твердження задокументовані в списку нижче:
assertTitle assertTitleContains assertUrlIs assertSchemeIs assertSchemeIsNot assertHostIs assertHostIsNot assertPortIs assertPortIsNot assertPathBeginsWith assertPathEndsWith assertPathContains assertPathIs assertPathIsNot assertRouteIs assertQueryStringHas assertQueryStringMissing assertFragmentIs assertFragmentBeginsWith assertFragmentIsNot assertHasCookie assertHasPlainCookie assertCookieMissing assertPlainCookieMissing assertCookieValue assertPlainCookieValue assertSee assertDontSee assertSeeIn assertDontSeeIn assertSeeAnythingIn assertSeeNothingIn assertCount assertScript assertSourceHas assertSourceMissing assertSeeLink assertDontSeeLink assertInputValue assertInputValueIsNot assertChecked assertNotChecked assertIndeterminate assertRadioSelected assertRadioNotSelected assertSelected assertNotSelected assertSelectHasOptions assertSelectMissingOptions assertSelectHasOption assertSelectMissingOption assertValue assertValueIsNot assertAttribute assertAttributeMissing assertAttributeContains assertAttributeDoesntContain assertAriaAttribute assertDataAttribute assertVisible assertPresent assertNotPresent assertMissing assertInputPresent assertInputMissing assertDialogOpened assertEnabled assertDisabled assertButtonEnabled assertButtonDisabled assertFocused assertNotFocused assertAuthenticated assertGuest assertAuthenticatedAs assertVue assertVueIsNot assertVueContains assertVueDoesntContain
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('/home');
assertPathEndsWith
Переконайтеся, що поточний шлях URL закінчується вказаним шляхом:
$browser->assertPathEndsWith('/home');
assertPathContains
Переконайтеся, що поточний шлях URL містить вказаний шлях:
$browser->assertPathContains('/home');
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
Переконайтеся, що поточний фрагмент хешу URL відповідає заданому фрагменту:
$browser->assertFragmentIs('anchor');
assertFragmentBeginsWith
Переконайтеся, що поточний фрагмент хешу URL починається з вказаного фрагмента:
$browser->assertFragmentBeginsWith('anchor');
assertFragmentIsNot
Переконайтеся, що поточний фрагмент хешу URL не відповідає заданому фрагменту:
$browser->assertFragmentIsNot('anchor');
assertHasCookie
Переконайтеся, що вказане зашифроване cookie присутнє:
$browser->assertHasCookie($name);
assertHasPlainCookie
Переконайтеся, що вказаний незашифрований cookie присутній:
$browser->assertHasPlainCookie($name);
assertCookieMissing
Переконайтеся, що вказаний зашифрований cookie відсутній:
$browser->assertCookieMissing($name);
assertPlainCookieMissing
Переконайтеся, що вказаний незашифрований cookie відсутній:
$browser->assertPlainCookieMissing($name);
assertCookieValue
Переконайтеся, що зашифроване cookie має задане значення:
$browser->assertCookieValue($name, $value);
assertPlainCookieValue
Переконайтеся, що незашифроване cookie має задане значення:
$browser->assertPlainCookieValue($name, $value);
assertSee
Переконайтеся, що вказаний текст присутній на сторінці:
$browser->assertSee($text);
assertDontSee
Переконайтеся, що вказаний текст відсутній на сторінці:
$browser->assertDontSee($text);
assertSeeIn
Переконайтеся, що даний текст присутній у вибраному елементі:
$browser->assertSeeIn($selector, $text);
assertDontSeeIn
Переконайтеся, що вказаний текст відсутній у вибраному елементі:
$browser->assertDontSeeIn($selector, $text);
assertSeeAnythingIn
Переконайтеся, що будь-який текст присутній у селекторі:
$browser->assertSeeAnythingIn($selector);
assertSeeNothingIn
Переконайтеся, що в межах селектора немає тексту:
$browser->assertSeeNothingIn($selector);
assertCount
Переконайтеся, що елементи, які відповідають заданому селектору, з'являються вказану кількість разів:
$browser->assertCount($selector, $count);
assertScript
Переконайтеся, що даний вираз JavaScript оцінюється до заданого значення:
$browser->assertScript('window.isLoaded')
->assertScript('document.readyState', 'complete');
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);
assertIndeterminate
Переконайтеся, що вказаний прапорець знаходиться в невизначеному стані:
$browser->assertIndeterminate($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);
assertSelectMissingOption
Переконайтеся, що вказане значення недоступне для вибору:
$browser->assertSelectMissingOption($field, $value);
assertValue
Переконайтеся, що елемент, який відповідає заданому селектору, має задане значення:
$browser->assertValue($selector, $value);
assertValueIsNot
Переконайтеся, що елемент, який відповідає заданому селектору, не має заданого значення:
$browser->assertValueIsNot($selector, $value);
assertAttribute
Переконайтеся, що елемент, який відповідає заданому селектору, має задане значення в наданому атрибуті:
$browser->assertAttribute($selector, $attribute, $value);
assertAttributeMissing
Переконайтеся, що елемент, який відповідає заданому селектору, не має вказаного атрибута:
$browser->assertAttributeMissing($selector, $attribute);
assertAttributeContains
Переконайтеся, що елемент, який відповідає заданому селектору, містить задане значення в наданому атрибуті:
$browser->assertAttributeContains($selector, $attribute, $value);
assertAttributeDoesntContain
Переконайтеся, що елемент, який відповідає заданому селектору, не містить заданого значення в наданому атрибуті:
$browser->assertAttributeDoesntContain($selector, $attribute, $value);
assertAriaAttribute
Переконайтеся, що елемент, який відповідає заданому селектору, має задане значення в наданому атрибуті aria:
$browser->assertAriaAttribute($selector, $attribute, $value);
Наприклад, маючи розмітку <button aria-label="Add"></button>, ви можете перевірити атрибут aria-label таким чином:
$browser->assertAriaAttribute('button', 'label', 'Add')
assertDataAttribute
Переконайтеся, що елемент, який відповідає заданому селектору, має задане значення в наданому атрибуті даних:
$browser->assertDataAttribute($selector, $attribute, $value);
Наприклад, для розмітки <tr id="row-1" data-content="attendees"></tr>, ви можете перевірити атрибут data-label таким чином:
$browser->assertDataAttribute('#row-1', 'content', 'attendees')
assertVisible
Переконайтеся, що елемент, який відповідає заданому селектору, є видимим:
$browser->assertVisible($selector);
assertPresent
Переконайтеся, що елемент, який відповідає заданому селектору, присутній у джерелі:
$browser->assertPresent($selector);
assertNotPresent
Переконайтеся, що елемент, який відповідає заданому селектору, відсутній у джерелі:
$browser->assertNotPresent($selector);
assertMissing
Переконайтеся, що елемент, який відповідає заданому селектору, не відображається:
$browser->assertMissing($selector);
assertInputPresent
Переконайтеся, що вхід з вказаним ім'ям присутній:
$browser->assertInputPresent($name);
assertInputMissing
Переконайтеся, що вхід з даним ім'ям відсутній у джерелі:
$browser->assertInputMissing($name);
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);
assertAuthenticated
Переконайтеся, що користувач автентифікований:
$browser->assertAuthenticated();
assertGuest
Переконайтеся, що користувач не автентифікований:
$browser->assertGuest();
assertAuthenticatedAs
Переконайтеся, що користувач автентифікований як вказаний користувач:
$browser->assertAuthenticatedAs($user);
assertVue
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 наступним чином:
test('vue', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertVue('user.name', 'Taylor', '@profile-component');
});
});
/**
* A basic Vue test example.
*/
public function test_vue(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertVue('user.name', 'Taylor', '@profile-component');
});
}
assertVueIsNot
Переконайтеся, що вказана властивість даних компонента Vue не відповідає вказаному значенню:
$browser->assertVueIsNot($property, $value, $componentSelector = null);
assertVueContains
Переконайтеся, що задана властивість даних компонента Vue є масивом і містить задане значення:
$browser->assertVueContains($property, $value, $componentSelector = null);
assertVueDoesntContain
Переконайтеся, що задана властивість даних компонента Vue є масивом і не містить заданого значення:
$browser->assertVueDoesntContain($property, $value, $componentSelector = null);
Сторінки
Іноді тести вимагають виконання кількох складних дій у послідовності. Це може ускладнити читання та розуміння ваших тестів. Сторінки Dusk дозволяють визначати виразні дії, які потім можуть бути виконані на заданій сторінці через один метод. Сторінки також дозволяють визначати скорочення для загальних селекторів для вашого застосунку або для однієї сторінки.
Генерація сторінок
Щоб згенерувати об'єкт сторінки, виконайте команду Artisan dusk:page. Усі об'єкти сторінок будуть розміщені в директорії tests/Browser/Pages вашого застосунку:
php artisan dusk:page Login
Налаштування Сторінок
За замовчуванням, сторінки мають три методи: url, assert та elements. Ми обговоримо методи url та assert зараз. Метод elements буде обговорено детальніше нижче.
The url Method
Метод url повинен повертати шлях URL, який представляє сторінку. Dusk використовуватиме цей URL при переході на сторінку в браузері:
/**
* Отримати URL-адресу сторінки.
*/
public function url(): string
{
return '/login';
}
The assert Method
Метод assert може виконувати будь-які перевірки, необхідні для підтвердження того, що браузер дійсно знаходиться на вказаній сторінці. Насправді, не обов'язково розміщувати щось у цьому методі; однак, ви можете виконати ці перевірки, якщо бажаєте. Ці перевірки будуть виконані автоматично при переході на сторінку:
/**
* Переконайтеся, що браузер знаходиться на сторінці.
*/
public function assert(Browser $browser): void
{
$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" на сторінці входу в застосунок:
/**
* Отримати ярлики елементів для сторінки.
*
* @return array<string, string>
*/
public function elements(): array
{
return [
'@email' => 'input[name=email]',
];
}
Після того, як ярлик було визначено, ви можете використовувати скорочений селектор всюди, де зазвичай використовували б повний CSS селектор:
$browser->type('@email', 'example@example.com');
Global Shorthand Selectors
Після встановлення Dusk, базовий клас Page буде розміщено у вашому каталозі tests/Browser/Pages. Цей клас містить метод siteElements, який може бути використаний для визначення глобальних скорочених селекторів, що повинні бути доступні на кожній сторінці вашого застосунку:
/**
* Отримати глобальні ярлики елементів для сайту.
*
* @return array<string, string>
*/
public static function siteElements(): array
{
return [
'@element' => '#selector',
];
}
Методи Сторінки
На додаток до методів за замовчуванням, визначених на сторінках, ви можете визначити додаткові методи, які можуть використовуватися у ваших тестах. Наприклад, уявімо, що ми створюємо застосунок для управління музикою. Загальною дією для однієї сторінки застосунку може бути створення плейлиста. Замість переписування логіки створення плейлиста в кожному тесті, ви можете визначити метод createPlaylist у класі сторінки:
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
use Laravel\Dusk\Page;
class Dashboard extends Page
{
// Інші методи сторінки...
/**
* Створити новий плейлист.
*/
public function createPlaylist(Browser $browser, string $name): void
{
$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, але призначені для частин інтерфейсу користувача та функціональності, які повторно використовуються у вашому застосунку, таких як панель навігації або вікно сповіщень. Таким чином, компоненти не прив'язані до конкретних URL-адрес.
Генерація Компонентів
Щоб згенерувати компонент, виконайте команду Artisan dusk:component. Нові компоненти розміщуються в каталозі tests/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
{
/**
* Отримати кореневий селектор для компонента.
*/
public function selector(): string
{
return '.date-picker';
}
/**
* Переконайтеся, що сторінка браузера містить компонент.
*/
public function assert(Browser $browser): void
{
$browser->assertVisible($this->selector());
}
/**
* Отримати ярлики елементів для компонента.
*
* @return array<string, string>
*/
public function elements(): array
{
return [
'@date-field' => 'input.datepicker-input',
'@year-list' => 'div > div.datepicker-years',
'@month-list' => 'div > div.datepicker-months',
'@day-list' => 'div > div.datepicker-days',
];
}
/**
* Виберіть задану дату.
*/
public function selectDate(Browser $browser, int $year, int $month, int $day): void
{
$browser->click('@date-field')
->within('@year-list', function (Browser $browser) use ($year) {
$browser->click($year);
})
->within('@month-list', function (Browser $browser) use ($month) {
$browser->click($month);
})
->within('@day-list', function (Browser $browser) use ($day) {
$browser->click($day);
});
}
}
Використання Компонентів
Після того як компонент було визначено, ми можемо легко вибрати дату в межах вибору дати з будь-якого тесту. І якщо логіка, необхідна для вибору дати, зміниться, нам потрібно лише оновити компонент:
<?php use Illuminate\Foundation\Testing\DatabaseMigrations; use Laravel\Dusk\Browser; use Tests\Browser\Components\DatePicker; uses(DatabaseMigrations::class); test('basic example', function () { $this->browse(function (Browser $browser) { $browser->visit('/') ->within(new DatePicker, function (Browser $browser) { $browser->selectDate(2019, 1, 30); }) ->assertSee('January'); }); });
<?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 { /** * Приклад базового тесту компонента. */ public function test_basic_example(): void { $this->browse(function (Browser $browser) { $browser->visit('/') ->within(new DatePicker, function (Browser $browser) { $browser->selectDate(2019, 1, 30); }) ->assertSee('January'); }); } }
Метод component може бути використаний для отримання екземпляра браузера, обмеженого даним компонентом:
$datePicker = $browser->component(new DatePickerComponent);
$datePicker->selectDate(2019, 1, 30);
$datePicker->assertSee('January');
Безперервна інтеграція
Більшість конфігурацій безперервної інтеграції Dusk очікують, що ваш застосунок Laravel буде обслуговуватися за допомогою вбудованого PHP-сервера розробки на порту 8000. Тому, перед тим як продовжити, ви повинні переконатися, що ваше середовище безперервної інтеграції має значення змінної середовища APP_URL як http://127.0.0.1:8000.
Heroku CI
Щоб запустити тести Dusk на Heroku CI, додайте наступний Google Chrome buildpack та скрипти до вашого Heroku файлу app.json:
{
"environments": {
"test": {
"buildpacks": [
{ "url": "heroku/php" },
{ "url": "https://github.com/heroku/heroku-buildpack-chrome-for-testing" }
],
"scripts": {
"test-setup": "cp .env.testing .env",
"test": "nohup bash -c './vendor/laravel/dusk/bin/chromedriver-linux --port=9515 > /dev/null 2>&1 &' && nohup bash -c 'php artisan serve --no-reload > /dev/null 2>&1 &' && php artisan dusk"
}
}
}
}
Travis CI
Щоб запустити ваші Dusk тести на Travis CI, використовуйте наступну конфігурацію .travis.yml. Оскільки Travis CI не є графічним середовищем, нам потрібно буде виконати кілька додаткових кроків, щоб запустити браузер Chrome. Крім того, ми будемо використовувати php artisan serve для запуску вбудованого веб-сервера PHP:
language: php
php:
- 8.2
addons:
chrome: stable
install:
- cp .env.testing .env
- travis_retry composer install --no-interaction --prefer-dist
- php artisan key:generate
- php artisan dusk:chrome-driver
before_script:
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
- php artisan serve --no-reload &
script:
- php artisan dusk
GitHub Actions
Якщо ви використовуєте GitHub Actions для запуску ваших Dusk тестів, ви можете використовувати наступний файл конфігурації як відправну точку. Як і в TravisCI, ми будемо використовувати команду php artisan serve для запуску вбудованого веб-сервера PHP:
name: CI
on: [push]
jobs:
dusk-php:
runs-on: ubuntu-latest
env:
APP_URL: "http://127.0.0.1:8000"
DB_USERNAME: root
DB_PASSWORD: root
MAIL_MAILER: log
steps:
- uses: actions/checkout@v4
- name: Prepare The Environment
run: cp .env.example .env
- name: Create Database
run: |
sudo systemctl start mysql
mysql --user="root" --password="root" -e "CREATE DATABASE \`my-database\` character set UTF8mb4 collate utf8mb4_bin;"
- name: Install Composer Dependencies
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: Generate Application Key
run: php artisan key:generate
- name: Upgrade Chrome Driver
run: php artisan dusk:chrome-driver --detect
- name: Start Chrome Driver
run: ./vendor/laravel/dusk/bin/chromedriver-linux --port=9515 &
- name: Run Laravel Server
run: php artisan serve --no-reload &
- name: Run Dusk Tests
run: php artisan dusk
- name: Upload Screenshots
if: failure()
uses: actions/upload-artifact@v4
with:
name: screenshots
path: tests/Browser/screenshots
- name: Upload Console Logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: console
path: tests/Browser/console
Chipper CI
Якщо ви використовуєте Chipper CI для запуску ваших Dusk тестів, ви можете використовувати наступний файл конфігурації як відправну точку. Ми будемо використовувати вбудований сервер PHP для запуску Laravel, щоб ми могли слухати запити:
# file .chipperci.yml
version: 1
environment:
php: 8.2
node: 16
# Include Chrome in the build environment
services:
- dusk
# Build all commits
on:
push:
branches: .*
pipeline:
- name: Setup
cmd: |
cp -v .env.example .env
composer install --no-interaction --prefer-dist --optimize-autoloader
php artisan key:generate
# Create a dusk env file, ensuring APP_URL uses BUILD_HOST
cp -v .env .env.dusk.ci
sed -i "s@APP_URL=.*@APP_URL=http://$BUILD_HOST:8000@g" .env.dusk.ci
- name: Compile Assets
cmd: |
npm ci --no-audit
npm run build
- name: Browser Tests
cmd: |
php -S [::0]:8000 -t public 2>server.log &
sleep 2
php artisan dusk:chrome-driver $CHROME_DRIVER
php artisan dusk --env=ci
Щоб дізнатися більше про запуск тестів Dusk на Chipper CI, включаючи використання баз даних, зверніться до офіційної документації Chipper CI.
