diff --git a/src/app/DTO/Service/Telegram/Anime/AnimeMessageDTO.php b/src/app/DTO/Service/Telegram/Anime/AnimeMessageDTO.php index ad476516..6793a3ab 100644 --- a/src/app/DTO/Service/Telegram/Anime/AnimeMessageDTO.php +++ b/src/app/DTO/Service/Telegram/Anime/AnimeMessageDTO.php @@ -8,31 +8,43 @@ use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardButton; use SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardMarkup; -final class AnimeMessageDTO +final readonly class AnimeMessageDTO { + /** + * @param list|list> $inlineKeyboardButtons + */ public function __construct( - public readonly string $photo, - public readonly string $caption, - /** @var InlineKeyboardButtonDTO[] */ - private array $inlineKeyboardButtons = [], + public string $photo, + public string $caption, + private array $inlineKeyboardButtons = [], ) { } - public function addButton(InlineKeyboardButtonDTO $dto): void - { - $this->inlineKeyboardButtons[] = $dto; - } - public function generateReplyMarkup(): InlineKeyboardMarkup { $markup = InlineKeyboardMarkup::make(); - foreach ($this->inlineKeyboardButtons as $keyboardButton) { + foreach ($this->inlineKeyboardButtons as $button) { + if (is_array($button)) { + $row = []; + + foreach ($button as $keyboardButton) { + $row[] = InlineKeyboardButton::make( + text : $keyboardButton->text, + url : $keyboardButton->url, + callback_data: $keyboardButton->callbackData + ); + } + + $markup->addRow(...$row); + continue; + } + $markup->addRow( InlineKeyboardButton::make( - text : $keyboardButton->text, - url : $keyboardButton->url, - callback_data: $keyboardButton->callbackData + text : $button->text, + url : $button->url, + callback_data: $button->callbackData ) ); } diff --git a/src/app/Http/Middleware/HandleInertiaRequests.php b/src/app/Http/Middleware/HandleInertiaRequests.php index f8908dbd..c0ea48b1 100644 --- a/src/app/Http/Middleware/HandleInertiaRequests.php +++ b/src/app/Http/Middleware/HandleInertiaRequests.php @@ -6,7 +6,6 @@ use Illuminate\Http\Request; use Inertia\Middleware; -use Tighten\Ziggy\Ziggy; class HandleInertiaRequests extends Middleware { @@ -40,10 +39,6 @@ public function share(Request $request): array 'flash' => [ 'message' => fn() => $request->session()->get('message'), ], - 'ziggy' => fn() => [ - ...(new Ziggy())->toArray(), - 'location' => $request->url(), - ], ]; } } diff --git a/src/app/Models/Anime.php b/src/app/Models/Anime.php index 96239d8b..feec7f3a 100644 --- a/src/app/Models/Anime.php +++ b/src/app/Models/Anime.php @@ -15,7 +15,6 @@ use Database\Factories\AnimeFactory; use Illuminate\Database\Eloquent\Attributes\ObservedBy; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Concerns\HasUuids; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -113,24 +112,4 @@ public function scopeCountScrapedPerMonth(Builder $query): Builder return $query->selectRaw('COUNT(id) as per_month, MONTH(created_at) as month_number') ->groupBy('month_number'); } - - /** - * @psalm-suppress TooManyTemplateParams - * @return Attribute - */ - protected function toTelegramCaption(): Attribute - { - /** @see https://github.com/larastan/larastan/issues/2038 */ - return Attribute::make( - get: fn(): string => sprintf( - "Название: %s\nСтатус: %s\nЭпизоды: %s\nОценка: %s\nОзвучки: %s\nЖанры: %s", - $this->title, - $this->status->value, // @phpstan-ignore-line Ignored because of parser issues - $this->episodes, - $this->rating, - $this->voiceActing->implode('name', ', '), - $this->genres->implode('name', ', '), - ) - )->shouldCache(); - } } diff --git a/src/app/Services/Telegram/AnimeMessageService.php b/src/app/Services/Telegram/AnimeMessageService.php index f86549b9..5e85810d 100644 --- a/src/app/Services/Telegram/AnimeMessageService.php +++ b/src/app/Services/Telegram/AnimeMessageService.php @@ -11,6 +11,7 @@ use App\Factory\Telegram\CallbackData\CallbackDataFactory; use App\Models\Anime; use App\Models\AnimeUrl; +use App\ValueObject\Telegram\Anime\AnimeCaptionText; use Illuminate\Pagination\LengthAwarePaginator; final readonly class AnimeMessageService @@ -21,41 +22,65 @@ public function __construct(private CallbackDataFactory $callbackDataFactory) public function createMessage(Anime $anime): AnimeMessageDTO { - $buttons = $anime->urls->map(function (AnimeUrl $url) { - return new InlineKeyboardButtonDTO($url->domain, $url->url); - })->toArray(); - - return new AnimeMessageDTO($anime->image->path, $anime->to_telegram_caption, $buttons); + return new AnimeMessageDTO( + $anime->image->path, + (string) AnimeCaptionText::fromAnime($anime), + $this->generateExternalLinks($anime) + ); } + /** + * @param LengthAwarePaginator $paginator + */ public function createMessageWithPagination( LengthAwarePaginator $paginator, CallbackDataTypeEnum $queryType ): AnimeMessageDTO { - $message = $this->createMessage($paginator->first()); + $anime = $paginator->first(); + + $buttons = [$this->generateExternalLinks($anime), $this->generatePagination($paginator, $queryType)]; + + return new AnimeMessageDTO( + $anime->image->path, + (string) AnimeCaptionText::fromAnime($anime), + $buttons + ); + } + + private function generateExternalLinks(Anime $anime): array + { + return $anime->urls->map( + static fn(AnimeUrl $url) => new InlineKeyboardButtonDTO($url->domain, $url->url) + )->toArray(); + } + + /** + * @param LengthAwarePaginator $paginator + */ + private function generatePagination( + LengthAwarePaginator $paginator, + CallbackDataTypeEnum $queryType + ): array { + $pagination = []; if ($paginator->previousPageUrl()) { - $message->addButton( - new InlineKeyboardButtonDTO( - text : '<', - callbackData: $this->callbackDataFactory->resolve( - new PaginationCallbackDataDTO($paginator->currentPage() - 1, $queryType) - ), + $pagination[] = new InlineKeyboardButtonDTO( + text : '<', + callbackData: $this->callbackDataFactory->resolve( + new PaginationCallbackDataDTO($paginator->currentPage() - 1, $queryType) ) ); } if ($paginator->hasMorePages()) { - $message->addButton( - new InlineKeyboardButtonDTO( - text : '>', - callbackData: $this->callbackDataFactory->resolve( - new PaginationCallbackDataDTO($paginator->currentPage() + 1, $queryType) - ), + $pagination[] = new InlineKeyboardButtonDTO( + text : '>', + callbackData: $this->callbackDataFactory->resolve( + new PaginationCallbackDataDTO($paginator->currentPage() + 1, $queryType) ) ); } - return $message; + return $pagination; } } diff --git a/src/app/Telegram/Commands/AnimeListCommand.php b/src/app/Telegram/Commands/AnimeListCommand.php index b9aa637d..99f248d2 100644 --- a/src/app/Telegram/Commands/AnimeListCommand.php +++ b/src/app/Telegram/Commands/AnimeListCommand.php @@ -32,6 +32,8 @@ public function handle(Nutgram $bot, AnimeMessageUseCase $animeMessageUseCase): 'exception_message' => $exception->getMessage(), 'exception_trace' => $exception->getTraceAsString(), ]); + + $bot->sendMessage(text: __('telegram.callbacks.anime_list.render_error')); } } } diff --git a/src/app/ValueObject/Telegram/Anime/AnimeCaptionText.php b/src/app/ValueObject/Telegram/Anime/AnimeCaptionText.php new file mode 100644 index 00000000..645d5356 --- /dev/null +++ b/src/app/ValueObject/Telegram/Anime/AnimeCaptionText.php @@ -0,0 +1,34 @@ + $this->anime->title, + 'status' => $this->anime->status->value, // @phpstan-ignore-line Ignored because of parser issues + 'episodes' => $this->anime->episodes, + 'rating' => $this->anime->rating, + 'voiceacting' => $this->anime->voiceActing->implode('name', ', '), + 'genres' => $this->anime->genres->implode('name', ', '), + ]); + } +} diff --git a/src/lang/en/telegram.php b/src/lang/en/telegram.php index 71fa6164..d576a547 100644 --- a/src/lang/en/telegram.php +++ b/src/lang/en/telegram.php @@ -45,4 +45,7 @@ ], ], + 'captions' => [ + 'anime' => "Title: :title\nStatus: :status\nEpisodes: :episodes\nRating: :rating\nVoice Acting: :voiceacting\nGenres: :genres", + ], ]; diff --git a/src/tests/Concerns/Fake/CanCreateFakeAnime.php b/src/tests/Concerns/Fake/CanCreateFakeAnime.php index 14e2af8d..cf96c66f 100644 --- a/src/tests/Concerns/Fake/CanCreateFakeAnime.php +++ b/src/tests/Concerns/Fake/CanCreateFakeAnime.php @@ -31,7 +31,7 @@ protected function createAnimeWithRelations(array $data = []): Anime } /** - * @return Collection + * @return Collection */ protected function createAnimeCollection(int $quantity = 1): Collection { @@ -39,7 +39,7 @@ protected function createAnimeCollection(int $quantity = 1): Collection } /** - * @return Collection + * @return Collection */ protected function createAnimeCollectionWithRelations(int $quantity = 1): Collection { diff --git a/src/tests/Feature/Telegram/Callbacks/AnimeListCallbackTest.php b/src/tests/Feature/Telegram/Callbacks/AnimeListCallbackTest.php index 48630928..7e71de25 100644 --- a/src/tests/Feature/Telegram/Callbacks/AnimeListCallbackTest.php +++ b/src/tests/Feature/Telegram/Callbacks/AnimeListCallbackTest.php @@ -7,12 +7,14 @@ use App\DTO\Factory\Telegram\CallbackData\PaginationCallbackDataDTO; use App\Factory\Telegram\CallbackData\CallbackDataFactory; use App\Models\Anime; +use App\ValueObject\Telegram\Anime\AnimeCaptionText; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\Concerns\CanCreateMocks; use Tests\Concerns\Fake\CanCreateFakeAnime; use Tests\TestCase; -class AnimeListCallbackTest extends TestCase +final class AnimeListCallbackTest extends TestCase { use RefreshDatabase; use CanCreateMocks; @@ -28,7 +30,7 @@ protected function setUp(): void $this->callbackDataFactory = $this->app->make(CallbackDataFactory::class); } - public function testCallbackWillNotRenderAnimeListIfDatabaseIsEmpty(): void + public function testWillNotRespondWithAnimeListIfDatabaseIsEmpty(): void { $callbackData = $this->callbackDataFactory->resolve(new PaginationCallbackDataDTO()); @@ -37,64 +39,70 @@ public function testCallbackWillNotRenderAnimeListIfDatabaseIsEmpty(): void ->assertReplyMessage(['text' => __('telegram.callbacks.anime_list.render_error')]); } - public function testCallbackWillRenderAnimeList(): void + public function testWillSwitchAnimeListPage(): void { - $anime = $this->createAnimeWithRelations(); - $callbackData = $this->callbackDataFactory->resolve(new PaginationCallbackDataDTO()); + /** @var Collection $list */ + $list = $this->createAnimeCollectionWithRelations(quantity: 2); + $firstPage = $this->callbackDataFactory->resolve(new PaginationCallbackDataDTO()); + $secondPage = $this->callbackDataFactory->resolve(new PaginationCallbackDataDTO(2)); - $reply = [ - 'type' => 'photo', - 'media' => $anime->image->path, - 'caption' => $anime->to_telegram_caption, - 'has_spoiler' => false, - ]; + $firstAnime = $list->first(); + $lastAnime = $list->last(); - $this->bot->hearCallbackQueryData($callbackData) + // First page render + $this->bot->hearCallbackQueryData($firstPage) ->reply() ->assertReplyMessage([ - 'media' => json_encode($reply), + 'media' => json_encode([ + 'type' => 'photo', + 'media' => $firstAnime->image->path, + 'caption' => (string) AnimeCaptionText::fromAnime($firstAnime), + 'has_spoiler' => false, + ]), + 'reply_markup' => json_encode([ + 'inline_keyboard' => [ + [ + [ + 'text' => $firstAnime->urls->first()->domain, + 'url' => $firstAnime->urls->first()->url, + ], + ], + [ + [ + 'text' => '>', + 'callback_data' => $secondPage, + ], + ], + ], + ]), ]); - } - - public function testCallbackWillRenderAnimeListWithPagination(): void - { - $animeCollection = $this->createAnimeCollectionWithRelations(quantity: 2); - $firstPage = $this->callbackDataFactory->resolve(new PaginationCallbackDataDTO()); - $secondPage = $this->callbackDataFactory->resolve(new PaginationCallbackDataDTO(2)); - $anime = $animeCollection->first(); - $this->assertInstanceOf(Anime::class, $anime); - - $media = [ - 'type' => 'photo', - 'media' => $anime->image->path, - 'caption' => $anime->to_telegram_caption, - 'has_spoiler' => false, - ]; - - $replyMarkup = [ - 'inline_keyboard' => [ - [ - [ - 'text' => $anime->urls->first()->domain, - 'url' => $anime->urls->first()->url, - ], - ], - [ - - [ - 'text' => '>', - 'callback_data' => $secondPage, - ], - ], - ], - ]; - - $this->bot->hearCallbackQueryData($firstPage) + // Second page render + $this->bot->hearCallbackQueryData($secondPage) ->reply() ->assertReplyMessage([ - 'media' => json_encode($media), - 'reply_markup' => json_encode($replyMarkup), + 'media' => json_encode([ + 'type' => 'photo', + 'media' => $lastAnime->image->path, + 'caption' => (string) AnimeCaptionText::fromAnime($lastAnime), + 'has_spoiler' => false, + ]), + 'reply_markup' => json_encode([ + 'inline_keyboard' => [ + [ + [ + 'text' => $lastAnime->urls->first()->domain, + 'url' => $lastAnime->urls->first()->url, + ], + ], + [ + [ + 'text' => '<', + 'callback_data' => $firstPage, + ], + ], + ], + ]), ]); } } diff --git a/src/tests/Feature/Telegram/Callbacks/ViewAnimeCallbackTest.php b/src/tests/Feature/Telegram/Callbacks/ViewAnimeCallbackTest.php index 338b65cb..e4284871 100644 --- a/src/tests/Feature/Telegram/Callbacks/ViewAnimeCallbackTest.php +++ b/src/tests/Feature/Telegram/Callbacks/ViewAnimeCallbackTest.php @@ -6,13 +6,14 @@ use App\DTO\Factory\Telegram\CallbackData\ViewAnimeCallbackDataDTO; use App\Factory\Telegram\CallbackData\CallbackDataFactory; +use App\ValueObject\Telegram\Anime\AnimeCaptionText; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Str; use Tests\Concerns\CanCreateMocks; use Tests\Concerns\Fake\CanCreateFakeAnime; use Tests\TestCase; -class ViewAnimeCallbackTest extends TestCase +final class ViewAnimeCallbackTest extends TestCase { use RefreshDatabase; use CanCreateMocks; @@ -28,7 +29,7 @@ protected function setUp(): void $this->callbackDataFactory = $this->app->make(CallbackDataFactory::class); } - public function testCallbackWillRespondWithFailureMessageItCouldNotMakeInlineMessageForCallbackData(): void + public function testWillRespondWithErrorMessageIfAnimeDoesNotExist(): void { // Create callback data for non-existing anime $callbackData = $this->callbackDataFactory->resolve(new ViewAnimeCallbackDataDTO(Str::uuid()->toString())); @@ -38,14 +39,14 @@ public function testCallbackWillRespondWithFailureMessageItCouldNotMakeInlineMes ]); } - public function testCallbackWillRespondWithInlineAnimeMessage(): void + public function testWillRespondWithAnimeMessage(): void { $anime = $this->createAnimeWithRelations(); $callbackData = $this->callbackDataFactory->resolve(new ViewAnimeCallbackDataDTO($anime->id)); $this->bot->hearCallbackQueryData($callbackData)->reply()->assertReplyMessage([ 'photo' => $anime->image->path, - 'caption' => $anime->to_telegram_caption, + 'caption' => (string) AnimeCaptionText::fromAnime($anime), ]); } } diff --git a/src/tests/Feature/Telegram/Commands/AnimeListCommandTest.php b/src/tests/Feature/Telegram/Commands/AnimeListCommandTest.php index d434fd72..a21b715f 100644 --- a/src/tests/Feature/Telegram/Commands/AnimeListCommandTest.php +++ b/src/tests/Feature/Telegram/Commands/AnimeListCommandTest.php @@ -4,62 +4,49 @@ namespace Tests\Feature\Telegram\Commands; -use App\DTO\Factory\Telegram\CallbackData\PaginationCallbackDataDTO; use App\Enums\Telegram\Actions\CommandEnum; -use App\Factory\Telegram\CallbackData\CallbackDataFactory; -use App\Models\Anime; +use App\ValueObject\Telegram\Anime\AnimeCaptionText; use Illuminate\Foundation\Testing\RefreshDatabase; -use Illuminate\Foundation\Testing\WithFaker; -use Tests\TestCase; use Tests\Concerns\CanCreateMocks; use Tests\Concerns\Fake\CanCreateFakeAnime; +use Tests\Feature\Telegram\Callbacks\AnimeListCallbackTest; +use Tests\TestCase; -class AnimeListCommandTest extends TestCase +final class AnimeListCommandTest extends TestCase { use RefreshDatabase; - use WithFaker; use CanCreateMocks; use CanCreateFakeAnime; - private CallbackDataFactory $callbackDataFactory; - protected function setUp(): void { parent::setUp(); $this->setUpFakeBot(); - $this->callbackDataFactory = $this->app->make(CallbackDataFactory::class); } - public function testCanGenerateAnimeList(): void + public function testWillNotRespondWithAnimeListIfDatabaseIsEmpty(): void { - $animeList = $this->createAnimeCollectionWithRelations(2); - - $firstPageData = $animeList->first(); - $lastPageData = $animeList->last(); - - $this->assertInstanceOf(Anime::class, $firstPageData); - $this->assertInstanceOf(Anime::class, $lastPageData); - - $secondPageCallback = $this->callbackDataFactory->resolve(new PaginationCallbackDataDTO(2)); - - // After pressing button or using command bot must render anime with pagination - // After pressing pagination button callback must render next page $this->bot->hearText(CommandEnum::ANIME_LIST_COMMAND->value) ->reply() ->assertReplyMessage([ - 'photo' => $firstPageData->image->path, - 'caption' => $firstPageData->to_telegram_caption, - ]) - ->hearCallbackQueryData($secondPageCallback) + 'text' => __('telegram.callbacks.anime_list.render_error'), + ]); + } + + /** + * This case only checks that command renders first page of a list. To check pagination + * @see AnimeListCallbackTest + */ + public function testCanRespondWithAnimeList(): void + { + $anime = $this->createAnimeWithRelations(); + + $this->bot->hearText(CommandEnum::ANIME_LIST_COMMAND->value) ->reply() ->assertReplyMessage([ - 'media' => json_encode([ - 'type' => 'photo', - 'media' => $lastPageData->image->path, - 'caption' => $lastPageData->to_telegram_caption, - 'has_spoiler' => false, - ]), + 'photo' => $anime->image->path, + 'caption' => (string) AnimeCaptionText::fromAnime($anime), ]); } } diff --git a/src/tests/Feature/Telegram/Commands/RandomAnimeCommandTest.php b/src/tests/Feature/Telegram/Commands/RandomAnimeCommandTest.php index c8580b03..8502754e 100644 --- a/src/tests/Feature/Telegram/Commands/RandomAnimeCommandTest.php +++ b/src/tests/Feature/Telegram/Commands/RandomAnimeCommandTest.php @@ -6,16 +6,15 @@ use App\Enums\Telegram\Actions\CommandEnum; use App\Enums\Telegram\Buttons\CommandButtonEnum; +use App\ValueObject\Telegram\Anime\AnimeCaptionText; use Illuminate\Foundation\Testing\RefreshDatabase; -use Illuminate\Foundation\Testing\WithFaker; use Tests\Concerns\CanCreateMocks; use Tests\Concerns\Fake\CanCreateFakeAnime; use Tests\TestCase; -class RandomAnimeCommandTest extends TestCase +final class RandomAnimeCommandTest extends TestCase { use RefreshDatabase; - use WithFaker; use CanCreateMocks; use CanCreateFakeAnime; @@ -26,27 +25,27 @@ protected function setUp(): void $this->setUpFakeBot(); } - public function testHandlerWillRespondWithTextMessageIfDatabaseIsEmpty(): void + public function testWillRespondWithErrorMessageIfDatabaseIsEmpty(): void { $this->bot->hearText(CommandEnum::RANDOM_ANIME_COMMAND->value)->reply()->assertReplyMessage( ['text' => __('telegram.commands.random_anime.unable_to_find_anime')] ); } - public function testCommandWillRespondWhenButtonIsPressed(): void + public function testWillRespondWithErrorMessageWhenButtonIsPressedAndDatabaseIsEmpty(): void { $this->bot->hearText(CommandButtonEnum::RANDOM_ANIME_BUTTON->value)->reply()->assertReplyMessage( ['text' => __('telegram.commands.random_anime.unable_to_find_anime')] ); } - public function testCommandWillSendMessageWithAnimeData(): void + public function testWillRespondWithAnimeMessage(): void { $anime = $this->createAnimeWithRelations(); $this->bot->hearText(CommandEnum::RANDOM_ANIME_COMMAND->value)->reply()->assertReplyMessage([ 'photo' => $anime->image->path, - 'caption' => $anime->to_telegram_caption, + 'caption' => (string) AnimeCaptionText::fromAnime($anime), ]); } } diff --git a/src/tests/Feature/Telegram/Conversations/AddAnimeConversationTest.php b/src/tests/Feature/Telegram/Conversations/AddAnimeConversationTest.php index 3bd9e20d..3fad42d8 100644 --- a/src/tests/Feature/Telegram/Conversations/AddAnimeConversationTest.php +++ b/src/tests/Feature/Telegram/Conversations/AddAnimeConversationTest.php @@ -144,7 +144,6 @@ public function testBotCanScrapeSupportedUrls(string $url): void ->assertReplyMessage(['text' => __('telegram.conversations.add_anime.scrape_has_ended')]); $anime = Anime::query()->first(); - $this->assertInstanceOf(Anime::class, $anime); Bus::assertDispatched(UpsertAnimeJob::class); Bus::assertDispatched(UploadJob::class, fn(UploadJob $job): bool => $job->image === $image); diff --git a/src/tests/Feature/Telegram/Conversations/SearchAnimeConversationTest.php b/src/tests/Feature/Telegram/Conversations/SearchAnimeConversationTest.php index c35abea8..4d79cfad 100644 --- a/src/tests/Feature/Telegram/Conversations/SearchAnimeConversationTest.php +++ b/src/tests/Feature/Telegram/Conversations/SearchAnimeConversationTest.php @@ -7,6 +7,7 @@ use App\Enums\Telegram\Actions\CommandEnum; use App\Facades\Telegram\State\UserStateFacade; use App\Models\Anime; +use App\ValueObject\Telegram\Anime\AnimeCaptionText; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithFaker; use Tests\Concerns\CanCreateMocks; @@ -14,7 +15,7 @@ use Tests\Helpers\Elasticsearch\JsonResponse; use Tests\TestCase; -class SearchAnimeConversationTest extends TestCase +final class SearchAnimeConversationTest extends TestCase { use RefreshDatabase; use WithFaker; @@ -67,7 +68,6 @@ public function testBotWillRespondWithSearchResultsAndPagination(): void UserStateFacade::shouldReceive('saveSearchResultPreview')->once(); $anime = $animeList->first(); - $this->assertInstanceOf(Anime::class, $anime); $this->bot->willStartConversation() ->hearText(CommandEnum::SEARCH_ANIME_COMMAND->value) @@ -77,7 +77,7 @@ public function testBotWillRespondWithSearchResultsAndPagination(): void ->reply() ->assertReplyMessage([ 'photo' => $anime->image->path, - 'caption' => $anime->to_telegram_caption, + 'caption' => (string) AnimeCaptionText::fromAnime($anime), ]); } @@ -109,7 +109,6 @@ public function testBotWillDeletePreviousSearchResultsOnNewSearch(): void UserStateFacade::shouldReceive('saveSearchResultPreview')->once(); $anime = $animeList->first(); - $this->assertInstanceOf(Anime::class, $anime); $this->bot->willStartConversation() ->hearText(CommandEnum::SEARCH_ANIME_COMMAND->value) diff --git a/src/tests/Feature/UseCase/Telegram/AnimeMessageUseCaseTest.php b/src/tests/Feature/UseCase/Telegram/AnimeMessageUseCaseTest.php index dc84337a..0f37a68c 100644 --- a/src/tests/Feature/UseCase/Telegram/AnimeMessageUseCaseTest.php +++ b/src/tests/Feature/UseCase/Telegram/AnimeMessageUseCaseTest.php @@ -8,9 +8,9 @@ use App\DTO\UseCase\Telegram\Anime\GenerateAnimeSearchResultDTO; use App\Exceptions\UseCase\Telegram\AnimeMessageException; use App\Facades\Telegram\State\UserStateFacade; -use App\Models\Anime; use App\Services\Telegram\EncoderService; use App\UseCase\Telegram\AnimeMessageUseCase; +use App\ValueObject\Telegram\Anime\AnimeCaptionText; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Str; @@ -18,7 +18,7 @@ use Tests\Concerns\Fake\CanCreateFakeAnime; use Tests\TestCase; -class AnimeMessageUseCaseTest extends TestCase +final class AnimeMessageUseCaseTest extends TestCase { use RefreshDatabase; use WithFaker; @@ -52,7 +52,7 @@ public function testCanGenerateAnimeMessage(): void $replyMarkup = $message->generateReplyMarkup(); $this->assertEquals($anime->image->path, $message->photo); - $this->assertEquals($anime->to_telegram_caption, $message->caption); + $this->assertEquals((string) AnimeCaptionText::fromAnime($anime), $message->caption); $this->assertNotEmpty($replyMarkup->inline_keyboard); $row = $replyMarkup->inline_keyboard[0]; // Message has only one row, but can have multiple buttons @@ -66,7 +66,7 @@ public function testCanGenerateAnimeMessage(): void public function testCanGenerateAnimeListMessage(): void { - $animeList = $this->createAnimeCollectionWithRelations(3); + $animeList = $this->createAnimeCollectionWithRelations(quantity: 3); // Starting from page 1 // Message must have only next page button and anime information @@ -74,9 +74,8 @@ public function testCanGenerateAnimeListMessage(): void $replyMarkup = $message->generateReplyMarkup(); $first = $animeList->first(); - $this->assertInstanceOf(Anime::class, $first); $this->assertEquals($first->image->path, $message->photo); - $this->assertEquals($first->to_telegram_caption, $message->caption); + $this->assertEquals((string) AnimeCaptionText::fromAnime($first), $message->caption); $keyboard = $replyMarkup->inline_keyboard; $this->assertNotEmpty($keyboard); @@ -92,19 +91,18 @@ public function testCanGenerateAnimeListMessage(): void $replyMarkup = $message->generateReplyMarkup(); $middle = $animeList->offsetGet(1); - $this->assertInstanceOf(Anime::class, $middle); $this->assertEquals($middle->image->path, $message->photo); - $this->assertEquals($middle->to_telegram_caption, $message->caption); + $this->assertEquals((string) AnimeCaptionText::fromAnime($middle), $message->caption); $keyboard = $replyMarkup->inline_keyboard; $this->assertNotEmpty($keyboard); - $this->assertCount(3, $keyboard); // Keyboard must have 3 rows: one for urls, others for controls + $this->assertCount(2, $keyboard); // Keyboard must have 2 rows: one for urls, others for controls $prevPage = $keyboard[1][0]; // Prev page button from first row $this->assertInstanceOf(InlineKeyboardButton::class, $prevPage); $this->assertEquals('<', $prevPage->text); - $nextPage = $keyboard[2][0]; // Next page button from second row + $nextPage = $keyboard[1][1]; // Next page button from second row $this->assertInstanceOf(InlineKeyboardButton::class, $nextPage); $this->assertEquals('>', $nextPage->text); @@ -114,9 +112,8 @@ public function testCanGenerateAnimeListMessage(): void $replyMarkup = $message->generateReplyMarkup(); $last = $animeList->last(); - $this->assertInstanceOf(Anime::class, $last); $this->assertEquals($last->image->path, $message->photo); - $this->assertEquals($last->to_telegram_caption, $message->caption); + $this->assertEquals((string) AnimeCaptionText::fromAnime($last), $message->caption); $keyboard = $replyMarkup->inline_keyboard; $this->assertNotEmpty($keyboard); @@ -141,7 +138,7 @@ public function testWillNotCreateSearchCaptionIfThereIsNoSearchResults(): void public function testWillCreateSearchCaptionIfThereIsSearchResults(): void { - $animeList = $this->createAnimeCollectionWithRelations(2); + $animeList = $this->createAnimeCollectionWithRelations(quantity: 2); UserStateFacade::shouldReceive('getSearchResult')->once()->andReturn( $animeList->pluck('id')->toArray() @@ -153,8 +150,7 @@ public function testWillCreateSearchCaptionIfThereIsSearchResults(): void $anime = $animeList->first(); - $this->assertInstanceOf(Anime::class, $anime); $this->assertEquals($anime->image->path, $message->photo); - $this->assertEquals($anime->to_telegram_caption, $message->caption); + $this->assertEquals((string) AnimeCaptionText::fromAnime($anime), $message->caption); } }