create([ 'username' => 'draw_pages_admin', 'name' => 'Draw QA', 'email' => null, 'password' => Hash::make('secret-strong'), 'status' => 0, ]); return $admin->createToken('test', ['*'], now()->addDay())->plainTextToken; } test('admin draws index requires authentication', function (): void { $this->getJson('/api/v1/admin/draws')->assertUnauthorized(); }); test('admin draws index returns pagination', function (): void { Carbon::setTestNow(Carbon::parse('2026-05-09 12:00:00', 'UTC')); Draw::query()->create([ 'draw_no' => '20260509-001', 'business_date' => '2026-05-09', 'sequence_no' => 1, 'status' => 'pending', 'start_time' => now()->copy()->addHour(), 'close_time' => null, 'draw_time' => now()->copy()->addHours(2), 'cooling_end_time' => null, 'result_source' => null, 'current_result_version' => 0, 'settle_version' => 0, 'is_reopened' => false, ]); $token = mintAdminBearer(); $this->withHeader('Authorization', 'Bearer '.$token) ->getJson('/api/v1/admin/draws?per_page=5') ->assertOk() ->assertJsonPath('data.meta.total', 1) ->assertJsonPath('data.items.0.draw_no', '20260509-001'); Carbon::setTestNow(); }); test('admin draw show exposes hall preview status', function (): void { Carbon::setTestNow(Carbon::parse('2026-05-09 16:30:20', 'UTC')); $drawTime = Carbon::parse('2026-05-09 16:30:40', 'UTC'); $closeTime = $drawTime->copy()->subSeconds(30); $draw = Draw::query()->create([ 'draw_no' => '20260509-802', 'business_date' => '2026-05-09', 'sequence_no' => 802, 'status' => 'open', 'start_time' => $closeTime->copy()->subMinutes(5), 'close_time' => $closeTime, 'draw_time' => $drawTime, 'cooling_end_time' => null, 'result_source' => null, 'current_result_version' => 0, 'settle_version' => 0, 'is_reopened' => false, ]); $token = mintAdminBearer(); $this->withHeader('Authorization', 'Bearer '.$token) ->getJson('/api/v1/admin/draws/'.$draw->id) ->assertOk() ->assertJsonPath('data.draw_no', '20260509-802') ->assertJsonPath('data.status', 'open') ->assertJsonPath('data.hall_preview_status', 'closing'); Carbon::setTestNow(); }); test('admin draw result batches lists items', function (): void { Carbon::setTestNow(Carbon::parse('2026-05-09 16:10:00', 'UTC')); $draw = Draw::query()->create([ 'draw_no' => '20260509-400', 'business_date' => '2026-05-09', 'sequence_no' => 400, 'status' => 'cooldown', 'start_time' => now()->copy()->subHour(), 'close_time' => now()->copy()->subMinutes(40), 'draw_time' => now()->copy()->subMinutes(20), 'cooling_end_time' => now()->copy()->addMinutes(10), 'result_source' => 'rng', 'current_result_version' => 1, 'settle_version' => 0, 'is_reopened' => false, ]); $batch = DrawResultBatch::query()->create([ 'draw_id' => $draw->id, 'result_version' => 1, 'source_type' => 'rng', 'rng_seed_hash' => hash('sha256', 'x'), 'raw_seed_encrypted' => null, 'status' => DrawResultBatchStatus::Published->value, 'created_by' => null, 'confirmed_by' => null, 'confirmed_at' => now(), ]); DrawResultItem::query()->create([ 'draw_id' => $draw->id, 'result_batch_id' => $batch->id, 'prize_type' => 'first', 'prize_index' => 0, 'number_4d' => '1234', 'suffix_3d' => '234', 'suffix_2d' => '34', 'head_digit' => 1, 'tail_digit' => 4, ]); $token = mintAdminBearer(); $this->withHeader('Authorization', 'Bearer '.$token) ->getJson('/api/v1/admin/draws/'.$draw->id.'/result-batches') ->assertOk() ->assertJsonPath('data.draw_no', '20260509-400') ->assertJsonPath('data.batches.0.result_version', 1) ->assertJsonPath('data.batches.0.items.0.number_4d', '1234'); Carbon::setTestNow(); });