Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature | Record Requests In Telescope #24

Closed
wants to merge 17 commits into from
Next Next commit
Basic tests working
  • Loading branch information
Sammyjo20 committed Jul 22, 2022
commit 6f429b9b6d8c0ff4707b2783f4aa5309500b83c8
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.5",
"laravel/telescope": "^4.9",
"orchestra/testbench": "^v6.24.0",
"pestphp/pest": "^1.21"
},
Expand Down
2 changes: 2 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@
<php>
<env name="APP_KEY" value="base64:g6rX3ygsFZiO446CYsmZVbPZBGavoH0sVbGXZbS03SI="/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="DB_CONNECTION" value="sqlite"/>
Sammyjo20 marked this conversation as resolved.
Show resolved Hide resolved
<env name="DB_DATABASE" value=":memory:"/>
</php>
</phpunit>
63 changes: 63 additions & 0 deletions src/Listeners/RecordSaloonToTelescope.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace Sammyjo20\SaloonLaravel\Listeners;

use Illuminate\Support\Str;
use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope;
use Sammyjo20\SaloonLaravel\Events\SentSaloonRequest;

class RecordSaloonToTelescope
{
/**
* Handle the event.
*
* @param SentSaloonRequest $event
* @return void
* @throws \Illuminate\Contracts\Container\BindingResolutionException
* @throws \ReflectionException
* @throws \Sammyjo20\Saloon\Exceptions\SaloonInvalidConnectorException
*/
public function handle(SentSaloonRequest $event): void
{
$request = $event->request;
$response = $event->response;

// We'll attempt to guess if the response is JSON.

$responseIsJson = Str::of($response->header('Content-Type'))->lower()->contains('application/json');

// Let's now append any query parameters to the end of the URL, since Saloon's getFullRequestUrl
// does not provide it.

$url = $request->getFullRequestUrl();
$glue = str_contains($url, '?') ? '&' : '?';
$query = http_build_query($request->getQuery());

$fullUrl = empty($query) ? $url : ($url . $glue . $query);

// We'll now record the client request!

$telescope = app()->make(Telescope::class);

$entry = IncomingEntry::make([
'method' => $request->getMethod(),
'uri' => $fullUrl,
'headers' => $request->getHeaders(),
'payload' => $request->getData(),
'response_status' => $response->status(),
'response_headers' => $response->headers(),
'response' => $responseIsJson ? $response->json() : $response->body(),
'saloon_connector' => get_class($request->getConnector()),
'saloon_request' => get_class($request),
]);

$entry->tags([
'Saloon',
'SaloonConnector:' . get_class($request->getConnector()),
'SaloonRequest:' . get_class($request),
]);

$telescope->recordClientRequest($entry);
}
}
54 changes: 54 additions & 0 deletions tests/Feature/TelescopeRecorderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

use Illuminate\Support\Facades\Event;
use Laravel\Telescope\EntryType;
use Sammyjo20\Saloon\Clients\MockClient;
use Sammyjo20\Saloon\Http\MockResponse;
use Sammyjo20\SaloonLaravel\Events\SentSaloonRequest;
use Sammyjo20\SaloonLaravel\Listeners\RecordSaloonToTelescope;
use Sammyjo20\SaloonLaravel\Tests\Fixtures\Connectors\TestConnector;
use Sammyjo20\SaloonLaravel\Tests\Fixtures\Requests\PostRequest;

beforeEach(function () {
Event::listen(SentSaloonRequest::class, RecordSaloonToTelescope::class);
});

test('when a request is made - it is reported to telescope', function () {
$request = new PostRequest;

$mockClient = new MockClient([
MockResponse::fromRequest($request),
]);

$request->send($mockClient);

$entries = $this->loadTelescopeEntries()->where('type', EntryType::CLIENT_REQUEST);

expect($entries)->toHaveCount(1);

$entry = $entries->sole();
$entryContent = $entry->content;

// Make sure all fields are present and it's stored correctly.

dd($entry);

expect($entryContent)->toBeArray();
expect($entryContent)->toHaveKey('method', 'POST');
expect($entryContent)->toHaveKey('uri', 'https://tests.saloon.dev/api/post');
expect($entryContent)->toHaveKey('headers', ['X-Foo' => 'Bar']);
expect($entryContent)->toHaveKey('payload', ['name' => 'Sammy']);
expect($entryContent)->toHaveKey('response_status', 200);
expect($entryContent)->toHaveKey('response_headers', ['Content-Type' => [0 => 'application/json'], 'X-Foo' => [0 => 'Bar']]);
expect($entryContent)->toHaveKey('response', ['name' => 'Sammy']);
expect($entryContent)->toHaveKey('saloon_connector', TestConnector::class);
expect($entryContent)->toHaveKey('saloon_request', PostRequest::class);
});

test('query parameters are shown in the url of the telescope report', function () {

});

test('it will format the response data as json if it can find the correct content type header', function () {
// Test it won't format without.
});
56 changes: 56 additions & 0 deletions tests/Fixtures/Requests/PostRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace Sammyjo20\SaloonLaravel\Tests\Fixtures\Requests;

use Sammyjo20\Saloon\Constants\Saloon;
use Sammyjo20\Saloon\Http\SaloonRequest;
use Sammyjo20\Saloon\Traits\Plugins\HasJsonBody;
use Sammyjo20\SaloonLaravel\Tests\Fixtures\Connectors\TestConnector;

class PostRequest extends SaloonRequest
{
use HasJsonBody;

/**
* Define the method that the request will use.
*
* @var string|null
*/
protected ?string $method = Saloon::POST;

/**
* The connector.
*
* @var string|null
*/
protected ?string $connector = TestConnector::class;

/**
* Define the endpoint for the request.
*
* @return string
*/
public function defineEndpoint(): string
{
return '/post';
}

/**
* Default Data
*
* @return string[]
*/
public function defaultData(): array
{
return [
'name' => 'Sammy',
];
}

public function defaultHeaders(): array
{
return [
'X-Foo' => 'Bar',
];
}
}
28 changes: 28 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

namespace Sammyjo20\SaloonLaravel\Tests;

use Illuminate\Support\Collection;
use Laravel\Telescope\Contracts\EntriesRepository;
use Laravel\Telescope\Storage\EntryModel;
use Laravel\Telescope\Telescope;
use Laravel\Telescope\TelescopeServiceProvider;
use Sammyjo20\SaloonLaravel\Facades\Saloon;
use Orchestra\Testbench\TestCase as BaseTestCase;
use Sammyjo20\SaloonLaravel\SaloonServiceProvider;
Expand All @@ -12,9 +17,20 @@ public function getPackageProviders($app)
{
return [
SaloonServiceProvider::class,
TelescopeServiceProvider::class,
];
}

/**
* Define database migrations.
*
* @return void
*/
protected function defineDatabaseMigrations()
{
$this->loadMigrationsFrom(__DIR__ . '/../vendor/laravel/telescope/database/migrations');
}

/**
* Override application aliases.
*
Expand All @@ -28,4 +44,16 @@ protected function getPackageAliases($app)
'Saloon' => Saloon::class,
];
}

/**
* Load the Telescope entries.
*
* @return Collection
*/
protected function loadTelescopeEntries(): Collection
{
Telescope::store(app(EntriesRepository::class));

return EntryModel::all();
}
}