From fef7f4e2bc4261a126e68205af2f1b3a9fb519c0 Mon Sep 17 00:00:00 2001 From: alex-chevski Date: Wed, 10 Jan 2024 17:11:50 +0300 Subject: [PATCH] added tests for diets --- app/Livewire/Diet/Create.php | 23 ++-- app/Livewire/Diet/Edit.php | 23 ++-- app/Models/Diet.php | 48 ++++--- database/seeders/DatabaseSeeder.php | 1 + tests/Feature/Diet/CreateTest.php | 187 +++++++++++++++++++++++++ tests/Feature/Diet/EditTest.php | 204 ++++++++++++++++++++++++++++ tests/Feature/Diet/IndexTest.php | 31 +++++ tests/Feature/Diet/ShowTest.php | 31 +++++ 8 files changed, 509 insertions(+), 39 deletions(-) create mode 100644 tests/Feature/Diet/CreateTest.php create mode 100644 tests/Feature/Diet/EditTest.php create mode 100644 tests/Feature/Diet/IndexTest.php create mode 100644 tests/Feature/Diet/ShowTest.php diff --git a/app/Livewire/Diet/Create.php b/app/Livewire/Diet/Create.php index 4ff25be..b9426a1 100644 --- a/app/Livewire/Diet/Create.php +++ b/app/Livewire/Diet/Create.php @@ -53,44 +53,47 @@ class Create extends Component $this->publish(); } - public function makeCopy($day) + public function makeCopy(string $day): void { $this->copyedDay = $day; } - public function makePaste($copyToDay) + public function makePaste(string $copyToDay): void { $data = $this->days[$this->copyedDay]; $this->dispatch('takePaste', day: $copyToDay, data: $data)->to('diet.day-edit'); } - public function publish() + public function publish(): void { $this->validate(); $diet = new Diet(); $diet->name = $this->name; - $diet->image = $this->image->store('diets', 'public'); + // $diet->image = $this->image->store('diets', 'public'); + $diet->image = $this->image->store('diets'); $diet->duration = $this->duration; $diet->state = $this->state; - $diet->type = json_encode($this->type); + $diet->type = $this->type; $diet->details = $this->details; - $diet->daily_schedule = json_encode($this->days); - $diet->save(); + $diet->daily_schedule = $this->days; + $diet->saveOrFail(); $user = Auth::user(); $user->author_of_diets()->attach($diet->id); - return redirect()->route('diet.show', $diet->id); + $this->redirectRoute('diet.show', $diet); + + // return redirect()->route('diet.show', $diet->id); } - protected function rules() + protected function rules(): array { return [ 'name' => 'required|min:3', 'image' => 'required|image|max:2048', 'duration' => 'required|numeric|min:7', - 'state' => 'required|in:draft,active,inactive', + 'state' => 'required|in:active,draft,archived', 'type' => ['required', 'array:meat,veg,corb,alko', 'min:1'], 'details' => 'required|min:3', ]; diff --git a/app/Livewire/Diet/Edit.php b/app/Livewire/Diet/Edit.php index 46df9b2..386fc59 100644 --- a/app/Livewire/Diet/Edit.php +++ b/app/Livewire/Diet/Edit.php @@ -2,11 +2,13 @@ namespace App\Livewire\Diet; -use App\Models\Diet; -use Livewire\Component; +use App\Models\Diet; use Livewire\Component; +use Livewire\WithFileUploads; class Edit extends Component { + use WithFileUploads; + public Diet $diet; public $name = ''; @@ -35,9 +37,9 @@ class Edit extends Component $this->image = $diet->image; $this->duration = $diet->duration; $this->state = $diet->state; - $this->type = json_decode($diet->type, true); + $this->type = $diet->type; $this->details = $diet->details; - $this->days = json_decode($diet->daily_schedule, true); + $this->days = $diet->daily_schedule; } public function render() @@ -78,7 +80,7 @@ class Edit extends Component )->to('diet.day-edit'); } - public function publish() + public function publish(): void { $this->validate(); @@ -86,17 +88,18 @@ class Edit extends Component $diet->name = $this->name; /* $diet->image = $this->image->store('diets', 'public'); */ + $diet->image = ! is_string($this->image) ? $this->image->store('plans') : $this->image; $diet->duration = $this->duration; $diet->state = $this->state; - $diet->type = json_encode($this->type); + $diet->type = $this->type; $diet->details = $this->details; - $diet->daily_schedule = json_encode($this->days); + $diet->daily_schedule = $this->days; $diet->save(); + $this->redirectRoute('diet.show', $diet); + /* $user = Auth::user(); */ /* $user->author_of_diets()->attach($diet->id); */ - - return redirect()->route('diet.show', $diet->id); } protected function rules() @@ -105,7 +108,7 @@ class Edit extends Component 'name' => 'required|min:3', /* 'image' => 'required|image|max:2048', */ 'duration' => 'required|numeric|min:7', - 'state' => 'required|in:draft,active,inactive', + 'state' => 'required|in:active,draft,archived', 'type' => ['required', 'array:meat,veg,corb,alko', 'min:1'], 'details' => 'required|min:3', ]; diff --git a/app/Models/Diet.php b/app/Models/Diet.php index a72fa4e..0500147 100644 --- a/app/Models/Diet.php +++ b/app/Models/Diet.php @@ -4,11 +4,11 @@ namespace App\Models; use CyrildeWit\EloquentViewable\Contracts\Viewable; use CyrildeWit\EloquentViewable\InteractsWithViews; -use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; -use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Model; /** * App\Models\Diet @@ -64,10 +64,20 @@ class Diet extends Model implements Viewable { use HasFactory, InteractsWithViews; - protected $withCount = [ - 'likes', - 'comments', - 'choses', + // protected $withCount = [ + // 'likes', + // 'comments', + // 'choses', + // ]; + + public static function getWithLikesCommentsChosesCount(): Builder + { + return self::withCount(['likes', 'comments', 'choses']); + } + + protected $casts = [ + 'type' => 'array', + 'daily_schedule' => 'array', ]; private $allowedDietTypes = [ @@ -120,19 +130,19 @@ class Diet extends Model implements Viewable public function types(): Attribute { - $data = $this->unserializeOptionsArr($this->type); + $data = $this->type; return new Attribute( - get: fn () => array_keys($data), + get: fn() => array_keys($data), ); } public function schedules(): Attribute { - $data = $this->unserializeOptionsArr($this->daily_schedule); + $data = $this->daily_schedule; return new Attribute( - get: fn () => $data, + get: fn() => $data, ); } @@ -168,8 +178,8 @@ class Diet extends Model implements Viewable foreach ($types as $type) { if (in_array($type, $this->allowedDietTypes)) { $query = $i === 0 - ? $query->whereJsonContainsKey('type->'.$type) - : $query->orWhereJsonContainsKey('type->'.$type); + ? $query->whereJsonContainsKey('type->' . $type) + : $query->orWhereJsonContainsKey('type->' . $type); $i++; } } @@ -177,12 +187,12 @@ class Diet extends Model implements Viewable return $query; } - private function unserializeOptionsArr($str) - { - if (preg_match('/^".*"$/', $str)) { - return json_decode(stripslashes(mb_substr($str, 1, -1)), true); - } + // private function unserializeOptionsArr($str) + // { + // if (preg_match('/^".*"$/', $str)) { + // return stripslashes(mb_substr($str, 1, -1)), true; + // } - return json_decode(stripslashes($str), true); - } + // return json_decode(stripslashes($str), true); + // } } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 0be680a..b389b53 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -18,5 +18,6 @@ class DatabaseSeeder extends Seeder $this->call(RecipeAuthor::class); $this->call(RecipeCommentSeeder::class); $this->call(RecipeTagSeeder::class); + $this->call(DietsSeeder::class); } } diff --git a/tests/Feature/Diet/CreateTest.php b/tests/Feature/Diet/CreateTest.php new file mode 100644 index 0000000..e2e384e --- /dev/null +++ b/tests/Feature/Diet/CreateTest.php @@ -0,0 +1,187 @@ +refreshApplicationWithLocale('en'); + + Storage::fake('tmp-for-tests'); + $this->image = UploadedFile::fake()->image('diet.png'); + + $this->user = User::factory()->create(['is_consultant' => true]); + $this->diet = Diet::factory()->make(); + } + + public function test_show_form_create_diet(): void + { + $response = $this + ->actingAs($this->user) + ->get(route('diet.create')); + + $response->assertSuccessful(); + } + + public function test_publish_new_diet_success(): void + { + $this->actingAs($this->user); + + $dietCountAtStart = Diet::count(); + + $testCase = Livewire::test(Create::class) + ->set('name', $this->diet->name) + ->assertSet('name', $this->diet->name) + ->set('image', $this->image) + ->set('duration', $this->diet->duration) + ->assertSet('duration', $this->diet->duration) + ->set('state', $this->diet->state) + ->assertSet('state', $this->diet->state) + ->set('type', $this->diet->type) + ->assertSet('type', $this->diet->type) + ->set('details', $this->diet->details) + ->assertSet('details', $this->diet->details) + ->set('daily_schedule', $this->diet->daily_schedule) + ->assertSet('daily_schedule', $this->diet->daily_schedule) + ->call('publish') + ->assertSuccessful() + ->assertHasNoErrors(['name', 'image', 'duration', 'state', 'details', 'daily_schedule', 'type']); + + $lastCreatedDiet = Diet::orderBy('id', 'desc')->first(); + + + $this->assertEquals($dietCountAtStart + 1, Diet::count()); + + $newDietUrl = route('diet.show', $lastCreatedDiet); + + $testCase->assertRedirect($newDietUrl); + + Storage::disk('tmp-for-tests')->assertExists($lastCreatedDiet->image); + + + $response = $this->actingAs($this->user)->get(route('diet.index')); + + $response->assertSuccessful(); + } + + public function test_to_draft_new_diet_success(): void + { + $this->actingAs($this->user); + + $dietCountAtStart = Diet::count(); + + $testCase = Livewire::test(Create::class) + ->set('name', $this->diet->name) + ->assertSet('name', $this->diet->name) + ->set('image', $this->image) + ->set('duration', $this->diet->duration) + ->assertSet('duration', $this->diet->duration) + ->set('state', $this->diet->state) + ->assertSet('state', $this->diet->state) + ->set('type', $this->diet->type) + ->assertSet('type', $this->diet->type) + ->set('details', $this->diet->details) + ->assertSet('details', $this->diet->details) + ->set('daily_schedule', $this->diet->daily_schedule) + ->assertSet('daily_schedule', $this->diet->daily_schedule) + ->call('addToDrafts') + ->assertSuccessful() + ->assertHasNoErrors(['name', 'image', 'duration', 'details', 'daily_schedule']); + + self::assertEquals('draft', $testCase->state); + + $lastCreatedDiet = Diet::orderBy('id', 'desc')->first(); + + $newDietUrl = route('diet.show', $lastCreatedDiet); + + $testCase->assertRedirect($newDietUrl); + + Storage::disk('tmp-for-tests')->assertExists($lastCreatedDiet->image); + + $this->assertEquals($dietCountAtStart + 1, Diet::count()); + + $response = $this->actingAs($this->user)->get(route('diet.index')); + + $response->assertSuccessful(); + } + + public function test_to_preview_new_diet_success(): void + { + $this->actingAs($this->user); + + $dietCountAtStart = Diet::count(); + + $testCase = Livewire::test(Create::class) + ->set('name', $this->diet->name) + ->assertSet('name', $this->diet->name) + ->set('image', $this->image) + ->set('duration', $this->diet->duration) + ->assertSet('duration', $this->diet->duration) + ->set('state', $this->diet->state) + ->assertSet('state', $this->diet->state) + ->set('type', $this->diet->type) + ->assertSet('type', $this->diet->type) + ->set('details', $this->diet->details) + ->assertSet('details', $this->diet->details) + ->set('daily_schedule', $this->diet->daily_schedule) + ->assertSet('daily_schedule', $this->diet->daily_schedule) + ->call('showPreview') + ->assertSuccessful() + ->assertHasNoErrors(['name', 'image', 'duration', 'details', 'daily_schedule']); + + self::assertEquals('draft', $testCase->state); + + $lastCreatedDiet = Diet::orderBy('id', 'desc')->first(); + + $newDietUrl = route('diet.show', $lastCreatedDiet); + + $testCase->assertRedirect($newDietUrl); + + Storage::disk('tmp-for-tests')->assertExists($lastCreatedDiet->image); + + $this->assertEquals($dietCountAtStart + 1, Diet::count()); + + $response = $this->actingAs($this->user)->get(route('diet.index')); + + $response->assertSuccessful(); + } + + public function test_set_empty_data(): void + { + $this->actingAs($this->user); + + $dietCountAtStart = Diet::count(); + + Livewire::test(Create::class) + ->set('name', null) + ->set('image', null) + ->set('duration', null) + ->set('state', null) + ->set('type', null) + ->set('details', null) + ->set('daily_schedule', null) + ->call('publish') + ->assertHasErrors(['name', 'image', 'duration', 'details', 'state', 'type']); + + $this->assertEquals($dietCountAtStart, Diet::count()); + } +} diff --git a/tests/Feature/Diet/EditTest.php b/tests/Feature/Diet/EditTest.php new file mode 100644 index 0000000..725ebfe --- /dev/null +++ b/tests/Feature/Diet/EditTest.php @@ -0,0 +1,204 @@ +refreshApplicationWithLocale('en'); + + Storage::fake('tmp-for-tests'); + $this->image = UploadedFile::fake()->image('diet.png'); + + $this->user = User::factory()->create(['is_consultant' => true]); + $this->diet = Diet::factory()->create(); + } + + public function test_show_form_edit_diet(): void + { + $response = $this + ->actingAs($this->user) + ->get(route('diet.edit', $this->diet)); + + $response->assertSuccessful(); + } + + public function test_publish_new_diet_success(): void + { + $this->actingAs($this->user); + + $updatedDietBeforeToAddDatabase = Diet::factory()->make(); + + $testCase = Livewire::test(Edit::class, [ + 'diet' => $this->diet, + ]) + ->set('name', $updatedDietBeforeToAddDatabase->name) + ->assertSet('name', $updatedDietBeforeToAddDatabase->name) + ->set('image', $this->image) + ->set('duration', $updatedDietBeforeToAddDatabase->duration) + ->assertSet('duration', $updatedDietBeforeToAddDatabase->duration) + ->set('state', $updatedDietBeforeToAddDatabase->state) + ->assertSet('state', $updatedDietBeforeToAddDatabase->state) + ->set('type', $updatedDietBeforeToAddDatabase->type) + ->assertSet('type', $updatedDietBeforeToAddDatabase->type) + ->set('details', $updatedDietBeforeToAddDatabase->details) + ->assertSet('details', $updatedDietBeforeToAddDatabase->details) + ->set('daily_schedule', $this->diet->daily_schedule) + ->assertSet('daily_schedule', $this->diet->daily_schedule) + ->call('publish') + ->assertSuccessful() + ->assertHasNoErrors(['name', 'image', 'duration', 'state', 'details', 'daily_schedule', 'type']); + + $updatedDietAfterToAddDatabase = Diet::orderByDesc('id')->first(); + + $newDietUrl = route('diet.show', $updatedDietAfterToAddDatabase); + + Storage::disk('tmp-for-tests')->assertExists($updatedDietAfterToAddDatabase->image); + + + // check data after update recipe + self::assertEquals($updatedDietBeforeToAddDatabase->name, $updatedDietAfterToAddDatabase->name); + self::assertEquals($updatedDietBeforeToAddDatabase->duration, $updatedDietAfterToAddDatabase->duration); + self::assertEquals($updatedDietBeforeToAddDatabase->state, $updatedDietAfterToAddDatabase->state); + self::assertEquals($updatedDietBeforeToAddDatabase->type, $updatedDietAfterToAddDatabase->type); + self::assertEquals($updatedDietBeforeToAddDatabase->details, $updatedDietAfterToAddDatabase->details); + // self::assertEquals($updatedDietBeforeToAddDatabase->daily_schedule, $updatedDietAfterToAddDatabase->daily_schedule); + + $testCase->assertRedirect($newDietUrl); + + } + + public function test_to_draft_new_diet_success(): void + { + $this->actingAs($this->user); + + $updatedDietBeforeToAddDatabase = Diet::factory()->make(); + + $testCase = Livewire::test(Edit::class, [ + 'diet' => $this->diet, + ]) + ->set('name', $updatedDietBeforeToAddDatabase->name) + ->assertSet('name', $updatedDietBeforeToAddDatabase->name) + ->set('image', $this->image) + ->set('duration', $updatedDietBeforeToAddDatabase->duration) + ->assertSet('duration', $updatedDietBeforeToAddDatabase->duration) + ->set('state', $updatedDietBeforeToAddDatabase->state) + ->assertSet('state', $updatedDietBeforeToAddDatabase->state) + ->set('type', $updatedDietBeforeToAddDatabase->type) + ->assertSet('type', $updatedDietBeforeToAddDatabase->type) + ->set('details', $updatedDietBeforeToAddDatabase->details) + ->assertSet('details', $updatedDietBeforeToAddDatabase->details) + ->set('daily_schedule', $this->diet->daily_schedule) + ->assertSet('daily_schedule', $this->diet->daily_schedule) + ->call('addToDrafts') + ->assertSuccessful() + ->assertHasNoErrors(['name', 'image', 'duration', 'state', 'details', 'days', 'type']); + + $updatedDietAfterToAddDatabase = Diet::orderByDesc('id')->first(); + + $newDietUrl = route('diet.show', $updatedDietAfterToAddDatabase); + + Storage::disk('tmp-for-tests')->assertExists($updatedDietAfterToAddDatabase->image); + + + // check data after update recipe + self::assertEquals($updatedDietBeforeToAddDatabase->name, $updatedDietAfterToAddDatabase->name); + self::assertEquals($updatedDietBeforeToAddDatabase->duration, $updatedDietAfterToAddDatabase->duration); + self::assertEquals('draft', $updatedDietAfterToAddDatabase->state); + self::assertEquals($updatedDietBeforeToAddDatabase->type, $updatedDietAfterToAddDatabase->type); + self::assertEquals($updatedDietBeforeToAddDatabase->details, $updatedDietAfterToAddDatabase->details); + // self::assertEquals($updatedDietBeforeToAddDatabase->daily_schedule, $updatedDietAfterToAddDatabase->daily_schedule); + + $testCase->assertRedirect($newDietUrl); + } + + public function test_to_preview_new_diet_success(): void + { + $this->actingAs($this->user); + + $updatedDietBeforeToAddDatabase = Diet::factory()->make(); + + $testCase = Livewire::test(Edit::class, [ + 'diet' => $this->diet, + ]) + ->set('name', $updatedDietBeforeToAddDatabase->name) + ->assertSet('name', $updatedDietBeforeToAddDatabase->name) + ->set('image', $this->image) + ->set('duration', $updatedDietBeforeToAddDatabase->duration) + ->assertSet('duration', $updatedDietBeforeToAddDatabase->duration) + ->set('state', $updatedDietBeforeToAddDatabase->state) + ->assertSet('state', $updatedDietBeforeToAddDatabase->state) + ->set('type', $updatedDietBeforeToAddDatabase->type) + ->assertSet('type', $updatedDietBeforeToAddDatabase->type) + ->set('details', $updatedDietBeforeToAddDatabase->details) + ->assertSet('details', $updatedDietBeforeToAddDatabase->details) + ->set('daily_schedule', $this->diet->daily_schedule) + ->assertSet('daily_schedule', $this->diet->daily_schedule) + ->call('showPreview') + ->assertSuccessful() + ->assertHasNoErrors(['name', 'image', 'duration', 'state', 'details', 'days', 'type']); + + $updatedDietAfterToAddDatabase = Diet::orderByDesc('id')->first(); + + $newDietUrl = route('diet.show', $updatedDietAfterToAddDatabase); + + Storage::disk('tmp-for-tests')->assertExists($updatedDietAfterToAddDatabase->image); + + + // check data after update recipe + self::assertEquals($updatedDietBeforeToAddDatabase->name, $updatedDietAfterToAddDatabase->name); + self::assertEquals($updatedDietBeforeToAddDatabase->duration, $updatedDietAfterToAddDatabase->duration); + self::assertEquals('draft', $updatedDietAfterToAddDatabase->state); + self::assertEquals($updatedDietBeforeToAddDatabase->type, $updatedDietAfterToAddDatabase->type); + self::assertEquals($updatedDietBeforeToAddDatabase->details, $updatedDietAfterToAddDatabase->details); + // self::assertEquals($updatedDietBeforeToAddDatabase->daily_schedule, $updatedDietAfterToAddDatabase->daily_schedule); + + $testCase->assertRedirect($newDietUrl); + } + + public function testNothingChange(): void + { + $this->actingAs($this->user); + + $dietUpdate = Livewire::test(Edit::class, [ + 'diet' => $this->diet, + ]) + ->call('publish') + ->assertSuccessful() + ->assertHasNoErrors(['name', 'image', 'duration', 'state', 'details', 'days', 'type']); + + $newDietUrl = route('diet.show', $this->diet, false); + + Storage::disk('tmp-for-tests')->assertMissing($dietUpdate->image); + + // check data after update recipe + self::assertEquals($this->diet->name, $dietUpdate->name); + self::assertEquals($this->diet->duration, $dietUpdate->duration); + self::assertEquals($this->diet->state, $dietUpdate->state); + self::assertEquals($this->diet->type, $dietUpdate->type); + self::assertEquals($this->diet->details, $dietUpdate->details); + self::assertEquals($this->diet->daily_schedule, $dietUpdate->days); + + $dietUpdate->assertRedirect($newDietUrl); + } + +} + diff --git a/tests/Feature/Diet/IndexTest.php b/tests/Feature/Diet/IndexTest.php new file mode 100644 index 0000000..d7e6702 --- /dev/null +++ b/tests/Feature/Diet/IndexTest.php @@ -0,0 +1,31 @@ +refreshApplicationWithLocale('en'); + + $this->user = User::factory()->create(['is_consultant' => true]); + } + + public function test_index_page_success(): void + { + $response = $this + ->actingAs($this->user) + ->get(route('plan.index')); + + $response + ->assertOk(); + } +} diff --git a/tests/Feature/Diet/ShowTest.php b/tests/Feature/Diet/ShowTest.php new file mode 100644 index 0000000..f16a855 --- /dev/null +++ b/tests/Feature/Diet/ShowTest.php @@ -0,0 +1,31 @@ +refreshApplicationWithLocale('en'); + + $this->user = User::factory()->create(['is_consultant' => true]); + $this->diet = Diet::inRandomOrder()->first(); + } + + public function test_show_page_success(): void + { + $response = $this + ->actingAs($this->user) + ->get(route('diet.show', $this->diet)); + + $response + ->assertOk(); + } +}