Testovanie
Notifications::fake() vymení manažéra za NotificationsFake za fasádou aj v kontajneri a vráti ho:
use RoundlyConsulting\Notifications\Facades\Notifications;
it('asks the approvers', function (): void {
$notifications = Notifications::fake(); // record-only: nothing is written, nothing is mailed
$request = PurchaseRequest::factory()->create();
$this->actingAs($request->author)->post("/requests/{$request->id}/submit")->assertRedirect();
$notifications->assertSent('request.awaiting_approval', to: $approver, about: $request);
$notifications->assertNotSent('security.alert');
});- Len zaznamenáva: každé meniace volanie — odoslania (aj cez type()->…->send(), for()->send() a sendNotification()), zmeny schránky, zápisy preferencií, schedule / sync / remind / cancel / acknowledge pripomienok, revoke, sweepy, prune, kanál inbox aj volania cez traity modelov — sa zaznamená a nevykoná. Odoslanie pod fake vráti prázdny SendResult.
- Čítanie (inbox()->paginate(), types(), preferences()->matrix()) ide do skutočného úložiska a registrácia druhov prebehne normálne.
- Vyhodnotenie príjemcov stále beží, takže assertSent(to: $user) funguje aj s Recipients::role(). Kontroly prístupu, preferencie, tiché hodiny ani deduplikácia nebežia: asercia dokazuje zámer upozorniť, nie doručenie.
- NotificationsFake rozširuje manažéra, takže aj injektovaný NotificationsManager je fake a prejde typovou kontrolou. Priame volanie akcie sa nezaznamená.
- Interop listener fake nikdy nezaznamená ani nezablokuje.
- ->passthrough() zaznamená a zároveň vykoná každú operáciu.
Asercie
Každá asercia je na fake a fasáda ju preposiela:
| Asercia | Prejde, keď |
|---|---|
assertSent($type, to: ?Model|Closure, about: ?Model, times: ?int) | Bolo zaznamenané odoslanie druhu (príjemcovi, o subjekte; presne times-krát). Closure v to dostane každého vyhodnoteného príjemcu. |
assertNotSent($type) · assertNothingSent() | Žiadne odoslanie druhu / žiadne odoslanie vôbec. |
assertMarkedRead(?Model $recipient) | markRead() alebo markAllRead(). |
assertArchived(?Model $recipient) | archive(). |
assertPreferenceSet($user, $type, Channel $channel, bool $enabled) | mute, unmute alebo set daného kanála na danú hodnotu. |
assertMuted($user, $type) | E-mail druhu bol stlmený. |
assertPreferencesUpdated($user, ?Closure $where) | preferences($user)->update(); $where(PreferencesUpdate): bool ho zúži. |
assertRemindersSynced($subject) | Vrátane synchronizácie, ktorú HasNotificationReminders spustí pri uložení. |
assertReminderScheduled($subject, $type) | schedule() alebo remind(). |
assertRemindersCancelled($subject) | cancel(). |
assertAcknowledged($subject, ?$type) | acknowledge(). |
assertRevoked($subject, ?Model $recipient) | revoke(). |
assertSwept() | sweep() alebo notifications:sweep. |
$fake = Notifications::fake();
$fake->assertSent('comment.posted', to: fn (User $user): bool => $user->is_admin, times: 2);
$fake->assertMarkedRead($user);
$fake->assertPreferencesUpdated($user, fn (PreferencesUpdate $update): bool => isset($update->channels['comment.posted']));
$fake->assertRemindersSynced($contract); // also the sync HasNotificationReminders runs on save
$fake->assertAcknowledged($contract, 'contract.expiring');
$fake->assertRevoked($request, $formerMember);
$fake->assertSwept();
// The facade forwards every assertion too
Notifications::assertNothingSent();
// Record and still run
Notifications::fake()->passthrough();Zaznamenané operácie
$fake->recorded(?NotificationOperation $operation = null) vráti záznamy RecordedOperation v poradí volaní — operation, context (argumenty volania), vyhodnotených príjemcov odoslania, type a subject:
use RoundlyConsulting\Notifications\Enums\NotificationOperation;
foreach ($fake->recorded(NotificationOperation::Send) as $send) {
$send->operation; // NotificationOperation::Send
$send->type; // 'request.awaiting_approval'
$send->subject; // the subject model
$send->recipients; // list<Model> — the resolved recipients
$send->context; // the call's arguments
}Pest expectations
Registrujú sa automaticky cez Pest plugin balíka a čítajú databázu:
| Expectation | Prejde, keď |
|---|---|
toHaveUnreadInboxItems(int $count) | Presne toľko neprečítaných, nearchivovaných položiek. |
toHaveInboxItem(string $type, ?Model $subject = null) | Položka daného druhu (o subjekte). |
toHaveMuted(string $type) | E-mail druhu je pre používateľa vypnutý. |
expect($user)->toHaveUnreadInboxItems(1);
expect($user)->toHaveInboxItem('request.awaiting_approval', $request);
expect($user)->toHaveMuted('comment.posted');
// Where Pest plugin discovery is off
RoundlyConsulting\Notifications\Testing\NotificationExpectations::register();Skutočný postup s Notification::fake()
Ak chcete overiť doručenie, spustite skutočný postup a fake použite na notifikácie Laravelu. Súhrny prichádzajú ako DigestMailNotification. Pri tichých hodinách, súhrnoch a pripomienkach zmrazte čas a splatné veci uvoľnite cez Notifications::sweep():
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Notification;
use RoundlyConsulting\Notifications\Mail\TypedMailNotification;
Notification::fake();
Notifications::send('security.alert', null, $user);
Notification::assertSentTo($user, TypedMailNotification::class, fn ($n) => $n->type === 'security.alert');
expect($user)->toHaveUnreadInboxItems(1);
// Quiet hours, digests and reminders: freeze time, then release what is due
Carbon::setTestNow('2026-11-10 07:01');
Notifications::sweep();Notification::fake() nespúšťa NotificationSending, takže pod ním interop nebeží.
Factories
Každý model má factory, ktorá rešpektuje vymenený model:
InboxItem::factory()->recipient($user)->read()->create();
NotificationDelivery::factory()->recipient($user)->status(DeliveryStatus::Held)->create();
NotificationReminder::factory()->subject($contract)->create();
DigestRun::factory()->recipient($user)->create();
NotificationReceipt::factory()->create();Testovanie aplikácie
- Publikujte obe sady migrácií (notifications aj options) — RefreshDatabase v testoch funguje na SQLite.
- Pre každú triedu subjektu, ktorú vaše druhy používajú, definujte policy alebo oprávnenie view, inak prvé odoslanie vyhodí MissingAccessCheckException.
- Ak test potrebuje, aby e-mail odišiel priamo, vypnite front (alebo použite spojenie sync).
- V phpunit.xml používajte hodnoty on / off:
<php>
<env name="NOTIFICATIONS_ROUTES_ENABLED" value="on"/>
<env name="NOTIFICATIONS_QUEUE_ENABLED" value="off"/>
</php>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.