feat(test|api): add PlaylistSong tests

This commit is contained in:
Phan An 2022-07-27 10:49:33 +02:00
parent b3ee1ff528
commit 334c53727e
No known key found for this signature in database
GPG key ID: A81E4477F0BB6FDC
34 changed files with 224 additions and 95 deletions

View file

@ -43,6 +43,8 @@ class PlaylistSongController extends Controller
abort_if($playlist->is_smart, Response::HTTP_FORBIDDEN); abort_if($playlist->is_smart, Response::HTTP_FORBIDDEN);
$this->playlistService->addSongsToPlaylist($playlist, $request->songs); $this->playlistService->addSongsToPlaylist($playlist, $request->songs);
return response()->noContent();
} }
public function remove(Playlist $playlist, RemoveSongsFromPlaylistRequest $request) public function remove(Playlist $playlist, RemoveSongsFromPlaylistRequest $request)
@ -52,5 +54,7 @@ class PlaylistSongController extends Controller
abort_if($playlist->is_smart, Response::HTTP_FORBIDDEN); abort_if($playlist->is_smart, Response::HTTP_FORBIDDEN);
$this->playlistService->removeSongsFromPlaylist($playlist, $request->songs); $this->playlistService->removeSongsFromPlaylist($playlist, $request->songs);
return response()->noContent();
} }
} }

View file

@ -34,7 +34,6 @@ class Playlist extends Model
protected $guarded = ['id']; protected $guarded = ['id'];
protected $casts = [ protected $casts = [
'user_id' => 'int',
'rules' => SmartPlaylistRulesCast::class, 'rules' => SmartPlaylistRulesCast::class,
]; ];

View file

@ -37,7 +37,6 @@ class User extends Authenticatable
protected $appends = ['avatar']; protected $appends = ['avatar'];
protected $casts = [ protected $casts = [
'id' => 'int',
'is_admin' => 'bool', 'is_admin' => 'bool',
'preferences' => UserPreferencesCast::class, 'preferences' => UserPreferencesCast::class,
]; ];

View file

@ -9,6 +9,6 @@ class PlaylistPolicy
{ {
public function owner(User $user, Playlist $playlist): bool public function owner(User $user, Playlist $playlist): bool
{ {
return $user->id === $playlist->user_id; return $playlist->user->is($user);
} }
} }

View file

@ -13,6 +13,6 @@ class UserPolicy
public function destroy(User $currentUser, User $userToDestroy): bool public function destroy(User $currentUser, User $userToDestroy): bool
{ {
return $currentUser->is_admin && $currentUser->id !== $userToDestroy->id; return $currentUser->is_admin && $currentUser->isNot($userToDestroy);
} }
} }

View file

@ -8,30 +8,28 @@ use Throwable;
final class SmartPlaylistRuleGroup implements Arrayable final class SmartPlaylistRuleGroup implements Arrayable
{ {
public ?int $id; private function __construct(public ?int $id, public Collection $rules)
{
/** @var Collection|array<SmartPlaylistRule> */ }
public Collection $rules;
public static function tryCreate(array $jsonArray): ?self public static function tryCreate(array $jsonArray): ?self
{ {
try { try {
return self::create($jsonArray); return self::create($jsonArray);
} catch (Throwable $exception) { } catch (Throwable) {
return null; return null;
} }
} }
public static function create(array $jsonArray): self public static function create(array $jsonArray): self
{ {
$group = new self(); $id = $jsonArray['id'] ?? null;
$group->id = $jsonArray['id'] ?? null;
$group->rules = collect(array_map(static function (array $rawRuleConfig) { $rules = collect(array_map(static function (array $rawRuleConfig) {
return SmartPlaylistRule::create($rawRuleConfig); return SmartPlaylistRule::create($rawRuleConfig);
}, $jsonArray['rules'])); }, $jsonArray['rules']));
return $group; return new self($id, $rules);
} }
/** @return array<mixed> */ /** @return array<mixed> */

View file

@ -33,7 +33,7 @@ class AlbumCoverTest extends TestCase
return $album->id === 9999; return $album->id === 9999;
}), 'Foo', 'jpeg'); }), 'Foo', 'jpeg');
$response = $this->putAsUser('api/album/' . $album->id . '/cover', [ $response = $this->putAs('api/album/' . $album->id . '/cover', [
'cover' => 'data:image/jpeg;base64,Rm9v', 'cover' => 'data:image/jpeg;base64,Rm9v',
], User::factory()->admin()->create()); ], User::factory()->admin()->create());
@ -49,7 +49,7 @@ class AlbumCoverTest extends TestCase
->shouldReceive('writeAlbumCover') ->shouldReceive('writeAlbumCover')
->never(); ->never();
$this->putAsUser('api/album/' . $album->id . '/cover', [ $this->putAs('api/album/' . $album->id . '/cover', [
'cover' => 'data:image/jpeg;base64,Rm9v', 'cover' => 'data:image/jpeg;base64,Rm9v',
], User::factory()->create()) ], User::factory()->create())
->assertStatus(403); ->assertStatus(403);

View file

@ -37,7 +37,7 @@ class AlbumThumbnailTest extends TestCase
})) }))
->andReturn($thumbnailUrl); ->andReturn($thumbnailUrl);
$response = $this->getAsUser("api/album/{$createdAlbum->id}/thumbnail"); $response = $this->getAs("api/album/{$createdAlbum->id}/thumbnail");
$response->assertJson(['thumbnailUrl' => $thumbnailUrl]); $response->assertJson(['thumbnailUrl' => $thumbnailUrl]);
} }
} }

View file

@ -33,7 +33,7 @@ class ArtistImageTest extends TestCase
return $artist->id === 9999; return $artist->id === 9999;
}), 'Foo', 'jpeg'); }), 'Foo', 'jpeg');
$this->putAsUser('api/artist/9999/image', [ $this->putAs('api/artist/9999/image', [
'image' => 'data:image/jpeg;base64,Rm9v', 'image' => 'data:image/jpeg;base64,Rm9v',
], User::factory()->admin()->create()) ], User::factory()->admin()->create())
->assertStatus(200); ->assertStatus(200);
@ -47,7 +47,7 @@ class ArtistImageTest extends TestCase
->shouldReceive('writeArtistImage') ->shouldReceive('writeArtistImage')
->never(); ->never();
$this->putAsUser('api/artist/9999/image', [ $this->putAs('api/artist/9999/image', [
'image' => 'data:image/jpeg;base64,Rm9v', 'image' => 'data:image/jpeg;base64,Rm9v',
], User::factory()->create()) ], User::factory()->create())
->assertStatus(403); ->assertStatus(403);

View file

@ -164,9 +164,7 @@ class DownloadTest extends TestCase
self::mock(InteractionRepository::class) self::mock(InteractionRepository::class)
->shouldReceive('getUserFavorites') ->shouldReceive('getUserFavorites')
->once() ->once()
->with(Mockery::on(static function (User $retrievedUser) use ($user): bool { ->with(Mockery::on(static fn (User $retrievedUser) => $retrievedUser->is($user)))
return $retrievedUser->id === $user->id;
}))
->andReturn($favorites); ->andReturn($favorites);
$this->downloadService $this->downloadService

View file

@ -26,7 +26,7 @@ class InteractionTest extends TestCase
/** @var Song $song */ /** @var Song $song */
$song = Song::orderBy('id')->first(); $song = Song::orderBy('id')->first();
$this->postAsUser('api/interaction/play', ['song' => $song->id], $user); $this->postAs('api/interaction/play', ['song' => $song->id], $user);
self::assertDatabaseHas('interactions', [ self::assertDatabaseHas('interactions', [
'user_id' => $user->id, 'user_id' => $user->id,
@ -35,7 +35,7 @@ class InteractionTest extends TestCase
]); ]);
// Try again // Try again
$this->postAsUser('api/interaction/play', ['song' => $song->id], $user); $this->postAs('api/interaction/play', ['song' => $song->id], $user);
self::assertDatabaseHas('interactions', [ self::assertDatabaseHas('interactions', [
'user_id' => $user->id, 'user_id' => $user->id,
@ -53,7 +53,7 @@ class InteractionTest extends TestCase
/** @var Song $song */ /** @var Song $song */
$song = Song::orderBy('id')->first(); $song = Song::orderBy('id')->first();
$this->postAsUser('api/interaction/like', ['song' => $song->id], $user); $this->postAs('api/interaction/like', ['song' => $song->id], $user);
self::assertDatabaseHas('interactions', [ self::assertDatabaseHas('interactions', [
'user_id' => $user->id, 'user_id' => $user->id,
@ -62,7 +62,7 @@ class InteractionTest extends TestCase
]); ]);
// Try again // Try again
$this->postAsUser('api/interaction/like', ['song' => $song->id], $user); $this->postAs('api/interaction/like', ['song' => $song->id], $user);
self::assertDatabaseHas('interactions', [ self::assertDatabaseHas('interactions', [
'user_id' => $user->id, 'user_id' => $user->id,
@ -82,7 +82,7 @@ class InteractionTest extends TestCase
$songs = Song::orderBy('id')->take(2)->get(); $songs = Song::orderBy('id')->take(2)->get();
$songIds = array_pluck($songs->toArray(), 'id'); $songIds = array_pluck($songs->toArray(), 'id');
$this->postAsUser('api/interaction/batch/like', ['songs' => $songIds], $user); $this->postAs('api/interaction/batch/like', ['songs' => $songIds], $user);
foreach ($songs as $song) { foreach ($songs as $song) {
self::assertDatabaseHas('interactions', [ self::assertDatabaseHas('interactions', [
@ -92,7 +92,7 @@ class InteractionTest extends TestCase
]); ]);
} }
$this->postAsUser('api/interaction/batch/unlike', ['songs' => $songIds], $user); $this->postAs('api/interaction/batch/unlike', ['songs' => $songIds], $user);
foreach ($songs as $song) { foreach ($songs as $song) {
self::assertDatabaseHas('interactions', [ self::assertDatabaseHas('interactions', [

View file

@ -31,7 +31,7 @@ class LastfmTest extends TestCase
{ {
/** @var User $user */ /** @var User $user */
$user = User::factory()->create(); $user = User::factory()->create();
$this->postAsUser('api/lastfm/session-key', ['key' => 'foo'], $user) $this->postAs('api/lastfm/session-key', ['key' => 'foo'], $user)
->assertStatus(204); ->assertStatus(204);
self::assertEquals('foo', $user->refresh()->lastfm_session_key); self::assertEquals('foo', $user->refresh()->lastfm_session_key);
@ -120,7 +120,7 @@ class LastfmTest extends TestCase
/** @var User $user */ /** @var User $user */
$user = User::factory()->create(); $user = User::factory()->create();
self::assertNotNull($user->lastfm_session_key); self::assertNotNull($user->lastfm_session_key);
$this->deleteAsUser('api/lastfm/disconnect', [], $user); $this->deleteAs('api/lastfm/disconnect', [], $user);
$user->refresh(); $user->refresh();
self::assertNull($user->lastfm_session_key); self::assertNull($user->lastfm_session_key);

View file

@ -33,9 +33,7 @@ class PlaylistSongTest extends TestCase
$user = User::factory()->create(); $user = User::factory()->create();
/** @var Playlist $playlist */ /** @var Playlist $playlist */
$playlist = Playlist::factory()->create([ $playlist = Playlist::factory()->create([], $user);
'user_id' => $user->id,
]);
/** @var array<Song>|Collection $songs */ /** @var array<Song>|Collection $songs */
$songs = Song::orderBy('id')->take(4)->get(); $songs = Song::orderBy('id')->take(4)->get();
@ -46,7 +44,7 @@ class PlaylistSongTest extends TestCase
$path = $useDeprecatedRoute ? "api/playlist/$playlist->id/sync" : "api/playlist/$playlist->id/songs"; $path = $useDeprecatedRoute ? "api/playlist/$playlist->id/sync" : "api/playlist/$playlist->id/songs";
$this->putAsUser($path, [ $this->putAs($path, [
'songs' => $songs->pluck('id')->all(), 'songs' => $songs->pluck('id')->all(),
], $user)->assertOk(); ], $user)->assertOk();
@ -77,7 +75,7 @@ class PlaylistSongTest extends TestCase
$songs = Song::factory(2)->create(); $songs = Song::factory(2)->create();
$playlist->songs()->saveMany($songs); $playlist->songs()->saveMany($songs);
$this->getAsUser("api/playlist/$playlist->id/songs", $user) $this->getAs("api/playlist/$playlist->id/songs", $user)
->assertJson($songs->pluck('id')->all()); ->assertJson($songs->pluck('id')->all());
} }
} }

View file

@ -25,7 +25,7 @@ class PlaylistTest extends TestCase
/** @var array<Song>|Collection $songs */ /** @var array<Song>|Collection $songs */
$songs = Song::orderBy('id')->take(3)->get(); $songs = Song::orderBy('id')->take(3)->get();
$response = $this->postAsUser('api/playlist', [ $response = $this->postAs('api/playlist', [
'name' => 'Foo Bar', 'name' => 'Foo Bar',
'songs' => $songs->pluck('id')->toArray(), 'songs' => $songs->pluck('id')->toArray(),
'rules' => [], 'rules' => [],
@ -52,7 +52,7 @@ class PlaylistTest extends TestCase
'value' => ['Bob Dylan'], 'value' => ['Bob Dylan'],
]); ]);
$this->postAsUser('api/playlist', [ $this->postAs('api/playlist', [
'name' => 'Smart Foo Bar', 'name' => 'Smart Foo Bar',
'rules' => [ 'rules' => [
[ [
@ -74,7 +74,7 @@ class PlaylistTest extends TestCase
public function testCreatingSmartPlaylistIgnoresSongs(): void public function testCreatingSmartPlaylistIgnoresSongs(): void
{ {
$this->postAsUser('api/playlist', [ $this->postAs('api/playlist', [
'name' => 'Smart Foo Bar', 'name' => 'Smart Foo Bar',
'rules' => [ 'rules' => [
[ [
@ -100,7 +100,7 @@ class PlaylistTest extends TestCase
public function testCreatingPlaylistWithNonExistentSongsFails(): void public function testCreatingPlaylistWithNonExistentSongsFails(): void
{ {
$response = $this->postAsUser('api/playlist', [ $response = $this->postAs('api/playlist', [
'name' => 'Foo Bar', 'name' => 'Foo Bar',
'rules' => [], 'rules' => [],
'songs' => ['foo'], 'songs' => ['foo'],
@ -120,7 +120,7 @@ class PlaylistTest extends TestCase
'name' => 'Foo', 'name' => 'Foo',
]); ]);
$this->putAsUser("api/playlist/$playlist->id", ['name' => 'Bar'], $user); $this->putAs("api/playlist/$playlist->id", ['name' => 'Bar'], $user);
self::assertSame('Bar', $playlist->refresh()->name); self::assertSame('Bar', $playlist->refresh()->name);
} }
@ -132,7 +132,7 @@ class PlaylistTest extends TestCase
'name' => 'Foo', 'name' => 'Foo',
]); ]);
$response = $this->putAsUser("api/playlist/$playlist->id", ['name' => 'Qux']); $response = $this->putAs("api/playlist/$playlist->id", ['name' => 'Qux']);
$response->assertStatus(403); $response->assertStatus(403);
} }
@ -146,7 +146,7 @@ class PlaylistTest extends TestCase
'user_id' => $user->id, 'user_id' => $user->id,
]); ]);
$this->deleteAsUser("api/playlist/$playlist->id", [], $user); $this->deleteAs("api/playlist/$playlist->id", [], $user);
self::assertDatabaseMissing('playlists', ['id' => $playlist->id]); self::assertDatabaseMissing('playlists', ['id' => $playlist->id]);
} }
@ -155,7 +155,7 @@ class PlaylistTest extends TestCase
/** @var Playlist $playlist */ /** @var Playlist $playlist */
$playlist = Playlist::factory()->create(); $playlist = Playlist::factory()->create();
$this->deleteAsUser("api/playlist/$playlist->id") $this->deleteAs("api/playlist/$playlist->id")
->assertStatus(403); ->assertStatus(403);
} }
} }

View file

@ -19,7 +19,7 @@ class ProfileTest extends TestCase
public function testUpdateProfileRequiresCurrentPassword(): void public function testUpdateProfileRequiresCurrentPassword(): void
{ {
$this->putAsUser('api/me', [ $this->putAs('api/me', [
'name' => 'Foo', 'name' => 'Foo',
'email' => 'bar@baz.com', 'email' => 'bar@baz.com',
], $this->user) ], $this->user)
@ -28,7 +28,7 @@ class ProfileTest extends TestCase
public function testUpdateProfileWithoutNewPassword(): void public function testUpdateProfileWithoutNewPassword(): void
{ {
$this->putAsUser('api/me', [ $this->putAs('api/me', [
'name' => 'Foo', 'name' => 'Foo',
'email' => 'bar@baz.com', 'email' => 'bar@baz.com',
'current_password' => 'secret', 'current_password' => 'secret',
@ -43,7 +43,7 @@ class ProfileTest extends TestCase
public function testUpdateProfileWithNewPassword(): void public function testUpdateProfileWithNewPassword(): void
{ {
$this->putAsUser('api/me', [ $this->putAs('api/me', [
'name' => 'Foo', 'name' => 'Foo',
'email' => 'bar@baz.com', 'email' => 'bar@baz.com',
'new_password' => 'new-secret', 'new_password' => 'new-secret',

View file

@ -25,7 +25,7 @@ class ScrobbleTest extends TestCase
->with($song->album->artist->name, $song->title, $timestamp, $song->album->name, $user->lastfm_session_key) ->with($song->album->artist->name, $song->title, $timestamp, $song->album->name, $user->lastfm_session_key)
->once(); ->once();
$this->postAsUser("/api/$song->id/scrobble", ['timestamp' => $timestamp], $user) $this->postAs("/api/$song->id/scrobble", ['timestamp' => $timestamp], $user)
->assertNoContent(); ->assertNoContent();
} }
} }

View file

@ -23,7 +23,7 @@ class SettingTest extends TestCase
{ {
$this->mediaSyncService->shouldReceive('sync')->once(); $this->mediaSyncService->shouldReceive('sync')->once();
$this->putAsUser('/api/settings', ['media_path' => __DIR__], User::factory()->admin()->create()) $this->putAs('/api/settings', ['media_path' => __DIR__], User::factory()->admin()->create())
->assertSuccessful(); ->assertSuccessful();
self::assertEquals(__DIR__, Setting::get('media_path')); self::assertEquals(__DIR__, Setting::get('media_path'));
@ -31,7 +31,7 @@ class SettingTest extends TestCase
public function testNonAdminCannotSaveSettings(): void public function testNonAdminCannotSaveSettings(): void
{ {
$this->putAsUser('/api/settings', ['media_path' => __DIR__], User::factory()->create()) $this->putAs('/api/settings', ['media_path' => __DIR__], User::factory()->create())
->assertForbidden(); ->assertForbidden();
} }
} }

View file

@ -21,7 +21,7 @@ class SongTest extends TestCase
{ {
$song = Song::first(); $song = Song::first();
$this->putAsUser('/api/songs', [ $this->putAs('/api/songs', [
'songs' => [$song->id], 'songs' => [$song->id],
'data' => [ 'data' => [
'title' => 'Foo Bar', 'title' => 'Foo Bar',
@ -56,7 +56,7 @@ class SongTest extends TestCase
$song = Song::first(); $song = Song::first();
$originalArtistId = $song->artist->id; $originalArtistId = $song->artist->id;
$this->putAsUser('/api/songs', [ $this->putAs('/api/songs', [
'songs' => [$song->id], 'songs' => [$song->id],
'data' => [ 'data' => [
'title' => '', 'title' => '',
@ -79,7 +79,7 @@ class SongTest extends TestCase
{ {
$songIds = Song::latest()->take(3)->pluck('id')->toArray(); $songIds = Song::latest()->take(3)->pluck('id')->toArray();
$this->putAsUser('/api/songs', [ $this->putAs('/api/songs', [
'songs' => $songIds, 'songs' => $songIds,
'data' => [ 'data' => [
'title' => 'foo', 'title' => 'foo',
@ -109,7 +109,7 @@ class SongTest extends TestCase
$originalSongs = Song::latest()->take(3)->get(); $originalSongs = Song::latest()->take(3)->get();
$songIds = $originalSongs->pluck('id')->toArray(); $songIds = $originalSongs->pluck('id')->toArray();
$this->putAsUser('/api/songs', [ $this->putAs('/api/songs', [
'songs' => $songIds, 'songs' => $songIds,
'data' => [ 'data' => [
'title' => 'Foo Bar', 'title' => 'Foo Bar',
@ -143,7 +143,7 @@ class SongTest extends TestCase
{ {
$song = Song::first(); $song = Song::first();
$this->putAsUser('/api/songs', [ $this->putAs('/api/songs', [
'songs' => [$song->id], 'songs' => [$song->id],
'data' => [ 'data' => [
'title' => 'Foo Bar', 'title' => 'Foo Bar',

View file

@ -8,7 +8,7 @@ use Tests\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase abstract class TestCase extends BaseTestCase
{ {
private function jsonAsUser(?User $user, string $method, $uri, array $data = [], array $headers = []): TestResponse private function jsonAs(?User $user, string $method, $uri, array $data = [], array $headers = []): TestResponse
{ {
/** @var User $user */ /** @var User $user */
$user = $user ?: User::factory()->create(); $user = $user ?: User::factory()->create();
@ -17,23 +17,23 @@ abstract class TestCase extends BaseTestCase
return parent::json($method, $uri, $data, $headers); return parent::json($method, $uri, $data, $headers);
} }
protected function getAsUser(string $url, ?User $user = null): TestResponse protected function getAs(string $url, ?User $user = null): TestResponse
{ {
return $this->jsonAsUser($user, 'get', $url); return $this->jsonAs($user, 'get', $url);
} }
protected function deleteAsUser(string $url, array $data = [], ?User $user = null): TestResponse protected function deleteAs(string $url, array $data = [], ?User $user = null): TestResponse
{ {
return $this->jsonAsUser($user, 'delete', $url, $data); return $this->jsonAs($user, 'delete', $url, $data);
} }
protected function postAsUser(string $url, array $data, ?User $user = null): TestResponse protected function postAs(string $url, array $data, ?User $user = null): TestResponse
{ {
return $this->jsonAsUser($user, 'post', $url, $data); return $this->jsonAs($user, 'post', $url, $data);
} }
protected function putAsUser(string $url, array $data, ?User $user = null): TestResponse protected function putAs(string $url, array $data, ?User $user = null): TestResponse
{ {
return $this->jsonAsUser($user, 'put', $url, $data); return $this->jsonAs($user, 'put', $url, $data);
} }
} }

View file

@ -32,7 +32,7 @@ class UploadTest extends TestCase
->shouldReceive('handleUploadedFile') ->shouldReceive('handleUploadedFile')
->never(); ->never();
$this->postAsUser('/api/upload', ['file' => $file], User::factory()->create())->assertStatus(403); $this->postAs('/api/upload', ['file' => $file], User::factory()->create())->assertStatus(403);
} }
/** @return array<mixed> */ /** @return array<mixed> */
@ -55,7 +55,7 @@ class UploadTest extends TestCase
->with($file) ->with($file)
->andThrow($exceptionClass); ->andThrow($exceptionClass);
$this->postAsUser('/api/upload', ['file' => $file], User::factory()->admin()->create()) $this->postAs('/api/upload', ['file' => $file], User::factory()->admin()->create())
->assertStatus($statusCode); ->assertStatus($statusCode);
} }
@ -71,7 +71,7 @@ class UploadTest extends TestCase
->with($file) ->with($file)
->andReturn($song); ->andReturn($song);
$this->postAsUser('/api/upload', ['file' => $file], User::factory()->admin()->create()) $this->postAs('/api/upload', ['file' => $file], User::factory()->admin()->create())
->assertJsonStructure([ ->assertJsonStructure([
'song', 'song',
'album', 'album',

View file

@ -14,7 +14,7 @@ class UserTest extends TestCase
public function testNonAdminCannotCreateUser(): void public function testNonAdminCannotCreateUser(): void
{ {
$this->postAsUser('api/user', [ $this->postAs('api/user', [
'name' => 'Foo', 'name' => 'Foo',
'email' => 'bar@baz.com', 'email' => 'bar@baz.com',
'password' => 'secret', 'password' => 'secret',
@ -24,7 +24,7 @@ class UserTest extends TestCase
public function testAdminCreatesUser(): void public function testAdminCreatesUser(): void
{ {
$this->postAsUser('api/user', [ $this->postAs('api/user', [
'name' => 'Foo', 'name' => 'Foo',
'email' => 'bar@baz.com', 'email' => 'bar@baz.com',
'password' => 'secret', 'password' => 'secret',
@ -46,7 +46,7 @@ class UserTest extends TestCase
/** @var User $user */ /** @var User $user */
$user = User::factory()->admin()->create(['password' => 'secret']); $user = User::factory()->admin()->create(['password' => 'secret']);
$this->putAsUser("api/user/$user->id", [ $this->putAs("api/user/$user->id", [
'name' => 'Foo', 'name' => 'Foo',
'email' => 'bar@baz.com', 'email' => 'bar@baz.com',
'password' => 'new-secret', 'password' => 'new-secret',
@ -67,7 +67,7 @@ class UserTest extends TestCase
$user = User::factory()->create(); $user = User::factory()->create();
$admin = User::factory()->admin()->create(); $admin = User::factory()->admin()->create();
$this->deleteAsUser("api/user/$user->id", [], $admin); $this->deleteAs("api/user/$user->id", [], $admin);
self::assertDatabaseMissing('users', ['id' => $user->id]); self::assertDatabaseMissing('users', ['id' => $user->id]);
} }
@ -77,7 +77,7 @@ class UserTest extends TestCase
$admin = User::factory()->admin()->create(); $admin = User::factory()->admin()->create();
// A user can't delete himself // A user can't delete himself
$this->deleteAsUser("api/user/$admin->id", [], $admin) $this->deleteAs("api/user/$admin->id", [], $admin)
->assertStatus(403); ->assertStatus(403);
self::assertDatabaseHas('users', ['id' => $admin->id]); self::assertDatabaseHas('users', ['id' => $admin->id]);

View file

@ -57,7 +57,7 @@ class AlbumInformationTest extends TestCase
] ]
)); ));
$this->getAsUser('api/albums/' . $album->id . '/information') $this->getAs('api/albums/' . $album->id . '/information')
->assertJsonStructure(self::JSON_STRUCTURE); ->assertJsonStructure(self::JSON_STRUCTURE);
} }
@ -69,7 +69,7 @@ class AlbumInformationTest extends TestCase
/** @var Album $album */ /** @var Album $album */
$album = Album::factory()->create(); $album = Album::factory()->create();
$this->getAsUser('api/albums/' . $album->id . '/information') $this->getAs('api/albums/' . $album->id . '/information')
->assertJsonStructure(self::JSON_STRUCTURE); ->assertJsonStructure(self::JSON_STRUCTURE);
} }
} }

View file

@ -12,11 +12,9 @@ class AlbumSongTest extends TestCase
/** @var Album $album */ /** @var Album $album */
$album = Album::factory()->create(); $album = Album::factory()->create();
Song::factory(5)->create([ Song::factory(5)->for($album)->create();
'album_id' => $album->id,
]);
$this->getAsUser('api/albums/' . $album->id . '/songs') $this->getAs('api/albums/' . $album->id . '/songs')
->assertJsonStructure(['*' => SongTest::JSON_STRUCTURE]); ->assertJsonStructure(['*' => SongTest::JSON_STRUCTURE]);
} }
} }

View file

@ -42,7 +42,7 @@ class AlbumTest extends TestCase
{ {
Album::factory(10)->create(); Album::factory(10)->create();
$this->getAsUser('api/albums') $this->getAs('api/albums')
->assertJsonStructure(self::JSON_COLLECTION_STRUCTURE); ->assertJsonStructure(self::JSON_COLLECTION_STRUCTURE);
} }
@ -51,7 +51,7 @@ class AlbumTest extends TestCase
/** @var Album $album */ /** @var Album $album */
$album = Album::factory()->create(); $album = Album::factory()->create();
$this->getAsUser('api/albums/' . $album->id) $this->getAs('api/albums/' . $album->id)
->assertJsonStructure(self::JSON_STRUCTURE); ->assertJsonStructure(self::JSON_STRUCTURE);
} }
} }

View file

@ -38,7 +38,7 @@ class ArtistInformationTest extends TestCase
], ],
)); ));
$this->getAsUser('api/artists/' . $artist->id . '/information') $this->getAs('api/artists/' . $artist->id . '/information')
->assertJsonStructure(self::JSON_STRUCTURE); ->assertJsonStructure(self::JSON_STRUCTURE);
} }
@ -50,7 +50,7 @@ class ArtistInformationTest extends TestCase
/** @var Artist $artist */ /** @var Artist $artist */
$artist = Artist::factory()->create(); $artist = Artist::factory()->create();
$this->getAsUser('api/artists/' . $artist->id . '/information') $this->getAs('api/artists/' . $artist->id . '/information')
->assertJsonStructure(self::JSON_STRUCTURE); ->assertJsonStructure(self::JSON_STRUCTURE);
} }
} }

View file

@ -12,11 +12,9 @@ class ArtistSongTest extends TestCase
/** @var Artist $artist */ /** @var Artist $artist */
$artist = Artist::factory()->create(); $artist = Artist::factory()->create();
Song::factory(5)->create([ Song::factory(5)->for($artist)->create();
'artist_id' => $artist->id,
]);
$this->getAsUser('api/artists/' . $artist->id . '/songs') $this->getAs('api/artists/' . $artist->id . '/songs')
->assertJsonStructure(['*' => SongTest::JSON_STRUCTURE]); ->assertJsonStructure(['*' => SongTest::JSON_STRUCTURE]);
} }
} }

View file

@ -41,7 +41,7 @@ class ArtistTest extends TestCase
{ {
Artist::factory(10)->create(); Artist::factory(10)->create();
$this->getAsUser('api/artists') $this->getAs('api/artists')
->assertJsonStructure(self::JSON_COLLECTION_STRUCTURE); ->assertJsonStructure(self::JSON_COLLECTION_STRUCTURE);
} }
@ -50,7 +50,7 @@ class ArtistTest extends TestCase
/** @var Artist $artist */ /** @var Artist $artist */
$artist = Artist::factory()->create(); $artist = Artist::factory()->create();
$this->getAsUser('api/artists/' . $artist->id) $this->getAs('api/artists/' . $artist->id)
->assertJsonStructure(self::JSON_STRUCTURE); ->assertJsonStructure(self::JSON_STRUCTURE);
} }
} }

View file

@ -6,7 +6,7 @@ class DataTest extends TestCase
{ {
public function testIndex(): void public function testIndex(): void
{ {
$this->getAsUser('/api/data')->assertJsonStructure([ $this->getAs('/api/data')->assertJsonStructure([
'settings', 'settings',
'playlists', 'playlists',
'current_user', 'current_user',

View file

@ -19,7 +19,7 @@ class ExcerptSearchTest extends TestCase
Album::factory()->create(['name' => 'Foo Number Five']); Album::factory()->create(['name' => 'Foo Number Five']);
Album::factory(4)->create(); Album::factory(4)->create();
$this->getAsUser('api/search?q=foo') $this->getAs('api/search?q=foo')
->assertJsonStructure([ ->assertJsonStructure([
'songs' => ['*' => SongTest::JSON_STRUCTURE], 'songs' => ['*' => SongTest::JSON_STRUCTURE],
'artists' => ['*' => ArtistTest::JSON_STRUCTURE], 'artists' => ['*' => ArtistTest::JSON_STRUCTURE],

View file

@ -16,7 +16,7 @@ class FavoriteTest extends TestCase
'user_id' => $user->id, 'user_id' => $user->id,
]); ]);
$this->getAsUser('api/favorites', $user) $this->getAs('api/favorites', $user)
->assertJsonStructure(['*' => SongTest::JSON_STRUCTURE]); ->assertJsonStructure(['*' => SongTest::JSON_STRUCTURE]);
} }
} }

View file

@ -12,11 +12,9 @@ class OverviewTest extends TestCase
/** @var User $user */ /** @var User $user */
$user = User::factory()->create(); $user = User::factory()->create();
Interaction::factory(20)->create([ Interaction::factory(20)->for($user)->create();
'user_id' => $user->id,
]);
$this->getAsUser('api/overview', $user) $this->getAs('api/overview', $user)
->assertJsonStructure([ ->assertJsonStructure([
'most_played_songs' => ['*' => SongTest::JSON_STRUCTURE], 'most_played_songs' => ['*' => SongTest::JSON_STRUCTURE],
'recently_played_songs' => ['*' => SongTest::JSON_STRUCTURE], 'recently_played_songs' => ['*' => SongTest::JSON_STRUCTURE],

View file

@ -13,7 +13,7 @@ class PlayCountTest extends TestCase
'play_count' => 10, 'play_count' => 10,
]); ]);
$response = $this->postAsUser('/api/interaction/play', [ $response = $this->postAs('/api/interaction/play', [
'song' => $interaction->song->id, 'song' => $interaction->song->id,
], $interaction->user); ], $interaction->user);

View file

@ -0,0 +1,139 @@
<?php
namespace Tests\Feature\V6;
use App\Models\Playlist;
use App\Models\Song;
use App\Models\User;
use Illuminate\Http\Response;
class PlaylistSongTest extends TestCase
{
public function testGetNormalPlaylist(): void
{
/** @var Playlist $playlist */
$playlist = Playlist::factory()->create();
$playlist->songs()->attach(Song::factory(5)->create());
$this->getAs('api/playlists/' . $playlist->id . '/songs', $playlist->user)
->assertJsonStructure(['*' => SongTest::JSON_STRUCTURE]);
}
public function testGetSmartPlaylist(): void
{
Song::factory()->create(['title' => 'A foo song']);
/** @var Playlist $playlist */
$playlist = Playlist::factory()->create([
'rules' => [
[
'id' => 1658843809274,
'rules' => [
[
'id' => 1658843809274,
'model' => 'title',
'operator' => 'contains',
'value' => ['foo'],
],
],
],
],
]);
$this->getAs('api/playlists/' . $playlist->id . '/songs', $playlist->user)
->assertJsonStructure(['*' => SongTest::JSON_STRUCTURE]);
}
public function testNonOwnerCannotAccessPlaylist(): void
{
$user = User::factory()->create();
/** @var Playlist $playlist */
$playlist = Playlist::factory()->for($user)->create();
$playlist->songs()->attach(Song::factory(5)->create());
$this->getAs('api/playlists/' . $playlist->id . '/songs')
->assertStatus(Response::HTTP_FORBIDDEN);
}
public function testAddSongsToPlaylist(): void
{
/** @var Playlist $playlist */
$playlist = Playlist::factory()->create();
$songs = Song::factory(2)->create();
$this->postAs('api/playlists/' . $playlist->id . '/songs', [
'songs' => $songs->map(static fn (Song $song) => $song->id)->all(),
], $playlist->user)
->assertNoContent();
self::assertEqualsCanonicalizing($songs->pluck('id')->all(), $playlist->songs->pluck('id')->all());
}
public function testRemoveSongsFromPlaylist(): void
{
/** @var Playlist $playlist */
$playlist = Playlist::factory()->create();
$toRemainSongs = Song::factory(5)->create();
$toBeRemovedSongs = Song::factory(2)->create();
$playlist->songs()->attach($toRemainSongs->merge($toBeRemovedSongs));
self::assertCount(7, $playlist->songs);
$this->deleteAs('api/playlists/' . $playlist->id . '/songs', [
'songs' => $toBeRemovedSongs->map(static fn (Song $song) => $song->id)->all(),
], $playlist->user)
->assertNoContent();
$playlist->refresh();
self::assertEqualsCanonicalizing($toRemainSongs->pluck('id')->all(), $playlist->songs->pluck('id')->all());
}
public function testNonOwnerCannotModifyPlaylist(): void
{
$user = User::factory()->create();
/** @var Playlist $playlist */
$playlist = Playlist::factory()->for($user)->create();
/** @var Song $song */
$song = Song::factory()->create();
$this->postAs('api/playlists/' . $playlist->id . '/songs', ['songs' => [$song->id]])
->assertStatus(Response::HTTP_FORBIDDEN);
$this->deleteAs('api/playlists/' . $playlist->id . '/songs', ['songs' => [$song->id]])
->assertStatus(Response::HTTP_FORBIDDEN);
}
public function testSmartPlaylistContentCannotBeModified(): void
{
/** @var Playlist $playlist */
$playlist = Playlist::factory()->create([
'rules' => [
[
'id' => 1658843809274,
'rules' => [
[
'id' => 1658843809274,
'model' => 'title',
'operator' => 'contains',
'value' => ['foo'],
],
],
],
],
]);
$songs = Song::factory(2)->create()->map(static fn (Song $song) => $song->id)->all();
$this->postAs('api/playlists/' . $playlist->id . '/songs', ['songs' => $songs], $playlist->user)
->assertStatus(Response::HTTP_FORBIDDEN);
$this->deleteAs('api/playlists/' . $playlist->id . '/songs', ['songs' => $songs], $playlist->user)
->assertStatus(Response::HTTP_FORBIDDEN);
}
}

View file

@ -29,7 +29,7 @@ class YouTubeTest extends TestCase
}), 'foo') }), 'foo')
->once(); ->once();
$this->getAsUser("/api/youtube/search/song/{$song->id}?pageToken=foo") $this->getAs("/api/youtube/search/song/{$song->id}?pageToken=foo")
->assertOk(); ->assertOk();
} }
} }