Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

wonder95's avatar

How to avoid Slack notifications actually being sent during tests

In my continuing struggle to upgrade Slack functionality in Laravel 11 from the simple nathanheffley/laravel-slack-blocks to the much more complex core laravel/clack-communication-channel, I need to figure out how to keep notifications from actually being sent, because all my http requests are failing when running tests because there is no slack channel to connect to in CircleCI.

In the previous versions, this code

    public function send($notifiable, Notification $notification)
    {
        if (! $url = $notifiable->routeNotificationFor('slack', $notification)) {
            return;
        }

        return $this->http->post($url, $this->buildJsonPayload(
            $notification->toSlack($notifiable)
        ));
    }

would keep it from sending. But now, since I am notifying external workspaces (via our app), I end up with this version of send() in SlackChannel (aliased as SlackApiChannel)

    public function send(mixed $notifiable, Notification $notification): ?Response
    {
        $route = $this->determineRoute($notifiable, $notification);

        $message = $notification->toSlack($notifiable);

        $payload = $this->buildJsonPayload($message, $route);

        if (! $payload['channel']) {
            throw new LogicException('Slack notification channel is not set.');
        }

        if (! $route->token) {
            throw new LogicException('Slack API authentication token is not set.');
        }

        $response = $this->http->asJson()
            ->withToken($route->token)
            ->post('https://slack.com/api/chat.postMessage', $payload)
            ->throw();

        if ($response->successful() && $response->json('ok') === false) {
            throw new RuntimeException('Slack API call failed with error ['.$response->json('error').'].');
        }

        return $response;
    }

so if I don't provide a channel, it errors out, but if I do, it actually tries to send it, even though it's in a test. The SlackWebhookChannel still has the old version of send().

How can I keep notifications from actually being sent when I'm in a test and a notification is sent? For reasons I really don't understand I can't use the Slack webhook URL any more, even though that worked perfectly fine before. From what I've seen, there is no way in dusk or PHPUnit tests to just suppress all notifications, Can I use something like shouldSend() and somehow return false if it's in a test? Or is there another way?

0 likes
2 replies
LaryAI's avatar
Level 58

To avoid sending actual Slack notifications during tests in Laravel, you can use Laravel's built-in notification fake. This allows you to fake notifications during your tests, ensuring that no real notifications are sent out.

Here's how you can achieve this:

  1. Use Notification Fake in Your Tests:

    Laravel provides a Notification::fake() method that you can use to fake notifications. This will prevent any notifications from being sent during the test.

    use Illuminate\Support\Facades\Notification;
    
    public function test_example()
    {
        // Fake notifications
        Notification::fake();
    
        // Perform actions that trigger notifications
        $user = User::factory()->create();
        $user->notify(new SomeNotification());
    
        // Assert that a notification was sent
        Notification::assertSentTo(
            [$user], SomeNotification::class
        );
    
        // Assert that no notifications were sent
        Notification::assertNothingSent();
    }
    
  2. Conditionally Disable Notifications in Your Code:

    If you need to conditionally disable notifications based on the environment (e.g., during testing), you can use the shouldSend method in your notification class. This method can return false when running in a test environment.

    use Illuminate\Notifications\Notification;
    
    class SomeNotification extends Notification
    {
        // Other methods...
    
        public function shouldSend($notifiable, $channel)
        {
            // Disable notifications in the testing environment
            if (app()->environment('testing')) {
                return false;
            }
    
            return true;
        }
    }
    
  3. Mocking HTTP Requests:

    If you need to mock HTTP requests to the Slack API during tests, you can use Laravel's HTTP client fake. This allows you to fake HTTP responses.

    use Illuminate\Support\Facades\Http;
    
    public function test_example()
    {
        // Fake HTTP requests
        Http::fake([
            'slack.com/api/*' => Http::response(['ok' => true], 200),
        ]);
    
        // Perform actions that trigger HTTP requests
        $user = User::factory()->create();
        $user->notify(new SomeNotification());
    
        // Assert that the HTTP request was made
        Http::assertSent(function ($request) {
            return $request->url() === 'https://slack.com/api/chat.postMessage';
        });
    }
    

By using these methods, you can ensure that no real Slack notifications are sent during your tests, while still being able to test the notification logic.

Summary

  • Use Notification::fake() to fake notifications during tests.
  • Use the shouldSend method in your notification class to conditionally disable notifications.
  • Use Http::fake() to mock HTTP requests to the Slack API during tests.

These approaches should help you avoid sending actual Slack notifications during your tests.

puklipo's avatar

Use Notification::fake() or customize via().

    public function via(object $notifiable): array
    {
        $via = ['mail'];

        if (app()->isProduction()) {
            $via[] = 'slack';
        }

        return $via;
}

Please or to participate in this conversation.