Skip to content

Laravel Dusk

소개

Laravel Dusk는 표현력이 풍부하고 사용하기 쉬운 브라우저 자동화 및 테스트 API를 제공합니다. 기본적으로 Dusk는 로컬 컴퓨터에 JDK 또는 Selenium을 설치할 필요가 없습니다. 대신 Dusk는 독립형 ChromeDriver 설치를 사용합니다. 그러나 원하는 다른 Selenium 호환 드라이버를 자유롭게 활용할 수 있습니다.

설치

시작하려면 Google Chrome을 설치하고 프로젝트에 laravel/dusk Composer 종속성을 추가해야 합니다.

composer require laravel/dusk --dev
exclamation

Dusk의 서비스 제공자를 수동으로 등록하는 경우, 프로덕션 환경에서는 절대로 등록해서는 안 됩니다. 그렇게 하면 임의의 사용자가 애플리케이션으로 인증할 수 있게 될 수 있습니다.

Dusk 패키지를 설치한 후 dusk:install Artisan 명령어를 실행합니다. dusk:install 명령어는 tests/Browser 디렉토리, 예제 Dusk 테스트를 생성하고 운영 체제에 맞는 Chrome Driver 바이너리를 설치합니다:

php artisan dusk:install

다음으로, 애플리케이션의 .env 파일에서 APP_URL 환경 변수를 설정합니다. 이 값은 브라우저에서 애플리케이션에 접속하는 데 사용하는 URL과 일치해야 합니다.

lightbulb

Laravel Sail을 사용하여 로컬 개발 환경을 관리하는 경우, Dusk 테스트 구성 및 실행에 대한 Sail 설명서도 참조하십시오.

ChromeDriver 설치 관리

dusk:install 명령어를 통해 Laravel Dusk에서 설치하는 것과 다른 버전의 ChromeDriver를 설치하려면 dusk:chrome-driver 명령어를 사용할 수 있습니다:

# OS에 맞는 최신 버전의 ChromeDriver 설치...
php artisan dusk:chrome-driver
# OS에 맞는 특정 버전의 ChromeDriver 설치...
php artisan dusk:chrome-driver 86
# 지원되는 모든 OS에 맞는 특정 버전의 ChromeDriver 설치...
php artisan dusk:chrome-driver --all
# OS에 맞는 Chrome / Chromium의 감지된 버전과 일치하는 ChromeDriver 버전 설치...
php artisan dusk:chrome-driver --detect
exclamation

Dusk를 사용하려면 chromedriver 바이너리가 실행 가능해야 합니다. Dusk를 실행하는 데 문제가 있는 경우, 다음 명령을 사용하여 바이너리가 실행 가능한지 확인해야 합니다. chmod -R 0755 vendor/laravel/dusk/bin/.

다른 브라우저 사용하기

기본적으로 Dusk는 Google Chrome과 독립형 ChromeDriver 설치를 사용하여 브라우저 테스트를 실행합니다. 그러나 자체 Selenium 서버를 시작하고 원하는 브라우저에서 테스트를 실행할 수 있습니다.

시작하려면 애플리케이션의 기본 Dusk 테스트 케이스인 tests/DuskTestCase.php 파일을 엽니다. 이 파일 내에서 startChromeDriver 메서드 호출을 제거할 수 있습니다. 이렇게 하면 Dusk가 ChromeDriver를 자동으로 시작하지 않습니다.

/**
* Dusk 테스트 실행 준비.
*
* @beforeClass
*/
public static function prepare(): void
{
// static::startChromeDriver();
}

다음으로, driver 메서드를 수정하여 원하는 URL 및 포트에 연결할 수 있습니다. 또한 WebDriver에 전달해야 하는 "desired capabilities"를 수정할 수 있습니다.

use Facebook\WebDriver\Remote\RemoteWebDriver;
/**
* RemoteWebDriver 인스턴스 생성.
*/
protected function driver(): RemoteWebDriver
{
return RemoteWebDriver::create(
'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()
);
}

시작하기

테스트 생성

Dusk 테스트를 생성하려면 dusk:make Artisan 명령을 사용하십시오. 생성된 테스트는 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;
//
}
exclamation

Dusk 테스트를 실행할 때는 SQLite 인메모리 데이터베이스를 사용할 수 없습니다. 브라우저가 자체 프로세스 내에서 실행되므로 다른 프로세스의 인메모리 데이터베이스에 액세스할 수 없습니다.

데이터베이스 자르기 사용

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 속성을 정의할 수 있습니다.

lightbulb

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
{
//
}

테스트 실행

브라우저 테스트를 실행하려면 dusk Artisan 명령을 실행합니다.

php artisan dusk

마지막으로 dusk 명령을 실행했을 때 테스트 실패가 있었던 경우, dusk:fails 명령을 사용하여 실패한 테스트를 먼저 재실행하여 시간을 절약할 수 있습니다.

php artisan dusk:fails

dusk 명령어는 일반적으로 Pest / PHPUnit 테스트 러너에서 허용하는 모든 인수를 허용합니다. 예를 들어, 특정 그룹에 대한 테스트만 실행하도록 할 수 있습니다:

php artisan dusk --group=foo
lightbulb

로컬 개발 환경을 관리하기 위해 Laravel Sail을 사용 중인 경우, Dusk 테스트 구성 및 실행에 대한 Sail 문서를 참조하십시오.

ChromeDriver 수동 시작

기본적으로 Dusk는 자동으로 ChromeDriver를 시작하려고 시도합니다. 특정 시스템에서 작동하지 않는 경우, dusk 명령을 실행하기 전에 ChromeDriver를 수동으로 시작할 수 있습니다. ChromeDriver를 수동으로 시작하려는 경우, tests/DuskTestCase.php 파일에서 다음 줄을 주석 처리해야 합니다:

/**
* Dusk 테스트 실행을 준비합니다.
*
* @beforeClass
*/
public static function prepare(): void
{
// static::startChromeDriver();
}

또한, 9515 이외의 포트에서 ChromeDriver를 시작하는 경우, 동일한 클래스의 driver 메서드를 수정하여 올바른 포트를 반영해야 합니다:

use Facebook\WebDriver\Remote\RemoteWebDriver;
/**
* RemoteWebDriver 인스턴스를 생성합니다.
*/
protected function driver(): RemoteWebDriver
{
return RemoteWebDriver::create(
'http://localhost:9515', DesiredCapabilities::chrome()
);
}

환경 처리

테스트를 실행할 때 Dusk가 자체 환경 파일을 사용하도록 강제하려면 프로젝트 루트에 .env.dusk.{environment} 파일을 생성하십시오. 예를 들어, local 환경에서 dusk 명령을 시작하는 경우 .env.dusk.local 파일을 생성해야 합니다.

테스트를 실행할 때 Dusk는 .env 파일을 백업하고 Dusk 환경 파일 이름을 .env로 바꿉니다. 테스트가 완료되면 .env 파일이 복원됩니다.

브라우저 기본 사항

브라우저 생성

시작하기 위해 애플리케이션에 로그인할 수 있는지 확인하는 테스트를 작성해 보겠습니다. 테스트를 생성한 후에는 로그인 페이지로 이동하고, 자격 증명을 입력하고, "로그인" 버튼을 클릭하도록 수정할 수 있습니다. 브라우저 인스턴스를 생성하려면 Dusk 테스트 내에서 browse 메서드를 호출할 수 있습니다.

<?php
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
uses(DatabaseMigrations::class);
test('기본 예제', function () {
$user = User::factory()->create([
'email' => '[email protected]',
]);
$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' => '[email protected]',
]);
$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);

backforward 메서드를 사용하여 "뒤로" 및 "앞으로" 이동할 수 있습니다.

$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);

브라우저 매크로

다양한 테스트에서 재사용할 수 있는 사용자 정의 브라우저 메서드를 정의하려면 Browser 클래스에서 macro 메서드를 사용할 수 있습니다. 일반적으로 이 메서드는 서비스 제공자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');
});
exclamation

loginAs 메서드를 사용한 후에는 파일 내의 모든 테스트에 대해 사용자 세션이 유지됩니다.

쿠키

cookie 메서드를 사용하여 암호화된 쿠키의 값을 가져오거나 설정할 수 있습니다. 기본적으로 Laravel에서 생성된 모든 쿠키는 암호화됩니다.

$browser->cookie('name');
$browser->cookie('name', 'Taylor');

plainCookie 메서드를 사용하여 암호화되지 않은 쿠키의 값을 가져오거나 설정할 수 있습니다.

$browser->plainCookie('name');
$browser->plainCookie('name', 'Taylor');

deleteCookie 메서드를 사용하여 지정된 쿠키를 삭제할 수 있습니다.

$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 선택자를 기억하는 대신 효과적인 테스트를 작성하는 데 집중할 수 있습니다. 선택자를 정의하려면 HTML 요소에 dusk 속성을 추가합니다. 그런 다음 Dusk 브라우저와 상호 작용할 때 선택자에 @를 접두사로 추가하여 테스트 내에서 첨부된 요소를 조작합니다.

// HTML...
<button dusk="login-button">Login</button>
// Test...
$browser->click('@login-button');

원하는 경우 selectorHtmlAttribute 메서드를 통해 Dusk 선택자가 사용하는 HTML 속성을 사용자 정의할 수 있습니다. 일반적으로 이 메서드는 애플리케이션의 AppServiceProviderboot 메서드에서 호출해야 합니다.

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', '[email protected]');

필요한 경우 메서드가 허용하지만 type 메서드에 CSS 선택자를 전달할 필요는 없습니다. CSS 선택자가 제공되지 않으면 Dusk는 지정된 name 속성을 가진 input 또는 textarea 필드를 검색합니다.

내용을 지우지 않고 필드에 텍스트를 추가하려면 append 메서드를 사용할 수 있습니다.

$browser->type('tags', 'foo')
->append('tags', ', bar, baz');

clear 메서드를 사용하여 입력 값을 지울 수 있습니다.

$browser->clear('email');

typeSlowly 메서드를 사용하여 Dusk가 천천히 입력하도록 지시할 수 있습니다. 기본적으로 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']);

확인란

확인란 입력을 "선택"하려면 check 메서드를 사용할 수 있습니다. 다른 많은 입력 관련 메서드와 마찬가지로 전체 CSS 선택자가 필요하지 않습니다. CSS 선택자 일치를 찾을 수 없으면 Dusk는 일치하는 name 속성을 가진 확인란을 검색합니다.

$browser->check('terms');

uncheck 메서드를 사용하여 확인란 입력을 "선택 취소"할 수 있습니다.

$browser->uncheck('terms');

라디오 버튼

radio 입력 옵션을 "선택"하려면 radio 메서드를 사용할 수 있습니다. 다른 많은 입력 관련 메서드와 마찬가지로 전체 CSS 선택자가 필요하지 않습니다. CSS 선택자 일치를 찾을 수 없으면 Dusk는 일치하는 namevalue 속성을 가진 radio 입력을 검색합니다.

$browser->radio('size', 'large');

파일 첨부

attach 메서드를 사용하여 file 입력 요소에 파일을 첨부할 수 있습니다. 다른 많은 입력 관련 메서드와 마찬가지로 전체 CSS 선택자가 필요하지 않습니다. CSS 선택자 일치를 찾을 수 없으면 Dusk는 일치하는 name 속성을 가진 file 입력을 검색합니다.

$browser->attach('photo', __DIR__.'/photos/mountains.png');
exclamation

attach 함수를 사용하려면 서버에 Zip PHP 확장이 설치되어 활성화되어 있어야 합니다.

버튼 누르기

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)) {
// ...
}
exclamation

이러한 메서드는 jQuery와 상호 작용합니다. 페이지에서 jQuery를 사용할 수 없는 경우 Dusk는 테스트 기간 동안 사용할 수 있도록 페이지에 자동으로 삽입합니다.

키보드 사용하기

keys 메서드를 사용하면 type 메서드에서 일반적으로 허용되는 것보다 더 복잡한 입력 시퀀스를 지정된 요소에 제공할 수 있습니다. 예를 들어 값을 입력하는 동안 Dusk에 modifier 키를 누르고 있도록 지시할 수 있습니다. 이 예에서는 지정된 선택자와 일치하는 요소에 taylor를 입력하는 동안 shift 키를 누르고 있습니다. taylor를 입력한 후에는 modifier 키 없이 swift가 입력됩니다.

$browser->keys('selector', ['{shift}', 'taylor'], 'swift');

keys 메서드의 또 다른 유용한 사용 사례는 애플리케이션의 기본 CSS 선택자에 "키보드 단축키" 조합을 보내는 것입니다.

$browser->keys('.app', ['{command}', 'j']);
lightbulb

{command}와 같은 모든 modifier 키는 {} 문자로 묶여 있으며 GitHub에서 찾을 수 있는 Facebook\WebDriver\WebDriverKeys 클래스에 정의된 상수와 일치합니다.

유창한 키보드 상호 작용

Dusk는 또한 Laravel\Dusk\Keyboard 클래스를 통해 복잡한 키보드 상호 작용을 유창하게 수행할 수 있도록 하는 withKeyboard 메서드를 제공합니다. Keyboard 클래스는 press, release, typepause 메서드를 제공합니다.

use Laravel\Dusk\Keyboard;
$browser->withKeyboard(function (Keyboard $keyboard) {
$keyboard->press('c')
->pause(1000)
->release('c')
->type(['c', 'e', 'o']);
});

키보드 매크로

테스트 스위트 전체에서 쉽게 재사용할 수 있는 사용자 정의 키보드 상호 작용을 정의하려면 Keyboard 클래스에서 제공하는 macro 메서드를 사용할 수 있습니다. 일반적으로 이 메서드는 서비스 제공자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');

마우스오버

지정된 CSS 또는 Dusk 선택자와 일치하는 요소 위로 마우스를 이동해야 할 때 mouseover 메서드를 사용할 수 있습니다.

$browser->mouseover('.selector');

드래그 앤 드롭

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 대화 상자를 닫으려면 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');
});

현재 범위 외부에서 어설션을 실행해야 할 수도 있습니다. elsewhereelsewhereWhenAvailable 메서드를 사용하여 이를 수행할 수 있습니다.

$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 선택자와 일치하는 요소가 페이지에 표시될 때까지 테스트 실행을 일시 중지할 수 있습니다. 기본적으로 이 메서드는 예외를 발생시키기 전에 최대 5초 동안 테스트를 일시 중지합니다. 필요한 경우 메서드의 두 번째 인수로 사용자 정의 시간 초과 임계값을 전달할 수 있습니다.

// 최대 5초 동안 선택자를 기다립니다...
$browser->waitFor('.selector');
// 최대 1초 동안 선택자를 기다립니다...
$browser->waitFor('.selector', 1);

지정된 선택자와 일치하는 요소에 지정된 텍스트가 포함될 때까지 기다릴 수도 있습니다.

// 최대 5초 동안 선택자에 지정된 텍스트가 포함될 때까지 기다립니다...
$browser->waitForTextIn('.selector', 'Hello World');
// 최대 1초 동안 선택자에 지정된 텍스트가 포함될 때까지 기다립니다...
$browser->waitForTextIn('.selector', 'Hello World', 1);

지정된 선택자와 일치하는 요소가 페이지에서 사라질 때까지 기다릴 수도 있습니다.

// 최대 5초 동안 선택자가 사라질 때까지 기다립니다...
$browser->waitUntilMissing('.selector');
// 최대 1초 동안 선택자가 사라질 때까지 기다립니다...
$browser->waitUntilMissing('.selector', 1);

또는 지정된 선택자와 일치하는 요소가 활성화되거나 비활성화될 때까지 기다릴 수 있습니다.

// 최대 5초 동안 선택자가 활성화될 때까지 기다립니다...
$browser->waitUntilEnabled('.selector');
// 최대 1초 동안 선택자가 활성화될 때까지 기다립니다...
$browser->waitUntilEnabled('.selector', 1);
// 최대 5초 동안 선택자가 비활성화될 때까지 기다립니다...
$browser->waitUntilDisabled('.selector');
// 최대 1초 동안 선택자가 비활성화될 때까지 기다립니다...
$browser->waitUntilDisabled('.selector', 1);

사용 가능한 경우 선택자 범위 지정

경우에 따라 지정된 선택자와 일치하는 요소가 나타날 때까지 기다린 다음 요소와 상호 작용할 수 있습니다. 예를 들어 모달 창을 사용할 수 있을 때까지 기다린 다음 모달 내에서 "확인" 버튼을 누를 수 있습니다. whenAvailable 메서드를 사용하여 이를 수행할 수 있습니다. 지정된 클로저 내에서 수행되는 모든 요소 작업은 원래 선택자로 범위가 지정됩니다.

$browser->whenAvailable('.modal', function (Browser $modal) {
$modal->assertSee('Hello World')
->press('OK');
});

텍스트 기다리기

waitForText 메서드를 사용하여 지정된 텍스트가 페이지에 표시될 때까지 기다릴 수 있습니다.

// 최대 5초 동안 텍스트를 기다립니다...
$browser->waitForText('Hello World');
// 최대 1초 동안 텍스트를 기다립니다...
$browser->waitForText('Hello World', 1);

waitUntilMissingText 메서드를 사용하여 표시된 텍스트가 페이지에서 제거될 때까지 기다릴 수 있습니다.

// 최대 5초 동안 텍스트가 제거될 때까지 기다립니다...
$browser->waitUntilMissingText('Hello World');
// 최대 1초 동안 텍스트가 제거될 때까지 기다립니다...
$browser->waitUntilMissingText('Hello World', 1);

waitForLink 메서드를 사용하여 지정된 링크 텍스트가 페이지에 표시될 때까지 기다릴 수 있습니다.

// 최대 5초 동안 링크를 기다립니다...
$browser->waitForLink('Create');
// 최대 1초 동안 링크를 기다립니다...
$browser->waitForLink('Create', 1);

입력 기다리기

waitForInput 메서드를 사용하여 지정된 입력 필드가 페이지에 표시될 때까지 기다릴 수 있습니다.

// 최대 5초 동안 입력을 기다립니다...
$browser->waitForInput($field);
// 최대 1초 동안 입력을 기다립니다...
$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 키워드나 종료 세미콜론을 포함할 필요가 없습니다.

// 최대 5초 동안 식이 true가 될 때까지 기다립니다...
$browser->waitUntil('App.data.servers.length > 0');
// 최대 1초 동안 식이 true가 될 때까지 기다립니다...
$browser->waitUntil('App.data.servers.length > 0', 1);

Vue 식 기다리기

waitUntilVuewaitUntilVueIsNot 메서드를 사용하여 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의 load 이벤트를 기다립니다...
$iframe->waitForEvent('load');
});

waitForEvent 메서드에 두 번째 인수로 선택자를 제공하여 특정 요소에 이벤트 리스너를 연결할 수도 있습니다.

$browser->waitForEvent('load', '.selector');

documentwindow 객체에서 이벤트를 기다릴 수도 있습니다.

// 문서가 스크롤될 때까지 기다립니다...
$browser->waitForEvent('scroll', 'document');
// 최대 5초 동안 창 크기가 조정될 때까지 기다립니다...
$browser->waitForEvent('resize', 'window', 5);

콜백으로 기다리기

Dusk의 "wait" 메서드 중 다수는 기본 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');

<a name="```php tab=Pest test('vue', function () { $this->browse(function (Browser $browser) { $browser->visit('/') ->assertVue('user.name', 'Taylor', '@profile-component'); }); });

```php tab=PHPUnit
/**
* 기본 Vue 테스트 예제입니다.
*/
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 페이지를 사용하면 단일 메서드를 통해 주어진 페이지에서 수행할 수 있는 표현식 있는 동작을 정의할 수 있습니다. 또한 페이지를 사용하면 애플리케이션 또는 단일 페이지에 대한 일반적인 선택기에 대한 바로 가기를 정의할 수 있습니다.

페이지 생성

페이지 객체를 생성하려면 dusk:page Artisan 명령을 실행합니다. 모든 페이지 객체는 애플리케이션의 tests/Browser/Pages 디렉터리에 배치됩니다:

php artisan dusk:page Login

페이지 구성

기본적으로 페이지에는 url, assert, elements의 세 가지 메서드가 있습니다. 지금은 urlassert 메서드에 대해 설명하겠습니다. elements 메서드는 아래에서 더 자세히 설명합니다.

url 메서드

url 메서드는 페이지를 나타내는 URL의 경로를 반환해야 합니다. Dusk는 브라우저에서 페이지로 이동할 때 이 URL을 사용합니다:

/**
* 페이지의 URL을 가져옵니다.
*/
public function url(): string
{
return '/login';
}

assert 메서드

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 선택기에 대한 빠르고 기억하기 쉬운 바로 가기를 정의할 수 있습니다. 예를 들어 애플리케이션 로그인 페이지의 "이메일" 입력 필드에 대한 바로 가기를 정의해 보겠습니다:

/**
* 페이지에 대한 요소 바로 가기를 가져옵니다.
*
* @return array<string, string>
*/
public function elements(): array
{
return [
'@email' => 'input[name=email]',
];
}

바로 가기가 정의되면 일반적으로 전체 CSS 선택기를 사용하는 모든 위치에서 단축 선택기를 사용할 수 있습니다:

$browser->type('@email', '[email protected]');

전역 단축 선택기

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의 "페이지 객체"와 유사하지만 탐색 모음 또는 알림 창과 같이 애플리케이션 전체에서 재사용되는 UI 및 기능 조각을 위한 것입니다. 따라서 컴포넌트는 특정 URL에 바인딩되지 않습니다.

컴포넌트 생성

컴포넌트를 생성하려면 dusk:component Artisan 명령을 실행합니다. 새 컴포넌트는 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');
});
}
}

지속적 통합

exclamation

대부분의 Dusk 지속적 통합 구성은 Laravel 애플리케이션이 포트 8000에서 기본 제공 PHP 개발 서버를 사용하여 제공될 것으로 예상합니다. 따라서 계속하기 전에 지속적 통합 환경에 APP_URL 환경 변수 값이 http://127.0.0.1:8000인지 확인해야 합니다.

Heroku CI

Heroku CI에서 Dusk 테스트를 실행하려면 다음 Google Chrome 빌드팩 및 스크립트를 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

Travis CI에서 Dusk 테스트를 실행하려면 다음 .travis.yml 구성을 사용하세요. Travis CI는 그래픽 환경이 아니므로 Chrome 브라우저를 실행하기 위해 몇 가지 추가 단계를 수행해야 합니다. 또한 PHP의 내장 웹 서버를 실행하기 위해 php artisan serve를 사용할 것입니다.

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

Dusk 테스트를 실행하기 위해 GitHub Actions를 사용하고 있다면, 다음 설정 파일을 시작점으로 사용할 수 있습니다. TravisCI와 마찬가지로 PHP 내장 웹 서버를 실행하기 위해 php artisan serve 명령어를 사용할 것입니다.

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 테스트를 실행하는 경우, 다음 구성 파일을 시작점으로 사용할 수 있습니다. Laravel을 실행하기 위해 PHP 내장 서버를 사용하여 요청을 수신할 수 있도록 합니다.

# file .chipperci.yml
version: 1
environment:
php: 8.2
node: 16
# 빌드 환경에 Chrome 포함
services:
- dusk
# 모든 커밋 빌드
on:
push:
branches: .*
pipeline:
- name: Setup
cmd: |
cp -v .env.example .env
composer install --no-interaction --prefer-dist --optimize-autoloader
php artisan key:generate
# APP_URL이 BUILD_HOST를 사용하도록 보장하여 dusk env 파일 생성
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

데이터베이스 사용 방법을 포함하여 Chipper CI에서 Dusk 테스트를 실행하는 방법에 대해 자세히 알아보려면 공식 Chipper CI 문서를 참조하십시오.