fix dashboard and apis
PHP Tests / php-tests (push) Failing after 9m1s

This commit is contained in:
Nyan Lin Paing
2026-08-16 23:50:39 +07:00
parent 60413bdebf
commit 8d74ac74cd
26 changed files with 638 additions and 55 deletions
@@ -1,6 +1,7 @@
<?php
use App\Models\User;
use Modules\Booking\Enums\BookingChannel;
use Modules\Booking\Enums\BookingStatus;
use Modules\Booking\Models\Booking;
use Modules\Catalog\Models\DepartureTimeSlot;
@@ -176,3 +177,47 @@ test('shape validation rejects an empty selections array', function () {
->assertStatus(422)
->assertJsonValidationErrors(['selections']);
});
test('created_by_channel defaults to kbz_miniapp when no Device-Type header is sent', function () {
[$route, $timeSlot] = bookableRouteAndSlot([[VehicleOption::BackSeat, '15000.00']]);
$this->withHeader('Authorization', "Bearer {$this->token}")
->postJson('/api/v1/bookings', bookingPayload($route, $timeSlot, [
['vehicle_option' => 'back_seat', 'passenger_count' => 1],
]))
->assertCreated()
->assertJsonPath('data.created_by_channel', BookingChannel::MiniApp->value);
});
test('created_by_channel is taken from the Device-Type header', function (string $deviceType, BookingChannel $expected) {
[$route, $timeSlot] = bookableRouteAndSlot([[VehicleOption::BackSeat, '15000.00']]);
$this->withHeader('Authorization', "Bearer {$this->token}")
->withHeader('Device-Type', $deviceType)
->postJson('/api/v1/bookings', bookingPayload($route, $timeSlot, [
['vehicle_option' => 'back_seat', 'passenger_count' => 1],
]))
->assertCreated()
->assertJsonPath('data.created_by_channel', $expected->value);
})->with([
'android' => ['android', BookingChannel::Android],
'ios' => ['ios', BookingChannel::Ios],
'web' => ['web', BookingChannel::Web],
'kbz_miniapp' => ['kbz_miniapp', BookingChannel::MiniApp],
]);
test('a Device-Type header cannot spoof the agent or admin channel', function (string $deviceType) {
[$route, $timeSlot] = bookableRouteAndSlot([[VehicleOption::BackSeat, '15000.00']]);
$this->withHeader('Authorization', "Bearer {$this->token}")
->withHeader('Device-Type', $deviceType)
->postJson('/api/v1/bookings', bookingPayload($route, $timeSlot, [
['vehicle_option' => 'back_seat', 'passenger_count' => 1],
]))
->assertCreated()
->assertJsonPath('data.created_by_channel', BookingChannel::MiniApp->value);
})->with([
'agent' => ['agent'],
'admin' => ['admin'],
'unrecognized value' => ['smart-fridge'],
]);
@@ -0,0 +1,86 @@
<?php
use Firebase\JWT\JWT;
use Modules\Booking\Enums\BookingChannel;
use Modules\Booking\Models\Booking;
use Modules\Catalog\Models\DepartureTimeSlot;
use Modules\Routing\Models\EvRoute;
use Modules\Routing\Models\RoutePricing;
use Modules\Shared\Enums\VehicleOption;
beforeEach(function () {
config(['services.fastapi_agent.jwt_secret' => 'test-fastapi-agent-secret-0123456789ABCDEF']);
config(['services.fastapi_agent.jwt_algorithm' => 'HS256']);
});
function fastApiAgentToken(string $openid): string
{
return JWT::encode([
'sub' => $openid,
'iat' => time(),
'exp' => time() + 3600,
], 'test-fastapi-agent-secret-0123456789ABCDEF', 'HS256');
}
test('a FastAPI JWT booking is stored against the verified openid, ignoring a spoofed body value', function () {
config(['booking.back_seat_enabled' => true]);
$route = EvRoute::factory()->create(['is_active' => true]);
$timeSlot = DepartureTimeSlot::factory()->create();
$route->timeSlots()->attach($timeSlot->id, ['is_active' => true]);
RoutePricing::factory()->create([
'ev_route_id' => $route->id,
'vehicle_option' => VehicleOption::BackSeat,
'price' => '15000.00',
]);
$token = fastApiAgentToken('real-customer-openid');
$this->withHeader('Authorization', "Bearer {$token}")
->withHeader('Device-Type', 'android') // the agent's own channel always wins, ignored here.
->postJson('/api/v1/bookings', [
'ev_route_id' => $route->id,
'departure_time_slot_id' => $timeSlot->id,
'travel_date' => now()->addDay()->toDateString(),
'selections' => [['vehicle_option' => 'back_seat', 'passenger_count' => 1]],
'passenger_name' => 'Jane Doe',
'passenger_phone' => '+959123456789',
'pickup_address' => '123 Pickup St',
'dropoff_address' => '456 Dropoff Ave',
'openid' => 'spoofed-openid',
])
->assertCreated();
$booking = Booking::sole();
expect($booking->openid)->toBe('real-customer-openid')
->and($booking->user_id)->toBeNull()
->and($booking->created_by_channel)->toBe(BookingChannel::Agent);
});
test('a FastAPI JWT can list and show only its own openid\'s bookings', function () {
$mine = Booking::factory()->create(['openid' => 'agent-openid-mine']);
Booking::factory()->create(['openid' => 'agent-openid-someone-else']);
$token = fastApiAgentToken('agent-openid-mine');
$this->withHeader('Authorization', "Bearer {$token}")
->getJson('/api/v1/bookings')
->assertSuccessful()
->assertJsonCount(1, 'data')
->assertJsonPath('data.0.id', $mine->id);
$this->withHeader('Authorization', "Bearer {$token}")
->getJson("/api/v1/bookings/{$mine->booking_ref}")
->assertSuccessful()
->assertJsonPath('data.id', $mine->id);
});
test('a FastAPI JWT gets a 404 for a booking belonging to a different openid', function () {
$someoneElses = Booking::factory()->create(['openid' => 'agent-openid-someone-else']);
$token = fastApiAgentToken('agent-openid-mine');
$this->withHeader('Authorization', "Bearer {$token}")
->getJson("/api/v1/bookings/{$someoneElses->booking_ref}")
->assertNotFound();
});