'reverb']); $this->seed(CurrencySeeder::class); }); test('wallet balance notifier dispatches balance update broadcast', function (): void { Event::fake([BalanceUpdateBroadcast::class]); $player = Player::query()->create([ 'site_code' => 'test', 'site_player_id' => 'ws-p1', 'username' => null, 'nickname' => null, 'default_currency' => 'NPR', 'status' => 0, ]); $wallet = PlayerWallet::query()->create([ 'player_id' => $player->id, 'wallet_type' => 'lottery', 'currency_code' => 'NPR', 'balance' => 10_000, 'frozen_balance' => 0, 'status' => 0, 'version' => 0, ]); app(WalletBalanceRealtimeNotifier::class)->notifyAfterMovement($wallet, -500, 'bet_deduct'); Event::assertDispatched( BalanceUpdateBroadcast::class, fn (BalanceUpdateBroadcast $event): bool => $event->playerId === $player->id && $event->currencyCode === 'NPR' && $event->balanceMinor === 10_000 && $event->changeMinor === -500 && $event->reason === 'bet', ); }); test('risk pool acquire dispatches warning and sold out broadcasts', function (): void { Event::fake([RiskWarningBroadcast::class, RiskSoldOutBroadcast::class]); $draw = Draw::query()->create([ 'draw_no' => '20260526-001', 'business_date' => '2026-05-26', 'sequence_no' => 1, 'status' => 'open', 'start_time' => now()->subHour(), 'close_time' => now()->addHour(), 'draw_time' => now()->addHours(2), 'cooling_end_time' => null, 'result_source' => null, 'current_result_version' => 0, 'settle_version' => 0, 'is_reopened' => false, ]); RiskPool::query()->create([ 'draw_id' => $draw->id, 'normalized_number' => '1234', 'total_cap_amount' => 1000, 'locked_amount' => 750, 'remaining_amount' => 250, 'sold_out_status' => 0, 'version' => 0, ]); app(RiskPoolService::class)->acquire($draw->id, null, [ ['number_4d' => '1234', 'amount' => 250], ]); Event::assertDispatched( RiskWarningBroadcast::class, fn (RiskWarningBroadcast $event): bool => $event->drawId === $draw->id && $event->drawNo === '20260526-001' && $event->normalizedNumber === '1234', ); Event::assertDispatched( RiskSoldOutBroadcast::class, fn (RiskSoldOutBroadcast $event): bool => $event->drawId === $draw->id && $event->normalizedNumber === '1234', ); }); test('risk cap publish dispatches play catalog updated broadcast', function (): void { Event::fake([PlayCatalogUpdatedBroadcast::class]); $admin = \App\Models\AdminUser::query()->create([ 'username' => 'risk_cap_admin', 'name' => 'Risk Cap QA', 'email' => null, 'password' => \Illuminate\Support\Facades\Hash::make('secret-strong'), 'status' => 0, ]); grantSuperAdminRole($admin); $draft = app(RiskCapStreamService::class)->createDraft($admin, 'test', null); app(RiskCapStreamService::class)->replaceItems($draft, [ [ 'normalized_number' => '1234', 'cap_amount' => 1_000_000, 'cap_type' => 'default', ], ], $admin); app(RiskCapStreamService::class)->publish($draft, $admin); Event::assertDispatched(PlayCatalogUpdatedBroadcast::class); }); test('transfer in dispatches balance update after success', function (): void { Event::fake([BalanceUpdateBroadcast::class]); $player = Player::query()->create([ 'site_code' => 'test', 'site_player_id' => 'ws-p2', 'username' => null, 'nickname' => null, 'default_currency' => 'NPR', 'status' => 0, ]); PlayerWallet::query()->create([ 'player_id' => $player->id, 'wallet_type' => 'lottery', 'currency_code' => 'NPR', 'balance' => 0, 'frozen_balance' => 0, 'status' => 0, 'version' => 0, ]); app(LotteryTransferService::class)->transferIn($player, 'NPR', 500, 'idem-ws-'.uniqid('', true)); Event::assertDispatched(BalanceUpdateBroadcast::class); });