hoàn thành chức năng các test case chính

This commit is contained in:
2026-04-08 07:46:11 +07:00
parent 92a150ab53
commit c026e4cc2c
11 changed files with 1278 additions and 20 deletions
+22 -4
View File
@@ -2,6 +2,7 @@
namespace Tests\Browser;
use App\Models\User;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
@@ -12,13 +13,16 @@ class AccountManagementTest extends DuskTestCase
*/
private function registerAndLogin(Browser $browser, string $phone): void
{
$browser->visit('/logout');
$browser->visit('/login')
->pause(300)
->type('name', 'Dusk Test User')
->type('phone', $phone)
->type('address', 'Cần Thơ')
->radio('known_sis', '1')
->type('job', 'Nhân viên văn phòng')
->press('Gửi thông tin')
->waitForText('thành công', 10)
->assertPathIs('/game');
}
@@ -33,7 +37,8 @@ class AccountManagementTest extends DuskTestCase
$this->registerAndLogin($browser, $phone);
$browser->visit('/login')
->assertSee('Cập nhật thông tin cá nhân')
->pause(300)
->assertInputValue('phone', $phone)
->clear('name')
->type('name', 'Tên Mới Test')
->clear('address')
@@ -42,9 +47,20 @@ class AccountManagementTest extends DuskTestCase
->clear('job')
->type('job', 'Giáo viên')
->press('Cập nhật')
->assertPathIs('/game')
->assertSee('Cập nhật tài khoản thành công');
->waitForText('thành công', 10)
->assertPathIs('/game');
});
// Kiểm tra DB: dữ liệu đã được cập nhật đúng
$user = User::where('phone', $phone)->first();
$this->assertNotNull($user);
$this->assertEquals('TÊN MỚI TEST', $user->name, 'Tên phải uppercase');
$this->assertEquals('Hà Nội', $user->address);
$this->assertEquals(0, $user->known_sis);
$this->assertEquals('Giáo viên', $user->job);
// Dọn dẹp
$user->delete();
}
/**
@@ -60,7 +76,8 @@ class AccountManagementTest extends DuskTestCase
$browser->visit('/login')
->clear('name')
->press('Cập nhật')
->assertSee('Nhập tên hiển thị');
->pause(300)
->assertPresent('.text-danger');
});
}
@@ -78,6 +95,7 @@ class AccountManagementTest extends DuskTestCase
->clear('phone')
->type('phone', 'abcde')
->press('Cập nhật')
->pause(500)
->assertSee('Số điện thoại không đúng định dạng');
});
}
+155
View File
@@ -0,0 +1,155 @@
<?php
namespace Tests\Browser;
use App\Models\Role;
use App\Models\User;
use App\Models\UserRole;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class AdminLoginTest extends DuskTestCase
{
private User $adminUser;
protected function setUp(): void
{
parent::setUp();
// Tạo admin test user với đầy đủ roles
$this->adminUser = User::create([
'name' => 'DUSK ADMIN TEST',
'email' => 'dusk_admin_test@test.local',
'phone' => '09' . rand(10000000, 99999999),
'password' => bcrypt('dusk_admin_pwd_2026'),
'status' => 1,
'address' => 'Test',
'known_sis'=> 0,
'job' => 'Admin',
'spined' => 0,
]);
// Gán tất cả roles
$roles = Role::where('role_status', 1)->get();
foreach ($roles as $role) {
UserRole::create(['user_id' => $this->adminUser->id, 'role_id' => $role->id]);
}
}
protected function tearDown(): void
{
UserRole::where('user_id', $this->adminUser->id)->delete();
$this->adminUser->delete();
parent::tearDown();
}
/**
* Trang admin hiển thị form đăng nhập.
*/
public function test_admin_login_page_shows_form(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/admin')
->assertPresent('input[name="email"]')
->assertPresent('input[name="password"]')
->assertPresent('input[type="submit"]');
});
}
/**
* Đăng nhập admin với email/password sai phải hiện lỗi.
*/
public function test_admin_login_with_wrong_credentials_shows_error(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/admin')
->type('email', 'wrong@email.com')
->type('password', 'wrongpassword')
->press('Login')
->pause(300)
->assertPresent('.alert-danger, .error, [class*="error"]');
});
}
/**
* Đăng nhập admin với email rỗng phải hiện lỗi validation (bypass HTML5 required).
*/
public function test_admin_login_with_empty_fields_shows_validation(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/admin');
// HTML5 `required` prevents native submit, strip it to get server-side validation
$browser->script("
document.querySelectorAll('input[required]').forEach(function(el) {
el.removeAttribute('required');
});
");
$browser->press('Login')
->pause(500)
->assertPresent('.text-danger, .alert-danger');
});
}
/**
* Đăng nhập admin thành công và redirect vào trang tài khoản.
*/
public function test_admin_login_successful(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/admin/logout')
->visit('/admin')
->type('email', 'dusk_admin_test@test.local')
->type('password', 'dusk_admin_pwd_2026')
->press('Login')
->waitForLocation('/admin/account', 10)
->assertPathIs('/admin/account');
});
}
/**
* Khi đã đăng nhập admin, truy cập /admin vẫn hiển thị form login (không có redirect).
*/
public function test_authenticated_admin_visiting_login_sees_form(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin')
->assertPathIs('/admin')
->assertPresent('input[name="email"]');
});
}
/**
* Truy cập trang admin khi chưa đăng nhập bị redirect về /admin login.
*/
public function test_unauthenticated_access_to_admin_account_redirects(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/admin/logout')
->visit('/admin/account')
->assertPathIs('/admin');
});
}
/**
* Đăng xuất admin thành công qua route /logout (route /admin/logout bị middleware chặn
* vì không có role admin/logout trong DB). Dùng real login thay vì loginAs()
* để tránh Dusk tự re-auth sau khi logout.
*/
public function test_admin_logout(): void
{
$this->browse(function (Browser $browser) {
// Đăng nhập thực qua form (không dùng loginAs để tránh Dusk re-auth)
$browser->visit('/admin/logout') // clear any previous session
->visit('/admin')
->type('email', $this->adminUser->email)
->type('password', 'dusk_admin_pwd_2026')
->press('Login')
->waitForLocation('/admin/account', 10)
// Thực hiện logout qua frontend /logout
->visit('/logout')
->pause(300)
// Truy cập trang cần auth -> phải bị redirect về /admin
->visit('/admin/account')
->assertPathIs('/admin');
});
}
}
+132
View File
@@ -0,0 +1,132 @@
<?php
namespace Tests\Browser;
use App\Models\Parameter;
use App\Models\Role;
use App\Models\User;
use App\Models\UserRole;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class AdminParameterTest extends DuskTestCase
{
private User $adminUser;
protected function setUp(): void
{
parent::setUp();
$this->adminUser = User::create([
'name' => 'DUSK PARAM ADMIN',
'email' => 'dusk_param_admin@test.local',
'phone' => '09' . rand(10000000, 99999999),
'password' => bcrypt('dusk_admin_pwd_2026'),
'status' => 1,
'address' => 'Test',
'known_sis'=> 0,
'job' => 'Admin',
'spined' => 0,
]);
$roles = Role::where('role_status', 1)->get();
foreach ($roles as $role) {
UserRole::create(['user_id' => $this->adminUser->id, 'role_id' => $role->id]);
}
}
protected function tearDown(): void
{
UserRole::where('user_id', $this->adminUser->id)->delete();
$this->adminUser->delete();
parent::tearDown();
}
/**
* Trang cấu hình hệ thống hiển thị.
*/
public function test_parameter_page_loads(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/parameter')
->assertPresent('form');
});
}
/**
* Cấu hình game_rule hiển thị trong textarea.
*/
public function test_parameter_page_shows_game_rule_field(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/parameter')
->assertPresent('[name="game_rule"], textarea');
});
}
/**
* Cập nhật thông số game_rule thành công và kiểm tra DB.
*/
public function test_update_game_rule_successfully(): void
{
// Backup giá trị hiện tại
$original = Parameter::where('parameter_key', 'game_rule')->first();
$originalValue = $original->parameter_value ?? '';
$newValue = 'Dusk Test Rule Content ' . rand(1000, 9999);
$this->browse(function (Browser $browser) use ($newValue) {
$browser->loginAs($this->adminUser)
->visit('/admin/parameter')
->pause(300);
// Gán trực tiếp qua JS vì có thể là CKEditor
$browser->script("
var el = document.querySelector('[name=\"game_rule\"]');
if (el) {
el.value = '{$newValue}';
}
if (typeof CKEDITOR !== 'undefined' && CKEDITOR.instances['game_rule']) {
CKEDITOR.instances['game_rule'].setData('{$newValue}');
}
");
$browser->press('Cập nhật')
->waitFor('.alert-success', 10);
});
// Kiểm tra DB: game_rule đã được cập nhật và chứa nội dung mới
$updated = Parameter::where('parameter_key', 'game_rule')->first();
$this->assertNotNull($updated, 'Tham số game_rule phải tồn tại trong DB');
$this->assertStringContainsString($newValue, $updated->parameter_value,
'Giá trị DB phải chứa nội dung vừa lưu');
// Restore giá trị gốc
$original->parameter_value = $originalValue;
$original->save();
}
/**
* Trang cấu hình có nút upload logo và banner.
*/
public function test_parameter_page_has_image_upload_fields(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/parameter')
->assertPresent('input[type="file"][name="logo_image"], input[name="logo_image"]');
});
}
/**
* Truy cập /admin/parameter khi chưa đăng nhập bị redirect.
*/
public function test_parameter_page_requires_auth(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/admin/logout')
->visit('/admin/parameter')
->assertPathIs('/admin');
});
}
}
+207
View File
@@ -0,0 +1,207 @@
<?php
namespace Tests\Browser;
use App\Models\Prize;
use App\Models\PrizeUser;
use App\Models\Role;
use App\Models\User;
use App\Models\UserRole;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class AdminPrizeTest extends DuskTestCase
{
private User $adminUser;
protected function setUp(): void
{
parent::setUp();
$this->adminUser = User::create([
'name' => 'DUSK PRIZE ADMIN',
'email' => 'dusk_prize_admin@test.local',
'phone' => '09' . rand(10000000, 99999999),
'password' => bcrypt('dusk_admin_pwd_2026'),
'status' => 1,
'address' => 'Test',
'known_sis'=> 0,
'job' => 'Admin',
'spined' => 0,
]);
$roles = Role::where('role_status', 1)->get();
foreach ($roles as $role) {
UserRole::create(['user_id' => $this->adminUser->id, 'role_id' => $role->id]);
}
}
protected function tearDown(): void
{
UserRole::where('user_id', $this->adminUser->id)->delete();
$this->adminUser->delete();
parent::tearDown();
}
/**
* Trang danh sách giải thưởng hiển thị đúng.
*/
public function test_prize_list_page_loads(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/prizes')
->assertPresent('table, .table');
});
}
/**
* Trang thêm mới giải thưởng hiển thị form.
*/
public function test_add_prize_form_loads(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/prize/update?id=0')
->assertPresent('input[name="prize_name"]')
->assertPresent('input[name="prize_order"]')
->assertPresent('select[name="prize_status"]');
});
}
/**
* Submit form thêm giải thưởng rỗng phải hiện lỗi.
*/
public function test_add_prize_with_empty_name_shows_error(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/prize/update?id=0');
// Strip HTML5 required nếu có, rồi submit để Server-side validation chạy
$browser->script("document.querySelectorAll('input[required]').forEach(function(el){el.removeAttribute('required');})");
$browser->press('Thêm mới')
->pause(500)
->assertPresent('.text-danger, .alert-danger, [class*="error"]');
});
}
/**
* Thêm mới giải thưởng thành công và kiểm tra DB.
*/
public function test_create_prize_successfully(): void
{
$prizeName = 'Dusk Test Prize ' . rand(1000, 9999);
$this->browse(function (Browser $browser) use ($prizeName) {
$browser->loginAs($this->adminUser)
->visit('/admin/prize/update?id=0')
->pause(500)
->type('prize_name', $prizeName)
->type('prize_number', '100')
->type('prize_order', '99')
->select('prize_status', '1')
->press('Thêm mới')
->waitFor('.alert-success', 10);
});
// Kiểm tra DB
$prize = Prize::where('prize_name', $prizeName)->first();
$this->assertNotNull($prize, 'Giải thưởng phải được tạo trong DB');
$this->assertEquals(1, $prize->prize_status);
$this->assertEquals(100, $prize->prize_number);
$this->assertEquals(99, $prize->prize_order);
// Dọn dẹp
$prize->delete();
}
/**
* Cập nhật tên giải thưởng thành công.
*/
public function test_update_prize_successfully(): void
{
// Tạo giải thưởng để cập nhật
$prize = Prize::create([
'prize_name' => 'Dusk Prize To Update',
'prize_status' => 1,
'prize_number' => 10,
'prize_order' => 88,
'user_id' => $this->adminUser->id,
]);
$newName = 'Dusk Prize Updated ' . rand(1000, 9999);
$this->browse(function (Browser $browser) use ($prize, $newName) {
$browser->loginAs($this->adminUser)
->visit('/admin/prize/update?id=' . $prize->id)
->clear('prize_name')
->type('prize_name', $newName)
->press('Cập nhật')
->waitFor('.alert-success', 10);
});
// Kiểm tra DB
$updated = Prize::find($prize->id);
$this->assertEquals($newName, $updated->prize_name);
$prize->delete();
}
/**
* Xóa giải thưởng thành công.
*/
public function test_delete_prize_successfully(): void
{
$prize = Prize::create([
'prize_name' => 'Dusk Prize To Delete',
'prize_status' => 1,
'prize_number' => 5,
'prize_order' => 77,
'user_id' => $this->adminUser->id,
]);
$prizeId = $prize->id;
$this->browse(function (Browser $browser) use ($prizeId) {
$browser->loginAs($this->adminUser)
->visit('/admin/prizes')
->visit('/admin/prize/delete/' . $prizeId)
->pause(1000); // redirect()->back() sau khi xóa
});
// Kiểm tra DB: giải thưởng đã bị xóa
$this->assertNull(Prize::find($prizeId), 'Giải thưởng phải bị xóa khỏi DB');
}
/**
* Trang danh sách người trúng giải hiển thị.
*/
public function test_prize_winner_list_loads(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/prizeuser')
->assertPresent('table, .table');
});
}
/**
* Trang danh sách người trúng giải có ô lọc ngày.
*/
public function test_prize_winner_list_has_date_filter(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/prizeuser')
->assertPresent('#fromDateTime, #toDateTime');
});
}
/**
* Link export Excel hoạt động.
*/
public function test_prize_winner_export_link_present(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/prizeuser')
->assertPresent('#excel_export');
});
}
}
+137
View File
@@ -0,0 +1,137 @@
<?php
namespace Tests\Browser;
use App\Models\Role;
use App\Models\User;
use App\Models\UserRole;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class AdminUserTest extends DuskTestCase
{
private User $adminUser;
private User $targetUser;
protected function setUp(): void
{
parent::setUp();
$this->adminUser = User::create([
'name' => 'DUSK USER ADMIN',
'email' => 'dusk_user_admin@test.local',
'phone' => '09' . rand(10000000, 99999999),
'password' => bcrypt('dusk_admin_pwd_2026'),
'status' => 1,
'address' => 'Test',
'known_sis'=> 0,
'job' => 'Admin',
'spined' => 0,
]);
$roles = Role::where('role_status', 1)->get();
foreach ($roles as $role) {
UserRole::create(['user_id' => $this->adminUser->id, 'role_id' => $role->id]);
}
// Tạo user mục tiêu để test cập nhật
$targetPhone = '09' . rand(10000000, 99999999);
$this->targetUser = User::create([
'name' => 'DUSK TARGET USER',
'email' => $targetPhone . '@phone.local',
'phone' => $targetPhone,
'password' => bcrypt('test123'),
'status' => 1,
'address' => 'Cần Thơ',
'known_sis'=> 1,
'job' => 'Sinh viên',
'spined' => 0,
]);
}
protected function tearDown(): void
{
UserRole::where('user_id', $this->adminUser->id)->delete();
$this->adminUser->delete();
$this->targetUser->delete();
parent::tearDown();
}
/**
* Trang danh sách user hiển thị.
*/
public function test_user_list_page_loads(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/users')
->assertPresent('table, .table');
});
}
/**
* Tên user mới tạo xuất hiện trong danh sách.
*/
public function test_user_list_shows_target_user(): void
{
// DB assertion: target user có trong query của controller (status != '')
$userInList = User::where('id', $this->targetUser->id)
->where('status', '!=', '')
->first();
$this->assertNotNull($userInList, 'Target user must be included in admin user list query');
$this->assertEquals($this->targetUser->email, $userInList->email);
// Browser: trang list load được với table
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/users')
->waitFor('#table', 5)
->assertPresent('#table');
});
}
/**
* Trang form cập nhật user hiển thị đúng thông tin.
*/
public function test_edit_user_form_shows_existing_data(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/users/update?id=' . $this->targetUser->id)
->assertInputValue('name', $this->targetUser->name)
->assertInputValue('email', $this->targetUser->email);
});
}
/**
* Cập nhật tên user thành công và kiểm tra DB.
*/
public function test_update_user_name_successfully(): void
{
$newName = 'Updated Dusk Name';
$this->browse(function (Browser $browser) use ($newName) {
$browser->loginAs($this->adminUser)
->visit('/admin/users/update?id=' . $this->targetUser->id)
->clear('name')
->type('name', $newName)
->press('Cập nhật')
->waitFor('.alert-success', 10);
});
// Kiểm tra DB: admin không chuyển uppercase
$updated = User::find($this->targetUser->id);
$this->assertEquals($newName, $updated->name);
}
/**
* Xem trang tài khoản admin.
*/
public function test_admin_account_page_shows_user_info(): void
{
$this->browse(function (Browser $browser) {
$browser->loginAs($this->adminUser)
->visit('/admin/account')
// Email là input field (readonly), dùng assertInputValue
->assertInputValue('email', $this->adminUser->email);
});
}
}
+27 -2
View File
@@ -2,6 +2,7 @@
namespace Tests\Browser;
use App\Models\User;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
@@ -13,7 +14,8 @@ class CreateAccountTest extends DuskTestCase
public function test_login_page_shows_form(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/login')
$browser->visit('/logout') // đảm bảo trạng thái guest
->visit('/login')
->assertSee('Nhập thông tin cá nhân')
->assertPresent('input[name="name"]')
->assertPresent('input[name="phone"]')
@@ -28,8 +30,10 @@ class CreateAccountTest extends DuskTestCase
public function test_empty_form_shows_validation_errors(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/login')
$browser->visit('/logout') // đảm bảo trạng thái guest
->visit('/login')
->press('Gửi thông tin')
->waitFor('.text-danger', 5)
->assertPresent('.text-danger');
});
}
@@ -71,6 +75,18 @@ class CreateAccountTest extends DuskTestCase
->waitForText('thành công', 10)
->assertPathIs('/game');
});
// Kiểm tra DB: user đã được tạo đúng
$user = User::where('phone', $uniquePhone)->first();
$this->assertNotNull($user, 'User phải được tạo trong DB');
$this->assertEquals('TEST DUSK USER', $user->name, 'Tên phải được uppercase');
$this->assertEquals('Cần Thơ', $user->address);
$this->assertEquals(1, $user->known_sis);
$this->assertEquals('Kỹ sư', $user->job);
$this->assertEquals($uniquePhone . '@phone.local', $user->email);
// Dọn dẹp
$user->delete();
}
/**
@@ -99,5 +115,14 @@ class CreateAccountTest extends DuskTestCase
$browser->visit('/login')
->assertInputValue('phone', $uniquePhone);
});
// Kiểm tra DB: user tồn tại và spined = 0 (chưa quay)
$user = User::where('phone', $uniquePhone)->first();
$this->assertNotNull($user, 'User phải tồn tại trong DB');
$this->assertEquals(0, $user->spined, 'Người dùng mới chưa được quay');
$this->assertEquals(1, $user->status, 'Tài khoản phải ở trạng thái active');
// Dọn dẹp
$user->delete();
}
}
+2 -1
View File
@@ -14,8 +14,9 @@ class ExampleTest extends DuskTestCase
public function test_basic_example(): void
{
$this->browse(function (Browser $browser) {
// Cả / và /game đều render view game (không redirect)
$browser->visit('/')
->assertPathIs('/game');
->assertPresent('#wheelCanvas');
});
}
}
+162 -10
View File
@@ -2,13 +2,15 @@
namespace Tests\Browser;
use App\Models\PrizeUser;
use App\Models\User;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class GamePageTest extends DuskTestCase
{
/**
* Trang game hiển thị đúng khi chưa đăng nhập.
* Trang game tải được khi chưa đăng nhập.
*/
public function test_game_page_loads_when_guest(): void
{
@@ -19,35 +21,185 @@ class GamePageTest extends DuskTestCase
}
/**
* Trang chủ (/) redirect về game.
* URL gốc (/) redirect về /game.
*/
public function test_root_redirects_to_game(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertPathIs('/game');
->assertPresent('#wheelCanvas'); // / và /game cùng render game
});
}
/**
* Trang game hiển thị vòng quay may mắn.
* Vòng quay (canvas) hiển thị trên trang game.
*/
public function test_game_page_shows_lucky_wheel(): void
public function test_game_page_shows_lucky_wheel_canvas(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/game')
->assertPresent('#wheel, canvas, .wheel, [id*="wheel"], [class*="wheel"]');
->assertPresent('#wheelCanvas');
});
}
/**
* Popup luật chơi có thể tải được.
* Nút quay hiển thị trên trang game.
*/
public function test_game_rule_endpoint_returns_content(): void
public function test_spin_button_is_present(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/game/rule')
->assertSee('luật');
$browser->visit('/game')
->assertPresent('#spinButton');
});
}
/**
* Banner "Thể lệ tham dự" hiển thị.
*/
public function test_game_rule_ribbon_is_present(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/game')
->assertPresent('#game_rule');
});
}
/**
* Khi guest vào /game, hiển thị thông báo yêu cầu đăng nhập.
*/
public function test_guest_sees_login_prompt_on_game(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/logout')
->visit('/game')
->assertPresent('.alert_wheel_spin')
->assertPresent('a[href*="login"]');
});
}
/**
* Khi đã đăng nhập và chưa quay, nút quay ở trạng thái sẵn sàng.
*/
public function test_logged_in_user_can_see_spin_button_enabled(): void
{
$phone = '09' . rand(10000000, 99999999);
$this->browse(function (Browser $browser) use ($phone) {
$browser->visit('/logout')
->visit('/login')
->pause(300)
->type('name', 'Spin Test User')
->type('phone', $phone)
->type('address', 'TP.HCM')
->radio('known_sis', '1')
->type('job', 'Kỹ sư')
->press('Gửi thông tin')
->waitForText('thành công', 10)
->assertPathIs('/game')
->assertAttribute('#spinButton', 'data-check', 'true');
});
User::where('phone', $phone)->delete();
}
/**
* Khi đã quay rồi (spined=1), nút quay bị khóa.
*/
public function test_already_spined_user_sees_spin_button_disabled(): void
{
$phone = '09' . rand(10000000, 99999999);
// Tạo user với spined=1
$user = User::create([
'name' => 'SPINED USER',
'phone' => $phone,
'email' => $phone . '@phone.local',
'password' => bcrypt('test123'),
'address' => 'Cần Thơ',
'known_sis' => 1,
'job' => 'Kỹ sư',
'status' => 1,
'spined' => 1,
]);
$this->browse(function (Browser $browser) use ($user) {
$browser->visit('/logout')
->loginAs($user)
->visit('/game')
->assertAttribute('#spinButton', 'data-check', 'false');
});
$user->delete();
}
/**
* Popup luật chơi tải nội dung.
*/
public function test_game_rule_popup_loads(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/logout')
->visit('/game')
->pause(500);
// Dismiss alerts che button rồi click bằng JS
$browser->script("document.querySelectorAll('.alert').forEach(el => el.remove())");
$browser->script("document.getElementById('game_rule').click()");
$browser->pause(800)
->assertPresent('#gamerule');
});
}
/**
* API /game/rule trả về nội dung HTML.
*/
public function test_game_rule_api_returns_html(): void
{
$this->browse(function (Browser $browser) {
// /game/rule được gọi qua AJAX, trả về fragment HTML không có <body>
$browser->visit('/game/rule')
->assertSourceHas('class='); // snippet HTML luon co class=
});
}
/**
* API /checkspined trả lỗi khi chưa đăng nhập.
*/
public function test_checkspined_returns_error_for_guest(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/logout')
->visit('/checkspined')
->assertSee('error');
});
}
/**
* API /checkspined trả spined=0 khi đăng nhập user mới.
*/
public function test_checkspined_returns_zero_for_new_user(): void
{
$phone = '09' . rand(10000000, 99999999);
$user = User::create([
'name' => 'CHECK SPINED USER',
'phone' => $phone,
'email' => $phone . '@phone.local',
'password' => bcrypt('test123'),
'address' => 'Cần Thơ',
'known_sis' => 0,
'job' => 'Sinh viên',
'status' => 1,
'spined' => 0,
]);
$this->browse(function (Browser $browser) use ($user) {
$browser->visit('/logout')
->loginAs($user)
->visit('/checkspined')
->assertSee('"spined":0');
});
$user->delete();
}
}