admin = User::factory()->create()->givePermissionTo(['view_bookings', 'manage_bookings', 'process_refunds']); $this->actingAs($this->admin); }); test('can list bookings', function () { $bookings = Booking::factory()->count(3)->create(); Livewire::test(ListBookings::class) ->assertOk() ->assertCanSeeTableRecords($bookings); }); test('can filter bookings by status', function () { $pending = Booking::factory()->create(['status' => BookingStatus::PendingPayment]); $confirmed = Booking::factory()->create(['status' => BookingStatus::Confirmed]); Livewire::test(ListBookings::class) ->filterTable('status', BookingStatus::PendingPayment->value) ->assertCanSeeTableRecords([$pending]) ->assertCanNotSeeTableRecords([$confirmed]); }); test('the cancel action is visible and enabled for a pending_payment booking', function () { $booking = Booking::factory()->create(['status' => BookingStatus::PendingPayment]); Livewire::test(ListBookings::class) ->assertTableActionVisible('cancel', $booking) ->assertTableActionEnabled('cancel', $booking); }); test('the cancel action is visible but disabled for a confirmed booking', function () { $booking = Booking::factory()->create(['status' => BookingStatus::Confirmed]); Livewire::test(ListBookings::class) ->assertTableActionVisible('cancel', $booking) ->assertTableActionDisabled('cancel', $booking); }); test('the cancel action is hidden from a user without manage_bookings and not the owner', function () { $stranger = User::factory()->create(); $this->actingAs($stranger); $booking = Booking::factory()->create(['user_id' => User::factory()->create()->id, 'status' => BookingStatus::PendingPayment]); Livewire::test(ListBookings::class) ->assertTableActionHidden('cancel', $booking); }); test('calling the cancel action cancels a pending_payment booking', function () { $booking = Booking::factory()->create(['status' => BookingStatus::PendingPayment]); Livewire::test(ListBookings::class) ->callTableAction('cancel', $booking) ->assertNotified(); expect($booking->refresh()->status)->toBe(BookingStatus::Cancelled); }); test('the view action is visible for a user with view_bookings', function () { $booking = Booking::factory()->create(); Livewire::test(ListBookings::class) ->assertTableActionVisible('view', $booking); }); test('the view action is hidden from a non-owner without view_bookings', function () { $stranger = User::factory()->create(); $this->actingAs($stranger); $booking = Booking::factory()->create(['user_id' => User::factory()->create()->id]); Livewire::test(ListBookings::class) ->assertTableActionHidden('view', $booking); }); test('can view a booking\'s detail page', function () { $booking = Booking::factory()->create([ 'passenger_name' => 'Jane Doe', 'passenger_phone' => '+959123456789', ]); BookingVehicleOption::factory()->create([ 'booking_id' => $booking->id, 'vehicle_option' => VehicleOption::BackSeat, 'passenger_count' => 2, 'unit_price' => 9000, 'line_total' => 18000, ]); Livewire::test(ViewBooking::class, ['record' => $booking->getRouteKey()]) ->assertOk() ->assertSee($booking->booking_ref) ->assertSee('Jane Doe') ->assertSee('+959123456789') ->assertSee($booking->route->company->name) ->assertSee($booking->pickup_address) ->assertSee($booking->dropoff_address); }); test('the booking detail page shows its related payments', function () { $booking = Booking::factory()->create(); Payment::factory()->completed()->create([ 'booking_id' => $booking->id, 'gateway' => PaymentMethod::KbzMiniApp, 'gateway_transaction_id' => 'EVB-INFOLIST-TEST-1', ]); Livewire::test(ViewBooking::class, ['record' => $booking->getRouteKey()]) ->assertOk() ->assertSee('EVB-INFOLIST-TEST-1') ->assertSee(PaymentStatus::Completed->value); }); test('the booking detail page shows a placeholder when there are no payments yet', function () { $booking = Booking::factory()->create(); Livewire::test(ViewBooking::class, ['record' => $booking->getRouteKey()]) ->assertOk() ->assertSee('No payment attempts yet.'); }); test('the assign driver action is visible for a confirmed booking and hidden otherwise', function () { $confirmed = Booking::factory()->create(['status' => BookingStatus::Confirmed]); $pending = Booking::factory()->create(['status' => BookingStatus::PendingPayment]); Livewire::test(ListBookings::class) ->assertTableActionVisible('assignDriver', $confirmed) ->assertTableActionHidden('assignDriver', $pending); }); test('the assign driver action is hidden from a user without manage_bookings', function () { $viewer = User::factory()->create()->givePermissionTo('view_bookings'); $this->actingAs($viewer); $booking = Booking::factory()->create(['status' => BookingStatus::Confirmed]); Livewire::test(ListBookings::class) ->assertTableActionHidden('assignDriver', $booking); }); test('calling the assign driver action sets driver and car details on a confirmed booking', function () { $booking = Booking::factory()->create(['status' => BookingStatus::Confirmed]); Livewire::test(ListBookings::class) ->callTableAction('assignDriver', $booking, data: [ 'driver_name' => 'U Aung', 'driver_phone' => '+959111222333', 'car_plate_number' => 'YGN-1234', 'car_model' => 'Tesla Model Y', ]) ->assertNotified(); $booking->refresh(); expect($booking->driver_name)->toBe('U Aung') ->and($booking->driver_phone)->toBe('+959111222333') ->and($booking->car_plate_number)->toBe('YGN-1234') ->and($booking->car_model)->toBe('Tesla Model Y'); }); test('the assign driver form requires driver_name, driver_phone, and car_plate_number', function () { $booking = Booking::factory()->create(['status' => BookingStatus::Confirmed]); Livewire::test(ListBookings::class) ->callTableAction('assignDriver', $booking, data: [ 'driver_name' => '', 'driver_phone' => '', 'car_plate_number' => '', ]) ->assertHasTableActionErrors(['driver_name' => 'required', 'driver_phone' => 'required', 'car_plate_number' => 'required']); expect($booking->refresh()->driver_name)->toBeNull(); }); test('the assign driver form is pre-filled with the booking\'s existing driver/car details', function () { $booking = Booking::factory()->create([ 'status' => BookingStatus::Confirmed, 'driver_name' => 'U Aung', 'driver_phone' => '+959111222333', 'car_plate_number' => 'YGN-1234', 'car_model' => 'Tesla Model Y', ]); Livewire::test(ListBookings::class) ->mountTableAction('assignDriver', $booking) ->assertTableActionDataSet([ 'driver_name' => 'U Aung', 'driver_phone' => '+959111222333', 'car_plate_number' => 'YGN-1234', 'car_model' => 'Tesla Model Y', ]); }); test('the detail page also has assign driver and cancel actions, shared with the table', function () { $confirmed = Booking::factory()->create(['status' => BookingStatus::Confirmed]); Livewire::test(ViewBooking::class, ['record' => $confirmed->getRouteKey()]) ->assertActionVisible('assignDriver') ->assertActionVisible('cancel') ->assertActionDisabled('cancel'); }); test('calling assign driver from the detail page sets driver and car details', function () { $booking = Booking::factory()->create(['status' => BookingStatus::Confirmed]); Livewire::test(ViewBooking::class, ['record' => $booking->getRouteKey()]) ->callAction('assignDriver', data: [ 'driver_name' => 'U Aung', 'driver_phone' => '+959111222333', 'car_plate_number' => 'YGN-1234', 'car_model' => 'Tesla Model Y', ]) ->assertNotified(); expect($booking->refresh()->driver_name)->toBe('U Aung'); }); test('the detail page\'s assign driver action is hidden for a pending_payment booking', function () { $pending = Booking::factory()->create(['status' => BookingStatus::PendingPayment]); Livewire::test(ViewBooking::class, ['record' => $pending->getRouteKey()]) ->assertActionHidden('assignDriver') ->assertActionEnabled('cancel'); }); test('the delete action is hidden for a pending_payment or confirmed booking, even with manage_bookings', function () { $pending = Booking::factory()->create(['status' => BookingStatus::PendingPayment]); $confirmed = Booking::factory()->create(['status' => BookingStatus::Confirmed]); // authorize('delete') ties visibility straight to BookingPolicy::delete // (status + permission combined) — a non-terminal booking never shows // this button at all, rather than a dead disabled one. Livewire::test(ListBookings::class) ->assertTableActionHidden('delete', $pending) ->assertTableActionHidden('delete', $confirmed); }); test('the delete action is visible and enabled for a cancelled or expired booking', function () { $cancelled = Booking::factory()->create(['status' => BookingStatus::Cancelled]); $expired = Booking::factory()->create(['status' => BookingStatus::Expired]); Livewire::test(ListBookings::class) ->assertTableActionVisible('delete', $cancelled) ->assertTableActionEnabled('delete', $cancelled) ->assertTableActionVisible('delete', $expired) ->assertTableActionEnabled('delete', $expired); }); test('the delete action is hidden from a user without manage_bookings', function () { $stranger = User::factory()->create(); $booking = Booking::factory()->create(['status' => BookingStatus::Cancelled]); $this->actingAs($stranger); Livewire::test(ListBookings::class) ->assertTableActionHidden('delete', $booking); }); test('deleting a cancelled booking soft-deletes it', function () { $booking = Booking::factory()->create(['status' => BookingStatus::Cancelled]); Livewire::test(ListBookings::class) ->callTableAction('delete', $booking) ->assertSuccessful(); expect(Booking::find($booking->id))->toBeNull(); expect(Booking::withTrashed()->find($booking->id))->not->toBeNull(); expect(Booking::withTrashed()->find($booking->id)->trashed())->toBeTrue(); }); test('a soft-deleted booking is hidden from the default list but visible via the trashed filter', function () { $active = Booking::factory()->create(); $deleted = Booking::factory()->create(); $deleted->delete(); Livewire::test(ListBookings::class) ->assertCanSeeTableRecords([$active]) ->assertCanNotSeeTableRecords([$deleted]) ->filterTable('trashed', true) ->assertCanSeeTableRecords([$active, $deleted]); }); test('the restore action is only visible for a trashed booking', function () { $active = Booking::factory()->create(); $deleted = Booking::factory()->create(); $deleted->delete(); Livewire::test(ListBookings::class) ->filterTable('trashed', true) ->assertTableActionHidden('restore', $active) ->assertTableActionVisible('restore', $deleted); }); test('restoring a deleted booking brings it back', function () { $booking = Booking::factory()->create(); $booking->delete(); Livewire::test(ListBookings::class) ->filterTable('trashed', true) ->callTableAction('restore', $booking) ->assertSuccessful(); expect(Booking::find($booking->id))->not->toBeNull(); expect(Booking::find($booking->id)->trashed())->toBeFalse(); }); test('the restore action is hidden from a user without manage_bookings', function () { $stranger = User::factory()->create(); $booking = Booking::factory()->create(); $booking->delete(); $this->actingAs($stranger); Livewire::test(ListBookings::class) ->filterTable('trashed', true) ->assertTableActionHidden('restore', $booking); });