본문 바로가기

Laravel Dusk

번역일: 2026년 6월 21일

Laravel Dusk

소개

WARNING

Pest 4에는 Laravel Dusk보다 성능과 사용성이 크게 향상된 브라우저 자동화 테스트 기능이 내장되어 있습니다. 새 프로젝트에서는 Pest를 사용한 브라우저 테스트를 권장합니다.

Laravel Dusk는 표현력 있고 사용하기 쉬운 브라우저 자동화 및 테스트 API를 제공합니다. 기본적으로 JDK나 Selenium을 별도로 설치할 필요가 없으며, 독립 실행형 ChromeDriver를 사용합니다. 물론 원한다면 Selenium 호환 드라이버를 직접 연결해 사용할 수도 있습니다.

설치

먼저 Google Chrome을 설치한 뒤, Composer로 laravel/dusk 패키지를 개발 의존성으로 추가합니다:

composer require laravel/dusk --dev

WARNING

Dusk의 서비스 프로바이더를 수동으로 등록하는 경우, 절대로 프로덕션 환경에 등록하지 마십시오. 프로덕션에 등록하면 임의의 사용자가 애플리케이션에 인증 없이 로그인할 수 있는 보안 취약점이 생길 수 있습니다.

패키지 설치 후 dusk:install Artisan 명령을 실행합니다. 이 명령은 tests/Browser 디렉터리와 예제 Dusk 테스트 파일을 생성하고, 현재 운영체제에 맞는 ChromeDriver 바이너리를 설치합니다:

php artisan dusk:install

이어서 .env 파일의 APP_URL 값을 브라우저에서 실제로 접근하는 애플리케이션 URL로 설정합니다.

NOTE

Laravel Sail로 로컬 개발 환경을 관리하는 경우, Sail 문서의 Dusk 테스트 설정 및 실행 항목도 함께 참고하세요.

ChromeDriver 관리

dusk:install로 설치된 것과 다른 버전의 ChromeDriver가 필요하다면 dusk:chrome-driver 명령을 사용하세요:

# 현재 OS에 맞는 최신 ChromeDriver 설치php artisan dusk:chrome-driver# 특정 버전의 ChromeDriver 설치php artisan dusk:chrome-driver 86# 지원하는 모든 OS용 특정 버전 설치php artisan dusk:chrome-driver --all# 설치된 Chrome/Chromium 버전에 맞는 ChromeDriver 자동 감지 후 설치php artisan dusk:chrome-driver --detect

WARNING

Dusk를 실행하려면 chromedriver 바이너리에 실행 권한이 있어야 합니다. 실행에 문제가 있다면 다음 명령으로 권한을 부여하세요: chmod -R 0755 vendor/laravel/dusk/bin/

다른 브라우저 사용

Dusk는 기본적으로 Google Chrome과 ChromeDriver를 사용합니다. 하지만 Selenium 서버를 직접 실행하여 다른 브라우저로도 테스트할 수 있습니다.

먼저 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:make Artisan 명령으로 Dusk 테스트를 생성합니다. 생성된 테스트 파일은 tests/Browser 디렉터리에 위치합니다:

php artisan dusk:make LoginTest

각 테스트 후 데이터베이스 초기화

대부분의 테스트는 데이터베이스 데이터를 조회하는 페이지와 상호작용하게 됩니다. 단, Dusk 테스트에서는 RefreshDatabase 트레이트를 절대 사용하지 마십시오. RefreshDatabase는 데이터베이스 트랜잭션을 활용하는데, 이는 HTTP 요청 간에 유지되지 않습니다. 대신 다음 두 가지 트레이트 중 하나를 사용하세요: DatabaseMigrations 또는 DatabaseTruncation.

DatabaseMigrations 사용

DatabaseMigrations 트레이트는 각 테스트 전에 마이그레이션을 실행합니다. 다만 매 테스트마다 테이블을 삭제하고 재생성하므로 DatabaseTruncation에 비해 속도가 느릴 수 있습니다:

Pest

<?php use Illuminate\Foundation\Testing\DatabaseMigrations; use Laravel\Dusk\Browser; pest()->use(DatabaseMigrations::class); //

PHPUnit

<?php namespace Tests\Browser; use Illuminate\Foundation\Testing\DatabaseMigrations; use Laravel\Dusk\Browser; use Tests\DuskTestCase; class ExampleTest extends DuskTestCase { use DatabaseMigrations; // }

WARNING

Dusk 테스트에서는 SQLite 인메모리 데이터베이스를 사용할 수 없습니다. 브라우저는 별도의 프로세스에서 실행되기 때문에 다른 프로세스의 인메모리 데이터베이스에 접근할 수 없습니다.

DatabaseTruncation 사용

DatabaseTruncation 트레이트는 첫 번째 테스트에서만 마이그레이션을 실행하고, 이후 테스트에서는 테이블을 비우기(truncate)만 합니다. 매번 마이그레이션을 재실행하지 않으므로 속도가 더 빠릅니다:

Pest

<?php use Illuminate\Foundation\Testing\DatabaseTruncation; use Laravel\Dusk\Browser; pest()->use(DatabaseTruncation::class); //

PHPUnit

<?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 프로퍼티를 정의하세요:

NOTE

Pest를 사용하는 경우, 프로퍼티나 메서드는 기본 DuskTestCase 클래스 또는 테스트 파일이 상속하는 클래스에 정의해야 합니다.

/** * 비울 테이블 목록 * * @var array */ protected $tablesToTruncate = ['users'];

반대로, 비우지 않을 테이블을 지정하려면 $exceptTables 프로퍼티를 사용합니다:

/** * truncation에서 제외할 테이블 목록 * * @var array */ protected $exceptTables = ['users'];

테이블을 비울 데이터베이스 커넥션을 지정하려면 $connectionsToTruncate 프로퍼티를 정의하세요:

/** * 테이블을 비울 커넥션 목록 * * @var array */ protected $connectionsToTruncate = ['mysql'];

데이터베이스 truncation 전후에 코드를 실행하고 싶다면 beforeTruncatingDatabase 또는 afterTruncatingDatabase 메서드를 정의하세요:

/** * 데이터베이스 truncation 시작 전에 실행할 작업 */ protected function beforeTruncatingDatabase(): void { // } /** * 데이터베이스 truncation 완료 후에 실행할 작업 */ protected function afterTruncatingDatabase(): void { // }

테스트 실행

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

php artisan dusk

마지막 실행에서 실패한 테스트가 있다면, dusk:fails 명령으로 실패한 테스트만 먼저 재실행하여 시간을 절약할 수 있습니다:

php artisan dusk:fails

dusk 명령은 Pest/PHPUnit 테스트 러너가 지원하는 인수를 모두 받을 수 있습니다. 예를 들어 특정 그룹의 테스트만 실행할 수 있습니다:

php artisan dusk --group=foo

NOTE

Laravel Sail을 사용하는 경우 Sail 문서의 Dusk 테스트 설정 및 실행 항목을 참고하세요.

ChromeDriver 수동 실행

Dusk는 기본적으로 ChromeDriver를 자동으로 시작합니다. 자동 시작이 환경에 맞지 않는다면, dusk 명령 실행 전에 ChromeDriver를 수동으로 시작할 수 있습니다. 이 경우 tests/DuskTestCase.php 파일에서 다음 줄을 주석 처리하세요:

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

ChromeDriver를 9515가 아닌 다른 포트에서 실행하는 경우, 같은 클래스의 driver 메서드에서 포트를 수정합니다:

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

환경 설정 처리

테스트 실행 시 별도의 환경 설정 파일을 사용하려면, 프로젝트 루트에 .env.dusk.{environment} 파일을 만드세요. 예를 들어 local 환경에서 dusk 명령을 실행한다면 .env.dusk.local 파일을 생성합니다.

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

브라우저 기초

브라우저 인스턴스 생성

간단한 예제로 시작해 보겠습니다. 로그인 페이지에 접속하여 이메일과 비밀번호를 입력하고 "로그인" 버튼을 눌렀을 때 정상적으로 인증되는지 확인하는 테스트입니다. browse 메서드를 호출하면 브라우저 인스턴스가 클로저에 자동으로 전달됩니다:

Pest

<?php use App\Models\User; use Illuminate\Foundation\Testing\DatabaseMigrations; use Laravel\Dusk\Browser; pest()->use(DatabaseMigrations::class); test('기본 로그인 테스트', function () { $user = User::factory()->create([ 'email' => 'taylor@laravel.com', ]); $this->browse(function (Browser $browser) use ($user) { $browser->visit('/login') ->type('email', $user->email) ->type('password', 'password') ->press('Login') ->assertPathIs('/home'); }); });

PHPUnit

<?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' => 'taylor@laravel.com', ]); $this->browse(function (Browser $browser) use ($user) { $browser->visit('/login') ->type('email', $user->email) ->type('password', 'password') ->press('Login') ->assertPathIs('/home'); }); } }

여러 브라우저 인스턴스 생성

WebSocket을 사용하는 채팅 화면처럼 두 명의 사용자가 동시에 상호작용해야 하는 시나리오를 테스트할 때는 브라우저 인스턴스를 여러 개 생성할 수 있습니다. browse에 전달하는 클로저의 인자를 늘리면 됩니다:

$this->browse(function (Browser $first, Browser $second) { $first->loginAs(User::find(1)) ->visit('/home') ->waitForText('메시지'); $second->loginAs(User::find(2)) ->visit('/home') ->waitForText('메시지') ->type('message', '안녕하세요!') ->press('전송'); $first->waitForText('안녕하세요!') ->assertSee('홍길동'); });

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('카드 정보를 입력하세요'); });

인증

인증이 필요한 페이지를 테스트할 때마다 로그인 과정을 반복하는 것은 번거롭습니다. Dusk의 loginAs 메서드를 사용하면 로그인 화면을 거치지 않고 바로 인증 상태로 만들 수 있습니다. 인증 가능한 모델의 기본 키 또는 모델 인스턴스를 전달합니다:

use App\Models\User; use Laravel\Dusk\Browser; $this->browse(function (Browser $browser) { $browser->loginAs(User::find(1)) ->visit('/home'); });

WARNING

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 셀렉터

Dusk 테스트 작성에서 가장 까다로운 부분 중 하나는 요소를 특정할 CSS 셀렉터를 선택하는 것입니다. 프론트엔드 코드가 변경되면 아래와 같은 CSS 셀렉터는 쉽게 깨질 수 있습니다:

<!-- HTML --> <button>로그인</button>
// 테스트 $browser->click('.login-page .container div > button');

Dusk 셀렉터를 사용하면 CSS 구조를 외울 필요 없이 안정적인 테스트를 작성할 수 있습니다. HTML 요소에 dusk 속성을 추가하고, 테스트에서 @ 접두사를 붙여 해당 요소를 참조합니다:

<!-- HTML --> <button dusk="login-button">로그인</button>
// 테스트 $browser->click('@login-button');

필요하다면 selectorHtmlAttribute 메서드로 Dusk가 사용하는 HTML 속성명을 변경할 수 있습니다. 보통 AppServiceProviderboot 메서드에서 설정합니다:

use Laravel\Dusk\Dusk; Dusk::selectorHtmlAttribute('data-dusk');

텍스트, 값, 속성

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 6월 21일