client = static::createClient(); $this->entityManager = static::getContainer()->get(EntityManagerInterface::class); $this->projectDir = (string) static::getContainer()->getParameter('kernel.project_dir'); $this->resetDatabase(); $this->ensureUploadDirectories(); } public function testAlbumEditAndDeleteRoutesWorkForUserAlbum(): void { $user = $this->createUser('album-owner@example.test'); $album = $this->createUserAlbum($user, 'u_album_route_fix'); $this->client->loginUser($user); $crawler = $this->client->request('GET', '/albums/' . $album->getExternalId()); self::assertResponseStatusCodeSame(200); $this->client->request('GET', '/albums/' . $album->getExternalId() . '/edit'); self::assertResponseStatusCodeSame(200); $token = $crawler->filter('form[action$="/albums/' . $album->getExternalId() . '/delete"] input[name="_token"]')->attr('value'); self::assertIsString($token); $this->client->request('POST', '/albums/' . $album->getExternalId() . '/delete', ['_token' => $token]); self::assertResponseStatusCodeSame(302); $deleted = $this->entityManager->getRepository(Album::class)->findOneBy(['externalId' => $album->getExternalId()]); self::assertNull($deleted); } public function testCreateAlbumWithCoverUploadDoesNotErrorAndPersistsCoverPath(): void { $user = $this->createUser('cover-upload@example.test'); $this->client->loginUser($user); $crawler = $this->client->request('GET', '/albums/new'); self::assertResponseStatusCodeSame(200); $formToken = $crawler->filter('input[name="album[_token]"]')->attr('value'); self::assertIsString($formToken); $tmpFile = tempnam(sys_get_temp_dir(), 'cover_'); self::assertIsString($tmpFile); file_put_contents($tmpFile, base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8Xw8AAoMBgQwM0R8AAAAASUVORK5CYII=', true)); $cover = new UploadedFile($tmpFile, 'cover.png', 'image/png', null, true); $this->client->request( 'POST', '/albums/new', [ 'album' => [ '_token' => $formToken, 'name' => 'Cover Upload Regression', 'artistsCsv' => 'Cover Artist', 'genresCsv' => 'Rock', 'releaseDate' => '2024-01-01', 'totalTracks' => '1', 'externalUrl' => 'https://example.test/cover-source', ], 'track_title' => ['Track One'], 'track_duration' => ['3:21'], 'track_disc' => ['1'], 'track_number' => ['1'], ], [ 'album' => [ 'coverUpload' => $cover, ], ] ); self::assertResponseStatusCodeSame(302); $album = $this->entityManager->getRepository(Album::class)->findOneBy(['name' => 'Cover Upload Regression']); self::assertInstanceOf(Album::class, $album); self::assertNotNull($album->getCoverImagePath()); self::assertStringStartsWith('/uploads/album_covers/', (string) $album->getCoverImagePath()); self::assertFileExists($this->projectDir . '/public' . $album->getCoverImagePath()); } public function testDashboardPagesLinkToUserAlbumByExternalId(): void { $owner = $this->createUser('dashboard-owner@example.test'); $moderator = $this->createUser('dashboard-moderator@example.test', ['ROLE_MODERATOR']); $album = $this->createUserAlbum($owner, 'u_dashboard_link'); $this->client->loginUser($owner); $this->client->request('GET', '/dashboard'); self::assertResponseStatusCodeSame(200); self::assertStringContainsString('/albums/' . $album->getExternalId(), (string) $this->client->getResponse()->getContent()); $this->client->loginUser($moderator); $this->client->request('GET', '/admin/dashboard'); self::assertResponseStatusCodeSame(200); self::assertStringContainsString('/albums/' . $album->getExternalId(), (string) $this->client->getResponse()->getContent()); } private function ensureUploadDirectories(): void { $base = $this->projectDir . '/public/uploads'; @mkdir($base . '/album_covers', 0777, true); @mkdir($base . '/avatars', 0777, true); } private function resetDatabase(): void { $allMetadata = $this->entityManager->getMetadataFactory()->getAllMetadata(); if ($allMetadata === []) { return; } $schemaTool = new SchemaTool($this->entityManager); $schemaTool->dropDatabase(); $schemaTool->createSchema($allMetadata); $this->entityManager->clear(); } /** * @param list $roles */ private function createUser(string $email, array $roles = []): User { /** @var UserPasswordHasherInterface $passwordHasher */ $passwordHasher = static::getContainer()->get(UserPasswordHasherInterface::class); $user = new User(); $user->setEmail($email); $user->setDisplayName('Regression User'); $user->setRoles($roles); $user->setPassword($passwordHasher->hashPassword($user, 'password123')); $this->entityManager->persist($user); $this->entityManager->flush(); return $user; } private function createUserAlbum(User $owner, string $externalId): Album { $album = new Album(); $album->setSource('user'); $album->setExternalId($externalId); $album->setName('User Album ' . $externalId); $album->setArtists(['Regression Artist']); $album->setGenres(['Rock']); $album->setReleaseDate('2024-01-01'); $album->setTotalTracks(1); $album->setOwner($owner); $track = new AlbumTrack(); $track->setDiscNumber(1); $track->setTrackNumber(1); $track->setName('Regression Track'); $track->setDurationMs(180000); $album->addTrack($track); $this->entityManager->persist($album); $this->entityManager->flush(); return $album; } }