Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added tests
Browse files Browse the repository at this point in the history
sethsandaru committed Sep 17, 2023
1 parent c588a3d commit 09a7631
Showing 7 changed files with 293 additions and 5 deletions.
15 changes: 13 additions & 2 deletions app/Http/Controllers/TranslationController.php
Original file line number Diff line number Diff line change
@@ -7,13 +7,15 @@
use App\Http\Requests\TranslationUpdateRequest;
use App\Http\Resources\TranslationResource;
use App\Models\Translation;
use App\Models\TranslationGroup;
use Illuminate\Http\JsonResponse;

class TranslationController extends Controller
{
public function index(TranslationIndexRequest $request): JsonResponse
{
$translations = $request->buildQueryBuilder()
->with(['translationGroup'])
->paginate();

return TranslationResource::collection($translations)->response();
@@ -26,7 +28,11 @@ public function show(Translation $translation): JsonResponse

public function store(TranslationStoreRequest $request): JsonResponse
{
$translation = Translation::create($request->validated());
$translationGroup = TranslationGroup::find($request->validated('translation_group_id'));
$translation = Translation::create([
...$request->validated(),
'key' => "{$translationGroup->key}.{$request->input('key')}",
]);

return new JsonResponse([
'uuid' => $translation->uuid,
@@ -36,7 +42,12 @@ public function store(TranslationStoreRequest $request): JsonResponse

public function update(TranslationUpdateRequest $request, Translation $translation): JsonResponse
{
$updateStatus = $translation->update($request->validated());
$translationGroup = TranslationGroup::find($request->validated('translation_group_id'));

$updateStatus = $translation->update([
...$request->validated(),
'key' => "{$translationGroup->key}.{$request->input('key')}",
]);

return new JsonResponse([
'uuid' => $translation->uuid,
9 changes: 7 additions & 2 deletions app/Http/Requests/TranslationStoreRequest.php
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
namespace App\Http\Requests;

use App\Models\Translation;
use App\Rules\TranslationTextRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

@@ -18,10 +19,14 @@ public function rules(): array
],
'translation_group_id' => [
'required',
'exists:translation_groups,id',
'exists:translation_groups,uuid',
],
'name' => 'required|string',
'text' => 'required|array',
'text' => [
'required',
'array',
new TranslationTextRule(),
],
];
}
}
8 changes: 7 additions & 1 deletion app/Http/Requests/TranslationUpdateRequest.php
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
namespace App\Http\Requests;

use App\Models\Translation;
use App\Rules\TranslationTextRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

@@ -25,10 +26,15 @@ public function rules(): array
])),
'translation_group_id' => [
'required',
'exists:translation_groups,id',
'exists:translation_groups,uuid',
],
'name' => 'required|string',
'description' => 'nullable|string',
'text' => [
'required',
'array',
new TranslationTextRule(),
],
];
}
}
6 changes: 6 additions & 0 deletions app/Http/Resources/TranslationResource.php
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
namespace App\Http\Resources;

use App\Models\Translation;
use App\Models\TranslationGroup;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

@@ -18,6 +19,11 @@ public function toArray(Request $request): array
'text' => $this->text,
'created_at' => $this->created_at?->toISOString(),
'updated_at' => $this->created_at?->toISOString(),

'translation_group' => self::whenLoaded(
'translationGroup',
fn () => TranslationGroupResource::make($this->translationGroup),
),
];
}
}
23 changes: 23 additions & 0 deletions app/Rules/TranslationTextRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace App\Rules;

use App\Models\Language;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class TranslationTextRule implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$allLanguageCodes = Language::pluck('code')->toArray();

$clientLangCodes = array_keys($value);

$isOk = empty(array_diff($allLanguageCodes, $clientLangCodes));

if (!$isOk) {
$fail('Missing languageCode in the object. Required langCodes: ' . implode(', ', $allLanguageCodes));
}
}
}
208 changes: 208 additions & 0 deletions tests/Feature/TranslationControllerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
<?php

namespace Tests\Feature;

use App\Models\Language;
use App\Models\Translation;
use App\Models\TranslationGroup;
use Tests\TestCase;

class TranslationControllerTest extends TestCase
{
public function testIndexReturnsAllTranslationGroups()
{
$baseGroup = TranslationGroup::factory()->create([
'key' => 'base',
'name' => 'Base Group',
]);
$loveTranslation = Translation::factory()->create([
'translation_group_id' => $baseGroup->uuid,
'key' => 'base.love',
'name' => 'Love',
'text' => [
'en' => 'Love',
'vi' => 'Yêu',
],
]);
$youTranslation = Translation::factory()->create([
'translation_group_id' => $baseGroup->uuid,
'key' => 'base.you',
'name' => 'You',
'text' => [
'en' => 'You',
'vi' => 'Bạn',
],
]);

$response = $this->get('api/v1/translations');

$response->assertStatus(200)
->assertJsonFragment([
'key' => 'base.love',
'name' => 'Love',
'text' => [
'en' => 'Love',
'vi' => 'Yêu',
],
])
->assertJsonFragment([
'key' => 'base.you',
'name' => 'You',
'text' => [
'en' => 'You',
'vi' => 'Bạn',
],
])
->assertJsonFragment([
'key' => 'base',
'name' => 'Base Group',
]);
}

public function testShowReturnsAGivenTranslation()
{
$youTranslation = Translation::factory()->create([
'key' => 'base.you',
'name' => 'You',
'text' => [
'en' => 'You',
'vi' => 'Bạn',
],
]);

$response = $this->get("api/v1/translations/{$youTranslation->uuid}");

$response->assertStatus(200)
->assertJsonFragment([
'key' => 'base.you',
'name' => 'You',
'text' => [
'en' => 'You',
'vi' => 'Bạn',
],
]);
}

public function testStoreCreatesANewTranslation()
{
$pricingGroup = TranslationGroup::factory()->create([
'key' => 'pricing',
'name' => 'Pricing Group',
]);
$language = Language::factory()->create([
'code' => 'en',
]);

$this->json('POST', "api/v1/translations", [
'translation_group_id' => $pricingGroup->uuid,
'key' => 'expensive',
'name' => 'Expensive',
'text' => [
'en' => 'Expensive (expensive)',
],
])->assertOk()
->assertJsonFragment([
'created' => true,
]);

$this->assertDatabaseHas((new Translation())->getTable(), [
'key' => 'pricing.expensive',
'name' => 'Expensive',
'text->en' => 'Expensive (expensive)',
]);
}

public function testStoreReturnsErrorOnInvalidTextFormat()
{
$pricingGroup = TranslationGroup::factory()->create([
'key' => 'pricing',
'name' => 'Pricing Group',
]);
$language = Language::factory()->create([
'code' => 'en',
]);
$language = Language::factory()->create([
'code' => 'vi',
]);

$this->json('POST', "api/v1/translations", [
'translation_group_id' => $pricingGroup->uuid,
'key' => 'inexpensive',
'name' => 'Inexpensive',
'text' => [
'en' => 'Inexpensive',
// missing vi
],
])->assertUnprocessable();

$this->json('POST', "api/v1/translations", [
'translation_group_id' => $pricingGroup->uuid,
'key' => 'inexpensive',
'name' => 'Inexpensive',
'text' => [1, 2, 3], // wrong type
])->assertUnprocessable();

}

public function testUpdateUpdatesAGivenLanguage()
{
$oldGroup = TranslationGroup::factory()->create([
'key' => 'old',
'name' => 'Old Group',
]);
$language = Language::factory()->create([
'code' => 'en',
]);
$translation = Translation::factory()->create([
'translation_group_id' => $oldGroup->uuid,
'key' => 'due-date',
'text' => [
'en' => 'Due date',
],
]);

$invoiceGroup = TranslationGroup::factory()->create([
'key' => 'invoice',
'name' => 'Invoice Group',
]);

$response = $this->json('PUT', "api/v1/translations/{$translation->uuid}", [
'translation_group_id' => $invoiceGroup->uuid,
'key' => 'due-date-v2',
'name' => 'due date v2',
'text' => [
'en' => 'Due date ok',
],
]);

$response->assertOk()
->assertJsonFragment([
'updated' => true,
]);

$this->assertDatabaseHas((new Translation())->getTable(), [
'translation_group_id' => $invoiceGroup->uuid,
'key' => 'invoice.due-date-v2',
'name' => 'due date v2',
'text->en' => 'Due date ok',
]);
}

public function testDestroyDeletesAGivenTranslation()
{
$translation = Translation::factory()->create([
'key' => 'to-be-deleted',
]);

$response = $this->json('DELETE', "api/v1/translations/{$translation->uuid}");

$response->assertOk()
->assertJsonFragment([
'deleted' => true,
]);

$this->assertDatabaseMissing((new TranslationGroup())->getTable(), [
'key' => 'to-be-deleted',
]);
}
}
29 changes: 29 additions & 0 deletions tests/Unit/Models/TranslationGroupTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Tests\Unit\Models;

use App\Models\Translation;
use App\Models\TranslationGroup;
use Tests\TestCase;

class TranslationGroupTest extends TestCase
{
public function testTranslationGroupHasManyTranslations()
{
/**
* @var TranslationGroup $template
*/
$group = TranslationGroup::factory()->create();
$translations = Translation::factory()->count(2)
->create([
'translation_group_id' => $group->uuid,
]);

$foundTranslations = $group->translations()->get();

$this->assertSame(
$translations->pluck('uuid')->toArray(),
$foundTranslations->pluck('uuid')->toArray()
);
}
}

0 comments on commit 09a7631

Please sign in to comment.