1

How one can phpunit subscriptions using only PHP/phpunit/Laravel and laravel-lighthouse GraphQL library?

I am trying to create a unit test for my app that will subscribe to a "hello world" subscription. The purpose of such test is to assert the subscription feature. The feature test should listen to a channel and assert the received message contains the same published message (that was published in he same phpunit file).

This is what I have so far:

public function test_hello_world_build_subscription()
{

    $config = config('broadcasting.connections.pusher');
    $graphql = app(\Nuwave\Lighthouse\GraphQL::class);
    $context = app(\Nuwave\Lighthouse\Schema\Context::class);

    $result = $graphql->executeQuery('
        subscription BuildEvent($input: BuildEventInput!) {
          buildEvent (input: $input) {
            message
          }
        }
        ', $context, [
            'input' => [
                "uuid" => "0a53b12e-7ae0-4db1-a030-26a7ffdb1902",
            ]
        ],
    );

    $channel = data_get($result, 'extensions.lighthouse_subscriptions.channel');
    
    $pusher = new Pusher($config['key'], $config['secret'], $config['app_id'], [
        'host' => 'localhost',
        'port' => 6001,
        'debug' => true,
    ]);

    $pusher->trigger($channel, 'App\Events\ExampleEvent', 'a hello world message');
    
}

I am glad it worked and returned something like this:

GraphQL\Executor\ExecutionResult^ {#2045
  +data: array:1 [
    "buildEvent" => null
  ]
  +errors: []
  +extensions: array:1 [
    "lighthouse_subscriptions" => array:2 [
      "version" => 2
      "channel" => "private-lighthouse-0IIVzatBhabTtfEe33vp9ARBHGa1iP1y-1626402747"
    ]
  ]
  -errorFormatter: null
  -errorsHandler: null
}

But I dont know what to do next.

The documentation did not talk anything about it. Could anyone point me to a direction? Any link for a blog, git repo, tutorial, etc. would be appreciated. Thanks.

mowses
  • 21
  • 1
  • 1
  • 7
  • Hi there, I'm not sure if it helps but have you taken a look how Lighthouse itself tests subscriptions [here](https://github.com/nuwave/lighthouse/tree/master/tests/Unit/Subscriptions) and [here](https://github.com/nuwave/lighthouse/tree/master/tests/Integration/Subscriptions)? Other than that others might be able to help you further if the existing tests are not helpful for you. – Alex Jul 16 '21 at 10:01
  • Thanks for your answer. I will take a look and post here the solution. – mowses Jul 19 '21 at 13:12
  • @mowses You got any results? – Steve Moretz Mar 07 '23 at 21:23

1 Answers1

1

Well took me a while to find out how this works, I wrote a trait for this

<?php

namespace Tests\Unit\Utils;

use Nuwave\Lighthouse\Subscriptions\Broadcasters\LogBroadcaster;
use Nuwave\Lighthouse\Subscriptions\BroadcastManager;
use Nuwave\Lighthouse\Subscriptions\Storage\CacheStorageManager;
use Nuwave\Lighthouse\Testing\MakesGraphQLRequests;
use Nuwave\Lighthouse\Testing\RefreshesSchemaCache;

trait GraphQLTesting
{
    use MakesGraphQLRequests, RefreshesSchemaCache;

    protected function setupGraphQL()
    {
        $this->bootRefreshesSchemaCache();

        //region config
        config()->set("lighthouse.subscriptions.broadcaster", "log");
        config()->set("lighthouse.subscriptions.queue_broadcasts", false);
        config()->set("lighthouse.subscriptions.storage", "array");
        config()->set("lighthouse.subscriptions.storage_ttl", null);
        //endregion
    }

    protected function getGraphQLSubscriptionChannelNameFromResponse($subscriptionResponse)
    {
        return $subscriptionResponse->json('extensions.lighthouse_subscriptions.channel');
    }

    protected function assertGraphQLSubscriptionAuthorization($channel)
    {
        $this
            ->postJson('graphql/subscriptions/auth', [
                'channel_name' => $channel,
            ])
            ->assertSuccessful()
            ->assertJson([
                "message" => "ok",
            ]);
    }

    protected function getGraphQLSubscribers($channelNameSnakeUpper)
    {
        $cache = $this->app->make(CacheStorageManager::class);
        assert($cache instanceof CacheStorageManager);
        return $cache->subscribersByTopic($channelNameSnakeUpper);
    }

    protected function getGraphQLCapturedBroadcasts()
    {
        $broadcastManager = $this->app->make(BroadcastManager::class);
        assert($broadcastManager instanceof BroadcastManager);
        $log = $broadcastManager->driver();
        assert($log instanceof LogBroadcaster);
        return $log->broadcasts();
    }
}

Import the trait in your tests, here's a complete test of how this can be used:

<?php

namespace Tests\Feature\Cart;

use Nuwave\Lighthouse\Execution\Utils\Subscription;

class CartSubscriptionTest extends BaseTest
{
    private function subscribe()
    {
        $query =
            /** @lang GraphQL */
            'subscription {
                individualUpdated {
                    context
                }
            }';

        return $this->graphQL($query);
    }

    public function test_it()
    {
        // write some code to add a new user and set it as the current user

        $response = $this->subscribe();
        $channel  = $this->getGraphQLSubscriptionChannelNameFromResponse($response);
        $this->assertGraphQLSubscriptionAuthorization($channel);

        $data = [
            "context" => "whatever",
        ];
        Subscription::broadcast('individualUpdated', $data);

        $this->assertEquals([
            $channel => [
                "data" => [
                    "individualUpdated" => $data
                ]
            ]
        ], $this->getGraphQLCapturedBroadcasts());
    }
}

Update

I added a pull request to add this feature to the package directly: https://github.com/nuwave/lighthouse/pull/2343

Steve Moretz
  • 2,758
  • 1
  • 17
  • 31