NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky

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:

AserciaPrejde, 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:

ExpectationPrejde, 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 kryptomien

Odoslaní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.