Skip to content

Commit 78be936

Browse files
authored
Put fake documentation on the actual pages (#8565)
* move fake documentation into the actual documentation * additional info * Update events.md * Update queues.md
1 parent d10357f commit 78be936

File tree

7 files changed

+468
-544
lines changed

7 files changed

+468
-544
lines changed

events.md

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
- [Event Subscribers](#event-subscribers)
1616
- [Writing Event Subscribers](#writing-event-subscribers)
1717
- [Registering Event Subscribers](#registering-event-subscribers)
18+
- [Testing](#testing)
19+
- [Faking A Subset Of Events](#faking-a-subset-of-events)
20+
- [Scoped Events Fakes](#scoped-event-fakes)
1821

1922
<a name="introduction"></a>
2023
## Introduction
@@ -519,7 +522,7 @@ To dispatch an event, you may call the static `dispatch` method on the event. Th
519522
OrderShipped::dispatchUnless($condition, $order);
520523

521524
> **Note**
522-
> When testing, it can be helpful to assert that certain events were dispatched without actually triggering their listeners. Laravel's [built-in testing helpers](/docs/{{version}}/mocking#event-fake) makes it a cinch.
525+
> When testing, it can be helpful to assert that certain events were dispatched without actually triggering their listeners. Laravel's [built-in testing helpers](#testing) makes it a cinch.
523526
524527
<a name="event-subscribers"></a>
525528
## Event Subscribers
@@ -634,3 +637,122 @@ After writing the subscriber, you are ready to register it with the event dispat
634637
UserEventSubscriber::class,
635638
];
636639
}
640+
641+
<a name="testing"></a>
642+
## Testing
643+
644+
When testing code that dispatches events, you may wish to instruct Laravel to not actually execute the event's listeners, since the listener's code can be tested directly and separately of the code that dispatches the corresponding event. Of course, to test the listener itself, you may instantiate a listener instance and invoke the `handle` method directly in your test.
645+
646+
Using the `Event` facade's `fake` method, you may prevent listeners from executing, execute the code under test, and then assert which events were dispatched by your application using the `assertDispatched`, `assertNotDispatched`, and `assertNothingDispatched` methods:
647+
648+
<?php
649+
650+
namespace Tests\Feature;
651+
652+
use App\Events\OrderFailedToShip;
653+
use App\Events\OrderShipped;
654+
use Illuminate\Support\Facades\Event;
655+
use Tests\TestCase;
656+
657+
class ExampleTest extends TestCase
658+
{
659+
/**
660+
* Test order shipping.
661+
*/
662+
public function test_orders_can_be_shipped(): void
663+
{
664+
Event::fake();
665+
666+
// Perform order shipping...
667+
668+
// Assert that an event was dispatched...
669+
Event::assertDispatched(OrderShipped::class);
670+
671+
// Assert an event was dispatched twice...
672+
Event::assertDispatched(OrderShipped::class, 2);
673+
674+
// Assert an event was not dispatched...
675+
Event::assertNotDispatched(OrderFailedToShip::class);
676+
677+
// Assert that no events were dispatched...
678+
Event::assertNothingDispatched();
679+
}
680+
}
681+
682+
You may pass a closure to the `assertDispatched` or `assertNotDispatched` methods in order to assert that an event was dispatched that passes a given "truth test". If at least one event was dispatched that passes the given truth test then the assertion will be successful:
683+
684+
Event::assertDispatched(function (OrderShipped $event) use ($order) {
685+
return $event->order->id === $order->id;
686+
});
687+
688+
If you would simply like to assert that an event listener is listening to a given event, you may use the `assertListening` method:
689+
690+
Event::assertListening(
691+
OrderShipped::class,
692+
SendShipmentNotification::class
693+
);
694+
695+
> **Warning**
696+
> After calling `Event::fake()`, no event listeners will be executed. So, if your tests use model factories that rely on events, such as creating a UUID during a model's `creating` event, you should call `Event::fake()` **after** using your factories.
697+
698+
<a name="faking-a-subset-of-events"></a>
699+
### Faking A Subset Of Events
700+
701+
If you only want to fake event listeners for a specific set of events, you may pass them to the `fake` or `fakeFor` method:
702+
703+
/**
704+
* Test order process.
705+
*/
706+
public function test_orders_can_be_processed(): void
707+
{
708+
Event::fake([
709+
OrderCreated::class,
710+
]);
711+
712+
$order = Order::factory()->create();
713+
714+
Event::assertDispatched(OrderCreated::class);
715+
716+
// Other events are dispatched as normal...
717+
$order->update([...]);
718+
}
719+
720+
You may fake all events except for a set of specified events using the `except` method:
721+
722+
Event::fake()->except([
723+
OrderCreated::class,
724+
]);
725+
726+
<a name="scoped-event-fakes"></a>
727+
### Scoped Event Fakes
728+
729+
If you only want to fake event listeners for a portion of your test, you may use the `fakeFor` method:
730+
731+
<?php
732+
733+
namespace Tests\Feature;
734+
735+
use App\Events\OrderCreated;
736+
use App\Models\Order;
737+
use Illuminate\Support\Facades\Event;
738+
use Tests\TestCase;
739+
740+
class ExampleTest extends TestCase
741+
{
742+
/**
743+
* Test order process.
744+
*/
745+
public function test_orders_can_be_processed(): void
746+
{
747+
$order = Event::fakeFor(function () {
748+
$order = Order::factory()->create();
749+
750+
Event::assertDispatched(OrderCreated::class);
751+
752+
return $order;
753+
});
754+
755+
// Events are dispatched as normal and observers will run ...
756+
$order->update([...]);
757+
}
758+
}

filesystem.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
- [File Visibility](#file-visibility)
2222
- [Deleting Files](#deleting-files)
2323
- [Directories](#directories)
24+
- [Testing](#testing)
2425
- [Custom Filesystems](#custom-filesystems)
2526

2627
<a name="introduction"></a>
@@ -608,6 +609,48 @@ Finally, the `deleteDirectory` method may be used to remove a directory and all
608609

609610
Storage::deleteDirectory($directory);
610611

612+
<a name="testing"></a>
613+
## Testing
614+
615+
The `Storage` facade's `fake` method allows you to easily generate a fake disk that, combined with the file generation utilities of the `Illuminate\Http\UploadedFile` class, greatly simplifies the testing of file uploads. For example:
616+
617+
<?php
618+
619+
namespace Tests\Feature;
620+
621+
use Illuminate\Http\UploadedFile;
622+
use Illuminate\Support\Facades\Storage;
623+
use Tests\TestCase;
624+
625+
class ExampleTest extends TestCase
626+
{
627+
public function test_albums_can_be_uploaded(): void
628+
{
629+
Storage::fake('photos');
630+
631+
$response = $this->json('POST', '/photos', [
632+
UploadedFile::fake()->image('photo1.jpg'),
633+
UploadedFile::fake()->image('photo2.jpg')
634+
]);
635+
636+
// Assert one or more files were stored...
637+
Storage::disk('photos')->assertExists('photo1.jpg');
638+
Storage::disk('photos')->assertExists(['photo1.jpg', 'photo2.jpg']);
639+
640+
// Assert one or more files were not stored...
641+
Storage::disk('photos')->assertMissing('missing.jpg');
642+
Storage::disk('photos')->assertMissing(['missing.jpg', 'non-existing.jpg']);
643+
644+
// Assert that a given directory is empty...
645+
Storage::disk('photos')->assertDirectoryEmpty('/wallpapers');
646+
}
647+
}
648+
649+
By default, the `fake` method will delete all files in its temporary directory. If you would like to keep these files, you may use the "persistentFake" method instead. For more information on testing file uploads, you may consult the [HTTP testing documentation's information on file uploads](/docs/{{version}}/http-tests#testing-file-uploads).
650+
651+
> **Warning**
652+
> The `image` method requires the [GD extension](https://www.php.net/manual/en/book.image.php).
653+
611654
<a name="custom-filesystems"></a>
612655
## Custom Filesystems
613656

mail.md

Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
- [Rendering Mailables](#rendering-mailables)
2525
- [Previewing Mailables In The Browser](#previewing-mailables-in-the-browser)
2626
- [Localizing Mailables](#localizing-mailables)
27-
- [Testing Mailables](#testing-mailables)
27+
- [Testing](#testing-mailables)
28+
- [Testing Mailable Content](#testing-mailable-content)
29+
- [Testing Mailable Sending](#testing-mailable-sending)
2830
- [Mail & Local Development](#mail-and-local-development)
2931
- [Events](#events)
3032
- [Custom Transports](#custom-transports)
@@ -929,7 +931,10 @@ Once you have implemented the interface, Laravel will automatically use the pref
929931
Mail::to($request->user())->send(new OrderShipped($order));
930932

931933
<a name="testing-mailables"></a>
932-
## Testing Mailables
934+
## Testing
935+
936+
<a name="testing-mailable-content"></a>
937+
### Testing Mailable Content
933938

934939
Laravel provides a variety of methods for inspecting your mailable's structure. In addition, Laravel provides several convenient methods for testing that your mailable contains the content that you expect. These methods are: `assertSeeInHtml`, `assertDontSeeInHtml`, `assertSeeInOrderInHtml`, `assertSeeInText`, `assertDontSeeInText`, `assertSeeInOrderInText`, `assertHasAttachment`, `assertHasAttachedData`, `assertHasAttachmentFromStorage`, and `assertHasAttachmentFromStorageDisk`.
935940

@@ -968,9 +973,98 @@ As you might expect, the "HTML" assertions assert that the HTML version of your
968973
}
969974

970975
<a name="testing-mailable-sending"></a>
971-
#### Testing Mailable Sending
976+
### Testing Mailable Sending
977+
978+
We suggest testing the content of your mailables separately from your tests that assert that a given mailable was "sent" to a specific user. Typically, the content of mailables it not relevant to the code you are testing, and it is sufficient to simply assert that Laravel was instructed to send a given mailable.
979+
980+
You may use the `Mail` facade's `fake` method to prevent mail from being sent. After calling the `Mail` facade's `fake` method, you may then assert that mailables were instructed to be sent to users and even inspect the data the mailables received:
981+
982+
<?php
983+
984+
namespace Tests\Feature;
985+
986+
use App\Mail\OrderShipped;
987+
use Illuminate\Support\Facades\Mail;
988+
use Tests\TestCase;
989+
990+
class ExampleTest extends TestCase
991+
{
992+
public function test_orders_can_be_shipped(): void
993+
{
994+
Mail::fake();
995+
996+
// Perform order shipping...
997+
998+
// Assert that no mailables were sent...
999+
Mail::assertNothingSent();
1000+
1001+
// Assert that a mailable was sent...
1002+
Mail::assertSent(OrderShipped::class);
1003+
1004+
// Assert a mailable was sent twice...
1005+
Mail::assertSent(OrderShipped::class, 2);
1006+
1007+
// Assert a mailable was not sent...
1008+
Mail::assertNotSent(AnotherMailable::class);
1009+
}
1010+
}
1011+
1012+
If you are queueing mailables for delivery in the background, you should use the `assertQueued` method instead of `assertSent`:
1013+
1014+
Mail::assertQueued(OrderShipped::class);
1015+
1016+
Mail::assertNotQueued(OrderShipped::class);
1017+
1018+
Mail::assertNothingQueued();
1019+
1020+
You may pass a closure to the `assertSent`, `assertNotSent`, `assertQueued`, or `assertNotQueued` methods in order to assert that a mailable was sent that passes a given "truth test". If at least one mailable was sent that passes the given truth test then the assertion will be successful:
9721021

973-
We suggest testing the content of your mailables separately from your tests that assert that a given mailable was "sent" to a specific user. To learn how to test that mailables were sent, check out our documentation on the [Mail fake](/docs/{{version}}/mocking#mail-fake).
1022+
Mail::assertSent(function (OrderShipped $mail) use ($order) {
1023+
return $mail->order->id === $order->id;
1024+
});
1025+
1026+
When calling the `Mail` facade's assertion methods, the mailable instance accepted by the provided closure exposes helpful methods for examining the mailable:
1027+
1028+
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($user) {
1029+
return $mail->hasTo($user->email) &&
1030+
$mail->hasCc('...') &&
1031+
$mail->hasBcc('...') &&
1032+
$mail->hasReplyTo('...') &&
1033+
$mail->hasFrom('...') &&
1034+
$mail->hasSubject('...');
1035+
});
1036+
1037+
The mailable instance also includes several helpful methods for examining the attachments on a mailable:
1038+
1039+
use Illuminate\Mail\Mailables\Attachment;
1040+
1041+
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) {
1042+
return $mail->hasAttachment(
1043+
Attachment::fromPath('/path/to/file')
1044+
->as('name.pdf')
1045+
->withMime('application/pdf')
1046+
);
1047+
});
1048+
1049+
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) {
1050+
return $mail->hasAttachment(
1051+
Attachment::fromStorageDisk('s3', '/path/to/file')
1052+
);
1053+
});
1054+
1055+
Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($pdfData) {
1056+
return $mail->hasAttachment(
1057+
Attachment::fromData(fn () => $pdfData, 'name.pdf')
1058+
);
1059+
});
1060+
1061+
You may have noticed that there are two methods for asserting that mail was not sent: `assertNotSent` and `assertNotQueued`. Sometimes you may wish to assert that no mail was sent **or** queued. To accomplish this, you may use the `assertNothingOutgoing` and `assertNotOutgoing` methods:
1062+
1063+
Mail::assertNothingOutgoing();
1064+
1065+
Mail::assertNotOutgoing(function (OrderShipped $mail) use ($order) {
1066+
return $mail->order->id === $order->id;
1067+
});
9741068

9751069
<a name="mail-and-local-development"></a>
9761070
## Mail & Local Development

0 commit comments

Comments
 (0)