diff --git a/app/Dto/AnimeSearchCommand.php b/app/Dto/AnimeSearchCommand.php index a36dfb9..a44eb66 100644 --- a/app/Dto/AnimeSearchCommand.php +++ b/app/Dto/AnimeSearchCommand.php @@ -8,7 +8,6 @@ use App\Enums\AnimeRatingEnum; use App\Enums\AnimeStatusEnum; use App\Http\Resources\V4\AnimeCollection; use App\Rules\Attributes\EnumValidation; -use Spatie\Enum\Laravel\Rules\EnumRule; use Spatie\LaravelData\Attributes\MapInputName; use Spatie\LaravelData\Attributes\MapOutputName; use Spatie\LaravelData\Attributes\Validation\IntegerType; diff --git a/app/Dto/QueryAnimeSchedulesCommand.php b/app/Dto/QueryAnimeSchedulesCommand.php index 7e24dc3..86af08c 100644 --- a/app/Dto/QueryAnimeSchedulesCommand.php +++ b/app/Dto/QueryAnimeSchedulesCommand.php @@ -10,11 +10,11 @@ use App\Contracts\DataRequest; use App\Dto\Concerns\HasLimitParameter; use App\Dto\Concerns\HasPageParameter; use App\Dto\Concerns\HasSfwParameter; +use App\Dto\Concerns\MapsRouteParameters; use App\Dto\Concerns\PreparesData; use App\Enums\AnimeScheduleFilterEnum; use App\Rules\Attributes\EnumValidation; use Illuminate\Http\JsonResponse; -use Illuminate\Http\Request; use Spatie\LaravelData\Attributes\Validation\BooleanType; use Spatie\LaravelData\Attributes\WithCast; use Spatie\LaravelData\Data; @@ -25,26 +25,11 @@ use Spatie\LaravelData\Optional; */ final class QueryAnimeSchedulesCommand extends Data implements DataRequest { - use HasLimitParameter, HasRequestFingerprint, HasPageParameter, PreparesData, HasSfwParameter; + use HasLimitParameter, HasRequestFingerprint, HasPageParameter, PreparesData, HasSfwParameter, MapsRouteParameters; #[BooleanType, WithCast(ContextualBooleanCast::class)] public bool|Optional $kids = false; #[WithCast(EnumCast::class, AnimeScheduleFilterEnum::class), EnumValidation(AnimeScheduleFilterEnum::class)] - public ?AnimeScheduleFilterEnum $filter; - - /** @noinspection PhpUnused */ - public static function fromRequestAndDay(Request $request, ?string $day): self - { - /** - * @var QueryAnimeSchedulesCommand $data - */ - $data = self::fromRequest($request); - - if (!is_null($day)) { - $data->filter = AnimeScheduleFilterEnum::from($day); - } - - return $data; - } + public ?AnimeScheduleFilterEnum $dayFilter; } diff --git a/app/Exceptions/CustomTestException.php b/app/Exceptions/CustomTestException.php new file mode 100644 index 0000000..885120d --- /dev/null +++ b/app/Exceptions/CustomTestException.php @@ -0,0 +1,7 @@ +limit ?? Env::get("MAX_RESULTS_PER_PAGE", 25)); - $results = $this->repository->getCurrentlyAiring($request->filter, $request->kids, $request->sfw); + $results = $this->repository->getCurrentlyAiring($request->dayFilter, $request->kids, $request->sfw); $results = $results->paginate( $limit, ["*"], diff --git a/app/Http/Controllers/V4DB/ScheduleController.php b/app/Http/Controllers/V4DB/ScheduleController.php index b96d11e..4b2d66a 100644 --- a/app/Http/Controllers/V4DB/ScheduleController.php +++ b/app/Http/Controllers/V4DB/ScheduleController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers\V4DB; use App\Dto\QueryAnimeSchedulesCommand; -use Illuminate\Http\Request; class ScheduleController extends Controller { @@ -74,9 +73,13 @@ class ScheduleController extends Controller * } * ) */ - public function main(Request $request, ?string $day = null) + public function main(QueryAnimeSchedulesCommand $command) { - $command = QueryAnimeSchedulesCommand::from($request, $day); return $this->mediator->send($command); } + +// public function byDay(QueryAnimeSchedulesByDayCommand $command) +// { +// return $this->mediator->send($command); +// } } diff --git a/app/Producers.php b/app/Producers.php index 59ab7ab..093bcfb 100644 --- a/app/Producers.php +++ b/app/Producers.php @@ -3,11 +3,12 @@ namespace App; use App\Concerns\FilteredByLetter; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Jikan\Request\Producer\ProducerRequest; class Producers extends JikanApiSearchableModel { - use FilteredByLetter; + use FilteredByLetter, HasFactory; protected array $filters = ["order_by", "sort", "letter"]; /** diff --git a/app/Profile.php b/app/Profile.php index 86313bb..ba5a486 100644 --- a/app/Profile.php +++ b/app/Profile.php @@ -3,11 +3,12 @@ namespace App; use App\Concerns\FilteredByLetter; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Jikan\Request\User\UserProfileRequest; class Profile extends JikanApiSearchableModel { - use FilteredByLetter; + use FilteredByLetter, HasFactory; protected array $filters = []; /** diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 7c06831..f54bc7e 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -280,8 +280,8 @@ class AppServiceProvider extends ServiceProvider ]; foreach ($requestHandlersWithScraperService as $handlerClass => $repositoryInstance) { - $jikan = $app->make(MalClient::class); - $serializer = $app->make("SerializerV4"); + $jikan = $app->get("JikanParser"); + $serializer = $app->get("SerializerV4"); $scraperService = $app->make(DefaultCachedScraperService::class, ["repository" => $repositoryInstance, "jikan" => $jikan, "serializer" => $serializer]); $requestHandlers[] = $app->make($handlerClass, [ diff --git a/app/Testing/SyntheticMongoDbTransaction.php b/app/Testing/SyntheticMongoDbTransaction.php index 3b09480..18b7ade 100644 --- a/app/Testing/SyntheticMongoDbTransaction.php +++ b/app/Testing/SyntheticMongoDbTransaction.php @@ -52,7 +52,16 @@ trait SyntheticMongoDbTransaction "manga_reviews", "manga_stats", "manga_userupdates", - "people_pictures" + "people_pictures", + "reviews", + "recommendations", + "themes_anime", + "themes_manga", + "users_history", + "users_friends", + "users_recommendations", + "users_reviews", + "users_clubs" ]; foreach ($jikanModels as $jikanModel) diff --git a/app/Testing/TestExceptionsHandler.php b/app/Testing/TestExceptionsHandler.php new file mode 100644 index 0000000..378880c --- /dev/null +++ b/app/Testing/TestExceptionsHandler.php @@ -0,0 +1,32 @@ +instance('HttpClient', $httpClient); -$jikan = new \Jikan\MyAnimeList\MalClient(app('HttpClient')); +$jikan = new \Jikan\MyAnimeList\MalClient($httpClient); $app->instance('JikanParser', $jikan); $app->instance('SerializerV4', SerializerFactory::createV4()); diff --git a/database/factories/AnimeFactory.php b/database/factories/AnimeFactory.php index a4457da..611c3c3 100644 --- a/database/factories/AnimeFactory.php +++ b/database/factories/AnimeFactory.php @@ -29,6 +29,18 @@ class AnimeFactory extends JikanMediaModelFactory return [ "mal_id" => $mal_id, "url" => $this->createMalUrl($mal_id, "anime"), + "images" => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644.jpg', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644t.jpg', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644l.jpg', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644.webp', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644t.webp', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644l.webp', + ], + ], "titles" => [ [ "type" => "Default", @@ -48,11 +60,11 @@ class AnimeFactory extends JikanMediaModelFactory "duration" => "", "rating" => $this->getRandomRating(), "score" => $this->faker->randomFloat(2, 1.00, 9.99), - "scored_by" => $this->faker->randomDigitNotNull(), - "rank" => $this->faker->randomDigitNotNull(), - "popularity" => $this->faker->randomDigitNotNull(), - "members" => $this->faker->randomDigitNotNull(), - "favorites" => $this->faker->randomDigitNotNull(), + "scored_by" => $this->faker->randomDigitNotnull(), + "rank" => $this->faker->randomDigitNotnull(), + "popularity" => $this->faker->randomDigitNotnull(), + "members" => $this->faker->randomDigitNotnull(), + "favorites" => $this->faker->randomDigitNotnull(), "synopsis" => "test", "background" => "test", "premiered" => $this->faker->randomElement(["Winter", "Spring", "Fall", "Summer"]), @@ -62,6 +74,18 @@ class AnimeFactory extends JikanMediaModelFactory "timezone" => "Asia/Tokyo", "string" => "Tuesdays at 00:00 (JST)" ], + 'trailer' => [ + 'youtube_id' => null, + 'url' => null, + 'embed_url' => null, + 'images' => [ + 'image_url' => null, + 'small_image_url' => null, + 'medium_image_url' => null, + 'large_image_url' => null, + 'maximum_image_url' => null, + ], + ], "producers" => [ [ "mal_id" => 16, @@ -70,7 +94,7 @@ class AnimeFactory extends JikanMediaModelFactory "url" => "https://myanimelist.net/anime/producer/16/TV_Tokyo" ] ], - "lincesors" => [ + "licensors" => [ [ "mal_id" => 119, "type" => "anime", @@ -78,7 +102,14 @@ class AnimeFactory extends JikanMediaModelFactory "url" => "https://myanimelist.net/anime/producer/119/VIZ_Media" ] ], - "studios" => [], + "studios" => [ + [ + 'mal_id' => 14, + 'type' => 'anime', + 'name' => 'Sunrise', + 'url' => 'https://myanimelist.net/anime/producer/14/Sunrise', + ] + ], "genres" => [ [ "mal_id" => 1, diff --git a/database/factories/CharacterFactory.php b/database/factories/CharacterFactory.php index b6c883d..833af15 100644 --- a/database/factories/CharacterFactory.php +++ b/database/factories/CharacterFactory.php @@ -33,11 +33,11 @@ class CharacterFactory extends JikanModelFactory "name" => $this->faker->name(), "name_kanji" => "岡", "nicknames" => [], - "favorites" => $this->faker->randomDigitNotNull(), + "member_favorites" => $this->faker->randomDigitNotNull(), "about" => "test", "createdAt" => new UTCDateTime(), "modifiedAt" => new UTCDateTime(), - "request_hash" => sprintf("request:%s:%s", "v4", $this->getItemTestUrl("character", $mal_id)), + "request_hash" => sprintf("request:%s:%s", "characters", $this->getItemTestUrl("character", $mal_id)), "animeography" => [], "mangaography" => [], "voice_actors" => [ @@ -45,7 +45,11 @@ class CharacterFactory extends JikanModelFactory "person" => [ "mal_id" => 11, "url" => "https://myanimelist.net/people/11/Kouichi_Yamadera", - "images" => [], + "images" => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/voiceactors/1/16847.jpg', + ], + ], "name" => "Yamadera, Kouichi" ], "language" => "Japanese" diff --git a/database/factories/JikanMediaModelFactory.php b/database/factories/JikanMediaModelFactory.php index eee77ec..b302bd1 100644 --- a/database/factories/JikanMediaModelFactory.php +++ b/database/factories/JikanMediaModelFactory.php @@ -201,8 +201,10 @@ abstract class JikanMediaModelFactory extends JikanModelFactory implements Media } if ($this->descriptor->hasRatingParam() && $additionalParams->has("rating")) { - - $overrides["rating"] = AnimeRatingEnum::from(strtolower($additionalParams["rating"]))->label; + $v = AnimeRatingEnum::tryFrom(strtolower($additionalParams["rating"])); + if (!is_null($v)) { + $overrides["rating"] = $v->value; + } } if ($additionalParams->has("genres")) { diff --git a/database/factories/MangaFactory.php b/database/factories/MangaFactory.php index 4d9a4e7..8cb6a73 100644 --- a/database/factories/MangaFactory.php +++ b/database/factories/MangaFactory.php @@ -22,6 +22,18 @@ class MangaFactory extends JikanMediaModelFactory return [ "mal_id" => $mal_id, "url" => $this->createMalUrl($mal_id, "manga"), + "images" => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644.jpg', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644t.jpg', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644l.jpg', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644.webp', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644t.webp', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644l.webp', + ], + ], "titles" => [ [ "type" => "Default", diff --git a/database/factories/PersonFactory.php b/database/factories/PersonFactory.php index 35409bb..ffd18c7 100644 --- a/database/factories/PersonFactory.php +++ b/database/factories/PersonFactory.php @@ -27,17 +27,26 @@ class PersonFactory extends JikanModelFactory "mal_id" => $mal_id, "url" => $this->createMalUrl($mal_id, "people"), "website_url" => "https://webiste.example", - "images" => [], + "images" => [ + "jpg" => [ + "image_url" => "https://cdn.myanimelist.net/images/voiceactors/1/55486.jpg" + ] + ], "name" => $name, "given_name" => $given_name, "family_name" => $family_name, - "alternate_names" => [], + "alternate_names" => [ + $this->faker->name() + ], "birthday" => $this->createRandomDateTime("-80 years")->toAtomString(), - "favorites" => $this->faker->randomDigitNotNull(), + "member_favorites" => $this->faker->randomDigitNotNull(), "about" => "test", "createdAt" => new UTCDateTime(), "modifiedAt" => new UTCDateTime(), - "request_hash" => sprintf("request:%s:%s", "v4", $this->getItemTestUrl("people", $mal_id)) + "request_hash" => sprintf("request:%s:%s", "v4", $this->getItemTestUrl("people", $mal_id)), + "published_manga" => [], + "voice_acting_roles" => [], + "anime_staff_positions" => [] ]; } } diff --git a/database/factories/ProducersFactory.php b/database/factories/ProducersFactory.php new file mode 100644 index 0000000..5fbedea --- /dev/null +++ b/database/factories/ProducersFactory.php @@ -0,0 +1,51 @@ +createMalId(); + $url = $this->createMalUrl($mal_id, "anime/producer"); + + return [ + "mal_id" => $mal_id, + "url" => $url, + "request_hash" => sprintf("request:%s:%s", "producers", $this->getItemTestUrl("producers", $mal_id)), + "images" => [ + "jpg" => [ + "image_url" => "https://cdn.myanimelist.net/images/company/441.png" + ] + ], + "name" => $this->faker->name(), + "titles" => [ + [ + "type" => "Default", + "title" => $this->faker->name() + ] + ], + "createdAt" => new UTCDateTime(), + "modifiedAt" => new UTCDateTime(), + "favorites" => 535, + "established" => new UTCDateTime(Carbon::now()->sub($this->faker->randomNumber(2, true) . " days")->getPreciseTimestamp(3)), + "about" => "", + "external_links" => [ + [ + "name" => $this->faker->name(), + "url" => $this->faker->url() + ] + ], + "count" => $this->faker->randomNumber() + ]; + } +} diff --git a/database/factories/ProfileFactory.php b/database/factories/ProfileFactory.php new file mode 100644 index 0000000..f1f4b6e --- /dev/null +++ b/database/factories/ProfileFactory.php @@ -0,0 +1,170 @@ +createMalId(); + $username = $this->faker->userName(); + $url = $this->createMalUrl($username, "profile"); + + return [ + "mal_id" => $mal_id, + "username" => $username, + "url" => $url, + "request_hash" => sprintf("request:%s:%s", "users", $this->getItemTestUrl("users", $username)), + "images" => [ + "jpg" => [ + "image_url" => $this->faker->url() + ], + "webp" => [ + "image_url" => $this->faker->url() + ] + ], + "last_online" => new UTCDateTime($this->faker->dateTimeBetween('-5 years')->format('Uv')), + "gender" => $this->faker->randomElement(["Male", "Female", "Other"]), + "birthday" => new UTCDateTime($this->faker->dateTimeBetween('-60 years')->format('Uv')), + "location" => $this->faker->country(), + "joined" => new UTCDateTime($this->faker->dateTimeBetween('-5 years')->format('Uv')), + "createdAt" => new UTCDateTime(), + "modifiedAt" => new UTCDateTime(), + "anime_stats" => [ + 'days_watched' => 106.8, + 'mean_score' => 8.21, + 'watching' => 44, + 'completed' => 449, + 'on_hold' => 15, + 'dropped' => 3, + 'plan_to_watch' => 426, + 'total_entries' => 937, + 'rewatched' => 22, + 'episodes_watched' => 6305, + ], + "manga_stats" => [ + 'days_read' => 91, + 'mean_score' => 8.45, + 'reading' => 380, + 'completed' => 145, + 'on_hold' => 3, + 'dropped' => 1, + 'plan_to_read' => 58, + 'total_entries' => 587, + 'reread' => 1, + 'chapters_read' => 16263, + 'volumes_read' => 777, + ], + "favorites" => [ + "anime" => [ + [ + 'mal_id' => 9253, + 'url' => 'https://myanimelist.net/anime/9253/Steins_Gate', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/5/73199.jpg?s=bd7fc157718660193b28926006b3fd1c', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/5/73199t.jpg?s=bd7fc157718660193b28926006b3fd1c', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/5/73199l.jpg?s=bd7fc157718660193b28926006b3fd1c', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/5/73199.webp?s=bd7fc157718660193b28926006b3fd1c', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/5/73199t.webp?s=bd7fc157718660193b28926006b3fd1c', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/5/73199l.webp?s=bd7fc157718660193b28926006b3fd1c', + ], + ], + 'title' => 'Steins;Gate', + 'type' => 'TV', + 'start_year' => 2011, + ] + ], + "manga" => [ + [ + 'mal_id' => 642, + 'url' => 'https://myanimelist.net/manga/642/Vinland_Saga', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/manga/2/188925.jpg?s=967b5e2908beae63c5c22e61176ef728', + 'small_image_url' => 'https://cdn.myanimelist.net/images/manga/2/188925t.jpg?s=967b5e2908beae63c5c22e61176ef728', + 'large_image_url' => 'https://cdn.myanimelist.net/images/manga/2/188925l.jpg?s=967b5e2908beae63c5c22e61176ef728', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/manga/2/188925.webp?s=967b5e2908beae63c5c22e61176ef728', + 'small_image_url' => 'https://cdn.myanimelist.net/images/manga/2/188925t.webp?s=967b5e2908beae63c5c22e61176ef728', + 'large_image_url' => 'https://cdn.myanimelist.net/images/manga/2/188925l.webp?s=967b5e2908beae63c5c22e61176ef728', + ], + ], + 'title' => 'Vinland Saga', + 'type' => 'Manga', + 'start_year' => 2005, + ] + ], + "characters" => [ + [ + 'mal_id' => 34470, + 'url' => 'https://myanimelist.net/character/34470/Kurisu_Makise', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/characters/10/114399.jpg?s=f259c43bfc8346dad813e9491d507165', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/characters/10/114399.webp?s=f259c43bfc8346dad813e9491d507165', + 'small_image_url' => 'https://cdn.myanimelist.net/images/characters/10/114399t.webp?s=f259c43bfc8346dad813e9491d507165', + ], + ], + 'name' => 'Makise, Kurisu', + ] + ], + "people" => [ + [ + 'mal_id' => 39950, + 'url' => 'https://myanimelist.net/people/39950/Sayuri', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/voiceactors/1/57707.jpg?s=2998fa772aea87259bbf3855e6c52043', + ], + ], + 'name' => 'Sayuri', + ] + ] + ], + "last_updates" => [ + "anime" => [ + [ + 'entry' => [ + 'mal_id' => 15227, + 'url' => 'https://myanimelist.net/anime/15227/Kono_Sekai_no_Katasumi_ni', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/2/87704.jpg?s=222f784bad4c7505ec2761715f585cc9', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/2/87704t.jpg?s=222f784bad4c7505ec2761715f585cc9', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/2/87704l.jpg?s=222f784bad4c7505ec2761715f585cc9', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/2/87704.webp?s=222f784bad4c7505ec2761715f585cc9', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/2/87704t.webp?s=222f784bad4c7505ec2761715f585cc9', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/2/87704l.webp?s=222f784bad4c7505ec2761715f585cc9', + ], + ], + 'title' => 'Kono Sekai no Katasumi ni', + ], + 'score' => 0, + 'status' => 'Plan to Watch', + 'episodes_seen' => NULL, + 'episodes_total' => NULL, + 'date' => '2022-05-19T23:38:00+00:00', + ] + ], + "manga" => [] + ], + "about" => "", + ]; + } +} diff --git a/phpunit.xml b/phpunit.xml index 664b0f9..2b5359c 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -6,9 +6,6 @@ verbose="true" > - - ./tests/HttpV4/ - ./tests/Integration/ diff --git a/routes/web.v4.php b/routes/web.v4.php index 04e55d8..84b2137 100644 --- a/routes/web.v4.php +++ b/routes/web.v4.php @@ -269,7 +269,7 @@ $router->group( } ); -$router->get('schedules[/{day:[A-Za-z]+}]', [ +$router->get('schedules[/{dayFilter:[A-Za-z]+}]', [ 'uses' => 'ScheduleController@main' ]); diff --git a/tests/HttpV4/Controllers/AnimeControllerTest.php b/tests/HttpV4/Controllers/AnimeControllerTest.php deleted file mode 100644 index 867c7cb..0000000 --- a/tests/HttpV4/Controllers/AnimeControllerTest.php +++ /dev/null @@ -1,261 +0,0 @@ -searchIndexModelCleanupList = ["App\\Anime"]; - } - - private function givenDummyCharactersStaffData($uri) - { - DB::table("anime_characters_staff")->insert([ - "createdAt" => new UTCDateTime(), - "modifiedAt" => new UTCDateTime(), - "request_hash" => "request:anime:" . sha1($uri), - "characters" => [ - [ - "character" => [ - "mal_id" => 3, - "url" => "https://myanimelist.net/character/3/Jet_Black", - "images" => [ - "jpg" => [ - "image_url" => "https://cdn.myanimelist.net/images/characters/11/253723.jpg?s=6c8a19a79a88c46ae15f30e3ef5fd839", - "small_image_url" => "https://cdn.myanimelist.net/images/characters/11/253723t.jpg?s=6c8a19a79a88c46ae15f30e3ef5fd839" - ], - "webp" => [ - "image_url" => "https://cdn.myanimelist.net/images/characters/11/253723.webp?s=6c8a19a79a88c46ae15f30e3ef5fd839", - "small_image_url" => "https://cdn.myanimelist.net/images/characters/11/253723t.webp?s=6c8a19a79a88c46ae15f30e3ef5fd839" - ] - ], - "name" => "Black, Jet" - ], - "role" => "Main", - "favorites" => 1, - "voice_actors" => [ - [ - "person" => [ - "mal_id" => 357, - "url" => "https://myanimelist.net/people/357/Unshou_Ishizuk", - "images" => [ - "jpg" => [ - "image_url" => "https://cdn.myanimelist.net/images/voiceactors/2/17135.jpg?s=5925123b8a7cf9b51a445c225442f0ef" - ] - ], - "name" => "Ishizuka, Unshou" - ], - "language" => "Japanese" - ] - ] - ] - ], - "staff" => [ - [ - "person" => [ - "mal_id" => 40009, - "url" => "https://myanimelist.net/people/40009/Yutaka_Maseba", - "images" => [ - "jpg" => [ - "image_url" => "https://cdn.myanimelist.net/images/voiceactors/3/40216.jpg?s=d9fb7a625868ec7d9cd3804fa0da3fd6" - ] - ], - "name" => "Maseba, Yutaka" - ], - "positions" => [ - "Producer" - ] - ] - ] - ]); - } - - public function testMain() - { - Anime::factory(1)->create([ - "mal_id" => 1 - ]); - $this->getJson('/v4/anime/1') - ->seeStatusCode(200) - ->seeJsonStructure(['data' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'trailer' => [ - 'youtube_id', - 'url', - 'embed_url', - 'images' => [ - 'image_url', - 'small_image_url', - 'medium_image_url', - 'large_image_url', - 'maximum_image_url', - ] - ], - 'title', - 'title_english', - 'title_japanese', - 'title_synonyms', - 'type', - 'source', - 'episodes', - 'status', - 'airing', - 'aired' => [ - 'from', - 'to', - 'prop' => [ - 'from' => [ - 'day', - 'month', - 'year' - ], - 'to' => [ - 'day', - 'month', - 'year' - ] - ], - 'string' - ], - 'duration', - 'rating', - 'score', - 'scored_by', - 'rank', - 'popularity', - 'members', - 'favorites', - 'synopsis', - 'background', - 'season', - 'year', - 'broadcast' => [ - 'day', - 'time', - 'timezone', - 'string' - ], - 'producers' => [ - [ - 'mal_id', - 'type', - 'name', - 'url' - ] - ], - 'licensors' => [ - [ - 'mal_id', - 'type', - 'name', - 'url' - ] - ], - 'studios' => [ - [ - 'mal_id', - 'type', - 'name', - 'url' - ] - ], - 'genres' => [ - [ - 'mal_id', - 'type', - 'name', - 'url' - ] - ], - ]]); - } - - public function testCharacters() - { - // let's avoid sending request to MAL in tests - $this->givenDummyCharactersStaffData("/v4/anime/1/characters"); - - $this->getJson('/v4/anime/1/characters') - ->seeStatusCode(200) - ->seeJsonStructure(['data' => [ - [ - 'character' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - ], - 'webp' => [ - 'image_url', - 'small_image_url', - ], - ], - 'name', - ], - 'role', - 'voice_actors' => [ - [ - 'person' => [ - 'mal_id', - 'images' => [ - 'jpg' => [ - 'image_url', - ], - ], - 'name' - ], - 'language' - ] - ] - ] - ]]); - } - - public function testStaff() - { - $this->givenDummyCharactersStaffData('/v4/anime/1/staff'); - $this->getJson('/v4/anime/1/staff') - ->seeStatusCode(200) - ->seeJsonStructure(['data'=>[ - [ - 'person' => [ - 'mal_id', - 'images' => [ - 'jpg' => [ - 'image_url', - ], - ], - 'name' - ], - 'positions' - ] - ]]); - } -} diff --git a/tests/HttpV4/Controllers/PersonControllerTest.php b/tests/HttpV4/Controllers/PersonControllerTest.php deleted file mode 100644 index 0a60bb7..0000000 --- a/tests/HttpV4/Controllers/PersonControllerTest.php +++ /dev/null @@ -1,154 +0,0 @@ -get('/v4/people/1') - ->seeStatusCode(200) - ->seeJsonStructure(['data'=>[ - 'mal_id', - 'url', - 'website_url', - 'images' => [ - 'jpg' => [ - 'image_url', - ], - ], - 'name', - 'given_name', - 'family_name', - 'alternate_names', - 'birthday', - 'favorites', - 'about', - ]]); - } - - - public function testAnimeography() - { - $this->get('/v4/people/1/anime') - ->seeStatusCode(200) - ->seeJsonStructure(['data'=>[ - [ - 'position', - 'anime' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'title' - ] - ] - ]]); - } - - public function testMangaography() - { - $this->get('/v4/characters/1/manga') - ->seeStatusCode(200) - ->seeJsonStructure(['data'=>[ - [ - 'role', - 'manga' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'title' - ] - ] - ]]); - } - - public function testVoices() - { - $this->get('/v4/people/1/voices') - ->seeStatusCode(200) - ->seeJsonStructure(['data'=>[ - [ - 'role', - 'anime' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'title' - ], - 'character' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - ], - 'webp' => [ - 'image_url', - 'small_image_url', - ], - ], - 'name' - ] - ] - ]]); - } - - public function testPictures() - { - $this->get('/v4/people/1/pictures') - ->seeStatusCode(200) - ->seeJsonStructure([ - 'data' => [ - [ - 'jpg' => [ - 'image_url' - ] - ] - ] - ]); - } - - public function test404() - { - $this->get('/v4/people/1000000') - ->seeStatusCode(404); - } -} diff --git a/tests/HttpV4/Controllers/RecommendationsControllerTest.php b/tests/HttpV4/Controllers/RecommendationsControllerTest.php deleted file mode 100644 index 8d99fdd..0000000 --- a/tests/HttpV4/Controllers/RecommendationsControllerTest.php +++ /dev/null @@ -1,55 +0,0 @@ -get('/v4/recommendations/anime') - ->seeStatusCode(200) - ->seeJsonStructure([ - 'pagination' => [ - 'last_visible_page', - 'has_next_page', - ], - 'data' => [ - [ - 'mal_id', - 'entry' => [ - [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'title' - ] - ], - 'content', - 'date', - 'user' => [ - 'username', - 'url', - ], - ] - ] - ]); - } - -} diff --git a/tests/HttpV4/Controllers/ReviewsControllerTest.php b/tests/HttpV4/Controllers/ReviewsControllerTest.php deleted file mode 100644 index 622c036..0000000 --- a/tests/HttpV4/Controllers/ReviewsControllerTest.php +++ /dev/null @@ -1,123 +0,0 @@ -get('/v4/reviews/anime') - ->seeStatusCode(200) - ->seeJsonStructure([ - 'pagination' => [ - 'last_visible_page', - 'has_next_page', - ], - 'data' => [ - [ - 'mal_id', - 'url', - 'type', - 'reactions', - 'date', - 'review', - 'score', - 'tags', - 'is_spoiler', - 'is_preliminary', - 'episodes_watched', - 'entry' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'title' - ], - 'user' => [ - 'username', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url' - ], - 'webp' => [ - 'image_url' - ] - ] - ], - ] - ] - ]); - } - - public function testMangaReviews() - { - $this->get('/v4/reviews/manga') - ->seeStatusCode(200) - ->seeJsonStructure([ - 'pagination' => [ - 'last_visible_page', - 'has_next_page', - ], - 'data' => [ - [ - 'mal_id', - 'url', - 'type', - 'reactions', - 'date', - 'review', - 'score', - 'tags', - 'is_spoiler', - 'is_preliminary', - 'chapters_read', - 'entry' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'title' - ], - 'user' => [ - 'username', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url' - ], - 'webp' => [ - 'image_url' - ] - ] - ], - ] - ] - ]); - } -} diff --git a/tests/HttpV4/Controllers/ScheduleControllerTest.php b/tests/HttpV4/Controllers/ScheduleControllerTest.php deleted file mode 100644 index 2a9b761..0000000 --- a/tests/HttpV4/Controllers/ScheduleControllerTest.php +++ /dev/null @@ -1,99 +0,0 @@ -get('/v4/schedules') - ->seeStatusCode(200) - ->seeJsonStructure(['data' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'trailer' => [ - 'youtube_id', - 'url', - 'embed_url', - 'images' => [ - 'image_url', - 'small_image_url', - 'medium_image_url', - 'large_image_url', - 'maximum_image_url', - ] - ], - 'title', - 'title_english', - 'title_japanese', - 'title_synonyms', - 'type', - 'source', - 'episodes', - 'status', - 'airing', - 'aired' => [ - 'from', - 'to', - 'prop' => [ - 'from' => [ - 'day', - 'month', - 'year' - ], - 'to' => [ - 'day', - 'month', - 'year' - ] - ], - 'string' - ], - 'duration', - 'rating', - 'score', - 'scored_by', - 'rank', - 'popularity', - 'members', - 'favorites', - 'synopsis', - 'background', - 'season', - 'year', - 'broadcast' => [ - 'day', - 'time', - 'timezone', - 'string' - ], - 'producers', - 'licensors', - 'studios', - 'genres', - ]]); - } - - public function test400() - { - $this->get('/v4/schedules/asdjkhas') - ->seeStatusCode(400); - } -} diff --git a/tests/HttpV4/Controllers/WatchControllerTest.php b/tests/HttpV4/Controllers/WatchControllerTest.php deleted file mode 100644 index cb6ad02..0000000 --- a/tests/HttpV4/Controllers/WatchControllerTest.php +++ /dev/null @@ -1,180 +0,0 @@ -get('/v4/watch/episodes') - ->seeStatusCode(200) - ->seeJsonStructure([ - 'pagination' => [ - 'last_visible_page', - 'has_next_page', - ], - 'data' => [ - [ - 'entry' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'title' - ], - 'episodes' => [ - [ - 'mal_id', - 'url', - 'title', - 'premium' - ] - ], - ] - ] - ]); - - $this->get('/v4/watch/episodes/popular') - ->seeStatusCode(200) - ->seeJsonStructure([ - 'pagination' => [ - 'last_visible_page', - 'has_next_page', - ], - 'data' => [ - [ - 'entry' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'title' - ], - 'episodes' => [ - [ - 'mal_id', - 'url', - 'title', - 'premium' - ] - ], - ] - ] - ]); - } - - public function testWatchPromos() - { - $this->get('/v4/watch/promos') - ->seeStatusCode(200) - ->seeJsonStructure([ - 'pagination' => [ - 'last_visible_page', - 'has_next_page', - ], - 'data' => [ - [ - 'title', - 'entry' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'title' - ], - 'trailer' => [ - 'youtube_id', - 'url', - 'embed_url', - 'images' => [ - 'image_url', - 'small_image_url', - 'medium_image_url', - 'large_image_url', - 'maximum_image_url', - ] - ], - ] - ] - ]); - - $this->get('/v4/watch/promos/popular') - ->seeStatusCode(200) - ->seeJsonStructure([ - 'pagination' => [ - 'last_visible_page', - 'has_next_page', - ], - 'data' => [ - [ - 'title', - 'entry' => [ - 'mal_id', - 'url', - 'images' => [ - 'jpg' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - 'webp' => [ - 'image_url', - 'small_image_url', - 'large_image_url' - ], - ], - 'title' - ], - 'trailer' => [ - 'youtube_id', - 'url', - 'embed_url', - 'images' => [ - 'image_url', - 'small_image_url', - 'medium_image_url', - 'large_image_url', - 'maximum_image_url', - ] - ], - ] - ] - ]); - } - -} diff --git a/tests/Integration/AnimeControllerTest.php b/tests/Integration/AnimeControllerTest.php new file mode 100644 index 0000000..acc5185 --- /dev/null +++ b/tests/Integration/AnimeControllerTest.php @@ -0,0 +1,924 @@ +searchIndexModelCleanupList = ["App\\Anime"]; + } + + public function testMain() + { + Anime::factory(1)->createOne([ + "mal_id" => 1, + "studios" => [ + [ + 'mal_id' => 18, + 'type' => 'anime', + 'name' => 'Toei Animation', + 'url' => 'https://myanimelist.net/anime/producer/18/Toei_Animation', + ] + ], + "producers" => [ + [ + 'mal_id' => 16, + 'type' => 'anime', + 'name' => 'TV Tokyo', + 'url' => 'https://myanimelist.net/anime/producer/16/TV_Tokyo', + ] + ], + "licensors" => [ + [ + 'mal_id' => 102, + 'type' => 'anime', + 'name' => 'Funimation', + 'url' => 'https://myanimelist.net/anime/producer/102/Funimation', + ] + ] + ]); + $this->getJson('/v4/anime/1') + ->seeStatusCode(200) + ->seeJsonStructure(['data' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'trailer' => [ + 'youtube_id', + 'url', + 'embed_url', + 'images' => [ + 'image_url', + 'small_image_url', + 'medium_image_url', + 'large_image_url', + 'maximum_image_url', + ] + ], + 'title', + 'title_english', + 'title_japanese', + 'title_synonyms', + 'type', + 'source', + 'episodes', + 'status', + 'airing', + 'aired' => [ + 'from', + 'to', + 'prop' => [ + 'from' => [ + 'day', + 'month', + 'year' + ], + 'to' => [ + 'day', + 'month', + 'year' + ] + ], + 'string' + ], + 'duration', + 'rating', + 'score', + 'scored_by', + 'rank', + 'popularity', + 'members', + 'favorites', + 'synopsis', + 'background', + 'season', + 'year', + 'broadcast' => [ + 'day', + 'time', + 'timezone', + 'string' + ], + 'producers' => [ + [ + 'mal_id', + 'type', + 'name', + 'url' + ] + ], + 'licensors' => [ + [ + 'mal_id', + 'type', + 'name', + 'url' + ] + ], + 'studios' => [ + [ + 'mal_id', + 'type', + 'name', + 'url' + ] + ], + 'genres' => [ + [ + 'mal_id', + 'type', + 'name', + 'url' + ] + ], + ]]); + } + + public function testCharacters() + { + // let's avoid sending request to MAL in tests + $this->givenDummyCharactersStaffData("/v4/anime/1/characters", "anime"); + + $this->getJson('/v4/anime/1/characters') + ->seeStatusCode(200) + ->seeJsonStructure(['data' => [ + [ + 'character' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + ], + 'webp' => [ + 'image_url', + 'small_image_url', + ], + ], + 'name', + ], + 'role', + 'voice_actors' => [ + [ + 'person' => [ + 'mal_id', + 'images' => [ + 'jpg' => [ + 'image_url', + ], + ], + 'name' + ], + 'language' + ] + ] + ] + ]]); + } + + public function testStaff() + { + $this->givenDummyCharactersStaffData('/v4/anime/1/staff', "anime"); + $this->getJson('/v4/anime/1/staff') + ->seeStatusCode(200) + ->seeJsonStructure(['data'=>[ + [ + 'person' => [ + 'mal_id', + 'images' => [ + 'jpg' => [ + 'image_url', + ], + ], + 'name' + ], + 'positions' + ] + ]]); + } + + private function dummyEpisode(): array + { + return [ + "mal_id" => 301, + "url" => "https://myanimelist.net/anime/516/Keroro_Gunsou/episode/301", + "title" => "Tamama, Exiled from the Nishizawa House, Sir? / Momoka: A Chocolate ", + "title_japanese" => null, + "title_romanji" => null, + "aired" => null, + "filler" => false, + "recap" => false, + "score" => 4.5, + "forum_url" => null + ]; + } + + public function testEpisodesOne() + { + DB::table("anime_episodes")->insert( + $this->dummyResultsDocument("/v4/anime/1/episodes", "anime", [ + $this->dummyEpisode() + ]) + ); + $this->get('/v4/anime/1/episodes') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'mal_id', + 'url', + 'title', + 'title_japanese', + 'title_romanji', + 'aired', + 'score', + 'filler', + 'recap', + 'forum_url' + ] + ] + ]); + } + + public function testEpisodesTwo() + { + DB::table("anime_episodes")->insert( + $this->dummyResultsDocument( + "/v4/anime/21/episodes?page=2", + "anime", + array_fill(0, 24, $this->dummyEpisode()), + true, + 2 + ) + ); + $this->get('/v4/anime/21/episodes?page=2') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'mal_id', + 'url', + 'title', + 'title_japanese', + 'title_romanji', + 'aired', + 'score', + 'filler', + 'recap', + 'forum_url' + ] + ] + ]); + } + + public function testEpisode() + { + $document = $this->dummyScraperResultDocument('/v4/anime/21/episodes/1', "anime", [ + 'mal_id' => 1, + 'url' => 'https://myanimelist.net/anime/21/One_Piece/episode/1', + 'title' => 'I\'m Luffy! The Man Who\'s Gonna Be King of the Pirates!', + 'title_japanese' => '俺はルフィ!海賊王になる男だ!', + 'title_romanji' => 'Ore wa Luffy! Kaizoku Ou ni Naru Otoko Da!', + 'duration' => 1475, + 'aired' => '1999-10-20T00:00:00+09:00', + 'filler' => false, + 'recap' => false, + 'synopsis' => 'The series begins with an attack' + ]); + DB::table("anime_episode")->insert($document); + $this->get('/v4/anime/21/episodes/1') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'data' => [ + 'mal_id', + 'url', + 'title', + 'title_japanese', + 'title_romanji', + 'duration', + 'aired', + 'aired', + 'filler', + 'recap', + 'synopsis', + ] + ]); + } + + public function testNews() + { + $document = $this->dummyResultsDocument('/v4/anime/1/news', 'anime', [[ + 'mal_id' => 60609964, + 'url' => 'https://myanimelist.net/news/60609964', + 'title' => 'North American Anime & Manga Releases for September', + 'date' => '2020-08-31T14:34:00+00:00', + 'author_username' => 'ImperfectBlue', + 'author_url' => 'https://myanimelist.net/profile/ImperfectBlue', + 'forum_url' => 'https://myanimelist.net/forum/?topicid=1862079', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/s/common/uploaded_files/1598909553-a6f9acc1b6c36cd7b792e5bd67321c13.png?s=3b52b4fe7a2670d33b32d8397d2776bb', + ], + ], + 'comments' => 0, + 'excerpt' => 'Here are the North American anime & manga releases for September Week 1: September 1 - 7 Anime Releases Africa no Salaryman (TV) (Africa Salaryman) Complete Coll...', + ]]); + DB::table("anime_news")->insert($document); + $this->get('/v4/anime/1/news') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'mal_id', + 'url', + 'title', + 'date', + 'author_username', + 'author_url', + 'forum_url', + 'images' => [ + 'jpg' => [ + 'image_url', + ], + ], + 'comments', + 'excerpt' + ] + ] + ]); + } + + public function testPictures() + { + $document = $this->dummyScraperResultDocument( + '/v4/anime/1/pictures', + 'anime', + [[ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/7/3791.jpg', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/7/3791t.jpg', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/7/3791l.jpg', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/7/3791.webp', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/7/3791t.webp', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/7/3791l.webp', + ], + ]], + 'pictures' + ); + DB::table("anime_pictures")->insert($document); + $this->get('/v4/anime/1/pictures') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'data' => [ + [ + 'jpg' => [ + 'image_url', + 'large_image_url', + 'small_image_url', + ], + 'webp' => [ + 'image_url', + 'large_image_url', + 'small_image_url', + ] + ] + ] + ]); + } + + public function testVideos() + { + $document = $this->dummyScraperResultDocument( + '/v4/anime/1/videos', + 'anime', + [ + 'promo' => [ + [ + 'title' => 'PV Blu-ray Box version', + 'trailer' => [ + 'youtube_id' => 'qig4KOK2R2g', + 'url' => 'https://www.youtube.com/watch?v=qig4KOK2R2g', + 'embed_url' => 'https://www.youtube.com/embed/qig4KOK2R2g?enablejsapi=1&wmode=opaque&autoplay=1', + 'images' => [ + 'image_url' => 'https://img.youtube.com/vi/qig4KOK2R2g/default.jpg', + 'small_image_url' => 'https://img.youtube.com/vi/qig4KOK2R2g/sddefault.jpg', + 'medium_image_url' => 'https://img.youtube.com/vi/qig4KOK2R2g/mqdefault.jpg', + 'large_image_url' => 'https://img.youtube.com/vi/qig4KOK2R2g/hqdefault.jpg', + 'maximum_image_url' => 'https://img.youtube.com/vi/qig4KOK2R2g/maxresdefault.jpg', + ], + ], + ] + ], + 'episodes' => [ + [ + 'mal_id' => 26, + 'title' => 'The Real Folk Blues (part 2)', + 'episode' => 'Episode 26', + 'url' => 'https://myanimelist.net/anime/1/Cowboy_Bebop/episode/26', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://img1.ak.crunchyroll.com/i/spire1-tmb/191b230426f0b0e6568b4ca6edab47321473136587_large.jpg', + ], + ], + ] + ], + 'music_videos' => [ + [ + 'title' => 'OP 1 (Artist ver.)', + 'video' => [ + 'youtube_id' => 'wbaILDE7Dco', + 'url' => 'https://www.youtube.com/watch?v=wbaILDE7Dco', + 'embed_url' => 'https://www.youtube.com/embed/wbaILDE7Dco?enablejsapi=1&wmode=opaque&autoplay=1', + 'images' => [ + 'image_url' => 'https://img.youtube.com/vi/wbaILDE7Dco/default.jpg', + 'small_image_url' => 'https://img.youtube.com/vi/wbaILDE7Dco/sddefault.jpg', + 'medium_image_url' => 'https://img.youtube.com/vi/wbaILDE7Dco/mqdefault.jpg', + 'large_image_url' => 'https://img.youtube.com/vi/wbaILDE7Dco/hqdefault.jpg', + 'maximum_image_url' => 'https://img.youtube.com/vi/wbaILDE7Dco/maxresdefault.jpg', + ], + ], + 'meta' => [ + 'title' => '"heavenly blue"', + 'author' => 'Kalafina', + ], + ] + ] + ] + ); + DB::table('anime_videos')->insert($document); + $this->get('/v4/anime/1/videos') + ->seeStatusCode(200) + ->seeJsonStructure(['data'=>[ + 'promo' => [ + [ + 'title', + 'trailer' => [ + 'youtube_id', + 'url', + 'embed_url', + 'images' => [ + 'image_url', + 'small_image_url', + 'medium_image_url', + 'large_image_url', + 'maximum_image_url', + ] + ], + ] + ], + 'episodes' => [ + [ + 'mal_id', + 'title', + 'episode', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + ], + ], + ] + ], + 'music_videos' => [ + [ + 'title', + 'video' => [ + 'youtube_id', + 'url', + 'embed_url', + 'images' => [ + 'image_url', + 'small_image_url', + 'medium_image_url', + 'large_image_url', + 'maximum_image_url', + ], + ], + 'meta' => [ + 'title', + 'author', + ], + ] + ] + ]]); + } + + public function testStats() + { + $document = $this->dummyScraperResultDocument('/v4/anime/21/statistics', "anime", + [ + 'watching' => 1293641, + 'completed' => 37, + 'on_hold' => 239382, + 'dropped' => 164598, + 'plan_to_watch' => 195375, + 'total' => 1893033, + 'scores' => [ + [ + 'score' => 1, + 'votes' => 9470, + 'percentage' => 0.9, + ], + [ + 'score' => 2, + 'votes' => 3363, + 'percentage' => 0.3, + ], + ], + ] + ); + DB::table("anime_stats")->insert($document); + $this->get('/v4/anime/21/statistics') + ->seeStatusCode(200) + ->seeJsonStructure(['data'=>[ + 'watching', + 'completed', + 'on_hold', + 'dropped', + 'plan_to_watch', + 'total', + 'scores' => [ + [ + 'score', + 'votes', + 'percentage' + ] + ] + ]]); + } + + public function testForum() + { + $document = $this->dummyScraperResultDocument('/v4/anime/1/forum', "anime", [ + [ + 'mal_id' => 2022869, + 'url' => 'https://myanimelist.net/forum/?topicid=2022869', + 'title' => 'What was the reception like when this first came out?', + 'date' => '2022-06-15T00:00:00+00:00', + 'author_username' => 'NextUniverse', + 'author_url' => 'https://myanimelist.net/profile/NextUniverse', + 'comments' => 7, + 'last_comment' => [ + 'url' => 'https://myanimelist.net/forum/?topicid=2022869&goto=lastpost', + 'author_username' => 'Bacon_and_Eggs', + 'author_url' => 'https://myanimelist.net/profile/Bacon_and_Eggs', + 'date' => '2022-06-19T06:26:00+00:00', + ], + ] + ], "topics"); + DB::table("anime_forum")->insert($document); + $this->get('/v4/anime/1/forum') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'data' => [ + [ + 'mal_id', + 'url', + 'title', + 'date', + 'author_username', + 'author_url', + 'comments', + 'last_comment' => [ + 'url', + 'author_username', + 'author_url', + 'date' + ] + ] + ] + ]); + } + + public function testMoreInfo() + { + $document = $this->dummyScraperResultDocument('/v4/anime/1/moreinfo', "anime", ["moreinfo" => "asd"]); + DB::table("anime_moreinfo")->insert($document); + $this->get('/v4/anime/1/moreinfo') + ->seeStatusCode(200) + ->seeJsonStructure(['data'=>[ + 'moreinfo' + ]]); + } + + public function testReviewsOne() + { + $document = $this->dummyResultsDocument('/v4/anime/1/reviews', "anime", [ + [ + 'mal_id' => 7406, + 'url' => 'https://myanimelist.net/reviews.php?id=7406', + 'type' => 'anime', + 'reactions' => [ + 'overall' => 2112, + 'nice' => 2105, + 'love_it' => 3, + 'funny' => 1, + 'confusing' => 0, + 'informative' => 2, + 'well_written' => 1, + 'creative' => 0, + ], + 'date' => '2008-08-24T05:46:00+00:00', + 'review' => 'People who know me dd', + 'score' => 10, + 'tags' => [ + 0 => 'Recommended', + ], + 'is_spoiler' => false, + 'is_preliminary' => false, + 'episodes_watched' => NULL, + 'user' => [ + 'url' => 'https://myanimelist.net/profile/TheLlama', + 'username' => 'TheLlama', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/11081.jpg?t=1666216200', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/11081.webp?t=1666216200', + ], + ], + ], + ] + ]); + DB::table("anime_reviews")->insert($document); + $this->get('/v4/anime/1/reviews') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'mal_id', + 'url', + 'type', + 'reactions', + 'date', + 'review', + 'score', + 'tags', + 'is_spoiler', + 'is_preliminary', + 'episodes_watched', + 'user' => [ + 'url', + 'username', + 'images' => [ + 'jpg' => [ + 'image_url', + ], + 'webp' => [ + 'image_url', + ], + ], + ] + ] + ] + ]); + } + + public function testReviewsTwo() + { + $this->mockJikanParserWith404RespondingUpstream(); + $this->get('/v4/anime/1/reviews?page=100') + ->seeStatusCode(404) + ->seeJsonStructure([ + 'status', + 'type', + 'message', + 'error' + ]); + } + + public function testRecommendations() + { + $document = $this->dummyScraperResultDocument('/v4/anime/1/recommendations', 'anime', [ + 'recommendations' => [ + [ + 'entry' => [ + 'mal_id' => 205, + 'url' => 'https://myanimelist.net/anime/205/Samurai_Champloo', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599.jpg?s=690d61d9517bcc79a007c21f1e9b58e8', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599t.jpg?s=690d61d9517bcc79a007c21f1e9b58e8', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599l.jpg?s=690d61d9517bcc79a007c21f1e9b58e8', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599.webp?s=690d61d9517bcc79a007c21f1e9b58e8', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599t.webp?s=690d61d9517bcc79a007c21f1e9b58e8', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599l.webp?s=690d61d9517bcc79a007c21f1e9b58e8', + ], + ], + 'title' => 'Samurai Champloo', + ], + 'url' => 'https://myanimelist.net/recommendations/anime/1-205', + 'votes' => 118, + ] + ] + ]); + DB::table('anime_recommendations')->insert($document); + $this->get('/v4/anime/1/recommendations') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'data' => [ + [ + 'entry' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'title' + ], + 'url', + 'votes', + ] + ] + ]); + } + + public function testAnimeUserUpdates() + { + $document = $this->dummyResultsDocument('/v4/anime/1/userupdates', 'anime', [ + [ + 'user' => [ + 'username' => 'Mar-E', + 'url' => 'https://myanimelist.net/profile/Mar-E', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/12234611.jpg?t=1675204800', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/12234611.webp?t=1675204800', + ], + ], + ], + 'score' => NULL, + 'status' => 'Watching', + 'episodes_seen' => 16, + 'episodes_total' => 26, + 'date' => '2023-01-31T22:34:00+00:00', + ] + ]); + DB::table("anime_userupdates")->insert($document); + $this->get('/v4/anime/1/userupdates') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'user' => [ + 'username', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + ], + 'webp' => [ + 'image_url', + ], + ], + ], + 'score', + 'status', + 'episodes_seen', + 'episodes_total', + 'date' + ] + ] + ]); + } + + public function testAnimeUserUpdatesNotFound() + { + $this->mockJikanParserWith404RespondingUpstream(); + $this->get('/v4/anime/1/userupdates?page=200') + ->seeStatusCode(404); + } + + public function testAnimeRelations() + { + Anime::factory()->createOne([ + "mal_id" => 1, + "related" => [ + [ + 'relation' => 'Adaptation', + 'entry' => [ + 0 => [ + 'mal_id' => 173, + 'type' => 'manga', + 'name' => 'Cowboy Bebop', + 'url' => 'https://myanimelist.net/manga/173/Cowboy_Bebop', + ], + 1 => [ + 'mal_id' => 174, + 'type' => 'manga', + 'name' => 'Shooting Star Bebop: Cowboy Bebop', + 'url' => 'https://myanimelist.net/manga/174/Shooting_Star_Bebop__Cowboy_Bebop', + ], + ], + ] + ] + ]); + $this->get('/v4/anime/1/relations') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'data' => [ + [ + 'relation', + 'entry' => [ + [ + 'mal_id', + 'type', + 'name', + 'url' + ] + ], + ] + ] + ]); + } + + public function testAnimeThemes() + { + Anime::factory()->createOne([ + "mal_id" => 1, + "themes" => [ + [ + 'mal_id' => 50, + 'type' => 'anime', + 'name' => 'Adult Cast', + 'url' => 'https://myanimelist.net/anime/genre/50/Adult_Cast', + ] + ] + ]); + $this->get('/v4/anime/1/themes') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'data' => [ + 'openings', + 'endings', + ] + ]); + } + + public function test404() + { + $this->mockJikanParserWith404RespondingUpstream(); + $this->get('/v4/anime/2') + ->seeStatusCode(404); + } +} diff --git a/tests/HttpV4/Controllers/CharacterControllerTest.php b/tests/Integration/CharacterControllerTest.php similarity index 65% rename from tests/HttpV4/Controllers/CharacterControllerTest.php rename to tests/Integration/CharacterControllerTest.php index add966d..590419b 100644 --- a/tests/HttpV4/Controllers/CharacterControllerTest.php +++ b/tests/Integration/CharacterControllerTest.php @@ -3,6 +3,7 @@ namespace Tests\HttpV4\Controllers; use App\Character; use App\Testing\ScoutFlush; use App\Testing\SyntheticMongoDbTransaction; +use Illuminate\Support\Facades\DB; use Tests\TestCase; @@ -46,7 +47,18 @@ class CharacterControllerTest extends TestCase "anime" => [ "mal_id" => 1, "url" => "https://myanimelist.net/anime/1/Cowboy_Bebop", - "images" => [], + "images" => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644.jpg?s=42d7666179a2851c99fada2e0ceb5da1', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644t.jpg?s=42d7666179a2851c99fada2e0ceb5da1', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644l.jpg?s=42d7666179a2851c99fada2e0ceb5da1', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644.webp?s=42d7666179a2851c99fada2e0ceb5da1', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644t.webp?s=42d7666179a2851c99fada2e0ceb5da1', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644l.webp?s=42d7666179a2851c99fada2e0ceb5da1', + ], + ], "title" => "Cowboy Bebop" ] ] @@ -88,7 +100,18 @@ class CharacterControllerTest extends TestCase "manga" => [ "mal_id" => 1, "url" => "https://myanimelist.net/anime/1/Cowboy_Bebop", - "images" => [], + "images" => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644.jpg?s=42d7666179a2851c99fada2e0ceb5da1', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644t.jpg?s=42d7666179a2851c99fada2e0ceb5da1', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644l.jpg?s=42d7666179a2851c99fada2e0ceb5da1', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644.webp?s=42d7666179a2851c99fada2e0ceb5da1', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644t.webp?s=42d7666179a2851c99fada2e0ceb5da1', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/4/19644l.webp?s=42d7666179a2851c99fada2e0ceb5da1', + ], + ], "title" => "Cowboy Bebop" ] ] @@ -146,9 +169,16 @@ class CharacterControllerTest extends TestCase public function testPictures() { - Character::factory()->createOne([ - "mal_id" => 1 + $document = $this->dummyScraperResultDocument('/v4/characters/1/pictures', 'characters', [ + 'pictures' => [ + [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/characters/10/34138.jpg', + ], + ] + ] ]); + DB::table("characters_pictures")->insert($document); $this->get('/v4/characters/1/pictures') ->seeStatusCode(200) ->seeJsonStructure([ diff --git a/tests/HttpV4/Controllers/ClubControllerTest.php b/tests/Integration/ClubControllerTest.php similarity index 63% rename from tests/HttpV4/Controllers/ClubControllerTest.php rename to tests/Integration/ClubControllerTest.php index 41ed78a..cdf70b0 100644 --- a/tests/HttpV4/Controllers/ClubControllerTest.php +++ b/tests/Integration/ClubControllerTest.php @@ -16,8 +16,8 @@ class ClubControllerTest extends TestCase Club::factory()->createOne([ "mal_id" => 1 ]); - $t = $this->get('/v4/clubs/1'); - $t->seeStatusCode(200) + $this->get('/v4/clubs/1') + ->seeStatusCode(200) ->seeJsonStructure(['data'=>[ 'mal_id', 'name', @@ -36,32 +36,22 @@ class ClubControllerTest extends TestCase public function testMembers() { - $m = Club::factory()->createOne([ - "mal_id" => 1 - ]); $dummyUsername = $this->faker->userName(); - DB::table("clubs_members")->insert([ - // we are just copying the data from the manufactured model out of convenience - "createdAt" => $m->createdAt, - "modifiedAt" => $m->modifiedAt, - "has_next_page" => false, - "last_visible_page" => 1, - "request_hash" => "request:clubs:".sha1("/v4/clubs/1/members"), - "results" => [ - [ - "username" => $this->faker->userName(), - "url" => "https://myanimelist.net/profile/".$dummyUsername, - "images" => [ - "jpg" => [ - "image_url" => "http://httpbin.org/get" - ], - "webp" => [ - "image_url" => "http://httpbin.org/get" - ] + $document = $this->dummyResultsDocument('/v4/clubs/1/members', 'clubs', [ + [ + "username" => $this->faker->userName(), + "url" => "https://myanimelist.net/profile/".$dummyUsername, + "images" => [ + "jpg" => [ + "image_url" => "http://httpbin.org/get" + ], + "webp" => [ + "image_url" => "http://httpbin.org/get" ] ] ] ]); + DB::table("clubs_members")->insert($document); $this->get('/v4/clubs/1/members') ->seeStatusCode(200) ->seeJsonStructure([ @@ -84,9 +74,6 @@ class ClubControllerTest extends TestCase ] ] ]); - - $this->get('/v4/clubs/1000000/members') - ->seeStatusCode(404); } public function test404() diff --git a/tests/HttpV4/Controllers/GenreControllerTest.php b/tests/Integration/GenreControllerTest.php similarity index 89% rename from tests/HttpV4/Controllers/GenreControllerTest.php rename to tests/Integration/GenreControllerTest.php index 28b4bc4..f32717c 100644 --- a/tests/HttpV4/Controllers/GenreControllerTest.php +++ b/tests/Integration/GenreControllerTest.php @@ -1,5 +1,7 @@ createOne(); $this->get('/v4/genres/anime') ->seeStatusCode(200) ->seeJsonStructure(['data'=>[ @@ -25,6 +28,7 @@ class GenreControllerTest extends TestCase public function testMangaGenre() { + GenreManga::factory()->createOne(); $this->get('/v4/genres/manga') ->seeStatusCode(200) ->seeJsonStructure(['data'=>[ diff --git a/tests/HttpV4/Controllers/MagazineControllerTest.php b/tests/Integration/MagazineControllerTest.php similarity index 88% rename from tests/HttpV4/Controllers/MagazineControllerTest.php rename to tests/Integration/MagazineControllerTest.php index ec5cc8c..3251b7d 100644 --- a/tests/HttpV4/Controllers/MagazineControllerTest.php +++ b/tests/Integration/MagazineControllerTest.php @@ -13,8 +13,8 @@ class MagazineControllerTest extends TestCase public function testMagazinesListing() { Magazine::factory(1)->create(); - $test = $this->get('/v4/magazines'); - $test->seeStatusCode(200) + $this->get('/v4/magazines') + ->seeStatusCode(200) ->seeJsonStructure(['data' => [ [ 'mal_id', diff --git a/tests/HttpV4/Controllers/MangaControllerTest.php b/tests/Integration/MangaControllerTest.php similarity index 52% rename from tests/HttpV4/Controllers/MangaControllerTest.php rename to tests/Integration/MangaControllerTest.php index 2895485..89b16e8 100644 --- a/tests/HttpV4/Controllers/MangaControllerTest.php +++ b/tests/Integration/MangaControllerTest.php @@ -1,7 +1,9 @@ createOne([ + "mal_id" => 1 + ]); $this->get('/v4/manga/1') ->seeStatusCode(200) ->seeJsonStructure(['data' => [ @@ -91,6 +96,8 @@ class MangaControllerTest extends TestCase public function testCharacters() { + $this->givenDummyCharactersStaffData("/v4/manga/1/characters", "manga"); + $this->get('/v4/manga/1/characters') ->seeStatusCode(200) ->seeJsonStructure(['data'=>[ @@ -116,6 +123,23 @@ class MangaControllerTest extends TestCase public function testNews() { + $document = $this->dummyResultsDocument('/v4/manga/1/news', 'manga', [[ + 'mal_id' => 60609964, + 'url' => 'https://myanimelist.net/news/60609964', + 'title' => 'North American Anime & Manga Releases for September', + 'date' => '2020-08-31T14:34:00+00:00', + 'author_username' => 'ImperfectBlue', + 'author_url' => 'https://myanimelist.net/profile/ImperfectBlue', + 'forum_url' => 'https://myanimelist.net/forum/?topicid=1862079', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/s/common/uploaded_files/1598909553-a6f9acc1b6c36cd7b792e5bd67321c13.png?s=3b52b4fe7a2670d33b32d8397d2776bb', + ], + ], + 'comments' => 0, + 'excerpt' => 'Here are the North American anime & manga releases for September Week 1: September 1 - 7 Anime Releases Africa no Salaryman (TV) (Africa Salaryman) Complete Coll...', + ]]); + DB::table("manga_news")->insert($document); $this->get('/v4/manga/1/news') ->seeStatusCode(200) ->seeJsonStructure([ @@ -146,6 +170,24 @@ class MangaControllerTest extends TestCase public function testPictures() { + $document = $this->dummyScraperResultDocument( + '/v4/manga/1/pictures', + 'manga', + [[ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/manga/7/3791.jpg', + 'small_image_url' => 'https://cdn.myanimelist.net/images/manga/7/3791t.jpg', + 'large_image_url' => 'https://cdn.myanimelist.net/images/manga/7/3791l.jpg', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/manga/7/3791.webp', + 'small_image_url' => 'https://cdn.myanimelist.net/images/manga/7/3791t.webp', + 'large_image_url' => 'https://cdn.myanimelist.net/images/manga/7/3791l.webp', + ], + ]], + 'pictures' + ); + DB::table("manga_pictures")->insert($document); $this->get('/v4/manga/1/pictures') ->seeStatusCode(200) ->seeJsonStructure([ @@ -168,6 +210,29 @@ class MangaControllerTest extends TestCase public function testStats() { + $document = $this->dummyScraperResultDocument('/v4/manga/1/statistics', "manga", + [ + 'reading' => 1293641, + 'completed' => 37, + 'on_hold' => 239382, + 'dropped' => 164598, + 'plan_to_read' => 195375, + 'total' => 1893033, + 'scores' => [ + [ + 'score' => 1, + 'votes' => 9470, + 'percentage' => 0.9, + ], + [ + 'score' => 2, + 'votes' => 3363, + 'percentage' => 0.3, + ], + ], + ] + ); + DB::table("manga_stats")->insert($document); $this->get('/v4/manga/1/statistics') ->seeStatusCode(200) ->seeJsonStructure(['data'=>[ @@ -189,6 +254,24 @@ class MangaControllerTest extends TestCase public function testForum() { + $document = $this->dummyScraperResultDocument('/v4/manga/1/forum', "manga", [ + [ + 'mal_id' => 2022869, + 'url' => 'https://myanimelist.net/forum/?topicid=2022869', + 'title' => 'What was the reception like when this first came out?', + 'date' => '2022-06-15T00:00:00+00:00', + 'author_username' => 'NextUniverse', + 'author_url' => 'https://myanimelist.net/profile/NextUniverse', + 'comments' => 7, + 'last_comment' => [ + 'url' => 'https://myanimelist.net/forum/?topicid=2022869&goto=lastpost', + 'author_username' => 'Bacon_and_Eggs', + 'author_url' => 'https://myanimelist.net/profile/Bacon_and_Eggs', + 'date' => '2022-06-19T06:26:00+00:00', + ], + ] + ], "topics"); + DB::table("manga_forum")->insert($document); $this->get('/v4/manga/1/forum') ->seeStatusCode(200) ->seeJsonStructure([ @@ -214,6 +297,8 @@ class MangaControllerTest extends TestCase public function testMoreInfo() { + $document = $this->dummyScraperResultDocument('/v4/manga/1/moreinfo', "manga", ["moreinfo" => "asd"]); + DB::table("manga_moreinfo")->insert($document); $this->get('/v4/manga/1/moreinfo') ->seeStatusCode(200) ->seeJsonStructure(['data'=>[ @@ -223,6 +308,45 @@ class MangaControllerTest extends TestCase public function testReviews() { + $document = $this->dummyResultsDocument('/v4/manga/1/reviews', "manga", [ + [ + 'mal_id' => 7406, + 'url' => 'https://myanimelist.net/reviews.php?id=7406', + 'type' => 'manga', + 'reactions' => [ + 'overall' => 2112, + 'nice' => 2105, + 'love_it' => 3, + 'funny' => 1, + 'confusing' => 0, + 'informative' => 2, + 'well_written' => 1, + 'creative' => 0, + ], + 'date' => '2008-08-24T05:46:00+00:00', + 'review' => 'People who know me dd', + 'score' => 10, + 'tags' => [ + 0 => 'Recommended', + ], + 'is_spoiler' => false, + 'is_preliminary' => false, + 'chapters_read' => null, + 'user' => [ + 'url' => 'https://myanimelist.net/profile/TheLlama', + 'username' => 'TheLlama', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/11081.jpg?t=1666216200', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/11081.webp?t=1666216200', + ], + ], + ], + ] + ]); + DB::table("manga_reviews")->insert($document); $this->get('/v4/manga/1/reviews') ->seeStatusCode(200) ->seeJsonStructure([ @@ -258,20 +382,49 @@ class MangaControllerTest extends TestCase ] ] ]); + } + public function testReviewsTwo() + { + $this->mockJikanParserWith404RespondingUpstream(); $this->get('/v4/manga/1/reviews?page=100') ->seeStatusCode(404) ->seeJsonStructure([ - 'pagination' => [ - 'last_visible_page', - 'has_next_page', - ], - 'data' => [] + 'status', + 'type', + 'message', + 'error' ]); } public function testRecommendations() { + $document = $this->dummyScraperResultDocument('/v4/manga/1/recommendations', 'manga', [ + 'recommendations' => [ + [ + 'entry' => [ + 'mal_id' => 205, + 'url' => 'https://myanimelist.net/anime/205/Samurai_Champloo', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599.jpg?s=690d61d9517bcc79a007c21f1e9b58e8', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599t.jpg?s=690d61d9517bcc79a007c21f1e9b58e8', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599l.jpg?s=690d61d9517bcc79a007c21f1e9b58e8', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599.webp?s=690d61d9517bcc79a007c21f1e9b58e8', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599t.webp?s=690d61d9517bcc79a007c21f1e9b58e8', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/1375/121599l.webp?s=690d61d9517bcc79a007c21f1e9b58e8', + ], + ], + 'title' => 'Samurai Champloo', + ], + 'url' => 'https://myanimelist.net/recommendations/anime/1-205', + 'votes' => 118, + ] + ] + ]); + DB::table('manga_recommendations')->insert($document); $this->get('/v4/manga/1/recommendations') ->seeStatusCode(200) ->seeJsonStructure([ @@ -303,6 +456,30 @@ class MangaControllerTest extends TestCase public function testUserUpdates() { + $document = $this->dummyResultsDocument('/v4/manga/1/userupdates', 'manga', [ + [ + 'user' => [ + 'username' => 'Mar-E', + 'url' => 'https://myanimelist.net/profile/Mar-E', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/12234611.jpg?t=1675204800', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/12234611.webp?t=1675204800', + ], + ], + ], + 'score' => NULL, + 'status' => 'Watching', + 'volumes_read' => 16, + 'volumes_total' => 26, + 'chapters_read' => 22, + 'chapters_total' => 22, + 'date' => '2023-01-31T22:34:00+00:00', + ] + ]); + DB::table("manga_userupdates")->insert($document); $this->get('/v4/manga/1/userupdates') ->seeStatusCode(200) ->seeJsonStructure([ @@ -334,13 +511,39 @@ class MangaControllerTest extends TestCase ] ] ]); + } + public function testUserUpdatesNotFound() + { + $this->mockJikanParserWith404RespondingUpstream(); $this->get('/v4/manga/1/userupdates?page=200') ->seeStatusCode(404); } public function testMangaRelations() { + Manga::factory()->createOne([ + "mal_id" => 1, + "related" => [ + [ + 'relation' => 'Other', + 'entry' => [ + [ + 'mal_id' => 793, + 'type' => 'manga', + 'name' => 'Wanted!', + 'url' => 'https://myanimelist.net/manga/793/Wanted', + ], + [ + 'mal_id' => 25146, + 'type' => 'manga', + 'name' => 'One Piece x Toriko', + 'url' => 'https://myanimelist.net/manga/25146/One_Piece_x_Toriko', + ], + ], + ] + ] + ]); $this->get('/v4/manga/1/relations') ->seeStatusCode(200) ->seeJsonStructure([ @@ -362,6 +565,7 @@ class MangaControllerTest extends TestCase public function test404() { + $this->mockJikanParserWith404RespondingUpstream(); $this->get('/v4/manga/1000000') ->seeStatusCode(404); } diff --git a/tests/Integration/PersonControllerTest.php b/tests/Integration/PersonControllerTest.php new file mode 100644 index 0000000..f8b31f8 --- /dev/null +++ b/tests/Integration/PersonControllerTest.php @@ -0,0 +1,259 @@ +createOne([ + "mal_id" => 1 + ]); + $this->get('/v4/people/1') + ->seeStatusCode(200) + ->seeJsonStructure(['data'=>[ + 'mal_id', + 'url', + 'website_url', + 'images' => [ + 'jpg' => [ + 'image_url', + ], + ], + 'name', + 'given_name', + 'family_name', + 'alternate_names', + 'birthday', + 'favorites', + 'about', + ]]); + } + + + public function testAnimeography() + { + Person::factory()->createOne([ + "mal_id" => 1, + "anime_staff_positions" => [ + [ + 'position' => 'Theme Song Performance', + 'anime' => [ + 'mal_id' => 3080, + 'url' => 'https://myanimelist.net/anime/3080/Anime_Tenchou', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635.jpg?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635t.jpg?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635l.jpg?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635.webp?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635t.webp?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635l.webp?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + ], + ], + 'title' => 'Anime Tenchou', + ], + ] + ] + ]); + $this->get('/v4/people/1/anime') + ->seeStatusCode(200) + ->seeJsonStructure(['data'=>[ + [ + 'position', + 'anime' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'title' + ] + ] + ]]); + } + + public function testMangaography() + { + Person::factory()->createOne([ + "mal_id" => 1, + "published_manga" => [ + [ + 'position' => 'Art', + 'manga' => [ + 'mal_id' => 3080, + 'url' => 'https://myanimelist.net/manga/3080/x', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635.jpg?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635t.jpg?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635l.jpg?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635.webp?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635t.webp?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/9/4635l.webp?s=ad3dd02ed42bccbc84e0bde5c9e4ac7d', + ], + ], + 'title' => 'Anime Tenchou', + ], + ] + ] + ]); + $this->get('/v4/people/1/manga') + ->seeStatusCode(200) + ->seeJsonStructure(['data'=>[ + [ + 'position', + 'manga' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'title' + ] + ] + ]]); + } + + public function testVoices() + { + Person::factory()->createOne([ + "mal_id" => 1, + "voice_acting_roles" => [ + [ + 'role' => 'Main', + 'anime' => [ + 'mal_id' => 53127, + 'url' => 'https://myanimelist.net/anime/53127/Fate_strange_Fake__Whispers_of_Dawn', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/1502/128320.jpg?s=6b3f95b29d8156f15851f720f06c42ca', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/1502/128320t.jpg?s=6b3f95b29d8156f15851f720f06c42ca', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/1502/128320l.jpg?s=6b3f95b29d8156f15851f720f06c42ca', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/1502/128320.webp?s=6b3f95b29d8156f15851f720f06c42ca', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/1502/128320t.webp?s=6b3f95b29d8156f15851f720f06c42ca', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/1502/128320l.webp?s=6b3f95b29d8156f15851f720f06c42ca', + ], + ], + 'title' => 'Fate/strange Fake: Whispers of Dawn', + ], + 'character' => [ + 'mal_id' => 2514, + 'url' => 'https://myanimelist.net/character/2514/Gilgamesh', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/r/84x124/images/characters/12/338672.jpg?s=45f9ea76970db587f1ab490b1a3573a1', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/r/84x124/images/characters/12/338672.webp?s=45f9ea76970db587f1ab490b1a3573a1', + 'small_image_url' => 'https://cdn.myanimelist.net/r/84x124/images/characters/12/338672t.webp?s=45f9ea76970db587f1ab490b1a3573a1', + ], + ], + 'name' => 'Gilgamesh', + ], + ] + ] + ]); + $this->get('/v4/people/1/voices') + ->seeStatusCode(200) + ->seeJsonStructure(['data'=>[ + [ + 'role', + 'anime' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'title' + ], + 'character' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + ], + 'webp' => [ + 'image_url', + 'small_image_url', + ], + ], + 'name' + ] + ] + ]]); + } + + public function testPictures() + { + $document = $this->dummyScraperResultDocument('/v4/people/1/pictures', 'people', [ + 'pictures' => [ + [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/voiceactors/10/34138.jpg', + ], + ] + ] + ]); + DB::table("people_pictures")->insert($document); + $this->get('/v4/people/1/pictures') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'data' => [ + [ + 'jpg' => [ + 'image_url' + ] + ] + ] + ]); + } + + public function test404() + { + $this->mockJikanParserWith404RespondingUpstream(); + $this->get('/v4/people/1000000') + ->seeStatusCode(404); + } +} diff --git a/tests/HttpV4/Controllers/ProducerControllerTest.php b/tests/Integration/ProducerControllerTest.php similarity index 92% rename from tests/HttpV4/Controllers/ProducerControllerTest.php rename to tests/Integration/ProducerControllerTest.php index ce5bb09..80071ac 100644 --- a/tests/HttpV4/Controllers/ProducerControllerTest.php +++ b/tests/Integration/ProducerControllerTest.php @@ -1,5 +1,6 @@ createOne(); $this->get('/v4/producers') ->seeStatusCode(200) ->seeJsonStructure(['data'=>[ diff --git a/tests/Integration/RecommendationsControllerTest.php b/tests/Integration/RecommendationsControllerTest.php new file mode 100644 index 0000000..0daf571 --- /dev/null +++ b/tests/Integration/RecommendationsControllerTest.php @@ -0,0 +1,102 @@ +dummyResultsDocument('/v4/recommendations/anime', 'recommendations', [[ + 'mal_id' => '4103-6675', + 'entry' => [ + [ + 'mal_id' => 4103, + 'url' => 'https://myanimelist.net/anime/4103/Oval_x_Over', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/5/29979.jpg', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/5/29979t.jpg', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/5/29979l.jpg', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/5/29979.webp', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/5/29979t.webp', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/5/29979l.webp', + ], + ], + 'title' => 'Oval x Over', + ], + [ + 'mal_id' => 6675, + 'url' => 'https://myanimelist.net/anime/6675/Redline', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/12/28553.jpg', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/12/28553t.jpg', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/12/28553l.jpg', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/12/28553.webp', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/12/28553t.webp', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/12/28553l.webp', + ], + ], + 'title' => 'Redline', + ], + ], + 'content' => 'Oval x Over looks like a prototype version of Redline....', + 'date' => '2022-06-20T17:21:22+00:00', + 'user' => [ + 'url' => 'https://myanimelist.net/profile/VBayer', + 'username' => 'VBayer', + ], + ]]); + DB::table("recommendations")->insert($document); + $this->get('/v4/recommendations/anime') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'mal_id', + 'entry' => [ + [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'title' + ] + ], + 'content', + 'date', + 'user' => [ + 'username', + 'url', + ], + ] + ] + ]); + } + +} diff --git a/tests/Integration/ReviewsControllerTest.php b/tests/Integration/ReviewsControllerTest.php new file mode 100644 index 0000000..1e99754 --- /dev/null +++ b/tests/Integration/ReviewsControllerTest.php @@ -0,0 +1,242 @@ +dummyResultsDocument('/v4/reviews/anime', 'reviews', [ + [ + 'mal_id' => 448579, + 'url' => 'https://myanimelist.net/reviews.php?id=448579', + 'type' => 'anime', + 'reactions' => [ + 'overall' => 0, + 'nice' => 0, + 'love_it' => 0, + 'funny' => 0, + 'confusing' => 0, + 'informative' => 0, + 'well_written' => 0, + 'creative' => 0, + ], + 'votes' => 0, + 'score' => 4, + 'tags' => ['Recommended'], + 'is_spoiler' => false, + 'is_preliminary' => false, + 'date' => '2022-06-20T12:13:00+00:00', + 'review' => 'Its good and enjoyable until Kanade drama kick in and it goes downhill since then. The drama is irritating to watch...', + 'episodes_watched' => 12, + 'scores' => [ + 'overall' => 5, + 'story' => 3, + 'animation' => 7, + 'sound' => 5, + 'character' => 5, + 'enjoyment' => 4, + ], + 'entry' => [ + 'mal_id' => 43470, + 'url' => 'https://myanimelist.net/anime/43470/Rikei_ga_Koi_ni_Ochita_no_de_Shoumei_shitemita_Heart', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948.jpg?s=22c36e71a40927d69da106c932bda628', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948t.jpg?s=22c36e71a40927d69da106c932bda628', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948l.jpg?s=22c36e71a40927d69da106c932bda628', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948.webp?s=22c36e71a40927d69da106c932bda628', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948t.webp?s=22c36e71a40927d69da106c932bda628', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948l.webp?s=22c36e71a40927d69da106c932bda628', + ], + ], + 'title' => 'Rikei ga Koi ni Ochita no de Shoumei shitemita. Heart', + ], + 'user' => [ + 'url' => 'https://myanimelist.net/profile/helmy47', + 'username' => 'helmy47', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/9023550.jpg?t=1655753400', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/9023550.webp?t=1655753400', + ], + ], + ], + ] + ]); + DB::table("reviews")->insert($document); + $this->get('/v4/reviews/anime') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'mal_id', + 'url', + 'type', + 'reactions', + 'date', + 'review', + 'score', + 'tags', + 'is_spoiler', + 'is_preliminary', + 'episodes_watched', + 'entry' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'title' + ], + 'user' => [ + 'username', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url' + ], + 'webp' => [ + 'image_url' + ] + ] + ], + ] + ] + ]); + } + + public function testMangaReviews() + { + $document = $this->dummyResultsDocument('/v4/reviews/manga', 'reviews', [ + [ + 'mal_id' => 448579, + 'url' => 'https://myanimelist.net/reviews.php?id=448579', + 'type' => 'manga', + 'reactions' => [ + 'overall' => 0, + 'nice' => 0, + 'love_it' => 0, + 'funny' => 0, + 'confusing' => 0, + 'informative' => 0, + 'well_written' => 0, + 'creative' => 0, + ], + 'votes' => 0, + 'date' => '2022-06-20T12:13:00+00:00', + 'review' => 'Its good and enjoyable until Kanade drama kick in and it goes downhill since then. The drama is irritating to watch...', + 'chapters_read' => 75, + 'score' => 5, + 'is_spoiler' => false, + 'is_preliminary' => false, + 'tags' => ['Recommended'], + 'entry' => [ + 'mal_id' => 43470, + 'url' => 'https://myanimelist.net/anime/43470/Rikei_ga_Koi_ni_Ochita_no_de_Shoumei_shitemita_Heart', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948.jpg?s=22c36e71a40927d69da106c932bda628', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948t.jpg?s=22c36e71a40927d69da106c932bda628', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948l.jpg?s=22c36e71a40927d69da106c932bda628', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948.webp?s=22c36e71a40927d69da106c932bda628', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948t.webp?s=22c36e71a40927d69da106c932bda628', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/1109/118948l.webp?s=22c36e71a40927d69da106c932bda628', + ], + ], + 'title' => 'Rikei ga Koi ni Ochita no de Shoumei shitemita. Heart', + ], + 'user' => [ + 'url' => 'https://myanimelist.net/profile/helmy47', + 'username' => 'helmy47', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/9023550.jpg?t=1655753400', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/userimages/9023550.webp?t=1655753400', + ], + ], + ], + ] + ]); + DB::table("reviews")->insert($document); + $this->get('/v4/reviews/manga') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'mal_id', + 'url', + 'type', + 'reactions', + 'date', + 'review', + 'score', + 'tags', + 'is_spoiler', + 'is_preliminary', + 'chapters_read', + 'entry' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'title' + ], + 'user' => [ + 'username', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url' + ], + 'webp' => [ + 'image_url' + ] + ] + ], + ] + ] + ]); + } +} diff --git a/tests/Integration/ScheduleControllerTest.php b/tests/Integration/ScheduleControllerTest.php new file mode 100644 index 0000000..a7836e7 --- /dev/null +++ b/tests/Integration/ScheduleControllerTest.php @@ -0,0 +1,116 @@ +state(new Sequence( + ["members" => 100], + ["members" => 50], + ["members" => 10] + ))->state([ + "type" => AnimeTypeEnum::tv()->label, + "status" => AnimeStatusEnum::airing()->label, + "airing" => true, + ])->create(); + $this->get('/v4/schedules') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'data' => [ + [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'trailer' => [ + 'youtube_id', + 'url', + 'embed_url', + 'images' => [ + 'image_url', + 'small_image_url', + 'medium_image_url', + 'large_image_url', + 'maximum_image_url', + ] + ], + 'title', + 'title_english', + 'title_japanese', + 'title_synonyms', + 'type', + 'source', + 'episodes', + 'status', + 'airing', + 'aired' => [ + 'from', + 'to', + 'prop' => [ + 'from' => [ + 'day', + 'month', + 'year' + ], + 'to' => [ + 'day', + 'month', + 'year' + ] + ], + 'string' + ], + 'duration', + 'rating', + 'score', + 'scored_by', + 'rank', + 'popularity', + 'members', + 'favorites', + 'synopsis', + 'background', + 'season', + 'year', + 'broadcast' => [ + 'day', + 'time', + 'timezone', + 'string' + ], + 'producers', + 'licensors', + 'studios', + 'genres', + ] + ] + ]); + } + + public function test400() + { + $this->get('/v4/schedules/asdjkhas') + ->seeStatusCode(400); + } +} diff --git a/tests/HttpV4/Controllers/SearchControllerTest.php b/tests/Integration/SearchControllerTest.php similarity index 94% rename from tests/HttpV4/Controllers/SearchControllerTest.php rename to tests/Integration/SearchControllerTest.php index 1ff6e9c..30b40e4 100644 --- a/tests/HttpV4/Controllers/SearchControllerTest.php +++ b/tests/Integration/SearchControllerTest.php @@ -1,5 +1,9 @@ get('/v4/anime?order_by=id&sort=asc') + Anime::factory(3)->create(); + $this->get('/v4/anime?order_by=mal_id&sort=asc') ->seeStatusCode(200) ->seeJsonStructure([ 'pagination' => [ @@ -89,6 +94,7 @@ class SearchControllerTest extends TestCase 'background', 'season', 'year', + 'themes', 'broadcast' => [ 'day', 'time', @@ -135,7 +141,8 @@ class SearchControllerTest extends TestCase public function testMangaSearch() { - $this->get('/v4/manga?order_by=id&sort=asc') + Manga::factory(3)->create(); + $this->get('/v4/manga?order_by=mal_id&sort=asc') ->seeStatusCode(200) ->seeJsonStructure([ 'pagination' => [ @@ -229,6 +236,10 @@ class SearchControllerTest extends TestCase public function testPeopleSearch() { + Person::factory(2)->create(); + Person::factory()->createOne([ + "name" => "Sawano Kuma" + ]); $this->get('/v4/people?q=Sawano') ->seeStatusCode(200) ->seeJsonStructure([ @@ -266,7 +277,11 @@ class SearchControllerTest extends TestCase public function testCharacterSearch() { - $this->get('/v4/characters?q=Okabe,%20Rintarou') + Character::factory(2)->create(); + Character::factory()->createOne([ + "name" => "Okabe" + ]); + $this->get('/v4/characters?q=Okabe') ->seeStatusCode(200) ->seeJsonStructure([ 'pagination' => [ diff --git a/tests/HttpV4/Controllers/TopControllerTest.php b/tests/Integration/TopControllerTest.php similarity index 91% rename from tests/HttpV4/Controllers/TopControllerTest.php rename to tests/Integration/TopControllerTest.php index 60a756a..8b832c1 100644 --- a/tests/HttpV4/Controllers/TopControllerTest.php +++ b/tests/Integration/TopControllerTest.php @@ -1,7 +1,12 @@ state(new Sequence( + ["rank" => 54], + ["rank" => 22], + ["rank" => 12] + ))->create(); $this->get('/v4/top/anime') ->seeStatusCode(200) ->seeJsonStructure([ @@ -125,6 +135,11 @@ class TopControllerTest extends TestCase public function testTopManga() { + Manga::factory(3)->state(new Sequence( + ["rank" => 54], + ["rank" => 22], + ["rank" => 12] + ))->create(); $this->get('/v4/top/manga') ->seeStatusCode(200) ->seeJsonStructure([ @@ -209,6 +224,11 @@ class TopControllerTest extends TestCase public function testTopPeople() { + Person::factory(3)->state(new Sequence( + ["member_favorites" => 524], + ["member_favorites" => 323], + ["member_favorites" => 224], + ))->create(); $this->get('/v4/top/people') ->seeStatusCode(200) ->seeJsonStructure([ @@ -236,6 +256,11 @@ class TopControllerTest extends TestCase public function testTopCharacters() { + Character::factory(3)->state(new Sequence( + ["member_favorites" => 524], + ["member_favorites" => 323], + ["member_favorites" => 224], + ))->create(); $this->get('/v4/top/characters') ->seeStatusCode(200) ->seeJsonStructure([ diff --git a/tests/HttpV4/Controllers/UserControllerTest.php b/tests/Integration/UserControllerTest.php similarity index 54% rename from tests/HttpV4/Controllers/UserControllerTest.php rename to tests/Integration/UserControllerTest.php index ece9541..a12a272 100644 --- a/tests/HttpV4/Controllers/UserControllerTest.php +++ b/tests/Integration/UserControllerTest.php @@ -1,7 +1,15 @@ createOne([ + "username" => "nekomata1037" + ]); $this->get('/v4/users/nekomata1037') ->seeStatusCode(200) ->seeJsonStructure(['data'=>[ @@ -35,6 +46,9 @@ class UserControllerTest extends TestCase public function testUserStatistics() { + Profile::factory()->createOne([ + "username" => "nekomata1037" + ]); $this->get('/v4/users/nekomata1037/statistics') ->seeStatusCode(200) ->seeJsonStructure(['data'=>[ @@ -69,6 +83,9 @@ class UserControllerTest extends TestCase public function testUserAbout() { + Profile::factory()->createOne([ + "username" => "nekomata1037" + ]); $this->get('/v4/users/nekomata1037/about') ->seeStatusCode(200) ->seeJsonStructure(['data'=>[ @@ -78,6 +95,9 @@ class UserControllerTest extends TestCase public function testUserFavorites() { + Profile::factory()->createOne([ + "username" => "nekomata1037" + ]); $this->get('/v4/users/nekomata1037/favorites') ->seeStatusCode(200) ->seeJsonStructure(['data'=>[ @@ -156,8 +176,23 @@ class UserControllerTest extends TestCase - public function testUserHistory() + public function testUserAnimeHistory() { + $document = $this->dummyScraperResultDocument('/v4/users/purplepinapples/history/anime', 'users', [ + 'history' => [ + [ + 'entry' => [ + 'mal_id' => $this->faker->numberBetween(2, 9999), + 'type' => 'anime', + 'name' => $this->faker->name(), + 'url' => $this->faker->url() + ], + 'increment' => 1, + 'date' => Carbon::now()->toAtomString() + ] + ] + ]); + DB::table("users_history")->insert($document); $this->get('/v4/users/purplepinapples/history/anime') ->seeStatusCode(200) ->seeJsonStructure([ @@ -174,7 +209,25 @@ class UserControllerTest extends TestCase ] ] ]); + } + public function testUserMangaHistory() + { + $document = $this->dummyScraperResultDocument('/v4/users/nekomata1037/history/manga', 'users', [ + 'history' => [ + [ + 'entry' => [ + 'mal_id' => $this->faker->numberBetween(2, 9999), + 'type' => 'manga', + 'name' => $this->faker->name(), + 'url' => $this->faker->url() + ], + 'increment' => 1, + 'date' => Carbon::now()->toAtomString() + ] + ] + ]); + DB::table("users_history")->insert($document); $this->get('/v4/users/nekomata1037/history/manga') ->seeStatusCode(200) ->seeJsonStructure([ @@ -186,6 +239,23 @@ class UserControllerTest extends TestCase public function testUserFriends() { + $document = $this->dummyResultsDocument('/v4/users/nekomata1037/friends', 'users', [[ + 'user' => [ + 'username' => $this->faker->userName(), + 'url' => $this->faker->url(), + "images" => [ + "jpg" => [ + "image_url" => $this->faker->url() + ], + "webp" => [ + "image_url" => $this->faker->url() + ] + ], + ], + 'last_online' => Carbon::now()->toAtomString(), + 'friends_since' => Carbon::now()->toAtomString() + ]]); + DB::table("users_friends")->insert($document); $this->get('/v4/users/nekomata1037/friends') ->seeStatusCode(200) ->seeJsonStructure([ @@ -212,6 +282,16 @@ class UserControllerTest extends TestCase ] ] ]); + } + + public function testInvalidUserFriendsRequest() + { + $jikanParser = \Mockery::mock(MalClient::class)->makePartial(); + /** @noinspection PhpParamsInspection */ + $jikanParser->allows() + ->getUserFriends(\Mockery::any()) + ->andReturn(new Friends()); + $this->app->instance('JikanParser', $jikanParser); $this->get('/v4/users/nekomata1037/friends?page=200') ->seeStatusCode(200); @@ -219,6 +299,37 @@ class UserControllerTest extends TestCase public function testUserRecommendations() { + $document = $this->dummyResultsDocument('/v4/users/xinil/recommendations', 'users', [ + [ + 'mal_id' => '263-1559', + 'entry' => [ + [ + 'mal_id' => 263, + 'url' => 'https://myanimelist.net/anime/263/Hajime_no_Ippo', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/4/86334.jpg?s=20b66bb8d0eb0af0a1810eb8717ec44f', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/4/86334t.jpg?s=20b66bb8d0eb0af0a1810eb8717ec44f', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/4/86334l.jpg?s=20b66bb8d0eb0af0a1810eb8717ec44f', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/4/86334.webp?s=20b66bb8d0eb0af0a1810eb8717ec44f', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/4/86334t.webp?s=20b66bb8d0eb0af0a1810eb8717ec44f', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/4/86334l.webp?s=20b66bb8d0eb0af0a1810eb8717ec44f', + ], + ], + 'title' => 'Hajime no Ippo', + ] + ], + 'content' => 'Hajime no Ippo and Kenichi are very similar, mostly by looking at the main characters. Makunouchi is a weakling, Kenichi is a weakling. However, they both train hard and become stronger in order to achieve their goals. Makounouchi wants to know what it means to be "strong", and Kenichi wants to become stronger to protect his friends from harm.', + 'date' => '2008-01-20T00:00:00+00:00', + 'user' => [ + 'url' => 'https://myanimelist.net/profile/Xinil', + 'username' => 'Xinil', + ], + ] + ]); + DB::table("users_recommendations")->insert($document); $this->get('/v4/users/xinil/recommendations') ->seeStatusCode(200) ->seeJsonStructure([ @@ -254,6 +365,17 @@ class UserControllerTest extends TestCase ] ] ]); + } + + public function testInvalidUserRecommendationsRequest() + { + // let's add a parser which returns nothing all the time for user recommendations request + $jikanParser = \Mockery::mock(MalClient::class)->makePartial(); + /** @noinspection PhpParamsInspection */ + $jikanParser->allows() + ->getUserRecommendations(\Mockery::type(UserRecommendationsRequest::class)) + ->andReturn(new UserRecommendations()); + $this->app->instance('JikanParser', $jikanParser); $this->get('/v4/users/xinil/recommendations?page=200') ->seeStatusCode(200) @@ -269,6 +391,54 @@ class UserControllerTest extends TestCase public function testUserReviews() { + $document = $this->dummyResultsDocument('/v4/users/xinil/reviews', 'users', [[ + 'mal_id' => 829, + 'url' => 'https://myanimelist.net/reviews.php?id=829', + 'type' => 'manga', + 'votes' => 78, + 'date' => '2007-09-09T16:43:00+00:00', + 'review' => 'Just an all around "fun"', + 'chapters_read' => 89, + 'is_spoiler' => false, + 'is_preliminary' => false, + 'tags' => [], + 'score' => 1, + 'reactions' => [ + 'overall' => 2112, + 'nice' => 2105, + 'love_it' => 3, + 'funny' => 1, + 'confusing' => 0, + 'informative' => 2, + 'well_written' => 1, + 'creative' => 0, + ], + 'scores' => [ + 'overall' => 7, + 'story' => 8, + 'art' => 6, + 'character' => 7, + 'enjoyment' => 8, + ], + 'entry' => [ + 'mal_id' => 1190, + 'url' => 'https://myanimelist.net/manga/1190/Asatte_Dance', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/manga/5/202582.jpg?s=3035988a19db4f7223de8b0168bdae30', + 'small_image_url' => 'https://cdn.myanimelist.net/images/manga/5/202582t.jpg?s=3035988a19db4f7223de8b0168bdae30', + 'large_image_url' => 'https://cdn.myanimelist.net/images/manga/5/202582l.jpg?s=3035988a19db4f7223de8b0168bdae30', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/manga/5/202582.webp?s=3035988a19db4f7223de8b0168bdae30', + 'small_image_url' => 'https://cdn.myanimelist.net/images/manga/5/202582t.webp?s=3035988a19db4f7223de8b0168bdae30', + 'large_image_url' => 'https://cdn.myanimelist.net/images/manga/5/202582l.webp?s=3035988a19db4f7223de8b0168bdae30', + ], + ], + 'title' => 'Asatte Dance', + ], + ]]); + DB::table("users_reviews")->insert($document); $this->get('/v4/users/xinil/reviews') ->seeStatusCode(200) ->seeJsonStructure([ @@ -308,6 +478,16 @@ class UserControllerTest extends TestCase ] ] ]); + } + + public function testInvalidUserReviewsRequest() + { + $jikanParser = \Mockery::mock(MalClient::class)->makePartial(); + /** @noinspection PhpParamsInspection */ + $jikanParser->allows() + ->getUserReviews(\Mockery::any()) + ->andReturn(new UserReviews()); + $this->app->instance('JikanParser', $jikanParser); $this->get('/v4/users/xinil/reviews?page=200') ->seeStatusCode(200); @@ -315,6 +495,12 @@ class UserControllerTest extends TestCase public function testUserClubs() { + $document = $this->dummyResultsDocument('/v4/users/nekomata1037/clubs', 'users', [[ + 'mal_id' => 1, + 'name' => 'a', + 'url' => $this->faker->url() + ]]); + DB::table('users_clubs')->insert($document); $this->get('/v4/users/nekomata1037/clubs') ->seeStatusCode(200) ->seeJsonStructure([ diff --git a/tests/Integration/WatchControllerTest.php b/tests/Integration/WatchControllerTest.php new file mode 100644 index 0000000..ab8041c --- /dev/null +++ b/tests/Integration/WatchControllerTest.php @@ -0,0 +1,334 @@ +dummyResultsDocument('/v4/watch/episodes', 'watch', [ + [ + 'entry' => [ + 'mal_id' => 21, + 'url' => 'https://myanimelist.net/anime/21/One_Piece', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245.jpg', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245t.jpg', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245l.jpg', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245.webp', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245t.webp', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245l.webp', + ], + ], + 'title' => 'One Piece', + ], + 'episodes' => [ + [ + 'mal_id' => 1022, + 'url' => 'https://myanimelist.net/anime/21/One_Piece/episode/1022', + 'title' => 'Episode 1022', + 'premium' => false, + ], + [ + 'mal_id' => 1021, + 'url' => 'https://myanimelist.net/anime/21/One_Piece/episode/1021', + 'title' => 'Episode 1021', + 'premium' => false, + ], + ], + 'region_locked' => false, + ] + ]); + DB::table("watch")->insert($document); + $this->get('/v4/watch/episodes') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'entry' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'title' + ], + 'episodes' => [ + [ + 'mal_id', + 'url', + 'title', + 'premium' + ] + ], + ] + ] + ]); + } + + public function testWatchEpisodesPopular() + { + $document = $this->dummyResultsDocument('/v4/watch/episodes/popular', 'watch', [ + [ + 'entry' => [ + 'mal_id' => 21, + 'url' => 'https://myanimelist.net/anime/21/One_Piece', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245.jpg', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245t.jpg', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245l.jpg', + ], + 'webp' => [ + 'image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245.webp', + 'small_image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245t.webp', + 'large_image_url' => 'https://cdn.myanimelist.net/images/anime/6/73245l.webp', + ], + ], + 'title' => 'One Piece', + ], + 'episodes' => [ + [ + 'mal_id' => 1022, + 'url' => 'https://myanimelist.net/anime/21/One_Piece/episode/1022', + 'title' => 'Episode 1022', + 'premium' => false, + ], + [ + 'mal_id' => 1021, + 'url' => 'https://myanimelist.net/anime/21/One_Piece/episode/1021', + 'title' => 'Episode 1021', + 'premium' => false, + ], + ], + 'region_locked' => false, + ] + ]); + DB::table("watch")->insert($document); + + $this->get('/v4/watch/episodes/popular') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'entry' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'title' + ], + 'episodes' => [ + [ + 'mal_id', + 'url', + 'title', + 'premium' + ] + ], + ] + ] + ]); + } + + public function testWatchPromos() + { + $document = $this->dummyResultsDocument('/v4/watch/promos', 'watch', [ + [ + 'title' => 'Character PV', + 'entry' => [ + 'mal_id' => 51019, + 'url' => 'https:\\/\\/myanimelist.net\\/anime\\/51019\\/Kimetsu_no_Yaiba__Katanakaji_no_Sato-hen', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027.jpg', + 'small_image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027t.jpg', + 'large_image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027l.jpg', + ], + 'webp' => [ + 'image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027.webp', + 'small_image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027t.webp', + 'large_image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027l.webp', + ], + ], + 'title' => 'Kimetsu no Yaiba: Katanakaji no Sato-hen', + ], + 'trailer' => [ + 'youtube_id' => 't0d7_6WCls8', + 'url' => 'https:\\/\\/www.youtube.com\\/watch?v=t0d7_6WCls8', + 'embed_url' => 'https:\\/\\/www.youtube.com\\/embed\\/t0d7_6WCls8?enablejsapi=1&wmode=opaque&autoplay=1', + 'images' => [ + 'image_url' => 'https:\\/\\/img.youtube.com\\/vi\\/t0d7_6WCls8\\/default.jpg', + 'small_image_url' => 'https:\\/\\/img.youtube.com\\/vi\\/t0d7_6WCls8\\/sddefault.jpg', + 'medium_image_url' => 'https:\\/\\/img.youtube.com\\/vi\\/t0d7_6WCls8\\/mqdefault.jpg', + 'large_image_url' => 'https:\\/\\/img.youtube.com\\/vi\\/t0d7_6WCls8\\/hqdefault.jpg', + 'maximum_image_url' => 'https:\\/\\/img.youtube.com\\/vi\\/t0d7_6WCls8\\/maxresdefault.jpg', + ], + ], + ] + ]); + DB::table("watch")->insert($document); + + $this->get('/v4/watch/promos') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'title', + 'entry' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'title' + ], + 'trailer' => [ + 'youtube_id', + 'url', + 'embed_url', + 'images' => [ + 'image_url', + 'small_image_url', + 'medium_image_url', + 'large_image_url', + 'maximum_image_url', + ] + ], + ] + ] + ]); + } + + public function testWatchPopularPromos() + { + $document = $this->dummyResultsDocument('/v4/watch/promos/popular', 'watch', [ + [ + 'title' => 'Character PV', + 'entry' => [ + 'mal_id' => 51019, + 'url' => 'https:\\/\\/myanimelist.net\\/anime\\/51019\\/Kimetsu_no_Yaiba__Katanakaji_no_Sato-hen', + 'images' => [ + 'jpg' => [ + 'image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027.jpg', + 'small_image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027t.jpg', + 'large_image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027l.jpg', + ], + 'webp' => [ + 'image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027.webp', + 'small_image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027t.webp', + 'large_image_url' => 'https:\\/\\/cdn.myanimelist.net\\/images\\/anime\\/1499\\/121027l.webp', + ], + ], + 'title' => 'Kimetsu no Yaiba: Katanakaji no Sato-hen', + ], + 'trailer' => [ + 'youtube_id' => 't0d7_6WCls8', + 'url' => 'https:\\/\\/www.youtube.com\\/watch?v=t0d7_6WCls8', + 'embed_url' => 'https:\\/\\/www.youtube.com\\/embed\\/t0d7_6WCls8?enablejsapi=1&wmode=opaque&autoplay=1', + 'images' => [ + 'image_url' => 'https:\\/\\/img.youtube.com\\/vi\\/t0d7_6WCls8\\/default.jpg', + 'small_image_url' => 'https:\\/\\/img.youtube.com\\/vi\\/t0d7_6WCls8\\/sddefault.jpg', + 'medium_image_url' => 'https:\\/\\/img.youtube.com\\/vi\\/t0d7_6WCls8\\/mqdefault.jpg', + 'large_image_url' => 'https:\\/\\/img.youtube.com\\/vi\\/t0d7_6WCls8\\/hqdefault.jpg', + 'maximum_image_url' => 'https:\\/\\/img.youtube.com\\/vi\\/t0d7_6WCls8\\/maxresdefault.jpg', + ], + ], + ] + ]); + DB::table("watch")->insert($document); + + $this->get('/v4/watch/promos/popular') + ->seeStatusCode(200) + ->seeJsonStructure([ + 'pagination' => [ + 'last_visible_page', + 'has_next_page', + ], + 'data' => [ + [ + 'title', + 'entry' => [ + 'mal_id', + 'url', + 'images' => [ + 'jpg' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + 'webp' => [ + 'image_url', + 'small_image_url', + 'large_image_url' + ], + ], + 'title' + ], + 'trailer' => [ + 'youtube_id', + 'url', + 'embed_url', + 'images' => [ + 'image_url', + 'small_image_url', + 'medium_image_url', + 'large_image_url', + 'maximum_image_url', + ] + ], + ] + ] + ]); + } + +} diff --git a/tests/IntegrationTestListener.php b/tests/IntegrationTestListener.php index 3264c81..70d67ff 100644 --- a/tests/IntegrationTestListener.php +++ b/tests/IntegrationTestListener.php @@ -1,7 +1,10 @@ getName(); return in_array($suiteName, [ - "integration", "http-integration", "Tests\HttpV4\Controllers", "Tests\Integration", - "Integration" + "integration", "Tests\Integration", "Integration" ]); } @@ -56,6 +58,8 @@ class IntegrationTestListener implements TestListener { if ($this->isIntegrationTest($suite)) { $app = $this->app; + Container::setInstance($app); + Facade::setFacadeApplication($app); $kernel = $app->make( 'Illuminate\Contracts\Console\Kernel' ); @@ -63,6 +67,7 @@ class IntegrationTestListener implements TestListener $kernel->call('migrate:fresh', []); } catch (\Exception $ex) { print_r($ex->getMessage()); + print_r($ex); throw $ex; } } @@ -71,11 +76,20 @@ class IntegrationTestListener implements TestListener public function endTestSuite(\PHPUnit\Framework\TestSuite $suite): void { if ($this->isIntegrationTest($suite)) { + $app = $this->app; + Container::setInstance($app); + Facade::setFacadeApplication($app); $kernel = $app->make( 'Illuminate\Contracts\Console\Kernel' ); - $kernel->call('migrate:rollback'); + try { + $kernel->call('migrate:rollback'); + } catch (\Exception $ex) { + print_r($ex->getMessage()); + print_r($ex); + throw $ex; + } } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 6069039..7a7baab 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,14 +1,22 @@ new UTCDateTime(), + "modifiedAt" => new UTCDateTime(), + "request_hash" => "request:$mediaType:" . sha1($uri), + ...($wrapKey !== null ? [$wrapKey => $content] : $content) + ]; + } + + protected function dummyResultsDocument(string $uri, string $mediaType, array $resultsContent, $hasNextPage = false, $lastVisiblePage = 1): array + { + return $this->dummyScraperResultDocument( + $uri, + $mediaType, + [ + "results" => $resultsContent, + "has_next_page" => $hasNextPage, + "last_visible_page" => $lastVisiblePage + ] + ); + } + + protected function givenDummyCharactersStaffData($uri, $mediaType) + { + DB::table($mediaType === "anime" ? $mediaType."_characters_staff" : $mediaType."_characters")->insert([ + "createdAt" => new UTCDateTime(), + "modifiedAt" => new UTCDateTime(), + "request_hash" => "request:$mediaType:" . sha1($uri), + "characters" => [ + [ + "character" => [ + "mal_id" => 3, + "url" => "https://myanimelist.net/character/3/Jet_Black", + "images" => [ + "jpg" => [ + "image_url" => "https://cdn.myanimelist.net/images/characters/11/253723.jpg?s=6c8a19a79a88c46ae15f30e3ef5fd839", + "small_image_url" => "https://cdn.myanimelist.net/images/characters/11/253723t.jpg?s=6c8a19a79a88c46ae15f30e3ef5fd839" + ], + "webp" => [ + "image_url" => "https://cdn.myanimelist.net/images/characters/11/253723.webp?s=6c8a19a79a88c46ae15f30e3ef5fd839", + "small_image_url" => "https://cdn.myanimelist.net/images/characters/11/253723t.webp?s=6c8a19a79a88c46ae15f30e3ef5fd839" + ] + ], + "name" => "Black, Jet" + ], + "role" => "Main", + "favorites" => 1, + ...($mediaType === "anime" ? [ + "voice_actors" => [ + [ + "person" => [ + "mal_id" => 357, + "url" => "https://myanimelist.net/people/357/Unshou_Ishizuk", + "images" => [ + "jpg" => [ + "image_url" => "https://cdn.myanimelist.net/images/voiceactors/2/17135.jpg?s=5925123b8a7cf9b51a445c225442f0ef" + ] + ], + "name" => "Ishizuka, Unshou" + ], + "language" => "Japanese" + ] + ] + ] : []) + ] + ], + ...( + $mediaType === "anime" ? [ + "staff" => [ + [ + "person" => [ + "mal_id" => 40009, + "url" => "https://myanimelist.net/people/40009/Yutaka_Maseba", + "images" => [ + "jpg" => [ + "image_url" => "https://cdn.myanimelist.net/images/voiceactors/3/40216.jpg?s=d9fb7a625868ec7d9cd3804fa0da3fd6" + ] + ], + "name" => "Maseba, Yutaka" + ], + "positions" => [ + "Producer" + ] + ] + ] + ] : [] + ) + ]); + } + protected function setUp(): void { parent::setUp(); @@ -34,11 +133,26 @@ abstract class TestCase extends LumenTestCase */ public function createApplication() { + /** + * @var Application $app + */ $app = require __DIR__.'/../bootstrap/app.php'; + // a http client which fails the tests if requests are leaking to MAL. + $mockHttpClient = \Mockery::mock(HttpClientInterface::class); + /** @noinspection PhpParamsInspection */ + $mockHttpClient->allows() + ->request(\Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andThrow(new CustomTestException("Http Request to MAL server was attempted during testing. By default we throw this exception to indicate a buggy test.")); + $jikan = new \Jikan\MyAnimeList\MalClient($mockHttpClient); + $app->instance('JikanParser', $jikan); + $app->singleton(ExceptionHandler::class, TestExceptionsHandler::class); $database = env('DB_DATABASE', 'jikan_tests'); $app['config']->set('database.connections.mongodb.database', $database === 'jikan' ? 'jikan_tests' : $database); $app['config']->set('jikan.micro_caching_enabled', false); $app->register(TestServiceProvider::class); + Container::setInstance($app); + /** @noinspection PhpParamsInspection */ + Facade::setFacadeApplication($app); return $app; } @@ -94,6 +208,7 @@ abstract class TestCase extends LumenTestCase "getHeaders" => [], "getContent" => "" ]); + $this->app->instance("HttpClient", $httpClient); $this->app->instance("JikanParser", new MalClient($httpClient)); } } diff --git a/tests/Unit/DefaultCachedScraperServiceTest.php b/tests/Unit/DefaultCachedScraperServiceTest.php index c5b1484..fe7e63d 100644 --- a/tests/Unit/DefaultCachedScraperServiceTest.php +++ b/tests/Unit/DefaultCachedScraperServiceTest.php @@ -5,6 +5,7 @@ namespace Unit; use App\Contracts\Repository; use App\Services\DefaultCachedScraperService; use Illuminate\Support\Carbon; +use Illuminate\Support\Collection; use Jenssegers\Mongodb\Eloquent\Builder; use Jikan\MyAnimeList\MalClient; use JMS\Serializer\SerializerInterface; @@ -70,8 +71,8 @@ final class DefaultCachedScraperServiceTest extends TestCase // the cached data in the database $dummyResults = collect([ - ["dummy" => "dummy1", "modifiedAt" => new UTCDateTime($now->sub("2 days")->timestamp)], - ["dummy" => "dummy2", "modifiedAt" => new UTCDateTime($now->sub("2 days")->timestamp)] + ["dummy" => "dummy1", "modifiedAt" => new UTCDateTime($now->sub("2 days")->getPreciseTimestamp(3))], + ["dummy" => "dummy2", "modifiedAt" => new UTCDateTime($now->sub("2 days")->getPreciseTimestamp(3))] ]); // the data returned by the scraper @@ -93,8 +94,8 @@ final class DefaultCachedScraperServiceTest extends TestCase $result = $target->findList($testRequestHash, fn() => []); $this->assertEquals([ - ["dummy" => "dummy1", "modifiedAt" => new UTCDateTime($now->getPreciseTimestamp(3))], - ["dummy" => "dummy2", "modifiedAt" => new UTCDateTime($now->getPreciseTimestamp(3))] + ["dummy" => "dummy1", "modifiedAt" => $dummyResults->toArray()[0]["modifiedAt"]], + ["dummy" => "dummy2", "modifiedAt" => $dummyResults->toArray()[1]["modifiedAt"]] ], $result->toArray()); }