tests: add mutation tests (#1100)

This commit is contained in:
Kyrch
2026-02-15 16:35:04 -03:00
committed by GitHub
parent fcf64b6406
commit d2ced8db70
16 changed files with 978 additions and 74 deletions
+24
View File
@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace App\GraphQL\Middleware;
use Closure;
use GraphQL\Type\Definition\ResolveInfo;
use Illuminate\Support\Facades\Auth;
use Rebing\GraphQL\Error\AuthorizationError;
use Rebing\GraphQL\Support\Middleware;
class AuthMutation extends Middleware
{
/**
* @param array<string, mixed> $args
*/
public function handle($root, array $args, $context, ResolveInfo $resolveInfo, Closure $next)
{
throw_unless(Auth::check(), AuthorizationError::class, 'Unauthenticated.');
return $next($root, $args, $context, $resolveInfo);
}
}
@@ -35,7 +35,7 @@ class AnimeYearsResolver extends BaseResolver
$fieldSelection = $resolveInfo->getFieldSelection(1);
Validator::make(['year' => $year], [new AnimeYearRule($fieldSelection)])
Validator::make(['year' => $year], ['year' => new AnimeYearRule($fieldSelection)])
->validate();
return Anime::query()
@@ -6,6 +6,7 @@ namespace App\GraphQL\Schema\Mutations;
use App\Concerns\GraphQL\ResolvesArguments;
use App\GraphQL\Argument\Argument;
use App\GraphQL\Middleware\AuthMutation;
use App\GraphQL\Middleware\ResolveBindableArgs;
use App\GraphQL\Schema\Types\BaseType;
use App\GraphQL\Schema\Unions\BaseUnion;
@@ -27,6 +28,7 @@ abstract class BaseMutation extends Mutation
$this->middleware = array_merge(
$this->middleware,
[
AuthMutation::class,
ResolveBindableArgs::class,
],
);
@@ -5,37 +5,19 @@ declare(strict_types=1);
namespace App\GraphQL\Schema\Mutations\Models\List\ExternalProfile;
use App\Contracts\GraphQL\Fields\BindableField;
use App\Features\AllowExternalProfileManagement;
use App\GraphQL\Argument\Argument;
use App\GraphQL\Resolvers\List\SyncExternalProfileResolver;
use App\GraphQL\Schema\Fields\Field;
use App\GraphQL\Schema\Mutations\BaseMutation;
use App\GraphQL\Schema\Types\List\ExternalProfileType;
use App\Http\Middleware\Api\EnabledOnlyOnLocalhost;
use GraphQL\Type\Definition\ResolveInfo;
use GraphQL\Type\Definition\Type;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Str;
use Laravel\Pennant\Middleware\EnsureFeaturesAreActive;
class SyncExternalProfileMutation extends BaseMutation
{
protected $middleware = [
EnabledOnlyOnLocalhost::class,
];
public function __construct()
{
$this->middleware = array_merge(
$this->middleware,
[
Str::of(EnsureFeaturesAreActive::class)
->append(':')
->append(AllowExternalProfileManagement::class)
->__toString(),
]
);
parent::__construct('SyncExternalProfile');
}
@@ -67,7 +67,7 @@ class PlaylistTrackPolicy extends BasePolicy
}
/**
* @param Playlist $playlist
* @param Playlist|null $playlist
*/
public function create(User $user, $playlist = null): Response
{
@@ -87,8 +87,9 @@ class PlaylistTrackPolicy extends BasePolicy
/**
* @param PlaylistTrack $track
* @param Playlist|null $playlist
*/
public function update(User $user, Model $track): Response
public function update(User $user, Model $track, $playlist = null): Response
{
if (Filament::isServing()) {
return $user->hasRole(RoleEnum::ADMIN->value)
@@ -97,7 +98,7 @@ class PlaylistTrackPolicy extends BasePolicy
}
/** @var Playlist|null $playlist */
$playlist = request()->route('playlist');
$playlist ??= request()->route('playlist');
return $playlist?->user()->is($user) && parent::update($user, $track)->allowed()
? Response::allow()
@@ -106,8 +107,9 @@ class PlaylistTrackPolicy extends BasePolicy
/**
* @param PlaylistTrack $track
* @param Playlist|null $playlist
*/
public function delete(User $user, Model $track): Response
public function delete(User $user, Model $track, $playlist = null): Response
{
if (Filament::isServing()) {
return $user->hasRole(RoleEnum::ADMIN->value)
@@ -116,7 +118,7 @@ class PlaylistTrackPolicy extends BasePolicy
}
/** @var Playlist|null $playlist */
$playlist = request()->route('playlist');
$playlist ??= request()->route('playlist');
return $playlist?->user()->is($user) && parent::delete($user, $track)->allowed()
? Response::allow()
+3
View File
@@ -54,3 +54,6 @@ parameters:
-
message: '#Call to method assertActionDoesNotExist\(\) on an unknown class static.#'
path: tests/Unit/Filament/*
-
message: '#Access to an undefined property PHPUnit\\Framework\\TestCase::\$mutation.#'
path: tests/Feature/GraphQL/*
@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
use App\Enums\Auth\CrudPermission;
use App\Enums\Models\List\PlaylistVisibility;
use App\Events\List\Playlist\PlaylistCreated;
use App\Models\Auth\User;
use App\Models\List\Playlist;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Event;
use function Pest\Laravel\actingAs;
beforeEach(function () {
$this->mutation = '
mutation($name: String!, $visibility: PlaylistVisibility!, $description: String) {
CreatePlaylist(name: $name, visibility: $visibility, description: $description) {
name
visibility
description
}
}
';
});
test('protected', function () {
$response = graphql([
'query' => $this->mutation,
'variables' => [
'name' => fake()->word(),
'visibility' => Arr::random(PlaylistVisibility::cases())->name,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden', function () {
actingAs(User::factory()->createOne());
$response = graphql([
'query' => $this->mutation,
'variables' => [
'name' => fake()->word(),
'visibility' => Arr::random(PlaylistVisibility::cases())->name,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
it('creates', function () {
Event::fakeExcept(PlaylistCreated::class);
$user = User::factory()
->withPermissions(CrudPermission::CREATE->format(Playlist::class))
->createOne();
actingAs($user);
$playlist = Playlist::factory()->makeOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
'name' => $playlist->name,
'visibility' => $playlist->visibility->name,
'description' => $playlist->description,
],
]);
$this->assertDatabaseCount(Playlist::class, 1);
$response->assertOk();
$response->assertJsonIsObject('data.CreatePlaylist');
});
@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
use App\Enums\Auth\CrudPermission;
use App\Events\List\Playlist\PlaylistCreated;
use App\Models\Auth\User;
use App\Models\List\Playlist;
use Illuminate\Support\Facades\Event;
use function Pest\Laravel\actingAs;
beforeEach(function () {
$this->mutation = '
mutation($id: String!) {
DeletePlaylist(id: $id) {
message
}
}
';
});
test('protected', function () {
$response = graphql([
'query' => $this->mutation,
'variables' => [
'id' => fake()->word(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden', function () {
Event::fakeExcept(PlaylistCreated::class);
actingAs(User::factory()->createOne());
$response = graphql([
'query' => $this->mutation,
'variables' => [
// Needed for the bind resolver.
'id' => Playlist::factory()->createOne()->hashid,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden if not owner', function () {
Event::fakeExcept(PlaylistCreated::class);
$user = User::factory()
->withPermissions(CrudPermission::DELETE->format(Playlist::class))
->createOne();
actingAs($user);
$response = graphql([
'query' => $this->mutation,
'variables' => [
'id' => Playlist::factory()->createOne()->hashid,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
it('deletes', function () {
Event::fakeExcept(PlaylistCreated::class);
$user = User::factory()
->withPermissions(CrudPermission::DELETE->format(Playlist::class))
->createOne();
actingAs($user);
$playlist = Playlist::factory()
->for($user)
->createOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
'id' => $playlist->hashid,
],
]);
$this->assertDatabaseCount(Playlist::class, 0);
$response->assertOk();
$this->assertIsString($response->json('data.DeletePlaylist.message'));
});
@@ -0,0 +1,121 @@
<?php
declare(strict_types=1);
use App\Enums\Auth\CrudPermission;
use App\Events\List\Playlist\PlaylistCreated;
use App\Events\List\Playlist\Track\TrackCreated;
use App\Models\Auth\User;
use App\Models\List\Playlist;
use App\Models\List\Playlist\PlaylistTrack;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Video;
use Illuminate\Support\Facades\Event;
use function Pest\Laravel\actingAs;
beforeEach(function () {
$this->mutation = '
mutation($playlist: String!, $entryId: Int!, $videoId: Int!) {
CreatePlaylistTrack(playlist: $playlist, entryId: $entryId, videoId: $videoId) {
id
}
}
';
});
test('protected', function () {
$response = graphql([
'query' => $this->mutation,
'variables' => [
'playlist' => fake()->word(),
'entryId' => fake()->randomDigitNotNull(),
'videoId' => fake()->randomDigitNotNull(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden', function () {
Event::fakeExcept(PlaylistCreated::class);
actingAs(User::factory()->createOne());
$response = graphql([
'query' => $this->mutation,
'variables' => [
// Needed for the bind resolver.
'playlist' => Playlist::factory()->createOne()->hashid,
'entryId' => AnimeThemeEntry::factory()->createOne()->getKey(),
'videoId' => Video::factory()->createOne()->getKey(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
it('fails if no entry video link', function () {
Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]);
$user = User::factory()
->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))
->createOne();
actingAs($user);
$entry = AnimeThemeEntry::factory()->createOne();
$video = Video::factory()->createOne();
$playlist = Playlist::factory()
->for($user)
->createOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
'playlist' => $playlist->hashid,
'entryId' => $entry->getKey(),
'videoId' => $video->getKey(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'validation');
$this->assertArrayHasKey('entryId', $response->json('errors.0.extensions.validation'));
$this->assertArrayHasKey('videoId', $response->json('errors.0.extensions.validation'));
});
it('creates', function () {
Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]);
$user = User::factory()
->withPermissions(CrudPermission::CREATE->format(PlaylistTrack::class))
->createOne();
actingAs($user);
$entry = AnimeThemeEntry::factory()->createOne();
$video = Video::factory()->createOne();
$entry->videos()->attach($video);
$playlist = Playlist::factory()
->for($user)
->createOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
'playlist' => $playlist->hashid,
'entryId' => $entry->getKey(),
'videoId' => $video->getKey(),
],
]);
$this->assertDatabaseCount(PlaylistTrack::class, 1);
$response->assertOk();
$response->assertJsonIsObject('data.CreatePlaylistTrack');
});
@@ -0,0 +1,107 @@
<?php
declare(strict_types=1);
use App\Enums\Auth\CrudPermission;
use App\Events\List\Playlist\PlaylistCreated;
use App\Events\List\Playlist\Track\TrackCreated;
use App\Models\Auth\User;
use App\Models\List\Playlist;
use App\Models\List\Playlist\PlaylistTrack;
use Illuminate\Support\Facades\Event;
use function Pest\Laravel\actingAs;
beforeEach(function () {
$this->mutation = '
mutation($playlist: String!, $id: String!) {
DeletePlaylistTrack(playlist: $playlist, id: $id) {
message
}
}
';
});
test('protected', function () {
$response = graphql([
'query' => $this->mutation,
'variables' => [
'playlist' => fake()->word(),
'id' => fake()->word(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden', function () {
Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]);
actingAs(User::factory()->createOne());
$playlist = Playlist::factory()->createOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
// Needed for the bind resolver.
'playlist' => $playlist->hashid,
'id' => PlaylistTrack::factory()->for($playlist)->createOne()->hashid,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden if not owner', function () {
Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]);
$user = User::factory()
->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))
->createOne();
actingAs($user);
$track = PlaylistTrack::factory()
->for(Playlist::factory())
->createOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
'playlist' => $track->playlist->hashid,
'id' => $track->hashid,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
it('deletes', function () {
Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]);
$user = User::factory()
->withPermissions(CrudPermission::DELETE->format(PlaylistTrack::class))
->createOne();
actingAs($user);
$track = PlaylistTrack::factory()
->for(Playlist::factory()->for($user))
->createOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
'playlist' => $track->playlist->hashid,
'id' => $track->hashid,
],
]);
$this->assertDatabaseCount(PlaylistTrack::class, 0);
$response->assertOk();
$this->assertIsString($response->json('data.DeletePlaylistTrack.message'));
});
@@ -0,0 +1,131 @@
<?php
declare(strict_types=1);
use App\Enums\Auth\CrudPermission;
use App\Events\List\Playlist\PlaylistCreated;
use App\Events\List\Playlist\Track\TrackCreated;
use App\Models\Auth\User;
use App\Models\List\Playlist;
use App\Models\List\Playlist\PlaylistTrack;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Video;
use Illuminate\Support\Facades\Event;
use function Pest\Laravel\actingAs;
beforeEach(function () {
$this->mutation = '
mutation($playlist: String!, $id: String!, $entryId: Int, $videoId: Int) {
UpdatePlaylistTrack(playlist: $playlist, id: $id, entryId: $entryId, videoId: $videoId) {
animethemeentry {
id
}
video {
id
}
}
}
';
});
test('protected', function () {
$response = graphql([
'query' => $this->mutation,
'variables' => [
'playlist' => fake()->word(),
'id' => fake()->word(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden', function () {
Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]);
actingAs(User::factory()->createOne());
$playlist = Playlist::factory()->createOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
// Needed for the bind resolver.
'playlist' => $playlist->hashid,
'id' => PlaylistTrack::factory()->for($playlist)->createOne()->hashid,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden if not owner', function () {
Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]);
$user = User::factory()
->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))
->createOne();
actingAs($user);
$track = PlaylistTrack::factory()
->for(Playlist::factory())
->createOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
'playlist' => $track->playlist->hashid,
'id' => $track->hashid,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
it('updates', function () {
Event::fakeExcept([PlaylistCreated::class, TrackCreated::class]);
$user = User::factory()
->withPermissions(CrudPermission::UPDATE->format(PlaylistTrack::class))
->createOne();
actingAs($user);
$track = PlaylistTrack::factory()
->for(Playlist::factory()->for($user))
->createOne();
$entry = AnimeThemeEntry::factory()->createOne();
$video = Video::factory()->createOne();
$entry->videos()->attach($video);
$response = graphql([
'query' => $this->mutation,
'variables' => [
'playlist' => $track->playlist->hashid,
'id' => $track->hashid,
'entryId' => $entry->getKey(),
'videoId' => $video->getKey(),
],
]);
$response->assertOk();
$response->assertJson([
'data' => [
'UpdatePlaylistTrack' => [
'animethemeentry' => [
'id' => $entry->getKey(),
],
'video' => [
'id' => $video->getKey(),
],
],
],
]);
});
@@ -0,0 +1,109 @@
<?php
declare(strict_types=1);
use App\Enums\Auth\CrudPermission;
use App\Events\List\Playlist\PlaylistCreated;
use App\Models\Auth\User;
use App\Models\List\Playlist;
use Illuminate\Support\Facades\Event;
use function Pest\Laravel\actingAs;
beforeEach(function () {
$this->mutation = '
mutation($id: String!, $name: String, $visibility: PlaylistVisibility, $description: String) {
UpdatePlaylist(id: $id, name: $name, visibility: $visibility, description: $description) {
name
visibility
description
}
}
';
});
test('protected', function () {
$response = graphql([
'query' => $this->mutation,
'variables' => [
'id' => fake()->word(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden', function () {
Event::fakeExcept(PlaylistCreated::class);
actingAs(User::factory()->createOne());
$response = graphql([
'query' => $this->mutation,
'variables' => [
// Needed for the bind resolver.
'id' => Playlist::factory()->createOne()->hashid,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden if not owner', function () {
Event::fakeExcept(PlaylistCreated::class);
$user = User::factory()
->withPermissions(CrudPermission::UPDATE->format(Playlist::class))
->createOne();
actingAs($user);
$response = graphql([
'query' => $this->mutation,
'variables' => [
'id' => Playlist::factory()->createOne()->hashid,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
it('updates', function () {
Event::fakeExcept(PlaylistCreated::class);
$user = User::factory()
->withPermissions(CrudPermission::UPDATE->format(Playlist::class))
->createOne();
actingAs($user);
$playlist = Playlist::factory()
->for($user)
->createOne();
$newPlaylist = Playlist::factory()->makeOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
'id' => $playlist->hashid,
'name' => $newPlaylist->name,
'visibility' => $newPlaylist->visibility->name,
'description' => $newPlaylist->description,
],
]);
$response->assertOk();
$response->assertJson([
'data' => [
'UpdatePlaylist' => [
'name' => $newPlaylist->name,
'visibility' => $newPlaylist->visibility->name,
'description' => $newPlaylist->description,
],
],
]);
});
@@ -0,0 +1,141 @@
<?php
declare(strict_types=1);
use App\Enums\Auth\CrudPermission;
use App\Models\Auth\User;
use App\Models\List\Playlist;
use App\Models\User\Like;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use function Pest\Laravel\actingAs;
beforeEach(function () {
$this->mutation = '
mutation($entryId: Int, $playlistId: String) {
ToggleLike(entry: $entryId, playlist: $playlistId) {
animethemeentry: likeable {
... on AnimeThemeEntry {
id
}
}
playlist: likeable {
... on Playlist {
id
}
}
}
}
';
});
test('protected', function () {
$response = graphql([
'query' => $this->mutation,
'variables' => [
'entryId' => fake()->randomDigitNotNull(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden', function () {
actingAs(User::factory()->createOne());
$response = graphql([
'query' => $this->mutation,
'variables' => [
// Needed for the bind resolver.
'entryId' => AnimeThemeEntry::factory()->createOne()->getKey(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
it('fails if more than one resource is passed', function () {
$user = User::factory()
->withPermissions(CrudPermission::CREATE->format(Like::class))
->createOne();
actingAs($user);
$entry = AnimeThemeEntry::factory()->createOne();
$playlist = Playlist::factory()->createOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
'entryId' => $entry->getKey(),
'playlistId' => $playlist->hashid,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'validation');
$this->assertArrayHasKey('entry', $response->json('errors.0.extensions.validation'));
$this->assertArrayHasKey('playlist', $response->json('errors.0.extensions.validation'));
});
it('likes entry', function () {
$user = User::factory()
->withPermissions(CrudPermission::CREATE->format(Like::class))
->createOne();
actingAs($user);
$entry = AnimeThemeEntry::factory()->createOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
'entryId' => $entry->getKey(),
],
]);
$this->assertDatabaseCount(Like::class, 1);
$response->assertOk();
$response->assertJson([
'data' => [
'ToggleLike' => [
'animethemeentry' => [
'id' => $entry->getKey(),
],
],
],
]);
});
it('likes playlist', function () {
$user = User::factory()
->withPermissions(CrudPermission::CREATE->format(Like::class))
->createOne();
actingAs($user);
$playlist = Playlist::factory()->createOne([
Playlist::ATTRIBUTE_HASHID => fake()->word(),
]);
$response = graphql([
'query' => $this->mutation,
'variables' => [
'playlistId' => $playlist->hashid,
],
]);
$this->assertDatabaseCount(Like::class, 1);
$response->assertOk();
$response->assertJson([
'data' => [
'ToggleLike' => [
'playlist' => [
'id' => $playlist->hashid,
],
],
],
]);
});
@@ -0,0 +1,114 @@
<?php
declare(strict_types=1);
use App\Enums\Auth\CrudPermission;
use App\Models\Auth\User;
use App\Models\User\WatchHistory;
use App\Models\Wiki\Anime\Theme\AnimeThemeEntry;
use App\Models\Wiki\Video;
use function Pest\Laravel\actingAs;
beforeEach(function () {
$this->mutation = '
mutation($entryId: Int!, $videoId: Int!) {
Watch(entryId: $entryId, videoId: $videoId) {
animethemeentry {
id
}
video {
id
}
}
}
';
});
test('protected', function () {
$response = graphql([
'query' => $this->mutation,
'variables' => [
'entryId' => fake()->randomDigitNotNull(),
'videoId' => fake()->randomDigitNotNull(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('forbidden', function () {
actingAs(User::factory()->createOne());
$response = graphql([
'query' => $this->mutation,
'variables' => [
'entryId' => fake()->randomDigitNotNull(),
'videoId' => fake()->randomDigitNotNull(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'authorization');
});
test('invalid entry id or video id', function () {
$user = User::factory()
->withPermissions(CrudPermission::CREATE->format(WatchHistory::class))
->createOne();
actingAs($user);
$entry = AnimeThemeEntry::factory()->createOne();
$video = Video::factory()->createOne();
$response = graphql([
'query' => $this->mutation,
'variables' => [
'entryId' => $entry->getKey(),
'videoId' => $video->getKey(),
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'validation');
$this->assertArrayHasKey('entryId', $response->json('errors.0.extensions.validation'));
$this->assertArrayHasKey('videoId', $response->json('errors.0.extensions.validation'));
});
test('mark as watched', function () {
$user = User::factory()
->withPermissions(CrudPermission::CREATE->format(WatchHistory::class))
->createOne();
actingAs($user);
$entry = AnimeThemeEntry::factory()->createOne();
$video = Video::factory()->createOne();
$entry->videos()->attach($video);
$response = graphql([
'query' => $this->mutation,
'variables' => [
'entryId' => $entry->getKey(),
'videoId' => $video->getKey(),
],
]);
$this->assertDatabaseCount(WatchHistory::class, 1);
$response->assertOk();
$response->assertJson([
'data' => [
'Watch' => [
'animethemeentry' => [
'id' => $entry->getKey(),
],
'video' => [
'id' => $video->getKey(),
],
],
],
]);
});
@@ -4,6 +4,45 @@ declare(strict_types=1);
use App\Models\Wiki\Anime;
test('fails query season anime field without year', function () {
$animes = Anime::factory()
->count(fake()->randomDigitNotNull())
->create();
$response = graphql([
'query' => '
query($season: AnimeSeason!) {
animeyears {
year
season(season: $season) {
season
anime {
data {
id
}
}
}
seasons {
season
anime {
data {
id
}
}
}
}
}
',
'variables' => [
'season' => $animes->random()->getAttribute(Anime::ATTRIBUTE_SEASON)->name,
],
]);
$response->assertOk();
$response->assertJsonPath('errors.0.extensions.category', 'validation');
$this->assertArrayHasKey('year', $response->json('errors.0.extensions.validation'));
});
test('query season & seasons field', function () {
$animes = Anime::factory()
->count(fake()->randomDigitNotNull())
@@ -29,7 +68,6 @@ test('query season & seasons field', function () {
]);
$response->assertOk();
$response->assertJsonStructure([
'data' => [
'animeyears' => [[
@@ -42,48 +80,6 @@ test('query season & seasons field', function () {
]);
});
test('fails query season anime field without year', function () {
$animes = Anime::factory()
->count(fake()->randomDigitNotNull())
->create();
$response = graphql([
'query' => '
query($season: AnimeSeason!) {
animeyears {
year
season(season: $season) {
season
anime {
data {
id
}
}
}
seasons {
season {
anime {
data {
id
}
}
}
}
}
}
',
'variables' => [
'season' => $animes->random()->getAttribute(Anime::ATTRIBUTE_SEASON)->name,
],
]);
$response->assertOk();
$response->assertJsonCount(1, 'errors');
$response->assertJsonStructure([
'errors' => [['message']],
]);
});
test('query season anime field with year', function () {
$animes = Anime::factory()
->count(fake()->randomDigitNotNull())
@@ -25,9 +25,9 @@ test('fails without id or link', function () {
]);
$response->assertOk();
$response->assertJsonStructure([
'errors' => [['message']],
]);
$response->assertJsonPath('errors.0.extensions.category', 'validation');
$this->assertArrayHasKey('id', $response->json('errors.0.extensions.validation'));
$this->assertArrayHasKey('link', $response->json('errors.0.extensions.validation'));
});
test('fails with for than 100 ids', function () {
@@ -35,7 +35,7 @@ test('fails with for than 100 ids', function () {
$response = graphql([
'query' => '
query($site: ResourceSite!, ids: [Int!]) {
query($site: ResourceSite!, $ids: [Int!]) {
findAnimeByExternalSite(site: $site, id: $ids) {
id
}
@@ -48,9 +48,8 @@ test('fails with for than 100 ids', function () {
]);
$response->assertOk();
$response->assertJsonStructure([
'errors' => [['message']],
]);
$response->assertJsonPath('errors.0.extensions.category', 'validation');
$this->assertArrayHasKey('id', $response->json('errors.0.extensions.validation'));
});
test('passes with id', function () {