From da39143113ae18fb612c1c44ffc1de3c9bb8a5e9 Mon Sep 17 00:00:00 2001 From: "Christopher C. Wells" Date: Fri, 2 Apr 2021 21:39:27 -0700 Subject: [PATCH] Test JSON API relationships --- database/factories/RecipeFactory.php | 1 + tests/Feature/JsonApi/FoodApiTest.php | 7 ++-- tests/Feature/JsonApi/GoalApiTest.php | 6 ++-- .../JsonApi/IngredientAmountApiTest.php | 27 ++++++++++++++ tests/Feature/JsonApi/JournalEntryApiTest.php | 23 +++++++++++- tests/Feature/JsonApi/JsonApiTestCase.php | 35 ++++++++++++++++--- tests/Feature/JsonApi/RecipeApiTest.php | 35 +++++++++++++++++-- .../JsonApi/RecipeSeparatorApiTest.php | 6 ++-- tests/Feature/JsonApi/RecipeStepApiTest.php | 6 ++-- tests/Feature/JsonApi/TagApiTest.php | 2 +- .../JsonApi/Traits/BelongsToRecipe.php | 16 +++++++++ .../Feature/JsonApi/Traits/BelongsToUser.php | 16 +++++++++ tests/Feature/JsonApi/Traits/HasTags.php | 16 +++++++++ tests/Feature/JsonApi/UserApiTest.php | 22 +++++++++++- 14 files changed, 200 insertions(+), 18 deletions(-) create mode 100644 tests/Feature/JsonApi/Traits/BelongsToRecipe.php create mode 100644 tests/Feature/JsonApi/Traits/BelongsToUser.php create mode 100644 tests/Feature/JsonApi/Traits/HasTags.php diff --git a/database/factories/RecipeFactory.php b/database/factories/RecipeFactory.php index 35a1949..43c54ed 100644 --- a/database/factories/RecipeFactory.php +++ b/database/factories/RecipeFactory.php @@ -27,6 +27,7 @@ class RecipeFactory extends Factory 'source' => $this->faker->optional()->url, 'servings' => $this->faker->numberBetween(1, 10), 'weight' => $this->faker->randomFloat(1, 60, 2000), + 'tags' => $this->faker->words, ]; } } diff --git a/tests/Feature/JsonApi/FoodApiTest.php b/tests/Feature/JsonApi/FoodApiTest.php index 14c6c96..9952f39 100644 --- a/tests/Feature/JsonApi/FoodApiTest.php +++ b/tests/Feature/JsonApi/FoodApiTest.php @@ -3,12 +3,15 @@ namespace Tests\Feature\JsonApi; use App\Models\Food; +use App\Models\Recipe; use Database\Factories\FoodFactory; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\Feature\JsonApi\Traits\HasTags; class FoodApiTest extends JsonApiTestCase { - use RefreshDatabase; + use RefreshDatabase, HasTags; /** * @inheritdoc @@ -41,7 +44,7 @@ class FoodApiTest extends JsonApiTestCase foreach ($attributes as $attribute => $value) { $partial = substr($value, rand(0, 3), 3); - $search_route = route($this->indexRouteName, [ + $search_route = route("$this->routeBase.index", [ 'filter' => ['search' => $partial] ]); $response = $this->get($search_route); diff --git a/tests/Feature/JsonApi/GoalApiTest.php b/tests/Feature/JsonApi/GoalApiTest.php index aba2f9f..3ea6b82 100644 --- a/tests/Feature/JsonApi/GoalApiTest.php +++ b/tests/Feature/JsonApi/GoalApiTest.php @@ -3,14 +3,14 @@ namespace Tests\Feature\JsonApi; use App\Models\Goal; -use App\Models\User; use Database\Factories\GoalFactory; use Illuminate\Database\Eloquent\Collection; use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\Feature\JsonApi\Traits\BelongsToUser; class GoalApiTest extends JsonApiTestCase { - use RefreshDatabase; + use RefreshDatabase, BelongsToUser; /** * @inheritdoc @@ -32,7 +32,7 @@ class GoalApiTest extends JsonApiTestCase * @inheritdoc */ protected function createInstances(int $count = 1): Collection { - return User::factory()->count(1)->hasGoals($count)->create(); + return $this->factory()->count($count)->for($this->user)->create(); } } diff --git a/tests/Feature/JsonApi/IngredientAmountApiTest.php b/tests/Feature/JsonApi/IngredientAmountApiTest.php index 762311f..811cc46 100644 --- a/tests/Feature/JsonApi/IngredientAmountApiTest.php +++ b/tests/Feature/JsonApi/IngredientAmountApiTest.php @@ -2,7 +2,10 @@ namespace Tests\Feature\JsonApi; +use App\Models\Food; use App\Models\IngredientAmount; +use App\Models\JournalEntry; +use App\Models\Recipe; use Database\Factories\IngredientAmountFactory; use Illuminate\Foundation\Testing\RefreshDatabase; @@ -26,4 +29,28 @@ class IngredientAmountApiTest extends JsonApiTestCase return 'ingredient-amounts'; } + public function testCanGetRelatedIngredient(): void { + $ingredient = Food::factory()->create(); + $record = $this->factory()->ingredient($ingredient)->create(); + $this->getRelatedData($record, 'ingredient', 'foods'); + } + + public function testCanIncludeRelatedIngredient(): void { + $ingredient = Recipe::factory()->create(); + $record = $this->factory()->ingredient($ingredient)->create(); + $this->getRelatedData($record, 'ingredient', 'recipes'); + } + + public function testCanGetRelatedParent(): void { + $parent = Recipe::factory()->create(); + $record = $this->factory()->parent($parent)->create(); + $this->getRelatedData($record, 'parent', 'recipes'); + } + + public function testCanIncludeRelatedParent(): void { + $parent = JournalEntry::factory()->create(); + $record = $this->factory()->parent($parent)->create(); + $this->getRelatedData($record, 'parent', 'journal-entries'); + } + } diff --git a/tests/Feature/JsonApi/JournalEntryApiTest.php b/tests/Feature/JsonApi/JournalEntryApiTest.php index a84d204..ea357b4 100644 --- a/tests/Feature/JsonApi/JournalEntryApiTest.php +++ b/tests/Feature/JsonApi/JournalEntryApiTest.php @@ -5,10 +5,11 @@ namespace Tests\Feature\JsonApi; use App\Models\JournalEntry; use Database\Factories\JournalEntryFactory; use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\Feature\JsonApi\Traits\BelongsToUser; class JournalEntryApiTest extends JsonApiTestCase { - use RefreshDatabase; + use RefreshDatabase, BelongsToUser; /** * @inheritdoc @@ -26,4 +27,24 @@ class JournalEntryApiTest extends JsonApiTestCase return 'journal-entries'; } + public function testCanGetRelatedFoods(): void { + $record = $this->factory()->hasFoods(2)->create(); + $this->getRelatedData($record, 'foods'); + } + + public function testCanIncludeRelatedFoods(): void { + $record = $this->factory()->hasFoods(2)->create(); + $this->getRelatedData($record, 'foods'); + } + + public function testCanGetRelatedRecipes(): void { + $record = $this->factory()->hasRecipes(2)->create(); + $this->getRelatedData($record, 'recipes'); + } + + public function testCanIncludeRelatedRecipes(): void { + $record = $this->factory()->hasRecipes(2)->create(); + $this->getRelatedData($record, 'recipes'); + } + } diff --git a/tests/Feature/JsonApi/JsonApiTestCase.php b/tests/Feature/JsonApi/JsonApiTestCase.php index 1512e0a..718db83 100644 --- a/tests/Feature/JsonApi/JsonApiTestCase.php +++ b/tests/Feature/JsonApi/JsonApiTestCase.php @@ -4,15 +4,16 @@ namespace Tests\Feature\JsonApi; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Factories\Factory; +use Illuminate\Database\Eloquent\Model; use Tests\LoggedInTestCase; abstract class JsonApiTestCase extends LoggedInTestCase { /** - * API index route name. + * API route base. */ - protected string $indexRouteName; + protected string $routeBase; /** * Get the factory of the model to be tested. @@ -28,7 +29,7 @@ abstract class JsonApiTestCase extends LoggedInTestCase { parent::setUp(); $route_prefix = config('json-api-v1.url.name'); - $this->indexRouteName = "{$route_prefix}{$this->resourceName()}.index"; + $this->routeBase = "{$route_prefix}{$this->resourceName()}"; } /** @@ -38,10 +39,36 @@ abstract class JsonApiTestCase extends LoggedInTestCase return $this->factory()->count($count)->create(); } + /** + * Provide a template for getting related data. + */ + protected function getRelatedData(Model $record, string $related, string $expectedType = NULL): void { + $related_route = route( + "{$this->routeBase}.relationships.{$related}", + ['record' => $record] + ); + $response = $this->get($related_route); + $response->assertOk(); + $response->assertJsonFragment(['type' => $expectedType ?? $related]); + } + + /** + * Provide a template for included related data. + */ + protected function includeRelatedData(Model $record, string $related, string $expectedType = NULL): void { + $related_route = route( + "{$this->routeBase}.read", + ['record' => $record, 'include' => $related] + ); + $response = $this->get($related_route); + $response->assertOk(); + $response->assertJsonPath('included.0.type', $expectedType ?? $related); + } + public function testCanGetIndex(): void { $this->createInstances(10); - $index_url = route($this->indexRouteName); + $index_url = route("$this->routeBase.index"); $response = $this->get($index_url); $response->assertOk(); $response->assertJson(['data' => true]); diff --git a/tests/Feature/JsonApi/RecipeApiTest.php b/tests/Feature/JsonApi/RecipeApiTest.php index cd1593c..3857972 100644 --- a/tests/Feature/JsonApi/RecipeApiTest.php +++ b/tests/Feature/JsonApi/RecipeApiTest.php @@ -5,10 +5,11 @@ namespace Tests\Feature\JsonApi; use App\Models\Recipe; use Database\Factories\RecipeFactory; use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\Feature\JsonApi\Traits\HasTags; class RecipeApiTest extends JsonApiTestCase { - use RefreshDatabase; + use RefreshDatabase, HasTags; /** * @inheritdoc @@ -26,6 +27,36 @@ class RecipeApiTest extends JsonApiTestCase return 'recipes'; } + public function testCanGetRelatedIngredientAmounts(): void { + $record = $this->factory()->hasIngredientAmounts(2)->create(); + $this->getRelatedData($record, 'ingredient-amounts'); + } + + public function testCanIncludeRelatedIngredientAmounts(): void { + $record = $this->factory()->hasIngredientAmounts(2)->create(); + $this->getRelatedData($record, 'ingredient-amounts'); + } + + public function testCanGetRelatedSeparators(): void { + $record = $this->factory()->hasSeparators(2)->create(); + $this->getRelatedData($record, 'separators', 'recipe-separators'); + } + + public function testCanIncludeRelatedSeparators(): void { + $record = $this->factory()->hasSeparators(2)->create(); + $this->getRelatedData($record, 'separators', 'recipe-separators'); + } + + public function testCanGetRelatedSteps(): void { + $record = $this->factory()->hasSteps(2)->create(); + $this->getRelatedData($record, 'steps', 'recipe-steps'); + } + + public function testCanIncludeRelatedSteps(): void { + $record = $this->factory()->hasSteps(2)->create(); + $this->getRelatedData($record, 'steps', 'recipe-steps'); + } + public function testCanUseSearchFilter(): void { $attributes = [ 'name' => 'Chocolate Chip Cookies', @@ -41,7 +72,7 @@ class RecipeApiTest extends JsonApiTestCase foreach ($attributes as $attribute => $value) { $partial = substr($value, rand(0, 5), 5); - $search_route = route($this->indexRouteName, [ + $search_route = route("$this->routeBase.index", [ 'filter' => ['search' => $partial] ]); $response = $this->get($search_route); diff --git a/tests/Feature/JsonApi/RecipeSeparatorApiTest.php b/tests/Feature/JsonApi/RecipeSeparatorApiTest.php index ef2bedf..f59d4ae 100644 --- a/tests/Feature/JsonApi/RecipeSeparatorApiTest.php +++ b/tests/Feature/JsonApi/RecipeSeparatorApiTest.php @@ -7,10 +7,11 @@ use App\Models\RecipeSeparator; use Database\Factories\RecipeSeparatorFactory; use Illuminate\Database\Eloquent\Collection; use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\Feature\JsonApi\Traits\BelongsToRecipe; class RecipeSeparatorApiTest extends JsonApiTestCase { - use RefreshDatabase; + use RefreshDatabase, BelongsToRecipe; /** * @inheritdoc @@ -32,7 +33,8 @@ class RecipeSeparatorApiTest extends JsonApiTestCase * @inheritdoc */ protected function createInstances(int $count = 1): Collection { - return Recipe::factory()->count(1)->hasSeparators($count)->create(); + $recipe = Recipe::factory()->create(); + return $this->factory()->count($count)->for($recipe)->create(); } } diff --git a/tests/Feature/JsonApi/RecipeStepApiTest.php b/tests/Feature/JsonApi/RecipeStepApiTest.php index 8d36316..7b1bd9e 100644 --- a/tests/Feature/JsonApi/RecipeStepApiTest.php +++ b/tests/Feature/JsonApi/RecipeStepApiTest.php @@ -7,10 +7,11 @@ use App\Models\RecipeStep; use Database\Factories\RecipeStepFactory; use Illuminate\Database\Eloquent\Collection; use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\Feature\JsonApi\Traits\BelongsToRecipe; class RecipeStepApiTest extends JsonApiTestCase { - use RefreshDatabase; + use RefreshDatabase, BelongsToRecipe; /** * @inheritdoc @@ -32,7 +33,8 @@ class RecipeStepApiTest extends JsonApiTestCase * @inheritdoc */ protected function createInstances(int $count = 1): Collection { - return Recipe::factory()->count(1)->hasSteps($count)->create(); + $recipe = Recipe::factory()->create(); + return $this->factory()->count($count)->for($recipe)->create(); } } diff --git a/tests/Feature/JsonApi/TagApiTest.php b/tests/Feature/JsonApi/TagApiTest.php index 16f434a..9e70971 100644 --- a/tests/Feature/JsonApi/TagApiTest.php +++ b/tests/Feature/JsonApi/TagApiTest.php @@ -34,7 +34,7 @@ class TagApiTest extends JsonApiTestCase foreach ($names as $name) { $partial = substr($name, rand(0, 2), 3); - $search_route = route($this->indexRouteName, [ + $search_route = route("$this->routeBase.index", [ 'filter' => ['name' => $partial] ]); $response = $this->get($search_route); diff --git a/tests/Feature/JsonApi/Traits/BelongsToRecipe.php b/tests/Feature/JsonApi/Traits/BelongsToRecipe.php new file mode 100644 index 0000000..7e8454f --- /dev/null +++ b/tests/Feature/JsonApi/Traits/BelongsToRecipe.php @@ -0,0 +1,16 @@ +createInstances()->first(); + $this->getRelatedData($record, 'recipe', 'recipes'); + } + + public function testCanIncludeRelatedUser(): void { + $record = $this->createInstances()->first(); + $this->getRelatedData($record, 'recipe', 'recipes'); + } +} diff --git a/tests/Feature/JsonApi/Traits/BelongsToUser.php b/tests/Feature/JsonApi/Traits/BelongsToUser.php new file mode 100644 index 0000000..1b05903 --- /dev/null +++ b/tests/Feature/JsonApi/Traits/BelongsToUser.php @@ -0,0 +1,16 @@ +createInstances()->first(); + $this->getRelatedData($record, 'user', 'users'); + } + + public function testCanIncludeRelatedUser(): void { + $record = $this->createInstances()->first(); + $this->getRelatedData($record, 'user', 'users'); + } +} diff --git a/tests/Feature/JsonApi/Traits/HasTags.php b/tests/Feature/JsonApi/Traits/HasTags.php new file mode 100644 index 0000000..d570b14 --- /dev/null +++ b/tests/Feature/JsonApi/Traits/HasTags.php @@ -0,0 +1,16 @@ +createInstances()->first(); + $this->getRelatedData($record, 'tags'); + } + + public function testCanIncludeRelatedTags(): void { + $record = $this->createInstances()->first(); + $this->getRelatedData($record, 'tags'); + } +} diff --git a/tests/Feature/JsonApi/UserApiTest.php b/tests/Feature/JsonApi/UserApiTest.php index 50e0f3b..d99c670 100644 --- a/tests/Feature/JsonApi/UserApiTest.php +++ b/tests/Feature/JsonApi/UserApiTest.php @@ -30,11 +30,31 @@ class UserApiTest extends JsonApiTestCase { // Initial user created by test so only make 9 new instances. $this->createInstances(9); - $index_url = route($this->indexRouteName); + $index_url = route("$this->routeBase.index"); $response = $this->get($index_url); $response->assertOk(); $response->assertJson(['data' => true]); $response->assertJsonCount(10, 'data'); } + public function testCanGetRelatedGoals(): void { + $record = $this->factory()->hasGoals(2)->create(); + $this->getRelatedData($record, 'goals'); + } + + public function testCanIncludeRelatedGoals(): void { + $record = $this->factory()->hasGoals(2)->create(); + $this->getRelatedData($record, 'goals'); + } + + public function testCanGetRelatedJournalEntries(): void { + $record = $this->factory()->hasJournalEntries(2)->create(); + $this->getRelatedData($record, 'journal-entries'); + } + + public function testCanIncludeRelatedJournalEntries(): void { + $record = $this->factory()->hasJournalEntries(2)->create(); + $this->getRelatedData($record, 'journal-entries'); + } + }