Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@
"extra": {
"laravel": {
"providers": [
"Knuckles\\Scribe\\ScribeServiceProvider"
"Knuckles\\Scribe\\ScribeServiceProvider",
"Knuckles\\Scribe\\ScribeTestServiceProvider"
]
}
},
Expand Down
16 changes: 16 additions & 0 deletions src/Exceptions/LaravelNotPresent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Knuckles\Scribe\Exceptions;

use BadMethodCallException;

class LaravelNotPresent extends BadMethodCallException
{
public function __construct()
{
parent::__construct(
"\n\n`Scribe` requires Laravel to be present in your tests."
."\nPlease make sure the test class extends from Tests\TestCase or \Illuminate\Foundation\Testing\TestCase."
);
}
}
10 changes: 10 additions & 0 deletions src/Extracting/RouteDocBlocker.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ class RouteDocBlocker
public static function getDocBlocksFromRoute(Route $route): array
{
[$className, $methodName] = u::getRouteClassAndMethodNames($route);

return static::getDocBlocks($route, $className, $methodName);
}

public static function getDocBlocks(Route $route, $className, $methodName = null)
{
if (is_array($className)) {
[$className, $methodName] = $className;
}

$normalizedClassName = static::normalizeClassName($className);
$docBlocks = self::getCachedDocBlock($route, $normalizedClassName, $methodName);

Expand Down
13 changes: 13 additions & 0 deletions src/Extracting/Strategies/BodyParameters/GetFromPerformedTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Knuckles\Scribe\Extracting\Strategies\BodyParameters;

use Knuckles\Scribe\Extracting\Strategies\Strategy;

class GetFromPerformedTest extends Strategy
{
public function methodName()
{

}
}
2 changes: 2 additions & 0 deletions src/Extracting/Strategies/Headers/GetFromHeaderTag.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public function __invoke(ExtractedEndpointData $endpointData, array $routeRules)

$methodDocBlock = RouteDocBlocker::getDocBlocksFromRoute($endpointData->route)['method'];

// dd($methodDocBlock);

return $this->getHeadersFromDocBlock($methodDocBlock->getTags());
}

Expand Down
20 changes: 20 additions & 0 deletions src/Extracting/Strategies/Metadata/GetFromDocBlocksFromTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Knuckles\Scribe\Extracting\Strategies\Metadata;

use Knuckles\Camel\Extraction\ExtractedEndpointData;
use Knuckles\Scribe\Extracting\RouteDocBlocker;
use Knuckles\Scribe\Extracting\Strategies\Strategy;
use Mpociot\Reflection\DocBlock;

class GetFromDocBlocksFromTest extends GetFromDocBlocks
{
public function __invoke(ExtractedEndpointData $endpointData, array $routeRules): array
{
$docBlocks = RouteDocBlocker::getDocBlocksFromRoute($endpointData->route);
$methodDocBlock = $docBlocks['method'];
$classDocBlock = $docBlocks['class'];

return $this->getMetadataFromDocBlock($methodDocBlock, $classDocBlock);
}
}
27 changes: 27 additions & 0 deletions src/ScribeTestServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Knuckles\Scribe;

use Illuminate\Contracts\Http\Kernel as HttpKernel;
use Illuminate\Support\ServiceProvider;
use Knuckles\Scribe\Tests\HttpExamples\HttpExampleCreatorMiddleware;

class ScribeTestServiceProvider extends ServiceProvider
{
public function boot()
{
if (
$this->app->environment('testing') &&
$this->app->runningInConsole() &&
config('scribe.generate_test_examples', true)
) {
$this->registerMiddleware();
}
}

private function registerMiddleware(): void
{
$this->app[HttpKernel::class]->appendMiddlewareToGroup('web', HttpExampleCreatorMiddleware::class);
$this->app[HttpKernel::class]->appendMiddlewareToGroup('api', HttpExampleCreatorMiddleware::class);
}
}
156 changes: 156 additions & 0 deletions src/Tests/ExampleCreator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<?php

namespace Knuckles\Scribe\Tests;

use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Routing\Route;
use Illuminate\Support\Str;
use Knuckles\Scribe\Tests\ExampleRequest;
use Knuckles\Scribe\Tests\Traits\SetProps;

class ExampleCreator implements Arrayable
{
use SetProps;

public $id;
public $testClass;
public $testMethod;
public $providedData;
public $dataName;

private Route $route;
private $exampleRequests;
private $test;

public static $currentInstance;

public static $instances;

public function __construct(array $props)
{
$this->setProps($props);

$this->id = (string) Str::orderedUuid();

$this->testClass = get_class($this->test);
}

public static function getCurrentInstance()
{
return static::$currentInstance;
}

public static function setCurrentInstance($instance)
{
static::$currentInstance = $instance;
}

public static function normalizeUriForInstanceKey(Route $route)
{
$parts = [
str_replace('/', '~', $route->uri)
];
$parts = array_merge($parts, $route->methods);

return implode(',', $parts);
}

public static function getInstanceForRoute($route)
{
if ($instance = static::$instances[static::normalizeUriForInstanceKey($route)] ?? null) {
return $instance;
}

$instance = static::getCurrentInstance()->setRoute($route);

return static::registerInstance($instance);
}

protected static function registerInstance($instance)
{
return static::$instances[$instance->instanceKey()] = $instance;
}

public static function getInstances()
{
return static::$instances;
}

public static function flushInstances()
{
static::$instances = [];
}

public function addExampleRequest(ExampleRequest $exampleRequest)
{
$this->exampleRequests[] = $exampleRequest;

return $this;
}

public function setRoute(Route $route)
{
$this->route = $route;

return $this;
}

public function instanceKey()
{
return $this->normalizeUriForInstanceKey($this->route);
}

public function writeDir()
{
return storage_path('scribe/'.$this->instanceKey());
}

public function toArray()
{
return [
'id' => $this->id,
'test_class' => $this->testClass,
'test_method' => $this->testMethod,
'provided_data' => $this->providedData,
'data_name' => $this->dataName,
'key' => $this->instanceKey(),
'route' => [
'uri' => $this->route->uri,
'name' => $this->route->getName(),
'methods' => $this->route->methods,
],
];
}

public function mergeParamsExample($type)
{
$method = 'get'.ucfirst($type).'ParamsExample';
$results = [];

foreach ($exampleRequests as $request) {
$results = array_merge($results, $request->{$method}());
}

return $results;
}

public function writeExampleRequests()
{
return [
'urlParam' => [],
'queryParam' => [],
'bodyParam' => [],
'responses' => [
[
'status' => 200,
'scenario' => 'test_user_should_return_user',
'data' => [],
], [
'status' => 404,
'scenario' => 'test_user_not_found',
'data' => [],
],
],
];
}
}
39 changes: 39 additions & 0 deletions src/Tests/ExampleRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Knuckles\Scribe\Tests;

use Illuminate\Support\Str;

class ExampleRequest
{
public $id;
public $request;
public $response;

public function __construct($request, $response)
{
$this->id = (string) Str::orderedUuid();
$this->request = $request;
$this->response = $response;
}

public function getUrlParamsExample()
{
return [];
}

public function getQueryParamsExample()
{
return [];
}

public function getBodyParamsExample()
{
return $this->request->all();
}

public function getResponse()
{
return $this->response->getContent();
}
}
22 changes: 22 additions & 0 deletions src/Tests/HttpExamples/HttpExampleCreatorMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Knuckles\Scribe\Tests\HttpExamples;

use Closure;
use Illuminate\Testing\TestResponse;
use Knuckles\Scribe\Tests\ExampleCreator;
use Knuckles\Scribe\Tests\ExampleRequest;

class HttpExampleCreatorMiddleware
{
public function handle($request, Closure $next)
{
$response = $next($request);

$exampleCreator = ExampleCreator::getInstanceForRoute($request->route());

$exampleCreator->addExampleRequest(new ExampleRequest($request, $response));

return $response;
}
}
44 changes: 44 additions & 0 deletions src/Tests/ScribeSetup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace Knuckles\Scribe\Tests;

use Knuckles\Scribe\Exceptions\LaravelNotPresent;

trait ScribeSetup
{
public function setUpScribe(): void
{
if (empty($this->app)) {
throw new LaravelNotPresent;
}

if (config('scribe.generate_test_examples', true)) {
$this->afterApplicationCreated(function () {
dump('making example...');
$this->makeExample();
});

$this->beforeApplicationDestroyed(function () {
dump('writing examples...');
$instances = ExampleCreator::getInstances();
foreach ($instances as $instance) {
dump($instance->toArray());
}
ExampleCreator::flushInstances();
// $this->saveExampleStatus();
});
}
}

private function makeExample(): void
{
$exampleCreator = new ExampleCreator([
'test' => $this,
'testMethod' => $this->getName(false),
'providedData' => $this->getProvidedData(),
'dataName' => $this->dataName(),
]);

ExampleCreator::setCurrentInstance($exampleCreator);
}
}
15 changes: 15 additions & 0 deletions src/Tests/Traits/SetProps.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Knuckles\Scribe\Tests\Traits;

trait SetProps
{
public function setProps(array $props)
{
foreach ($props as $key => $value) {
$this->{$key} = $value;
}

return $this;
}
}