07/09/2018, 17:42

Laravel Dusk – Intuitive and Easy Browser Testing for All!

Laravel phát hành Dusk với hy vọng sẽ cung cấp cho người dùng một API chung cho việc "browser testing". Mặc định thì nó sẽ đi kèm với ChromeDriver và nếu chúng ta cần hỗ trợ cho các trình duyệt khác thì chúng ta có thể sử dụng Selenium. Nó vẫn sẽ có API test để đáp ứng nhu cầu đó của chúng ta. ...

Laravel phát hành Dusk với hy vọng sẽ cung cấp cho người dùng một API chung cho việc "browser testing". Mặc định thì nó sẽ đi kèm với ChromeDriver và nếu chúng ta cần hỗ trợ cho các trình duyệt khác thì chúng ta có thể sử dụng Selenium. Nó vẫn sẽ có API test để đáp ứng nhu cầu đó của chúng ta.

Installation

composer require laravel/dusk

Câu lệnh này sẽ cài đặt phiên bản ổn định mới nhất của package thông qua Composer.

Tiếp theo, chúng ta cần phải đăng ký DuskServiceProvider trong ứng dụng. Chúng ta có thể thực hiện theo một vài cách:

Cách 1:

Chúng ta có thể include nó vào trong mảng providers ở trong file config/app.php:

...

AppProvidersRouteServiceProvider::class,
LaravelDuskDuskServiceProvider::class,
...

Vấn đề là với cách này là DuskServiceProvider sẽ được đăng ký trong ứng dụng của chúng ta cho tất cả các môi trường. Nhưng chúng ta không cần Dusk có mặt và đăng ký trong môi trường production. Vậy chúng ta có thể tránh điều này với cách thứ 2.

Cách 2:

Đăng ký DuskServiceProvider trong class AppServiceProvider cho các môi trường cụ thể:

namespace AppProviders;

use IlluminateSupportServiceProvider;
use LaravelDuskDuskServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        if ($this->app->environment('local', 'testing', 'staging')) {
           $this->app->register(DuskServiceProvider::class);
        }
    }
}

Tiếp theo, để hoàn tất quá trình cài đặt:

php artisan dusk:install

Dusk sẽ cung cấp một khung cơ bản của các class và thư mục. Nếu chúng ta mở thư mục tests, chúng ta có thể thấy một thư mục Browser mới với một khung cần thiết cho các Dusk test.

First Test

Đầu tiên, chúng ta sẽ xây dựng một quy trình xác thực bằng cách sử dụng cơ chế được xây dựng trước của Laravel đó là make:auth:

php artisan make:auth

Bây giờ chúng ta hãy tạo test với Dusk đầu tiên:

php artisan dusk:make LoginTest

Lệnh trên sẽ tạo một class Login Test trong thư mục Browser.

class LoginTest extends DuskTestCase
{
    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function test_I_can_login_successfully()
    {
        $this->browse(function ($browser) {
            $browser->visit('/login')
                    ->type('email', '[email protected]')
                    ->type('password', 'secret')
                    ->press('Login')
                    ->assertSee('You are logged in!');
        });
    }
}

Trong trường hợp test ở trên, chúng ta kiểm tra xem người dùng có thể đăng nhập thành công vào hệ thống và xem trang chủ có message welcome hay không.

Lưu ý: Để thực hiện test này thành công, chúng tôi cần có một user thật trong database. Đối với phần này, chúng ta đã có một user với các thông tin đăng nhập ở trên. Hoặc bạn có thể tạo 1 Factory cho user để test.

Ok chạy thử test này của chúng ta:

php artisan dusk

Nếu bạn có một user dùng trong database với thông tin đăng nhập chính xác, bạn có thể thấy kết quả dưới đây:

PHPUnit 5.7.6 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 4.71 seconds, Memory: 10.00MB

OK (2 tests, 2 assertions)

Failed Tests

Khi test fail, PHPUnit sẽ throw một số lỗi cho chúng ta. Chúng ta cần phải hiểu những lỗi đó là gì.

Dusk có một vài bổ sung đáng chú ý tại chỗ để phục vụ cho trường hợp này.

Trước tiên chúng ta sẽ sửa test của chúng ta để nó fail:

public function test_I_can_login_successfully()
{
    $this->browse(function ($browser) {
        $browser->visit('/login')
                ->type('email', '[email protected]')
                ->type('password', 'secret')
                ->press('Login')
                ->assertSee('You are logged in!');
    });
}

Trong trường hợp test ở trên, chúng ta sẽ cố gắng đăng nhập với người dùng không tồn tại trong database. Bây giờ chúng ta hãy chạy test và xem điều gì sẽ xảy ra:

Nếu bạn để ý kỹ, thì một trình duyệt sẽ mở ra ngay trước khi test fail.

Cụ thể đó là Dusk chụp ảnh màn hình của trang nơi lỗi được kích hoạt và lưu nó trong thư mục ảnh chụp màn hình:

Điều này cho chúng ta một đại diện trực quan về lý do tại sao test của chúng ta lại fail. Chúng ta có thể thấy rằng các thông tin không khớp với bất kỳ bản ghi nào trong database. Với phản hồi trực quan như thế này, Dusk đảm bảo bạn có thể xác định nhanh các vấn đề.

Testing AJAX Calls

Dusk có nghĩa là end to end browser testing cho các ứng dụng JavaScript hiện đại. Trong các ứng dụng như vậy, một trường hợp sử dụng điển hình là chờ response của các request AJAX.

Chúng ta sẽ test tính năng Create Task từ một ứng dụng demo - bạn có thể clone nó để tiện theo dõi:

Chúng ta sử dụng một request AJAX để tạo một task mới và sau đó redirect người dùng đến trang danh sách các task.

php artisan dusk:make CreateTaskTest

Lệnh trên sẽ tạo một class CreateTaskTest trong thư mục Browser của chúng ta. Ok bây giờ chúng ta viết test:

class CreateTaskTest extends DuskTestCase
{
    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function test_I_can_create_task_successfully()
    {
        $this->browse(function ($browser) {

            $browser->visit('/tasks/create')
                    ->type('title', 'My Task')
                    ->press('Add Task')
                    ->pause(5000)
                    ->assertPathIs('/tasks');
        });
    }
}

Trong bài test ở trên, chúng ta cố gắng thêm một task mới bằng cách sử dụng form AJAX:

  • Nhập tiêu đề
  • Nhấp vào nút Add Task
  • Đợi 5 giây
  • Xác nhận rằng chúng ta được chuyển hướng đến trang danh sách task

Bây giờ chúng ta hãy chạy test và xem kết quả:

Như bạn có thể thấy, test trên đã pass.

Chúng ta cũng có thể sử dụng phương thức waitUntilMissing của Dusk để kiểm tra luồng trên:

<?php

namespace TestsBrowser;

use TestsDuskTestCase;
use IlluminateFoundationTestingDatabaseMigrations;

class CreateTaskTest extends DuskTestCase
{
    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function test_I_can_create_task_successfully()
    {
        $this->browse(function ($browser) {

            $browser->visit('/tasks/create')
                    ->type('title', 'My Task')
                    ->press('Add Task')
                    ->waitUntilMissing('.btn-primary')
                    ->assertPathIs('/tasks');
        });
    }
}

Bạn có thể tham khảo docs chính thức để tìm hiểu về các elements chờ khác có sẵn trong API.

A More Advanced Example

Chúng ta có một ứng dụng với menu item, và nếu chúng ta nhấp vào Support Email, một modal popup sẽ xuất hiện với form để gửi email hỗ trợ:

Chúng ta sẽ viết một trường hợp test để kiểm tra kịch bản sau:

  1. Đăng nhập
  2. Xem Support Email
  3. Nhấn vào Support Email
  4. Xác nhận rằng modal pop-up sẽ mở và có ID email của người dùng trong text box

Trong gif ở trên, chúng ta tương tác với giao diện bằng chuột và mở modal. Chúng ta hãy tạo lại luồng trên trong trường hợp test Dusk của chúng ta.

Đầu tiên, chúng ta sẽ tạo một class test mới:

php artisan dusk:make SupportEmailsTest

Sau đó là code test:

class SupportEmailsTest extends DuskTestCase
{
    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function test_I_can_open_modal_for_support_emails()
    {
        $this->browse(function ($browser) {
            
            // Bạn hãy nhớ là cần có 1 factory cho User model
            $user = factory(User::class)->create();

            $browser->loginAs($user)
                    ->visit('/tasks')
                    ->clickLink('Support Email')
                    ->whenAvailable('#modal-support', function ($modal) use($user) {
                        $modal->assertInputValue('#support-from', $user->email);
                    });
        });
    }
}

Ok, chạy thử test:

php artisan dusk tests/Browser/SupportEmailsTest.php

Chúng ta có thể thấy rằng test của chúng ta đã pass:

PHPUnit 5.7.13 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 3.63 seconds, Memory: 12.00MB

OK (1 test, 1 assertion)

Bạn có thể tham khảo thêm các assertions tại đây.

Pages

Có một khái niệm về Pages trong Dusk. Chúng không có gì hơn là các class test có thể sử dụng lại.

Hãy refactor lại class CreateTaskTest bằng cách sử dụng Pages.

Trước tiên chúng ta hãy tạo một Page mới:

php artisan dusk:page CreateTaskPage

Lệnh trên sẽ tạo một class mới trong thư mục Pages. Chúng ta hãy kiểm tra từng method và sửa đổi chúng để phù hợp hơn với việc test trường hợp create Task của chúng ta:

public function url()
{
    return '/tasks/create';
}

Method url định nghĩa url của trang. Bất cứ khi nào Pages này được gọi, Dusk sẽ điều hướng đến url này.

public function assert(Browser $browser)
{
    $browser->assertPathIs($this->url());
}

assert định nghĩa các assertions cho trang này. Bất cứ khi nào CreateTaskPage được gọi, tất cả các assertions được xác định trong method assert sẽ được thực hiện.

public function elements()
{
    return [
        '@addTask' => '.btn-primary',
    ];
}

Method elements có thể có các selector đã được định nghĩa trước. Chúng ta có thể định nghĩa tên dễ đọc cho selector và sử dụng lại chúng cho Page này trong các trường hợp test khác nhau. Trong ví dụ trên, chúng ta đã định nghĩa một selector cho nút Add Task.

Bây giờ chúng ta hãy sửa class CreateTaskTest và sử dụng selector:

class CreateTaskTest extends DuskTestCase
{
    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function test_I_can_create_task_successfully()
    {
        $this->browse(function ($browser) {

            $user = factory(User::class)->create();

            $browser->loginAs($user)
                    ->visit(new CreateTaskPage)
                    ->type('title', 'My Task')
                    ->click('@addTask')
                    ->waitUntilMissing('@addTask')
                    ->assertPathIs('/tasks');
        });
    }
}

Chúng ta đã sửa class test để có thể sử dụng CreateTaskPage. Bây giờ chúng ta hãy chạy lại test và xem mọi thứ có hoạt động tốt không:

PHPUnit 5.7.13 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 2.76 seconds, Memory: 12.00MB

OK (1 test, 2 assertions)

Chúng ta thậm chí có thể định nghĩa các method tùy chỉnh để thực hiện một số action để có thể sử dụng lại trên một Pages nhất định. Bạn có thể đọc thêm về nó trong docs chính thức.

Conclusion

Bài viết đã giới thiệu sơ lược về Laravel Dusk, một package của Laravel cung cấp một giải pháp thay thế cho việc end to end JavaScript testing. Chúng ta đã đề cập đến các config tùy chọn cần thiết để bắt đầu và các ví dụ ở trên sẽ giúp bạn và cung cấp một cách tổng quan về một số config tùy chọn khác phù hợp với bạn.

References

https://www.sitepoint.com/laravel-dusk-intuitive-and-easy-browser-testing-for-all/

0