ajithlal's avatar

Test filament action without actually calling it

I have a filament action which is calling an artisan command and that command is communicating with an external API.

//Filament action
Action::make('updatet')
                ->label('Update')
                ->color('success')
                ->action(function ( $record): void {
                    Artisan::call("... ");
                    Notification::make()
                        ->title("...")
                        ->icon('heroicon-o-document-text')
                        ->iconColor('success')
                        ->send();
                }),

I wrote a test for the action.

it(description: 'can mark the order as processsed', closure: function () {
    login();

    $order = Order::factory()
        ->unprocessed()
        ->create();

    livewire(name: OrdersTable::class)
        ->callTableAction(name: 'Mark as processed', record: $order)
        ->assertNotified(notification: "Order $order->reference marked as processed");
});

The filament provides a function callTableAction() which will call the action immediately. This will make an API request to the external API. Which is affecting the API quota. How do I write a test for the above action without touching the external API and make sure the action is working?

Thanks in advance.

0 likes
1 reply
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

To test the Filament action without actually calling the external API, you can mock the Artisan command that communicates with the API. This way, you can ensure that the command is being called without actually executing it. Here's how you can modify your test to mock the Artisan command:

it(description: 'can mark the order as processed', closure: function () {
    login();

    $order = Order::factory()
        ->unprocessed()
        ->create();

    // Mock the Artisan command
    Artisan::shouldReceive('call')
        ->once()
        ->withArgs(['...']) // Replace '...' with the actual command arguments
        ->andReturn(0); // Assuming the command is successful

    // Optionally, you can mock the Notification if needed
    Notification::fake();

    livewire(name: OrdersTable::class)
        ->callTableAction(name: 'Mark as processed', record: $order);

    // Assert that the notification was sent if necessary
    Notification::assertSentTo(
        new Notifiable, // Replace with the actual notifiable entity
        NotificationClass::class, // Replace with the actual notification class
        function ($notification, $channels) use ($order) {
            return $notification->title === "Order {$order->reference} marked as processed";
        }
    );
});

In this example, Artisan::shouldReceive('call') is used to mock the Artisan facade. We specify that the call method should be called once with the expected arguments and return 0, which typically indicates success.

Additionally, if you want to assert that a notification was sent, you can use Notification::fake() to prevent actual notifications from being sent and then use Notification::assertSentTo() to assert that the notification was sent to the correct notifiable entity with the expected content.

Remember to include the necessary namespaces at the top of your test file:

use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Notification;
use Illuminate\Contracts\Notifications\Notifiable;
// Other necessary namespaces...

By mocking the Artisan command and the Notification, you can test the behavior of your Filament action without making actual API requests or sending notifications.

Please or to participate in this conversation.