Testovanie
Events::fake() vymení manažéra za Testing\EventsFake a vráti ho:
use RoundlyConsulting\Events\Enums\RsvpStatus;
use RoundlyConsulting\Events\Facades\Events;
use RoundlyConsulting\Events\Models\Event;
it('lets a member join the meetup', function (): void {
$events = Events::fake();
$member = User::factory()->create();
$event = Event::factory()->published()->capacity(1)->create();
$this->actingAs($member)->post("/meetups/{$event->uuid}/join")->assertRedirect();
$events->assertRsvped($event, $member, RsvpStatus::Going);
$events->assertNothingCancelled();
expect($member)->toBeGoingTo($event);
});- Je to nahrávací fake, ktorý operácie aj tak vykoná: riadky, miesta, policies, doménové udalosti aj notifikácie sú skutočné, nech bola operácia zavolaná akokoľvek — cez fasádu, injektovaný EventsManager, handle, pod-handle, builder alebo trait modelu. Priame volanie triedy akcie sa nezaznamená.
- Vymení sa za fasádou aj v kontajneri, takže sa podvrhne aj injektovaný EventsManager.
- Volanie, ktoré vyhodí výnimku, nezaznamená nič, a rovnako ani to, ktoré vráti okolitá transakcia: v transakcii sa operácia zaznamená pri commite — mimo nej hneď, pričom transakcia RefreshDatabase vášho testu sa počíta ako mimo.
- Čítania sa nezaznamenávajú a kód pre check-in sa nezaznamená nikdy.
Asercie
Každá EventOperation má dvojicu asercií. ?$event, ?$attendee a ďalšie argumenty sú filtre a null znamená akýkoľvek. Každá asercia je aj na fasáde, takže funguje aj Events::assertRsvped(…):
| Operácia | Asercia | Negatívna |
|---|---|---|
| Create | assertCreated(?Closure) | assertNothingCreated() |
| Update | assertUpdated(?$event, ?array $keys) | assertNothingUpdated() |
| Delete · Restore | assertDeleted(?$event), assertRestored(?$event) | assertNothingDeleted(), assertNothingRestored() |
| Publish · Unpublish · Postpone · Reschedule · Cancel · Complete | assertPublished(?$event), assertUnpublished(), assertPostponed(), assertRescheduled(), assertCancelled(), assertCompleted() | assertNothingPublished(), assertNothingUnpublished(), assertNothingPostponed(), assertNothingRescheduled(), assertNothingCancelled(), assertNothingCompleted() |
| Transition | assertTransitioned(?$event, ?string $name) | assertNothingTransitioned() |
| MoveOnline | assertMovedOnline(?$event) | assertNothingMovedOnline() |
| TransferOrganizer | assertTransferred(?$event, ?Model $to) | assertNothingTransferred() |
| SetPoster | assertPosterChanged(?$event, ?bool $removed) | assertNoPosterChanged() |
| Categorize | assertCategorized(?$event, ?$category) | assertNothingCategorized() |
| AttachLabels · SyncLabels | assertLabelled(?$event, ?array $labels) | assertNothingLabelled() |
| DetachLabels | assertUnlabelled(?$event, ?array $labels) | assertNothingUnlabelled() |
| CreateVenue · UpdateVenue · DeleteVenue · RestoreVenue · GeocodeVenue | assertVenueCreated(?Closure), assertVenueUpdated(), assertVenueDeleted(), assertVenueRestored(), assertVenueGeocoded() | assertNoVenueCreated(), assertNoVenueUpdated(), assertNoVenueDeleted(), assertNoVenueRestored(), assertNoVenueGeocoded() |
| CreateTier · UpdateTier · DeleteTier · RestoreTier | assertTierCreated(?Closure), assertTierUpdated(), assertTierDeleted(), assertTierRestored() | assertNoTierCreated(), assertNoTierUpdated(), assertNoTierDeleted(), assertNoTierRestored() |
| ReorderTiers | assertTiersReordered(?$event) | assertNoTiersReordered() |
| Rsvp | assertRsvped(?$event, ?$attendee, ?RsvpStatus) | assertNothingRsvped() |
| AddAttendee · RemoveAttendee | assertAttendeeAdded(?$event, ?$attendee), assertAttendeeRemoved(?$event, ?$attendee) | assertNoAttendeeAdded(), assertNoAttendeeRemoved() |
| ChangeTier · ChangeGuests | assertTierChanged(?$event), assertGuestsChanged(?$event) | assertNoTierChanged(), assertNoGuestsChanged() |
| ConfirmRsvp · ReleaseHold · RequestPayment · RotateCode | assertRsvpConfirmed(?$event), assertHoldReleased(?$event), assertPaymentRequested(?$event), assertCodeRotated(?$event) | assertNoRsvpConfirmed(), assertNoHoldReleased(), assertNoPaymentRequested(), assertNoCodeRotated() |
| ConfirmPayment | assertPaymentConfirmed(?string $reference) | assertNoPaymentConfirmed() |
| PromoteWaitlist | assertPromoted(?$event) | assertNothingPromoted() |
| ForgetAttendee | assertAttendeeForgotten(?$attendee) | assertNoAttendeeForgotten() |
| CheckIn · ManualCheckIn | assertCheckedIn(?$event, ?$attendee) | assertNothingCheckedIn() |
| UndoCheckIn | assertCheckInUndone(?$event) | assertNoCheckInUndone() |
| AddCoHost · RemoveCoHost | assertCoHostAdded(?$event, ?$host), assertCoHostRemoved(?$event, ?$host) | assertNoCoHostAdded(), assertNoCoHostRemoved() |
| SendInvitation · RevokeInvitation | assertInvited(?$event, ?$invitee), assertInvitationRevoked(?$event, ?$invitee) | assertNothingInvited(), assertNoInvitationRevoked() |
| RespondToInvitation | assertInvitationAnswered(?$event, ?RsvpResponse) | assertNoInvitationAnswered() |
| Sweep · Repair | assertSwept(), assertRepaired() | assertNothingSwept(), assertNothingRepaired() |
| akákoľvek | assertPerformed(EventOperation, ?Closure) | assertNotPerformed(EventOperation) |
| — | assertNothingHappened() | — |
- Kľúče v assertUpdated() sú názvy vlastností UpdateEventData; closures pri miestach konania a typoch vstupeniek dostanú Venue alebo AdmissionTier.
- assertPromoted() znamená ručné posunutie, ktoré niekoho posunulo; automatické sa ukáže ako operácia, ktorá ho spustila — odmietnutie, sweep, zmena kapacity. assertNothingPromoted() prejde, keď sa nikto neposunul, aj po ručnom posunutí nad prázdnou listinou.
- assertAttendeeForgotten() je háčik AttendsEvents pri mazaní (trvalé zmazanie); assertCheckedIn() počíta prvé check-iny; assertInvitationAnswered() s RsvpResponse::NotGoing znamená odmietnutie.
Zaznamenané operácie
recorded(?EventOperation) vráti záznamy RecordedEventOperation v poradí volaní — operation, context a result, plus event(), concerns(?Event $event) a model(string $key):
use RoundlyConsulting\Events\Enums\EventOperation;
use RoundlyConsulting\Events\Testing\RecordedEventOperation;
$events->assertPerformed(EventOperation::Cancel, fn (RecordedEventOperation $op): bool => $op->context['reason'] === 'Venue flooded');
expect($events->recorded(EventOperation::Rsvp))->toHaveCount(2);Kľúče kontextu: event, actor, system a silent pri volaniach handle; data (DTO); reason, starts_at, ends_at, transition, keep_venue, force, removed; organizer, keep_as_host; labels, category; venue, tier, order, rsvp, attendee, guests, host, invitee, response, reference a options. EventOperation má 50 hodnôt, jednu na každý zaznamenaný zápis.
Pest očakávania
Zaregistrujte ich raz — automaticky sa neregistrujú. Každé číta uložené RSVP, takže fungujú s Events::fake() aj bez neho:
// tests/Pest.php
RoundlyConsulting\Events\Testing\EventExpectations::register();
expect($user)->toBeGoingTo($event);
expect($user)->toBeWaitlistedFor($event);
expect($user)->toBeCheckedInTo($event);Factories
use RoundlyConsulting\Events\Enums\RsvpStatus;
use RoundlyConsulting\Events\Facades\Events;
use RoundlyConsulting\Events\Models\AdmissionTier;
use RoundlyConsulting\Events\Models\Event;
use RoundlyConsulting\Events\Models\Rsvp;
use RoundlyConsulting\Events\Models\Venue;
use RoundlyConsulting\Money\Money;
Events::categories()->make('Jazz')->findOrCreate(); // categories are curated: create one before tagging
$venue = Venue::factory()->at(48.1439, 17.1097)->ownedBy($team)->create();
$event = Event::factory()->organizedBy($user)->at($venue)->capacity(60)->published()
->categorized('jazz')->labelled(['Live'])->create();
AdmissionTier::factory()->for($event)->key('supporter')->price(Money::ofMajor('15', 'EUR'))->create();
Rsvp::factory()->for($event)->by($member)->status(RsvpStatus::Waitlisted)->create(); // a row, no seats or counters| Factory | Stavy |
|---|---|
Event::factory() | organizedBy(), at(), online(), startingAt(CarbonImmutable $start, int $hours = 2), capacity(), maxGuests(), unlisted(), private(), withoutWaitlist(), published(), postponed(), rescheduled(), cancelled(), completed(), inPhase(EventPhase $phase, ?string $stamp = null), categorized(string), labelled(array) |
Venue::factory() | withoutCoordinates(), at(float $latitude, float $longitude), ownedBy(Model $owner) |
AdmissionTier::factory() | key(string), price(Money), capacity(?int), hidden() |
Rsvp::factory() | by(Model $attendee), status(RsvpStatus) |
EventHost::factory() · EventInvitation::factory() | host(Model) · invitee(Model), status(InvitationStatus) |
ReminderDelivery::factory() | — |
Stavy factories zapisujú riadky priamo — bez miest, počítadiel, kódov a notifikácií —, takže keď test potrebuje skutočné účinky, použite fasádu. Factories vymeniteľných modelov vytvárajú vašu nakonfigurovanú podtriedu.
Fasáda Event z Laravelu a fake z lifecycle
use Illuminate\Support\Facades\Event as EventBus;
use RoundlyConsulting\Events\Events\EventPublished;
EventBus::fake([EventPublished::class]); // fake only what you assert — the lifecycle bridge keeps working
// never EventBus::fake() bare, and never Lifecycles::fake() in an events test- Vlastné účinky balíka bežia na udalostiach lifecycle a vlastných doménových udalostiach. Podvrhujte len udalosti, ktoré overujete: Event::fake([EventPublished::class]) ponechá prepojenie s lifecycle aj dôsledky zrušenia funkčné, kým holé Event::fake() umlčí každý listener — žiadne zvýšenie SEQUENCE, žiadne uvoľnené rezervácie, žiadne notifikácie.
- Events::fake() ani žiadny test podujatí nikdy nekombinujte s Lifecycles::fake(): fake z lifecycle neuloží žiadny prechod, takže stavy sa nikdy nezmenia.
- Notifikácie overujte cez Notification::fake().
Čas a platby
use Carbon\CarbonImmutable;
CarbonImmutable::setTestNow('2026-11-14 18:30:00'); // RSVP and check-in windows, holds, reminders, completion
config(['events.payments.collector' => FakeCollector::class]); // your test double for paid ticket typesZmrazte hodiny: okná RSVP, okná check-inu, rezervácie, pripomienky aj automatické ukončenie z nich čítajú a miestne časy sa čítajú v pásme podujatia. Collector platieb sa volá po commite — vo vašej testovacej transakcii alebo v transakcii aplikácie beží, keď sa táto transakcia potvrdí.
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 kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
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.