service = app(CreditWalletService::class); }); test('a credit raises the balance and writes a ledger row', function () { $user = User::factory()->create(); $tx = $this->service->credit($user, 20, CreditTransactionType::Topup, 'Paket 20'); expect($this->service->balance($user))->toBe(20); expect($tx->amount_credits)->toBe(20); expect($tx->balance_after)->toBe(20); expect($tx->type)->toBe(CreditTransactionType::Topup); }); test('a debit lowers the balance and records the balance after', function () { $user = User::factory()->create(); $this->service->credit($user, 20); $tx = $this->service->debit($user, 12, 'Extra-PM'); expect($this->service->balance($user))->toBe(8); expect($tx->amount_credits)->toBe(-12); expect($tx->balance_after)->toBe(8); expect($tx->type)->toBe(CreditTransactionType::Spend); }); test('debiting more than the balance throws and keeps the balance untouched', function () { $user = User::factory()->create(); $this->service->credit($user, 8); $threw = null; try { $this->service->debit($user, 15); } catch (InsufficientCreditsException $e) { $threw = $e; } expect($threw)->toBeInstanceOf(InsufficientCreditsException::class); expect($threw->shortfall())->toBe(7); expect($this->service->balance($user))->toBe(8); expect($user->creditTransactions()->count())->toBe(1); // nur die Aufladung }); test('balance is zero and canAfford is false without a wallet', function () { $user = User::factory()->create(); expect($this->service->balance($user))->toBe(0); expect($this->service->canAfford($user, 1))->toBeFalse(); }); test('a refund credits back a prior spend', function () { $user = User::factory()->create(); $this->service->credit($user, 30); $this->service->debit($user, 25, 'Depublizieren'); $this->service->credit($user, 25, CreditTransactionType::Refund, 'Widerruf Depublizieren'); expect($this->service->balance($user))->toBe(30); });