tenant = Tenant::factory()->create(); $this->user = User::factory()->create(['tenant_id' => $this->tenant->id]); $this->actingAs($this->user); }); it('отдаёт движения кошелька, свежие сверху', function () { AdWallet::create(['tenant_id' => $this->tenant->id, 'balance_rub' => '0.00', 'frozen_rub' => '0.00']); $svc = app(AdWalletService::class); $svc->topup($this->tenant->id, '10000.00', 'yandex', 'Пополнение по счёту №12'); $svc->freeze($this->tenant->id, 'yandex', 'campaign', 6, '3333.36'); $svc->release($this->tenant->id, 'yandex', 'campaign', 6); $response = $this->getJson('/api/advertising/wallet/transactions'); $response->assertOk(); $items = $response->json('items'); expect($items)->toHaveCount(3); // Свежие сверху — клиент читает историю сверху вниз. expect($items[0]['type'])->toBe('release') ->and($items[1]['type'])->toBe('freeze') ->and($items[2]['type'])->toBe('topup'); expect($items[1]['amount_rub'])->toBe('-3333.36') ->and($items[1]['description'])->toContain('6') ->and($items[0]['amount_rub'])->toBe('3333.36'); // Каждое движение подписано человеческими словами, а не кодом типа. expect($items[1])->toHaveKey('title') ->and($items[1]['title'])->not->toBe('freeze'); }); it('чужие движения не отдаёт', function () { $chuzhoy = Tenant::factory()->create(); AdWallet::create(['tenant_id' => $chuzhoy->id, 'balance_rub' => '0.00', 'frozen_rub' => '0.00']); app(AdWalletService::class)->topup($chuzhoy->id, '99999.00', 'yandex', 'Чужое пополнение'); $response = $this->getJson('/api/advertising/wallet/transactions'); $response->assertOk(); expect($response->json('items'))->toBe([]); }); it('пустая история — пустой список, а не ошибка', function () { $this->getJson('/api/advertising/wallet/transactions') ->assertOk() ->assertJson(['items' => []]); }); it('без входа не отдаёт ничего', function () { auth()->logout(); $this->getJson('/api/advertising/wallet/transactions')->assertStatus(401); });