Skip to content

Commit

Permalink
Create tests and adjust code
Browse files Browse the repository at this point in the history
  • Loading branch information
Fernando Piovezan committed Jun 8, 2024
1 parent 349075c commit 8c2833f
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 105 deletions.
7 changes: 7 additions & 0 deletions config/request-docs.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,15 @@
'exclude_fields' => [
],

// Use factory to create data examples
'use_factory' => false,

// Regex to extract the model name from the controller name
'pattern_model_from_controller_name' => '/APIController$/',

// Path where the project's factories are located
'factory_path' => 'Database\Factories',

'rules_order' => [
'required',
'required_if',
Expand Down
7 changes: 6 additions & 1 deletion src/Doc.php
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,12 @@ public function getFieldInfo(): array
*/
public function setFieldInfo(array $fieldInfo): void
{
$this->fieldInfo = $fieldInfo;
foreach ($fieldInfo as $key => $item) {
$this->fieldInfo[$key] = [
'description' => $item,
'example' => $this->examples[$key] ?? ''
];
}
}

/**
Expand Down
36 changes: 19 additions & 17 deletions src/LaravelRequestDocs.php
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,6 @@ public function appendRequestRules(Collection $docs): Collection
$requestObject = $reflectionClass->newInstanceWithoutConstructor();
}

if (method_exists($requestObject, 'fieldDescriptions')) {
$doc->setFieldInfo($requestObject->fieldDescriptions());
}

foreach (config('request-docs.rules_methods') as $requestMethod) {
if (!method_exists($requestObject, $requestMethod)) {
continue;
Expand All @@ -315,6 +311,10 @@ public function appendRequestRules(Collection $docs): Collection
if (config('request-docs.use_factory')) {
$this->appendExample($doc);
}

if (method_exists($requestObject, 'fieldDescriptions')) {
$doc->setFieldInfo($requestObject->fieldDescriptions());
}
}
} catch (Throwable $e) {
// Do nothing.
Expand Down Expand Up @@ -362,24 +362,26 @@ public function lrdDocComment(string $docComment): string
public function appendExample(Doc $doc): void
{
try {
$controllerName = class_basename($doc->getController());
$modelName = Str::replace('APIController', '', $controllerName);
$fullModelName = "App\\Models\\" . $modelName;

if (!class_exists($fullModelName)) {
return;
}

/** @var \Illuminate\Database\Eloquent\Model $model */
$model = app($fullModelName);
$modelName = Str::replaceMatches(
config('request-docs.pattern_model_from_controller_name'),
'',
class_basename($doc->getController())
);
$fullFactoryName = config('request-docs.factory_path') . "\\{$modelName}Factory";

if (!method_exists($model, 'factory')) {
if (!class_exists($fullFactoryName)) {
return;
}

/** @var \Illuminate\Database\Eloquent\Factories\Factory $factory */
$factory = app($fullFactoryName);
$excludeFields = config('request-docs.exclude_fields') ?? [];
$example = $model->factory()->make()->toArray();
$example = array_filter($example, fn($key) => !in_array($key, $excludeFields), ARRAY_FILTER_USE_KEY);
$example = $factory::new()->make()->toArray();
$example = array_filter(
$example,
fn($key) => !in_array($key, $excludeFields),
ARRAY_FILTER_USE_KEY
);
$doc->mergeExamples($example);
} catch (Throwable $e) {
// Do nothing.
Expand Down
94 changes: 94 additions & 0 deletions tests/Controllers/LaravelRequestDocsControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -510,4 +510,98 @@ public function testPathWithGlobalPattern()

$this->assertSame($expected, $pathParameter);
}


public function testGenerateExampleToFactory()
{
config(['request-docs.factory_path' => 'Rakutentech\LaravelRequestDocs\Tests\Factories']);
config(['request-docs.use_factory' => true]);
config(['request-docs.pattern_model_from_controller_name' => '/Controller$/']);
Route::post('api/v1/users/store', [UserController::class, 'store']);

$response = $this->get(route('request-docs.api'))
->assertStatus(Response::HTTP_OK);
$docs = collect($response->json());
$userRoute = $docs
->filter(fn(array $item) => Str::startsWith($item['uri'], ['api']));
$examples = $userRoute->pluck('examples')->toArray();
$expected = [\Rakutentech\LaravelRequestDocs\Tests\Factories\UserFactory::new()->make()->toArray()];

$this->assertSame($expected, $examples);
}

public function testGenerateFieldDescriptionAndExamples()
{
config(['request-docs.factory_path' => 'Rakutentech\LaravelRequestDocs\Tests\Factories']);
config(['request-docs.use_factory' => true]);
config(['request-docs.pattern_model_from_controller_name' => '/Controller$/']);
Route::post('api/v1/users/store', [UserController::class, 'store']);

$response = $this->get(route('request-docs.api'))
->assertStatus(Response::HTTP_OK);
$docs = collect($response->json());
$userRoute = $docs
->filter(fn(array $item) => Str::startsWith($item['uri'], ['api']));
$fieldInfo = $userRoute->pluck('field_info')->get(0);
$expected = [
'name' => [
'description' => 'User Name',
'example' => 'John Doe'
],
'email' => [
'description' => 'User email',
'example' => '[email protected]'
]
];

$this->assertSame($expected, $fieldInfo);
}


public function testSummaryAndDescriptionMethod()
{
Route::post('api/v1/users/store', [UserController::class, 'store']);

$response = $this->get(route('request-docs.api'))
->assertStatus(Response::HTTP_OK);
$docs = collect($response->json());
$userRoute = $docs
->filter(fn(array $item) => Str::startsWith($item['uri'], ['api']));
$summary = $userRoute->pluck('summary')->get(0);
$description = $userRoute->pluck('description')->get(0);

$expectedSummary = 'Store a newly created resource in storage.';
$expectedDescription = 'This method creates a user when validations are met.';

$this->assertSame($expectedSummary, $summary);
$this->assertSame($description, $expectedDescription);
}

public function testRuleOrder()
{
Route::post('api/v1/users/store', [UserController::class, 'store']);

$response = $this->get(route('request-docs.api'))
->assertStatus(Response::HTTP_OK);
$docs = collect($response->json());
$userRoute = $docs
->filter(fn(array $item) => Str::startsWith($item['uri'], ['api']));
$rulesOrder = $userRoute->pluck('rules_order')->get(0);

$this->assertSame(config('request-docs.rules_order'), $rulesOrder);
}

public function testTag()
{
Route::post('api/v1/users/store', [UserController::class, 'store']);

$response = $this->get(route('request-docs.api'))
->assertStatus(Response::HTTP_OK);
$docs = collect($response->json());
$userRoute = $docs
->filter(fn(array $item) => Str::startsWith($item['uri'], ['api']));
$tag = $userRoute->pluck('tag')->get(0);

$this->assertSame('User', $tag);
}
}
29 changes: 29 additions & 0 deletions tests/Factories/UserFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Rakutentech\LaravelRequestDocs\Tests\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use Rakutentech\LaravelRequestDocs\Tests\Models\User;

class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var class-string<User>
*/
protected $model = User::class;

/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'name' => 'John Doe',
'email' => '[email protected]',
];
}
}
2 changes: 2 additions & 0 deletions tests/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace Rakutentech\LaravelRequestDocs\Tests\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
use HasFactory;
}
16 changes: 16 additions & 0 deletions tests/Stubs/TestControllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,27 @@
namespace Rakutentech\LaravelRequestDocs\Tests\Stubs\TestControllers;

use Illuminate\Http\Response;
use Rakutentech\LaravelRequestDocs\Tests\Stubs\TestRequests\UserStoreRequest;

/**
* class UserController
* @LRDtag User
*/
class UserController
{
public function __invoke(): Response
{
return response('true');
}

/**
* Store a newly created resource in storage.
* This method creates a user when validations are met.
* @param UserStoreRequest $request
* @return Response
*/
public function store(UserStoreRequest $request): Response
{
return response('true');
}
}
47 changes: 47 additions & 0 deletions tests/Stubs/TestRequests/UserStoreRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Rakutentech\LaravelRequestDocs\Tests\Stubs\TestRequests;

use Illuminate\Foundation\Http\FormRequest;

class UserStoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}

protected function prepareForValidation()
{
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|string',
'email' => 'required|email',
];
}

/**
* Provides a detailed description of the expected parameters
* in the body of an HTTP request.
*/
public function fieldDescriptions(): array
{
return [
'name' => 'User Name',
'email' => 'User email',
];
}
}
Loading

0 comments on commit 8c2833f

Please sign in to comment.