diff --git a/dusk.md b/dusk.md index 0f249810..713afd92 100644 --- a/dusk.md +++ b/dusk.md @@ -1,5 +1,5 @@ --- -git: 131983e0a57076fc769cc402876338704aa5810a +git: 50a8281a3ccf0589d5d61db53efafe26daa877ba --- # Laravel Dusk @@ -61,29 +61,33 @@ php artisan dusk:chrome-driver --detect Для начала откройте файл `tests/DuskTestCase.php`, который является базовым тестовым классом Dusk вашего приложения. Внутри этого файла вы можете удалить вызов метода `startChromeDriver`. Это остановит Dusk от автоматического запуска ChromeDriver: - /** - * Подготовить Dusk для выполнения теста. - * - * @beforeClass - */ - public static function prepare(): void - { - // static::startChromeDriver(); - } +```php +/** + * Подготовить Dusk для выполнения теста. + * + * @beforeClass + */ +public static function prepare(): void +{ + // static::startChromeDriver(); +} +``` Затем вы можете изменить метод `driver` для подключения к URL-адресу и порту по вашему выбору. Кроме того, вы можете изменить «требуемые характеристики» через класс `DesiredCapabilities`, передаваемые экземпляру WebDriver: - use Facebook\WebDriver\Remote\RemoteWebDriver; +```php +use Facebook\WebDriver\Remote\RemoteWebDriver; - /** - * Создать экземпляр RemoteWebDriver. - */ - protected function driver(): RemoteWebDriver - { - return RemoteWebDriver::create( - 'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs() - ); - } +/** + * Создать экземпляр RemoteWebDriver. + */ +protected function driver(): RemoteWebDriver +{ + return RemoteWebDriver::create( + 'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs() + ); +} +``` ## Начало работы @@ -177,48 +181,56 @@ class ExampleTest extends DuskTestCase > [!NOTE] > Если вы используете Pest, вам следует определить свойства или методы базового класса `DuskTestCase` или любого класса, расширяемого вашим тестовым файлом. - /** - * Указывает, какие таблицы должны быть очищены. - * - * @var array - */ - protected $tablesToTruncate = ['users']; +```php +/** + * Указывает, какие таблицы должны быть очищены. + * + * @var array + */ +protected $tablesToTruncate = ['users']; +``` Кроме того, вы можете определить свойство `$exceptTables` в вашем тестовом классе, чтобы указать, какие таблицы должны быть исключены из очистки: - /** - * Указывает, какие таблицы должны быть исключены из очистки. - * - * @var array - */ - protected $exceptTables = ['users']; +```php +/** + * Указывает, какие таблицы должны быть исключены из очистки. + * + * @var array + */ +protected $exceptTables = ['users']; +``` Чтобы указать, в каких соединениях базы данных должны быть очищены таблицы, вы можете определить свойство `$connectionsToTruncate` в вашем тестовом классе: - /** - * Указывает, в каких соединениях должны быть очищены таблицы. - * - * @var array - */ - protected $connectionsToTruncate = ['mysql']; +```php +/** + * Указывает, в каких соединениях должны быть очищены таблицы. + * + * @var array + */ +protected $connectionsToTruncate = ['mysql']; +``` Если вы хотите выполнить код до или после выполнения очистки базы данных, вы можете определить методы `beforeTruncatingDatabase` или `afterTruncatingDatabase` в вашем тестовом классе: - /** - * Выполните любые действия, которые должны быть выполнены перед началом очистки базы данных. - */ - protected function beforeTruncatingDatabase(): void - { - // - } +```php +/** + * Выполните любые действия, которые должны быть выполнены перед началом очистки базы данных. + */ +protected function beforeTruncatingDatabase(): void +{ + // +} - /** - * Выполните любые действия, которые должны быть выполнены после завершения очистки базы данных. - */ - protected function afterTruncatingDatabase(): void - { - // - } +/** + * Выполните любые действия, которые должны быть выполнены после завершения очистки базы данных. + */ +protected function afterTruncatingDatabase(): void +{ + // +} +``` ### Запуск тестов @@ -249,29 +261,33 @@ php artisan dusk --group=foo По умолчанию Dusk автоматически пытается запустить ChromeDriver. Если это не работает для вашей конкретной системы, вы можете вручную запустить ChromeDriver перед запуском команды `dusk`. Если вы решили запустить ChromeDriver вручную, то вы должны закомментировать следующую строку вашего файла `tests/DuskTestCase.php`: - /** - * Подготовить Dusk для выполнения теста. - * - * @beforeClass - */ - public static function prepare(): void - { - // static::startChromeDriver(); - } +```php +/** + * Подготовить Dusk для выполнения теста. + * + * @beforeClass + */ +public static function prepare(): void +{ + // static::startChromeDriver(); +} +``` Кроме того, если вы запускаете ChromeDriver на порту, отличном от `9515`, то вам следует изменить метод `driver` того же класса, чтобы указать необходимый порт: - use Facebook\WebDriver\Remote\RemoteWebDriver; +```php +use Facebook\WebDriver\Remote\RemoteWebDriver; - /** - * Создать экземпляр RemoteWebDriver. - */ - protected function driver(): RemoteWebDriver - { - return RemoteWebDriver::create( - 'http://localhost:9515', DesiredCapabilities::chrome() - ); - } +/** + * Создать экземпляр RemoteWebDriver. + */ +protected function driver(): RemoteWebDriver +{ + return RemoteWebDriver::create( + 'http://localhost:9515', DesiredCapabilities::chrome() + ); +} +``` ### Обработка файла переменных окружения @@ -304,10 +320,10 @@ test('basic example', function () { $this->browse(function (Browser $browser) use ($user) { $browser->visit('/login') - ->type('email', $user->email) - ->type('password', 'password') - ->press('Login') - ->assertPathIs('/home'); + ->type('email', $user->email) + ->type('password', 'password') + ->press('Login') + ->assertPathIs('/home'); }); }); ``` @@ -337,10 +353,10 @@ class ExampleTest extends DuskTestCase $this->browse(function (Browser $browser) use ($user) { $browser->visit('/login') - ->type('email', $user->email) - ->type('password', 'password') - ->press('Login') - ->assertPathIs('/home'); + ->type('email', $user->email) + ->type('password', 'password') + ->press('Login') + ->assertPathIs('/home'); }); } } @@ -353,112 +369,138 @@ class ExampleTest extends DuskTestCase Иногда для правильного проведения теста может потребоваться несколько браузеров. Например, для тестирования экрана чата, взаимодействующего с веб-сокетами, может потребоваться несколько браузеров. Чтобы создать несколько браузеров, просто добавьте больше аргументов браузера к сигнатуре замыкания, передаваемому методу `browse`: - $this->browse(function (Browser $first, Browser $second) { - $first->loginAs(User::find(1)) - ->visit('/home') - ->waitForText('Message'); +```php +$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'); + $second->loginAs(User::find(2)) + ->visit('/home') + ->waitForText('Message') + ->type('message', 'Hey Taylor') + ->press('Send'); - $first->waitForText('Hey Taylor') - ->assertSee('Jeffrey Way'); - }); + $first->waitForText('Hey Taylor') + ->assertSee('Jeffrey Way'); +}); +``` ### Навигация Метод `visit` используется для перехода к конкретному URI вашего приложения: - $browser->visit('/login'); +```php +$browser->visit('/login'); +``` Вы можете использовать метод `visitRoute` для перехода к [именованному маршруту](/docs/{{version}}/routing#named-routes): - $browser->visitRoute($routeName, $parameters); +```php +$browser->visitRoute($routeName, $parameters); +``` Вы можете перемещаться «назад» и «вперед», используя методы `back` и `forward`: - $browser->back(); +```php +$browser->back(); - $browser->forward(); +$browser->forward(); +``` Вы можете использовать метод `refresh` для обновления страницы: - $browser->refresh(); +```php +$browser->refresh(); +``` ### Изменение размера окна браузера Вы можете использовать метод `resize` для настройки размера окна браузера: - $browser->resize(1920, 1080); +```php +$browser->resize(1920, 1080); +``` Метод `maximize` используется для максимизации окна браузера: - $browser->maximize(); +```php +$browser->maximize(); +``` Метод `fitContent` изменит размер окна браузера в соответствии с размером его содержимого: - $browser->fitContent(); +```php +$browser->fitContent(); +``` Если тест не пройден, то Dusk автоматически изменяет размер окна браузера в соответствии с его содержимым, прежде чем сделать снимок экрана. Вы можете отключить эту функцию, вызвав в своем тесте метод `disableFitOnFailure`: - $browser->disableFitOnFailure(); +```php +$browser->disableFitOnFailure(); +``` Вы можете использовать метод `move`, чтобы переместить окно браузера в другое место на экране: - $browser->move($x = 100, $y = 100); +```php +$browser->move($x = 100, $y = 100); +``` ### Макрокоманды браузера Если вы хотите определить собственный метод браузера, который вы можете повторно использовать в различных ваших тестах, вы можете использовать метод `macro` класса `Browser`. Как правило, этот метод следует вызывать из метода `boot` [поставщика служб](/docs/{{version}}/providers): - script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);"); - - return $this; - }); - } + 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'); - }); +```php +$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; +```php +use App\Models\User; +use Laravel\Dusk\Browser; - $this->browse(function (Browser $browser) { - $browser->loginAs(User::find(1)) - ->visit('/home'); - }); +$this->browse(function (Browser $browser) { + $browser->loginAs(User::find(1)) + ->visit('/home'); +}); +``` > [!WARNING] > После использования метода `loginAs` сессия пользователя будет поддерживаться для всех тестов, находящихся в файле. @@ -468,62 +510,80 @@ class ExampleTest extends DuskTestCase Вы можете использовать метод `cookie` для получения или установления зашифрованного значения cookie. По умолчанию все файлы cookie, созданные Laravel, зашифрованы: - $browser->cookie('name'); +```php +$browser->cookie('name'); - $browser->cookie('name', 'Taylor'); +$browser->cookie('name', 'Taylor'); +``` Вы можете использовать метод `plainCookie` для получения или установления незашифрованного значения cookie: - $browser->plainCookie('name'); +```php +$browser->plainCookie('name'); - $browser->plainCookie('name', 'Taylor'); +$browser->plainCookie('name', 'Taylor'); +``` Вы можете использовать метод `deleteCookie` для удаления конкретного файла cookie: - $browser->deleteCookie('name'); +```php +$browser->deleteCookie('name'); +``` ### Выполнение JavaScript Вы можете использовать метод `script` для выполнения произвольных выражений JavaScript в браузере: - $browser->script('document.documentElement.scrollTop = 0'); +```php +$browser->script('document.documentElement.scrollTop = 0'); - $browser->script([ - 'document.body.scrollTop = 0', - 'document.documentElement.scrollTop = 0', - ]); +$browser->script([ + 'document.body.scrollTop = 0', + 'document.documentElement.scrollTop = 0', +]); - $output = $browser->script('return window.location.pathname'); +$output = $browser->script('return window.location.pathname'); +``` ### Получение снимка экрана Вы можете использовать метод `screenshot`, чтобы сделать снимок экрана и сохранить его с заданным именем файла. Все скриншоты будут храниться в каталоге `tests/Browser/screenshots`: - $browser->screenshot('filename'); +```php +$browser->screenshot('filename'); +``` Метод `responsiveScreenshots` может быть использован для создания серии скриншотов на различных контрольных точках: - $browser->responsiveScreenshots('filename'); +```php +$browser->responsiveScreenshots('filename'); +``` Метод `screenshotElement` можно использовать для создания снимка экрана определенного элемента на странице: - $browser->screenshotElement('#selector', 'filename'); +```php +$browser->screenshotElement('#selector', 'filename'); +``` ### Сохранение вывода консоли на диск Вы можете использовать метод `storeConsoleLog` для записи вывода консоли текущего браузера на диск с заданным именем файла. Вывод консоли будет храниться в каталоге `tests/Browser/console`: - $browser->storeConsoleLog('filename'); +```php +$browser->storeConsoleLog('filename'); +``` ### Сохранение исходного кода страницы на диск Вы можете использовать метод `storeSource` для записи исходного кода текущей страницы на диск с заданным именем файла. Исходный код страницы будет храниться в каталоге `tests/Browser/source`: - $browser->storeSource('filename'); +```php +$browser->storeSource('filename'); +``` ## Взаимодействие с элементами @@ -533,29 +593,39 @@ class ExampleTest extends DuskTestCase Выбор универсальных селекторов CSS для взаимодействия с элементами – одна из самых сложных частей написания тестов Dusk. Со временем изменения клиентского интерфейса могут привести к тому, что селекторы CSS, подобные приведенным ниже, нарушат ваши тесты: - // HTML-разметка... +```html +// HTML-разметка... - + +``` - // Выполнение теста... +```php +// Выполнение теста... - $browser->click('.login-page .container div > button'); +$browser->click('.login-page .container div > button'); +``` Селекторы Dusk позволяют сосредоточиться на написании эффективных тестов, а не на запоминании селекторов CSS. Чтобы определить селектор, добавьте к вашему элементу HTML-атрибут `dusk`. Затем, при взаимодействии с браузером Dusk, добавьте к селектору префикс `@`, чтобы управлять закрепленным элементом в вашем тесте: - // HTML-разметка... +```html +// HTML-разметка... - + +``` - // Выполнение теста... +```php +// Выполнение теста... - $browser->click('@login-button'); +$browser->click('@login-button'); +``` Если вам нужно, вы можете настроить HTML-атрибут, который использует селектор Dusk, с помощью метода `selectorHtmlAttribute`. Обычно этот метод следует вызывать из метода `boot` вашего `AppServiceProvider` приложения: - use Laravel\Dusk\Dusk; +```php +use Laravel\Dusk\Dusk; - Dusk::selectorHtmlAttribute('data-dusk'); +Dusk::selectorHtmlAttribute('data-dusk'); +``` ### Текст, значения и атрибуты @@ -565,29 +635,37 @@ class ExampleTest extends DuskTestCase Dusk содержит несколько методов для взаимодействия с текущим значением, отображаемым текстом и атрибутами элементов на странице. Например, чтобы получить «значение» элемента, которое соответствует указанному CSS или Dusk селектору, используйте метод `value`: - // Получить значение... - $value = $browser->value('selector'); +```php +// Получить значение... +$value = $browser->value('selector'); - // Установить значение... - $browser->value('selector', 'value'); +// Установить значение... +$browser->value('selector', 'value'); +``` Вы можете использовать метод `inputValue` для получения «значения» элемента ввода, имеющего указанное имя поля: - $value = $browser->inputValue('field'); +```php +$value = $browser->inputValue('field'); +``` #### Получение текста Метод `text` используется для получения отображаемого текста элемента, соответствующий указанному селектору: - $text = $browser->text('selector'); +```php +$text = $browser->text('selector'); +``` #### Получение атрибутов Наконец, метод `attribute` может быть использован для получения значения атрибута элемента, соответствующий указанному селектору: - $attribute = $browser->attribute('selector', 'value'); +```php +$attribute = $browser->attribute('selector', 'value'); +``` ### Взаимодействие с формами @@ -597,69 +675,93 @@ Dusk содержит несколько методов для взаимоде Dusk содержит множество методов для взаимодействия с формами и элементами ввода. Во-первых, давайте взглянем на пример ввода текста в поле: - $browser->type('email', 'taylor@laravel.com'); +```php +$browser->type('email', 'taylor@laravel.com'); +``` Обратите внимание, что, нам не требуется передавать селектор CSS в метод `type`, хотя метод принимает его при необходимости. Если селектор CSS не указан, то Dusk будет искать поле `input` или `textarea` с указанным атрибутом `name`. Чтобы добавить текст в поле, не очищая его содержимое, вы можете использовать метод `append`: - $browser->type('tags', 'foo') - ->append('tags', ', bar, baz'); +```php +$browser->type('tags', 'foo') + ->append('tags', ', bar, baz'); +``` Вы можете очистить значение поля с помощью метода `clear`: - $browser->clear('email'); +```php +$browser->clear('email'); +``` Вы можете указать Dusk печатать медленно, используя метод `typeSlowly`. По умолчанию Dusk будет делать паузу на `100` миллисекунд между нажатиями клавиш. Чтобы изменить время между нажатиями клавиш, вы можете передать соответствующее количество миллисекунд в качестве третьего аргумента метода: - $browser->typeSlowly('mobile', '+1 (202) 555-5555'); +```php +$browser->typeSlowly('mobile', '+1 (202) 555-5555'); - $browser->typeSlowly('mobile', '+1 (202) 555-5555', 300); +$browser->typeSlowly('mobile', '+1 (202) 555-5555', 300); +``` Вы можете использовать метод `appendSlowly` для медленного добавления текста: - $browser->type('tags', 'foo') - ->appendSlowly('tags', ', bar, baz'); +```php +$browser->type('tags', 'foo') + ->appendSlowly('tags', ', bar, baz'); +``` #### Выпадающие списки Чтобы выбрать значение, доступное для выпадающего списка, вы можете использовать метод `select`. Как и метод `type`, метод `select` не требует полного селектора CSS. При передаче значения методу `select` вы должны передать значение параметра `value` вместо отображаемого текста: - $browser->select('size', 'Large'); +```php +$browser->select('size', 'Large'); +``` Вы можете выбрать случайный вариант, опустив второй аргумент: - $browser->select('size'); +```php +$browser->select('size'); +``` Предоставляя массив в качестве второго аргумента метода `select`, вы можете указать методу на выбор нескольких параметров: - $browser->select('categories', ['Art', 'Music']); +```php +$browser->select('categories', ['Art', 'Music']); +``` #### Флажки Чтобы «отметить» флажок, вы можете использовать метод `check`. Как и многие другие методы, связанные с вводом, полный селектор CSS не требуется. Если совпадение селектора CSS не найдено, то Dusk будет искать флажок с соответствующим атрибутом `name`: - $browser->check('terms'); +```php +$browser->check('terms'); +``` Метод `uncheck` используется для «снятия галочки» с флажка: - $browser->uncheck('terms'); +```php +$browser->uncheck('terms'); +``` #### Радиокнопки Чтобы «выбрать» вариант из радиокнопок, вы можете использовать метод `radio`. Как и многие другие методы, связанные с вводом, полный селектор CSS не требуется. Если совпадение селектора CSS не найдено, то Dusk будет искать радиокнопку с соответствующими атрибутами `name` и `value`: - $browser->radio('size', 'large'); +```php +$browser->radio('size', 'large'); +``` ### Прикрепление файлов Метод `attach` используется для прикрепления файла к элементу выбора файлов. Как и многие другие методы, связанные с вводом, полный селектор CSS не требуется. Если совпадение селектора CSS не найдено, то Dusk будет искать элемент выбора файлов с соответствующим атрибутом `name`: - $browser->attach('photo', __DIR__.'/photos/mountains.png'); +```php +$browser->attach('photo', __DIR__.'/photos/mountains.png'); +``` > [!WARNING] > Функционал прикрепления требует, чтобы на вашем сервере было установлено и включено расширение `Zip` PHP. @@ -669,28 +771,36 @@ Dusk содержит множество методов для взаимоде Метод `press` используется для нажатия кнопки на странице. Аргумент, передаваемым методу `press`, может быть либо отображаемый текст кнопки, либо CSS / Dusk селектор: - $browser->press('Login'); +```php +$browser->press('Login'); +``` При отправке форм многие приложения отключают кнопку отправки формы после ее нажатия, а затем снова включают кнопку, когда HTTP-запрос отправки формы завершен. Чтобы нажать кнопку и дождаться ее повторного включения, вы можете использовать метод `pressAndWaitFor`: - // Нажимаем кнопку и ждем ее активности не более 5 секунд... - $browser->pressAndWaitFor('Save'); +```php +// Нажимаем кнопку и ждем ее активности не более 5 секунд... +$browser->pressAndWaitFor('Save'); - // Нажимаем кнопку и ждем ее активности не более 1 секунды... - $browser->pressAndWaitFor('Save', 1); +// Нажимаем кнопку и ждем ее активности не более 1 секунды... +$browser->pressAndWaitFor('Save', 1); +``` ### Клик по ссылкам Чтобы щелкнуть ссылку, вы можете использовать метод `clickLink` экземпляра браузера. Метод `clickLink` щелкнет ссылку с указанным видимым текстом: - $browser->clickLink($linkText); +```php +$browser->clickLink($linkText); +``` Вы можете использовать метод `seeLink`, чтобы определить, видна ли на странице ссылка с указанным видимым текстом: - if ($browser->seeLink($linkText)) { - // ... - } +```php +if ($browser->seeLink($linkText)) { + // ... +} +``` > [!WARNING] > Эти методы взаимодействуют с библиотеками jQuery. Если jQuery недоступен на странице, то Dusk автоматически вставит его на страницу, чтобы он был доступен во время теста. @@ -700,11 +810,15 @@ Dusk содержит множество методов для взаимоде Метод `keys` позволяет передавать более сложные последовательности ввода для указанного элемента, чем это обычно доступно при использовании метода `type`. Например, при вводе значений можно поручить Dusk удерживать клавиши-модификаторы. В этом примере клавиша shift будет удерживаться, пока строка «taylor» вводится в элемент заданного селектора. После ввода «taylor», строка «swift» будет вводиться без модификаторов: - $browser->keys('selector', ['{shift}', 'taylor'], 'swift'); +```php +$browser->keys('selector', ['{shift}', 'taylor'], 'swift'); +``` Другой значимый пример использования метода `keys` – это отправка комбинации «горячих клавиш» основному селектору CSS вашего приложения: - $browser->keys('.app', ['{command}', 'j']); +```php +$browser->keys('.app', ['{command}', 'j']); +``` > [!NOTE] > Все модификаторы клавиш, такие как `{command}` заключены в символы `{}` и соответствуют константам, определенным в классе `Facebook\WebDriver\WebDriverKeys`, который можно [найти на GitHub](https://github.com/php-webdriver/php-webdriver/blob/master/lib/WebDriverKeys.php). @@ -714,60 +828,66 @@ Dusk содержит множество методов для взаимоде Dusk также предоставляет метод `withKeyboard`, который позволяет гибко выполнять сложные взаимодействия с клавиатурой через класс `Laravel\Dusk\Keyboard`. Класс `Keyboard` предоставляет методы `press`, `release`, `type` и `pause`: - use Laravel\Dusk\Keyboard; +```php +use Laravel\Dusk\Keyboard; - $browser->withKeyboard(function (Keyboard $keyboard) { - $keyboard->press('c') - ->pause(1000) - ->release('c') - ->type(['c', 'e', 'o']); - }); +$browser->withKeyboard(function (Keyboard $keyboard) { + $keyboard->press('c') + ->pause(1000) + ->release('c') + ->type(['c', 'e', 'o']); +}); +``` #### Макросы Клавиатуры Если вы хотите определить пользовательские взаимодействия с клавиатурой, которые вы можете легко повторно использовать в вашем наборе тестов, вы можете использовать метод `macro`, предоставляемый классом `Keyboard`. Обычно этот метод следует вызывать из метода `boot` [поставщика услуг](/docs/{{version}}/providers): - 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; - }); - } + 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()); +```php +$browser->click('@textarea') + ->withKeyboard(fn (Keyboard $keyboard) => $keyboard->copy()) + ->click('@another-textarea') + ->withKeyboard(fn (Keyboard $keyboard) => $keyboard->paste()); +``` ### Использование мыши @@ -777,127 +897,165 @@ Dusk также предоставляет метод `withKeyboard`, котор Метод `click` используется для щелчка по элементу с указанным CSS / Dusk селектором: - $browser->click('.selector'); +```php +$browser->click('.selector'); +``` Метод `clickAtXPath` используется для щелчка по элементу с указанным XPath-выражением: - $browser->clickAtXPath('//div[@class = "selector"]'); +```php +$browser->clickAtXPath('//div[@class = "selector"]'); +``` Метод `clickAtPoint` используется для щелчка по самому верхнему элементу в точке с координатой, указанной относительно видимой области браузера: - $browser->clickAtPoint($x = 0, $y = 0); +```php +$browser->clickAtPoint($x = 0, $y = 0); +``` Метод `doubleClick` используется для имитации двойного щелчка мыши: - $browser->doubleClick(); +```php +$browser->doubleClick(); - $browser->doubleClick('.selector'); +$browser->doubleClick('.selector'); +``` Метод `rightClick` используется для имитации щелчка правой кнопкой мыши: - $browser->rightClick(); +```php +$browser->rightClick(); - $browser->rightClick('.selector'); +$browser->rightClick('.selector'); +``` Метод `clickAndHold` используется для имитации нажатия и удержания кнопки мыши. Последующий вызов метода `releaseMouse` отменяет это поведение и отпускает кнопку мыши: - $browser->clickAndHold('.selector'); +```php +$browser->clickAndHold('.selector'); - $browser->clickAndHold() - ->pause(1000) - ->releaseMouse(); +$browser->clickAndHold() + ->pause(1000) + ->releaseMouse(); +``` Метод `controlClick` может быть использован для симуляции события `ctrl+click` в браузере: - $browser->controlClick(); +```php +$browser->controlClick(); - $browser->controlClick('.selector'); +$browser->controlClick('.selector'); +``` #### Наведение мыши Метод `mouseover` используется, когда вам нужно навести указатель мыши на элемент с заданным CSS или Dusk селектором: - $browser->mouseover('.selector'); +```php +$browser->mouseover('.selector'); +``` #### Перетаскивания Метод `drag` используется для перетаскивания элемента с указанным селектором, на другой элемент: - $browser->drag('.from-selector', '.to-selector'); +```php +$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); +```php +$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); +```php +$browser->dragOffset('.selector', $x = 10, $y = 10); +``` ### Диалоговые окна JavaScript (Alert, Prompt, Confirm) Dusk содержит различные методы для взаимодействия с диалогами JavaScript. Например, вы можете использовать метод `waitForDialog`, чтобы дождаться появления диалогового окна JavaScript. Этот метод принимает необязательный аргумент, указывающий, сколько секунд ждать до появления диалогового окна: - $browser->waitForDialog($seconds = null); +```php +$browser->waitForDialog($seconds = null); +``` Метод `assertDialogOpened` используется для утверждения того, что диалоговое окно было отображено и содержит указанное сообщение: - $browser->assertDialogOpened('Dialog message'); +```php +$browser->assertDialogOpened('Dialog message'); +``` Если диалоговое окно JavaScript содержит поле ввода, то вы можете использовать метод `typeInDialog`, чтобы ввести значение: - $browser->typeInDialog('Hello World'); +```php +$browser->typeInDialog('Hello World'); +``` Чтобы закрыть открытое диалоговое окно JavaScript, нажав кнопку «ОК», вы можете вызвать метод `acceptDialog`: - $browser->acceptDialog(); +```php +$browser->acceptDialog(); +``` Чтобы закрыть открытое диалоговое окно JavaScript, нажав кнопку «Отмена», вы можете вызвать метод `dismissDialog`: - $browser->dismissDialog(); +```php +$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'); - }); +```php +$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'); - }); +```php +$browser->with('.table', function (Browser $table) { + $table->assertSee('Hello World') + ->clickLink('Delete'); +}); +``` Иногда требуется выполнить утверждения за пределами текущей области. Вы можете использовать для этого методы `elsewhere` и `elsewhereWhenAvailable`: - $browser->with('.table', function (Browser $table) { - // Текущая область `body .table`... +```php + $browser->with('.table', function (Browser $table) { + // Текущая область `body .table`... - $browser->elsewhere('.page-title', function (Browser $title) { - // Текущая область `body .page-title`... - $title->assertSee('Hello World'); - }); + $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'); - }); - }); + $browser->elsewhereWhenAvailable('.page-title', function (Browser $title) { + // Текущая область `body .page-title`... + $title->assertSee('Hello World'); + }); + }); +``` ### Ожидание доступности элементов @@ -909,204 +1067,254 @@ Dusk содержит различные методы для взаимодей Если вам нужно просто приостановить тест на определенное количество миллисекунд, используйте метод `pause`: - $browser->pause(1000); +```php +$browser->pause(1000); +``` Если вам нужно приостановить тест, только если определенное условие является `true`, используйте метод `pauseIf`: - $browser->pauseIf(App::environment('production'), 1000); +```php +$browser->pauseIf(App::environment('production'), 1000); +``` Точно так же, если вам нужно приостановить тест, если определенное условие не является `true`, вы можете использовать метод `pauseUnless`: - $browser->pauseUnless(App::environment('testing'), 1000); +```php +$browser->pauseUnless(App::environment('testing'), 1000); +``` #### Ожидание конкретных селекторов Метод `waitFor` используется для приостановки выполнения теста до тех пор, пока на странице не отобразится элемент с указанным CSS или Dusk селектором. По умолчанию это приостанавливает тест максимум на пять секунд перед выбросом исключения. При необходимости вы можете передать иной порог тайм-аута в качестве второго аргумента метода: - // Ожидание селектора не более пяти секунд... - $browser->waitFor('.selector'); +```php +// Ожидание селектора не более пяти секунд... +$browser->waitFor('.selector'); - // Ожидание селектора максимум одну секунду... - $browser->waitFor('.selector', 1); +// Ожидание селектора максимум одну секунду... +$browser->waitFor('.selector', 1); +``` Вы также можете подождать, пока элемент с указанным селектором не будет содержать необходимый текст: - // Ожидание селектора, содержащего указанный текст, не более пяти секунд... - $browser->waitForTextIn('.selector', 'Hello World'); +```php +// Ожидание селектора, содержащего указанный текст, не более пяти секунд... +$browser->waitForTextIn('.selector', 'Hello World'); - // Ожидание селектора, содержащего указанный текст, не более одной секунды... - $browser->waitForTextIn('.selector', 'Hello World', 1); +// Ожидание селектора, содержащего указанный текст, не более одной секунды... +$browser->waitForTextIn('.selector', 'Hello World', 1); +``` Вы также можете подождать, пока элемент с указанным селектором не исчезнет со страницы: - // Ожидание исчезновения селектора не более пяти секунд... - $browser->waitUntilMissing('.selector'); +```php +// Ожидание исчезновения селектора не более пяти секунд... +$browser->waitUntilMissing('.selector'); - // Ожидание исчезновения селектора не более одной секунды... - $browser->waitUntilMissing('.selector', 1); +// Ожидание исчезновения селектора не более одной секунды... +$browser->waitUntilMissing('.selector', 1); +``` Или вы можете подождать, пока элемент, соответствующий данному селектору, не будет включен или отключен: - // Ожидание не более пяти секунд, пока селектор не будет включен... - $browser->waitUntilEnabled('.selector'); +```php +// Ожидание не более пяти секунд, пока селектор не будет включен... +$browser->waitUntilEnabled('.selector'); - // Ожидание не более одной секунды, пока селектор не будет включен... - $browser->waitUntilEnabled('.selector', 1); +// Ожидание не более одной секунды, пока селектор не будет включен... +$browser->waitUntilEnabled('.selector', 1); - // Ожидание не более пяти секунд, пока селектор не будет выключен... - $browser->waitUntilDisabled('.selector'); +// Ожидание не более пяти секунд, пока селектор не будет выключен... +$browser->waitUntilDisabled('.selector'); - // Ожидание не более одной секунды, пока селектор не будет выключен... - $browser->waitUntilDisabled('.selector', 1); +// Ожидание не более одной секунды, пока селектор не будет выключен... +$browser->waitUntilDisabled('.selector', 1); +``` #### Сегментированное тестирование при доступности селекторов Иногда требуется дождаться появления элемента с указанным селектором, а затем взаимодействовать с этим элементом. Например, вы можете подождать, пока не станет доступно модальное окно, а затем нажать кнопку «ОК» в модальном окне. Для этого можно использовать метод `whenAvailable`. Все операции с элементами, выполняемые в рамках замыкания, будут привязаны к исходному селектору: - $browser->whenAvailable('.modal', function (Browser $modal) { - $modal->assertSee('Hello World') - ->press('OK'); - }); +```php +$browser->whenAvailable('.modal', function (Browser $modal) { + $modal->assertSee('Hello World') + ->press('OK'); +}); +``` #### Ожидание видимости текста Метод `waitForText` используется для ожидания видимости текста на странице: - // Ожидание видимости текста максимум пять секунд... - $browser->waitForText('Hello World'); +```php +// Ожидание видимости текста максимум пять секунд... +$browser->waitForText('Hello World'); - // Ожидание видимости текста максимум одну секунду... - $browser->waitForText('Hello World', 1); +// Ожидание видимости текста максимум одну секунду... +$browser->waitForText('Hello World', 1); +``` Вы можете использовать метод `waitUntilMissingText`, чтобы дождаться, пока отображаемый текст не будет удален со страницы: - // Ожидание удаления текста не более пяти секунд... - $browser->waitUntilMissingText('Hello World'); +```php +// Ожидание удаления текста не более пяти секунд... +$browser->waitUntilMissingText('Hello World'); - // Ожидание удаления текста не более одной секунды... - $browser->waitUntilMissingText('Hello World', 1); +// Ожидание удаления текста не более одной секунды... +$browser->waitUntilMissingText('Hello World', 1); +``` #### Ожидание доступности ссылок Метод `waitForLink` используется для ожидания появления текста указанной ссылки на странице: - // Ожидание видимости ссылки не более пяти секунд... - $browser->waitForLink('Create'); +```php +// Ожидание видимости ссылки не более пяти секунд... +$browser->waitForLink('Create'); - // Ожидание видимости ссылки не более одной секунды... - $browser->waitForLink('Create', 1); +// Ожидание видимости ссылки не более одной секунды... +$browser->waitForLink('Create', 1); +``` #### Ожидание Input-элементов Метод `waitForInput` может быть использован для ожидания, пока данное поле ввода не станет видимым на странице: - // Ожидание максимум пять секунд для поля ввода... - $browser->waitForInput($field); +```php +// Ожидание максимум пять секунд для поля ввода... +$browser->waitForInput($field); - // Ожидание максимум одну секунду для поля ввода... - $browser->waitForInput($field, 1); +// Ожидание максимум одну секунду для поля ввода... +$browser->waitForInput($field, 1); +``` #### Ожидание пути страницы При утверждении пути, например, `$browser->assertPathIs('/home')`, утверждение может завершиться ошибкой, если `window.location.pathname` обновляется асинхронно. Вы можете использовать метод `waitForLocation`, чтобы подождать, пока расположение не станет необходимым значением: - $browser->waitForLocation('/secret'); +```php +$browser->waitForLocation('/secret'); +``` Метод `waitForLocation` также может использоваться для ожидания, пока текущее местоположение окна не станет полным URL: - $browser->waitForLocation('https://example.com/path'); +```php +$browser->waitForLocation('https://example.com/path'); +``` Вы также можете дождаться расположения [именованного маршрута](/docs/{{version}}/routing#named-routes): - $browser->waitForRoute($routeName, $parameters); +```php +$browser->waitForRoute($routeName, $parameters); +``` #### Ожидание перезагрузки страницы Если вам нужно сделать утверждения после перезагрузки страницы, используйте метод `waitForReload`: - use Laravel\Dusk\Browser; +```php +use Laravel\Dusk\Browser; - $browser->waitForReload(function (Browser $browser) { - $browser->press('Submit'); - }) - ->assertSee('Success!'); +$browser->waitForReload(function (Browser $browser) { + $browser->press('Submit'); +}) +->assertSee('Success!'); +``` Поскольку необходимость дождаться перезагрузки страницы обычно возникает после нажатия кнопки, вы можете использовать метод `clickAndWaitForReload` для удобства: - $browser->clickAndWaitForReload('.selector') - ->assertSee('something'); +```php +$browser->clickAndWaitForReload('.selector') + ->assertSee('something'); +``` #### Ожидание выражений JavaScript По желанию можно приостановить выполнение теста до тех пор, пока указанное выражение JavaScript не станет истинным. Вы можете легко сделать это, используя метод `waitUntil`. При передаче выражения в этот метод вам не нужно включать в него ни ключевое слово `return`, ни конечную точку с запятой: - // Ожидание истинности выражения не более пяти секунд... - $browser->waitUntil('App.data.servers.length > 0'); +```php +// Ожидание истинности выражения не более пяти секунд... +$browser->waitUntil('App.data.servers.length > 0'); - // Ожидание истинности выражения не более одной секунды... - $browser->waitUntil('App.data.servers.length > 0', 1); +// Ожидание истинности выражения не более одной секунды... +$browser->waitUntil('App.data.servers.length > 0', 1); +``` #### Ожидание выражений Vue Методы `waitUntilVue` и `waitUntilVueIsNot` могут использоваться для ожидания, пока атрибут [компонента Vue](https://vuejs.org) не получит указанное значение: - // Ожидание соответствия атрибута компонента указанному значению... - $browser->waitUntilVue('user.name', 'Taylor', '@user'); +```php +// Ожидание соответствия атрибута компонента указанному значению... +$browser->waitUntilVue('user.name', 'Taylor', '@user'); - // Ожидание несоответствия атрибута компонента указанному значению... - $browser->waitUntilVueIsNot('user.name', null, '@user'); +// Ожидание несоответствия атрибута компонента указанному значению... +$browser->waitUntilVueIsNot('user.name', null, '@user'); +``` #### Ожидание событий JavaScript Метод `waitForEvent` можно использовать для приостановки выполнения теста до тех пор, пока не произойдет событие JavaScript: - $browser->waitForEvent('load'); +```php +$browser->waitForEvent('load'); +``` Слушатель событий прикрепляется к текущей области видимости, которая по умолчанию является элементом `body`. При использовании селектора с ограничением области видимости слушатель событий будет прикреплен к соответствующему элементу: - $browser->with('iframe', function (Browser $iframe) { - // Ожидание события загрузки iframe... - $iframe->waitForEvent('load'); - }); +```php +$browser->with('iframe', function (Browser $iframe) { + // Ожидание события загрузки iframe... + $iframe->waitForEvent('load'); +}); +``` Вы также можете предоставить селектор в качестве второго аргумента метода `waitForEvent`, чтобы прикрепить слушатель событий к определенному элементу: - $browser->waitForEvent('load', '.selector'); +```php +$browser->waitForEvent('load', '.selector'); +``` Вы также можете ожидать событий на объектах `document` и `window`: - // Ожидание, пока документ не будет прокручен... - $browser->waitForEvent('scroll', 'document'); +```php +// Ожидание, пока документ не будет прокручен... +$browser->waitForEvent('scroll', 'document'); - // Ожидание максимум пять секунд, пока окно не изменит размер... - $browser->waitForEvent('resize', 'window', 5); +// Ожидание максимум пять секунд, пока окно не изменит размер... +$browser->waitForEvent('resize', 'window', 5); +``` #### Использование замыканий при ожидании Многие из методов «ожидания» в Dusk основаны на методе `waitUsing`. Вы можете использовать этот метод напрямую, чтобы дождаться, пока переданное замыкание не вернет `true`. Метод `waitUsing` принимает максимальное количество секунд ожидания, интервал между выполнениями замыкания (паузу), само замыкание и необязательное сообщение об ошибке: - $browser->waitUsing(10, 1, function () use ($something) { - return $something->isReady(); - }, "Something wasn't ready in time."); +```php +$browser->waitUsing(10, 1, function () use ($something) { + return $something->isReady(); +}, "Something wasn't ready in time."); +``` ### Прокрутка элемента в область видимости пользователя Иногда вы не можете щелкнуть элемент, потому что он находится за пределами области просмотра браузера. Метод `scrollIntoView` будет прокручивать окно браузера до тех пор, пока элемент с указанным селектором не окажется видимым: - $browser->scrollIntoView('.selector') - ->click('.selector'); +```php +$browser->scrollIntoView('.selector') + ->click('.selector'); +``` ## Доступные утверждения @@ -1147,6 +1355,7 @@ Dusk содержит множество утверждений, которые - [assertDontSeeIn](#assert-dont-see-in) - [assertSeeAnythingIn](#assert-see-anything-in) - [assertSeeNothingIn](#assert-see-nothing-in) +- [assertCount](#assert-count) - [assertScript](#assert-script) - [assertSourceHas](#assert-source-has) - [assertSourceMissing](#assert-source-missing) @@ -1201,531 +1410,693 @@ Dusk содержит множество утверждений, которые Утверждает, что заголовок страницы соответствует переданному тексту: - $browser->assertTitle($title); +```php +$browser->assertTitle($title); +``` #### assertTitleContains Утверждает, что заголовок страницы содержит переданный текст: - $browser->assertTitleContains($title); +```php +$browser->assertTitleContains($title); +``` #### assertUrlIs Утверждает, что текущий URL (без строки запроса) соответствует переданной строке: - $browser->assertUrlIs($url); +```php +$browser->assertUrlIs($url); +``` #### assertSchemeIs Утверждает, что схема текущего URL соответствует переданной схеме: - $browser->assertSchemeIs($scheme); +```php +$browser->assertSchemeIs($scheme); +``` #### assertSchemeIsNot Утверждает, что схема текущего URL не соответствует переданной схеме: - $browser->assertSchemeIsNot($scheme); +```php +$browser->assertSchemeIsNot($scheme); +``` #### assertHostIs Утверждает, что хост текущего URL соответствует переданному хосту: - $browser->assertHostIs($host); +```php +$browser->assertHostIs($host); +``` #### assertHostIsNot Утверждает, что хост текущего URL не соответствует переданному хосту: - $browser->assertHostIsNot($host); +```php +$browser->assertHostIsNot($host); +``` #### assertPortIs Утверждает, что порт текущего URL соответствует переданному порту: - $browser->assertPortIs($port); +```php +$browser->assertPortIs($port); +``` #### assertPortIsNot Утверждает, что порт текущего URL не соответствует переданному порту: - $browser->assertPortIsNot($port); +```php +$browser->assertPortIsNot($port); +``` #### assertPathBeginsWith Утверждает, что путь текущего URL начинается с указанного пути: - $browser->assertPathBeginsWith('/home'); +```php +$browser->assertPathBeginsWith('/home'); +``` #### assertPathEndsWith Утверждает, что текущий путь URL-адреса заканчивается заданным путем: - $browser->assertPathEndsWith('/home'); +```php +$browser->assertPathEndsWith('/home'); +``` #### assertPathContains Утверждает, что текущий путь URL-адреса содержит заданный путь: - $browser->assertPathContains('/home'); +```php +$browser->assertPathContains('/home'); +``` #### assertPathIs Утверждает, что текущий путь соответствует переданному пути: - $browser->assertPathIs('/home'); +```php +$browser->assertPathIs('/home'); +``` #### assertPathIsNot Утверждает, что текущий путь не соответствует переданному пути: - $browser->assertPathIsNot('/home'); +```php +$browser->assertPathIsNot('/home'); +``` #### assertRouteIs Утверждает, что текущий URL соответствует переданному URL [именованного маршрута](/docs/{{version}}/routing#named-routes): - $browser->assertRouteIs($name, $parameters); +```php +$browser->assertRouteIs($name, $parameters); +``` #### assertQueryStringHas Утверждает, что переданный параметр строки запроса присутствует: - $browser->assertQueryStringHas($name); +```php +$browser->assertQueryStringHas($name); +``` Утверждает, что переданный параметр строки запроса присутствует и имеет указанное значение: - $browser->assertQueryStringHas($name, $value); +```php +$browser->assertQueryStringHas($name, $value); +``` #### assertQueryStringMissing Утверждает, что переданный параметр строки запроса отсутствует: - $browser->assertQueryStringMissing($name); +```php +$browser->assertQueryStringMissing($name); +``` #### assertFragmentIs Утверждает, что хеш-фрагмент текущего URL соответствует переданному фрагменту: - $browser->assertFragmentIs('anchor'); +```php +$browser->assertFragmentIs('anchor'); +``` #### assertFragmentBeginsWith Утверждает, что хеш-фрагмент текущего URL начинается с указанного фрагмента: - $browser->assertFragmentBeginsWith('anchor'); +```php +$browser->assertFragmentBeginsWith('anchor'); +``` #### assertFragmentIsNot Утверждает, что хеш-фрагмент текущего URL не соответствует переданному фрагменту: - $browser->assertFragmentIsNot('anchor'); +```php +$browser->assertFragmentIsNot('anchor'); +``` #### assertHasCookie Утверждает, что переданный зашифрованный файл cookie присутствует: - $browser->assertHasCookie($name); +```php +$browser->assertHasCookie($name); +``` #### assertHasPlainCookie Утверждает, что переданный незашифрованный файл cookie присутствует: - $browser->assertHasPlainCookie($name); +```php +$browser->assertHasPlainCookie($name); +``` #### assertCookieMissing Утверждает, что переданный зашифрованный файл cookie отсутствует: - $browser->assertCookieMissing($name); +```php +$browser->assertCookieMissing($name); +``` #### assertPlainCookieMissing Утверждает, что переданный незашифрованный файл cookie отсутствует: - $browser->assertPlainCookieMissing($name); +```php +$browser->assertPlainCookieMissing($name); +``` #### assertCookieValue Утверждает, что зашифрованный файл cookie имеет указанное значение: - $browser->assertCookieValue($name, $value); +```php +$browser->assertCookieValue($name, $value); +``` #### assertPlainCookieValue Утверждает, что незашифрованный файл cookie имеет указанное значение: - $browser->assertPlainCookieValue($name, $value); +```php +$browser->assertPlainCookieValue($name, $value); +``` #### assertSee Утверждает, что переданный текст присутствует на странице: - $browser->assertSee($text); +```php +$browser->assertSee($text); +``` #### assertDontSee Утверждает, что переданный текст отсутствует на странице: - - $browser->assertDontSee($text); +```php +$browser->assertDontSee($text); +``` #### assertSeeIn Утверждает, что переданный текст присутствует в селекторе: - $browser->assertSeeIn($selector, $text); +```php +$browser->assertSeeIn($selector, $text); +``` #### assertDontSeeIn Утверждает, что переданный текст отсутствует в селекторе: - $browser->assertDontSeeIn($selector, $text); +```php +$browser->assertDontSeeIn($selector, $text); +``` #### assertSeeAnythingIn Утверждает, что в селекторе присутствует какой-либо текст: - $browser->assertSeeAnythingIn($selector); +```php +$browser->assertSeeAnythingIn($selector); +``` #### assertSeeNothingIn Утверждает, что в селекторе отсутствует какой-либо текст: +```php $browser->assertSeeNothingIn($selector); +``` + + +#### assertCount + +Утверждает, что элементы, соответствующие данному селектору, появляются указанное количество раз: + +```php +$browser->assertCount($selector, $count); +``` #### assertScript Утверждает, что переданное выражение JavaScript возвращает указанное либо истинное значение: - $browser->assertScript('window.isLoaded') - ->assertScript('document.readyState', 'complete'); +```php +$browser->assertScript('window.isLoaded') + ->assertScript('document.readyState', 'complete'); +``` #### assertSourceHas Утверждает, что переданный исходный код присутствует на странице: - $browser->assertSourceHas($code); +```php +$browser->assertSourceHas($code); +``` #### assertSourceMissing Утверждает, что переданный исходный код отсутствует на странице: - $browser->assertSourceMissing($code); +```php +$browser->assertSourceMissing($code); +``` #### assertSeeLink Утверждает, что переданная ссылка присутствует на странице: - $browser->assertSeeLink($linkText); +```php +$browser->assertSeeLink($linkText); +``` #### assertDontSeeLink Утверждает, что переданная ссылка отсутствует на странице: - $browser->assertDontSeeLink($linkText); +```php +$browser->assertDontSeeLink($linkText); +``` #### assertInputValue Утверждает, что переданное поле ввода имеет указанное значение: - $browser->assertInputValue($field, $value); +```php +$browser->assertInputValue($field, $value); +``` #### assertInputValueIsNot Утверждает, что переданное поле ввода не имеет указанное значение: - $browser->assertInputValueIsNot($field, $value); +```php +$browser->assertInputValueIsNot($field, $value); +``` #### assertChecked Утверждает, что переданный флажок отмечен: - $browser->assertChecked($field); +```php +$browser->assertChecked($field); +``` #### assertNotChecked Утверждает, что переданный флажок не отмечен: - $browser->assertNotChecked($field); +```php +$browser->assertNotChecked($field); +``` #### assertIndeterminate Утверждение, что данный флажок (checkbox) находится в неопределенном состоянии: - $browser->assertIndeterminate($field); +```php +$browser->assertIndeterminate($field); +``` #### assertRadioSelected Утверждает, что переданная радиокнопка выбрана: - $browser->assertRadioSelected($field, $value); +```php +$browser->assertRadioSelected($field, $value); +``` #### assertRadioNotSelected Утверждает, что переданная радиокнопка не выбрана: - $browser->assertRadioNotSelected($field, $value); +```php +$browser->assertRadioNotSelected($field, $value); +``` #### assertSelected Утверждает, что в переданном выпадающем списке выбрано указанное значение: - $browser->assertSelected($field, $value); +```php +$browser->assertSelected($field, $value); +``` #### assertNotSelected Утверждает, что в переданном выпадающем списке не выбрано указанное значение: - $browser->assertNotSelected($field, $value); +```php +$browser->assertNotSelected($field, $value); +``` #### assertSelectHasOptions Утверждает, что переданный массив значений доступен для выбора: - $browser->assertSelectHasOptions($field, $values); +```php +$browser->assertSelectHasOptions($field, $values); +``` #### assertSelectMissingOptions Утверждает, что переданный массив значений недоступен для выбора: - $browser->assertSelectMissingOptions($field, $values); +```php +$browser->assertSelectMissingOptions($field, $values); +``` #### assertSelectHasOption Утверждает, что переданное значение доступно для выбора в указанном поле: - $browser->assertSelectHasOption($field, $value); +```php +$browser->assertSelectHasOption($field, $value); +``` #### assertSelectMissingOption Утверждает, что переданное значение недоступно для выбора в указанном поле: - $browser->assertSelectMissingOption($field, $value); +```php +$browser->assertSelectMissingOption($field, $value); +``` #### assertValue Утверждает, что элемент с указанным селектором, имеет переданное значение: - $browser->assertValue($selector, $value); +```php +$browser->assertValue($selector, $value); +``` #### assertValueIsNot Утверждают, что элемент, соответствующий данному селектору, не имеет заданного значения: - $browser->assertValueIsNot($selector, $value); +```php +$browser->assertValueIsNot($selector, $value); +``` #### assertAttribute Утверждает, что элемент с указанным селектором, имеет переданное значение атрибута: - $browser->assertAttribute($selector, $attribute, $value); +```php +$browser->assertAttribute($selector, $attribute, $value); +``` #### assertAttributeMissing Утверждает, что элементу с указанным селектором, не хватает переданного атрибута: - $browser->assertAttributeMissing($selector, $attribute); +```php +$browser->assertAttributeMissing($selector, $attribute); +``` #### assertAttributeContains Утверждают, что элемент, соответствующий данному селектору, содержит заданное значение в предоставленном атрибуте: - $browser->assertAttributeContains($selector, $attribute, $value); +```php +$browser->assertAttributeContains($selector, $attribute, $value); +``` #### assertAttributeDoesntContain Утверждение, что элемент, соответствующий данному селектору, не содержит заданное значение в указанном атрибуте: - $browser->assertAttributeDoesntContain($selector, $attribute, $value); +```php +$browser->assertAttributeDoesntContain($selector, $attribute, $value); +``` #### assertAriaAttribute Утверждает, что элемент с указанным селектором, имеет переданное значение `aria`-атрибута: - $browser->assertAriaAttribute($selector, $attribute, $value); +```php +$browser->assertAriaAttribute($selector, $attribute, $value); +``` Например, учитывая разметку ``, вы можете выстроить утверждение относительно атрибута `aria-label` следующим образом: - $browser->assertAriaAttribute('button', 'label', 'Add') +```php +$browser->assertAriaAttribute('button', 'label', 'Add') +``` #### assertDataAttribute Утверждает, что элемент с указанным селектором, имеет переданное значение `data`-атрибута: - $browser->assertDataAttribute($selector, $attribute, $value); +```php +$browser->assertDataAttribute($selector, $attribute, $value); +``` Например, учитывая разметку ``, вы можете выстроить утверждение относительно атрибута `data-content` следующим образом: - $browser->assertDataAttribute('#row-1', 'content', 'attendees') +```php +$browser->assertDataAttribute('#row-1', 'content', 'attendees') +``` #### assertVisible Утверждает, что элемент с указанным селектором, видим: - $browser->assertVisible($selector); +```php +$browser->assertVisible($selector); +``` #### assertPresent Утверждает, что элемент с указанным селектором, присутствует в исходном коде страницы: - $browser->assertPresent($selector); +```php +$browser->assertPresent($selector); +``` #### assertNotPresent Утверждает, что элемент с указанным селектором, отсутствует в исходном коде страницы: - $browser->assertNotPresent($selector); +```php +$browser->assertNotPresent($selector); +``` #### assertMissing Утверждает, что элемент с указанным селектором, не виден: - $browser->assertMissing($selector); +```php +$browser->assertMissing($selector); +``` #### assertInputPresent Утверждают, что присутствует "input" с заданным именем: - $browser->assertInputPresent($name); +```php +$browser->assertInputPresent($name); +``` #### assertInputMissing Утверждают, что "input" с данным именем отсутствует в источнике: - $browser->assertInputMissing($name); +```php +$browser->assertInputMissing($name); +``` #### assertDialogOpened Утверждает, что был открыт диалог JavaScript с указанным сообщением: - $browser->assertDialogOpened($message); +```php +$browser->assertDialogOpened($message); +``` #### assertEnabled Утверждает, что переданное поле доступно для использования: - $browser->assertEnabled($field); +```php +$browser->assertEnabled($field); +``` #### assertDisabled Утверждает, что переданное поле недоступно для использования: - $browser->assertDisabled($field); +```php +$browser->assertDisabled($field); +``` #### assertButtonEnabled Утверждает, что переданная кнопка доступна для использования: - $browser->assertButtonEnabled($button); +```php +$browser->assertButtonEnabled($button); +``` #### assertButtonDisabled Утверждает, что переданная кнопка недоступна для использования: - $browser->assertButtonDisabled($button); +```php +$browser->assertButtonDisabled($button); +``` #### assertFocused Утверждает, что переданное поле находится в фокусе: - $browser->assertFocused($field); +```php +$browser->assertFocused($field); +``` #### assertNotFocused Утверждает, что переданное поле не находится в фокусе: - $browser->assertNotFocused($field); +```php +$browser->assertNotFocused($field); +``` #### assertAuthenticated Утверждает, что пользователь аутентифицирован: - $browser->assertAuthenticated(); +```php +$browser->assertAuthenticated(); +``` #### assertGuest Утверждает, что пользователь не аутентифицирован: - $browser->assertGuest(); +```php +$browser->assertGuest(); +``` #### assertAuthenticatedAs Утверждает, что пользователь аутентифицирован как указанный пользователь: - $browser->assertAuthenticatedAs($user); +```php +$browser->assertAuthenticatedAs($user); +``` #### assertVue @@ -1756,7 +2127,7 @@ Dusk даже позволяет вам делать утверждения о test('vue', function () { $this->browse(function (Browser $browser) { $browser->visit('/') - ->assertVue('user.name', 'Taylor', '@profile-component'); + ->assertVue('user.name', 'Taylor', '@profile-component'); }); }); ``` @@ -1769,7 +2140,7 @@ public function test_vue(): void { $this->browse(function (Browser $browser) { $browser->visit('/') - ->assertVue('user.name', 'Taylor', '@profile-component'); + ->assertVue('user.name', 'Taylor', '@profile-component'); }); } ``` @@ -1779,21 +2150,27 @@ public function test_vue(): void Утверждает, что переданное свойство данных компонента Vue не соответствует указанному значению: - $browser->assertVueIsNot($property, $value, $componentSelector = null); +```php +$browser->assertVueIsNot($property, $value, $componentSelector = null); +``` #### assertVueContains Утверждает, что переданное свойство данных компонента Vue является массивом и содержит указанное значение: - $browser->assertVueContains($property, $value, $componentSelector = null); +```php +$browser->assertVueContains($property, $value, $componentSelector = null); +``` #### assertVueDoesntContain Утверждает, что переданное свойство данных компонента Vue является массивом и не содержит указанное значения: - $browser->assertVueDoesntContain($property, $value, $componentSelector = null); +```php +$browser->assertVueDoesntContain($property, $value, $componentSelector = null); +``` ## Тестовые страницы @@ -1805,7 +2182,9 @@ public function test_vue(): void Чтобы сгенерировать класс страницы, выполните команду `dusk:page` Artisan. Все классы страниц будут помещены в каталог `tests/Browser/Pages` вашего приложения: - php artisan dusk:page Login +```shell +php artisan dusk:page Login +``` ### Конфигурирование тестовых страниц @@ -1817,117 +2196,135 @@ public function test_vue(): void Метод `url` должен возвращать путь URL-адреса, представляющего страницу. Dusk будет использовать этот URL-адрес при переходе на страницу в браузере: - /** - * Получить URL-адрес страницы. - */ - public function url(): string - { - return '/login'; - } +```php +/** + * Получить URL-адрес страницы. + */ +public function url(): string +{ + return '/login'; +} +``` #### Метод `assert` Метод `assert` может делать любые утверждения, необходимые для подтверждения того, что браузер действительно находится на данной странице. На самом деле нет необходимости размещать что-либо в этом методе; однако вы можете сделать эти утверждения, если хотите. Эти утверждения будут запускаться автоматически при переходе на страницу: - /** - * Подтвердить, что браузер находится на странице. - */ - public function assert(Browser $browser): void - { - $browser->assertPathIs($this->url()); - } +```php +/** + * Подтвердить, что браузер находится на странице. + */ +public function assert(Browser $browser): void +{ + $browser->assertPathIs($this->url()); +} +``` ### Навигация по тестовым страницам После того как страница определена, вы можете посетить ее с помощью метода `visit`: - use Tests\Browser\Pages\Login; +```php +use Tests\Browser\Pages\Login; - $browser->visit(new Login); +$browser->visit(new Login); +``` Иногда, уже находясь на какой-либо странице, вам необходимо «загрузить» селекторы и методы страницы в текущий контекст теста. Это обычное явление, когда вы нажимаете кнопку и перенаправляетесь на указанную страницу без явного перехода к ней. В этой ситуации вы можете использовать метод `on` для загрузки страницы: - use Tests\Browser\Pages\CreatePlaylist; +```php +use Tests\Browser\Pages\CreatePlaylist; - $browser->visit('/dashboard') - ->clickLink('Create Playlist') - ->on(new CreatePlaylist) - ->assertSee('@create'); +$browser->visit('/dashboard') + ->clickLink('Create Playlist') + ->on(new CreatePlaylist) + ->assertSee('@create'); +``` ### Псевдонимы селекторов Метод `elements` внутри классов страниц позволяет вам определять быстрые, легко запоминающиеся псевдонимы для любого селектора CSS на вашей странице. Например, давайте определим псевдоним для поля ввода «электронная почта» на странице входа в приложение: - /** - * Получить псевдонимы элементов страницы. - * - * @return array - */ - public function elements(): array - { - return [ - '@email' => 'input[name=email]', - ]; - } +```php +/** + * Получить псевдонимы элементов страницы. + * + * @return array + */ +public function elements(): array +{ + return [ + '@email' => 'input[name=email]', + ]; +} +``` После того как псевдоним был определен, вы можете использовать сокращенный селектор в любом месте, где вы обычно используете полный селектор CSS: - $browser->type('@email', 'taylor@laravel.com'); +```php +$browser->type('@email', 'taylor@laravel.com'); +``` #### Глобальные псевдонимы селекторов После установки Dusk базовый класс `Page` будет помещен в ваш каталог `tests/Browser/Pages`. Этот класс содержит метод `siteElements`, используемый для определения глобальных псевдонимов селекторов, которые должны быть доступны на каждой странице вашего приложения: - /** - * Получить глобальные псевдонимы элементов сайта. - * - * @return array - */ - public static function siteElements(): array - { - return [ - '@element' => '#selector', - ]; - } +```php +/** + * Получить глобальные псевдонимы элементов сайта. + * + * @return array + */ +public static function siteElements(): array +{ + return [ + '@element' => '#selector', + ]; +} +``` ### Методы тестовых страниц В дополнение к методам по умолчанию, определенным на тестовых страницах, вы можете определить дополнительные методы, которые могут использоваться в ваших тестах. Например, представим, что мы создаем приложение для управления музыкой. Обычным действием для одной страницы приложения может быть создание списка воспроизведения. Вместо того чтобы переписывать логику создания списка воспроизведения в каждом тесте, вы можете определить пользовательский метод `createPlaylist` в классе страницы: - type('name', $name) - ->check('share') - ->press('Create Playlist'); - } + $browser->type('name', $name) + ->check('share') + ->press('Create Playlist'); } +} +``` Как только метод определен, вы можете использовать его в любом тесте, использующем данную страницу. Экземпляр браузера будет автоматически внедрен в качестве первого аргумента пользовательским методам страницы: - use Tests\Browser\Pages\Dashboard; +```php +use Tests\Browser\Pages\Dashboard; - $browser->visit(new Dashboard) - ->createPlaylist('My Playlist') - ->assertSee('My Playlist'); +$browser->visit(new Dashboard) + ->createPlaylist('My Playlist') + ->assertSee('My Playlist'); +``` ## Компоненты для тестов @@ -1939,67 +2336,71 @@ public function test_vue(): void Чтобы сгенерировать компонент, выполните команду `dusk:component` Artisan. Новые компоненты будут помещены в каталог `tests/Browser/Components`: - php artisan dusk:component DatePicker +```shell +php artisan dusk:component DatePicker +``` Компонент «выбора даты» является примером компонента, который может присутствовать в вашем приложении на различных страницах. Может оказаться обременительным вручную написать логику автоматизации браузера для выбора даты в десятках тестов. Вместо этого мы можем определить компонент Dusk для представления элемента выбора даты, что позволит нам инкапсулировать эту логику внутри компонента: - assertVisible($this->selector()); - } + /** + * Подтвердить, что страница браузера содержит компонент. + */ + public function assert(Browser $browser): void + { + $browser->assertVisible($this->selector()); + } - /** - * Получить псевдонимы элементов компонента. - * - * @return array - */ - 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', - ]; - } + /** + * Получить псевдонимы элементов компонента. + * + * @return array + */ + 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); - }); - } + /** + * Выбрать дату. + */ + 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); + }); } +} +``` ### Использование компонентов @@ -2018,10 +2419,10 @@ 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'); + ->within(new DatePicker, function (Browser $browser) { + $browser->selectDate(2019, 1, 30); + }) + ->assertSee('January'); }); }); ``` @@ -2045,15 +2446,25 @@ class ExampleTest extends DuskTestCase { $this->browse(function (Browser $browser) { $browser->visit('/') - ->within(new DatePicker, function (Browser $browser) { - $browser->selectDate(2019, 1, 30); - }) - ->assertSee('January'); + ->within(new DatePicker, function (Browser $browser) { + $browser->selectDate(2019, 1, 30); + }) + ->assertSee('January'); }); } } ``` +Метод `component` может использоваться для получения экземпляра браузера, ограниченного указанным компонентом: + +```php +$datePicker = $browser->component(new DatePickerComponent); + +$datePicker->selectDate(2019, 1, 30); + +$datePicker->assertSee('January'); +``` + ## Непрерывная интеграция @@ -2065,20 +2476,22 @@ class ExampleTest extends DuskTestCase Чтобы запустить тесты Dusk на [Heroku CI](https://www.heroku.com/continuous-integration), добавьте следующий пакет сборки и скрипты Google Chrome в свой файл `app.json` Heroku: - { - "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" - } - } +```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