---
title: "Testovanie — Approvals for Laravel | Roundly"
description: "Approvals::fake() zaznamená každú operáciu na overenie, k tomu Pest expectations, testovací trait schvaľovateľa a factories pre každý model."
url: https://roundly-consulting.com/sk/open-source/navody/approvals-for-laravel/testovanie
language: sk
---

[Všetky balíky](https://roundly-consulting.com/sk/open-source.md)

[Approvals for Laravel](https://roundly-consulting.com/sk/open-source/navody/approvals-for-laravel.md)

# Testovanie

Pomocníci na testovanie vašej aplikácie sú v RoundlyConsulting\\Approvals\\Testing. Nepridávajú žiadnu runtime závislosť — Pest sa použije, až keď zavoláte registráciu.

## Approvals::fake()

Approvals::fake() podstrčí fasáde aj injektovaným manažérom ApprovalsFake, podtyp ApprovalsManager, a vráti ho. Je to zaznamenávajúci fake, ktorý operácie naďalej vykonáva: bežia voči vašej databáze ako zvyčajne a fake každú zaznamená — či prišla cez fasádu, injektovaný manažér, trait modelu ako $user->approve($post) alebo cez testovacích pomocníkov nižšie:

```php
use RoundlyConsulting\Approvals\Facades\Approvals;

it('approves the invoice', function (): void {
    $fake = Approvals::fake();

    $this->actingAs($cfo)->post("/invoices/{$invoice->id}/approve");

    $fake->assertApproved($invoice, by: $cfo);   // or Approvals::assertApproved(...)
    $fake->assertNothingRejected();
});
```

Každý assert zavoláte aj staticky na fasáde — Approvals::assertApproved($invoice, $cfo). Operácia, ktorá vyhodí výnimku, sa nezaznamená.

## Všetky overenia

| Assert | Prejde, keď | Opak |
| --- | --- | --- |
| `assertApproved($approvable, ?$by)` | sa zaznamenalo schválenie (od $by) | `assertNothingApproved()` |
| `assertRejected($approvable, ?$by)` | sa zaznamenalo zamietnutie | `assertNothingRejected()` |
| `assertAsked($approvable, ?$actor)` | sa cez ask() vyžiadalo čakajúce rozhodnutie | `assertNothingAsked()` |
| `assertCancelled($approvable, ?$by)` | prebehlo stiahnutie | `assertNothingCancelled()` |
| `assertToggled($approvable, ?$by)` | prebehlo prepnutie | `assertNothingToggled()` |
| `assertOpened($subject, ?$workflow)` | sa pre subjekt otvorila žiadosť (zo šablóny) | `assertNothingOpened()` |
| `assertDelegated($delegator, ?$to)` | sa udelilo delegovanie | `assertNothingDelegated()` |
| `assertRevoked($delegator, ?$delegate)` | prebehlo zrušenie — zrušenie všetkých nezaznamená zástupcu | `assertNothingRevoked()` |
| `assertExpired(?$count, ?$subjectType)` | prebehlo vypršanie (a spolu vypršalo $count rozhodnutí a žiadostí); s $subjectType sa rátajú len vypršania obmedzené na daný typ | `assertNothingExpired()` |
| `assertClosed($subject, ?$outcome)` | sa cez close() vyžiadalo uzavretie kola subjektu (ako $outcome); počíta sa aj uzavretie, ktoré nenašlo žiadne otvorené kolo | `assertNothingClosed()` |

```php
$fake = Approvals::fake();

// Decisions — the actor argument is optional
$fake->assertApproved($invoice, by: $cfo);
$fake->assertRejected($invoice, by: $auditor);
$fake->assertAsked($contract, $legal);
$fake->assertCancelled($contract, by: $legal);
$fake->assertToggled($post, by: $user);

// Requests — optionally from a named preset
$fake->assertOpened($release);
$fake->assertOpened($budget, 'payout');

// Delegation
$fake->assertDelegated($manager, to: $assistant);
$fake->assertRevoked($manager, $assistant);

// Expiry sweeps — a sweep ran, and lapsed 3 decisions and requests in total
$fake->assertExpired(3);
$fake->assertExpired(subjectType: Invoice::class);   // only sweeps scoped to invoices count

// Rounds your app closed — optionally with the outcome
$fake->assertClosed($purchase);
$fake->assertClosed($purchase, ApprovalStatus::Cancelled);

// Every assert has a negative twin
$fake->assertNothingApproved();
$fake->assertNothingRejected();
$fake->assertNothingAsked();
$fake->assertNothingCancelled();
$fake->assertNothingToggled();
$fake->assertNothingOpened();
$fake->assertNothingDelegated();
$fake->assertNothingRevoked();
$fake->assertNothingExpired();   // nothing lapsed
$fake->assertNothingClosed();
```

## Surový záznam

recorded(?ApprovalOperation) vráti zoznam RecordedApprovalOperation v poradí volaní — voliteľne len jeden druh operácie: Approve, Reject, Ask, Cancel, Toggle, Open, Delegate, Revoke, Expire alebo Close. Každý záznam nesie operáciu, jej kontextové modely a výsledok pre vlastné overenia:

```php
use RoundlyConsulting\Approvals\Enums\ApprovalOperation;

$opened = $fake->recorded(ApprovalOperation::Open);   // list<RecordedApprovalOperation>

$opened[0]->operation;                  // ApprovalOperation::Open
$opened[0]->context['workflow'];        // 'payout' or null
$opened[0]->model('subject');           // ?Model
$opened[0]->involves('subject', $budget);   // bool
$opened[0]->result;                     // the ApprovalRequest the call returned
```

Kontext rozhodnutia obsahuje because(), weight() a expiresIn() / expiringAt() z buildera tak, ako boli zadané — reason, weight a expires\_at, null, ak nastavené neboli — nie to, čo z nich akcia vypočítala (vlastnú váhu aktéra, predvolenú platnosť); skutočne zapísané schválenie nájdete v result. Uzavretie zaznamená subject, request a outcome a jeho result je počet uzavretých kôl. Na tieto hodnoty assert neexistuje — čítajte ich z recorded():

```php
use RoundlyConsulting\Approvals\Enums\ApprovalOperation;
use RoundlyConsulting\Approvals\Enums\ApprovalStatus;
use RoundlyConsulting\Approvals\Facades\Approvals;

it('closes the approval round when the purchase is cancelled', function (): void {
    $fake = Approvals::fake();

    $purchase->cancel();   // your code calls Approvals::for($purchase)->close()

    $fake->assertClosed($purchase, ApprovalStatus::Cancelled);
});

it('asks the director with a deadline', function (): void {
    $fake = Approvals::fake();

    $budget->escalate();   // your code calls ->because('Over limit')->expiresIn(86400)->ask()

    $ask = $fake->recorded(ApprovalOperation::Ask)[0]->context;

    expect($ask['reason'])->toBe('Over limit')
        ->and($ask['expires_at'])->not->toBeNull()
        ->and($ask['weight'])->toBeNull();
});
```

ApprovalOperation pribudol vo verzii 1.1.0 prípad Close — match nad ním bez vetvy default ho potrebuje doplniť.

## Pest expectations

Zaregistrujte ich raz v tests/Pest.php:

```php
// tests/Pest.php
use RoundlyConsulting\Approvals\Testing\ApprovalExpectations;

ApprovalExpectations::register();
```

- toBeApproved() — stav modelu je Approved.
- toBePendingApproval() — stav je Pending.
- toBeRejected() — stav je Rejected.

Stav sa berie z currentApprovalStatus(), ak model používa RequiresApproval; inak sa odvodí z platných rozhodnutí zapísaných k modelu — prednosť má akékoľvek zamietnutie, potom akékoľvek schválenie, inak pending.

## Konanie za schvaľovateľa

```php
use App\Models\Release;
use App\Models\User;
use RoundlyConsulting\Approvals\Testing\InteractsWithApprovals;

uses(InteractsWithApprovals::class);

it('approves a release once both reviewers sign off', function (): void {
    $release = Release::factory()->create();
    $lead = User::factory()->create();
    $qa = User::factory()->create();

    $release->requestApproval([$lead, $qa]);

    $this->actingAsApprover($lead)->approveAs($release);
    expect($release)->toBePendingApproval();

    $this->approveAs($release, 'Tests pass', $qa);
    expect($release)->toBeApproved();
});

it('rejects with a reason', function (): void {
    $release = Release::factory()->create();
    $reviewer = User::factory()->create();
    $release->requestApproval([$reviewer]);

    $this->rejectAs($release, 'needs work', $reviewer);

    expect($release)->toBeRejected();
});
```

approveAs() a rejectAs() prijímajú schvaľovaný model, voliteľný dôvod a voliteľného aktéra; bez zapamätaného či odovzdaného aktéra vyhodia RuntimeException. Prechádzajú cez ApprovalsManager, takže platí Gate, menovaní schvaľovatelia, delegovanie aj vyhodnotenie žiadosti — a Approvals::fake() ich zaznamená.

## Factories

```php
use RoundlyConsulting\Approvals\Models\Approval;
use RoundlyConsulting\Approvals\Models\ApprovalDelegation;
use RoundlyConsulting\Approvals\Models\ApprovalRequest;

Approval::factory()->pending()->forActor($user)->forApprovable($post)
    ->create(['expires_at' => now()->subHour()]);

Approval::factory()->approved()->weight(3)->delegated($assistant)->create();

ApprovalRequest::factory()->forSubject($release)->weighted(3)->create();

ApprovalDelegation::factory()->forDelegator($manager)->toDelegate($assistant)->create();
```

| Factory | Stavy |
| --- | --- |
| `ApprovalFactory` | pending(), approved(), rejected(), cancelled(), expired(), weight($n), delegated($decidedBy), forStage($stage), forActor($actor), forApprovable($approvable) |
| `ApprovalRequestFactory` | unanimous(), quorum($n), any(), weighted($threshold), staged(), forSubject($subject) |
| `ApprovalRequestStageFactory` | forRequest($request), atPosition($n), quorum($n), cleared(), pending() |
| `ApprovalDelegationFactory` | forDelegator($delegator), toDelegate($delegate), expired(), revoked() |

## Testy samotného balíka

Testy balíka spustíte z klonu repozitára:

```bash
composer test
```

## Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

[Ďalšie spôsoby podpory vrátane kryptomien](https://roundly-consulting.com/sk/podporte-nas.md)

Odoslaním daru súhlasíte s našimi [podmienkami prijímania darov](https://roundly-consulting.com/sk/podmienky-darov.md).

[Podporte našu open-source prácu (otvorí sa v novej karte)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Pridajte sa k nám na Patreone (otvorí sa v novej karte)](https://www.patreon.com/cw/roundly)

## Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.

[Ponuka do 48 hodín](https://roundly-consulting.com/sk/kontakt.md) [Prezrieť všetky balíky](https://roundly-consulting.com/sk/open-source/navody/approvals-for-laravel.md)
