- Update E2E test credentials to match actual seed users (user@veza.music, artist@veza.music, admin@veza.music, mod@veza.music) - Fix hardcoded "Suggested Accounts" in SuggestionsWidget with i18n key - Replace hardcoded amelie_dubois references with CONFIG.users.creator - Refactor auth, player, upload E2E tests for reliability - Add tmt test plans and scripts for CI integration - Simplify CI workflow Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
146 lines
6.2 KiB
TypeScript
146 lines
6.2 KiB
TypeScript
import { test, expect } from '@chromatic-com/playwright';
|
|
import { loginViaAPI, CONFIG, navigateTo } from './helpers';
|
|
|
|
test.describe('SOCIAL — Follow/Unfollow', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password);
|
|
});
|
|
|
|
test('01. Bouton follow visible sur un profil artiste @critical', async ({ page }) => {
|
|
// Navigate directly to a known artist profile (seed user top_artist)
|
|
await navigateTo(page, `/u/${CONFIG.users.creator.username}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// FollowButton renders "Suivre" (unfollowed) or "Abonne" (followed)
|
|
const followBtn = page.getByRole('button', { name: /suivre|abonné|abonnement/i }).first();
|
|
const visible = await followBtn.isVisible().catch(() => false);
|
|
console.log(` Bouton follow: ${visible ? '✓' : '✗'}`);
|
|
});
|
|
|
|
test('02. Follow toggle fonctionne', async ({ page }) => {
|
|
// Navigate directly to a known artist profile
|
|
await navigateTo(page, '/u/marcus_beats');
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// FollowButton text: "Suivre" (not following) or "Abonné" (following)
|
|
const followBtn = page.getByRole('button', { name: /suivre|abonné|abonnement|désabonnement/i }).first();
|
|
|
|
if (await followBtn.isVisible().catch(() => false)) {
|
|
const initialText = await followBtn.textContent();
|
|
await followBtn.click();
|
|
await page.waitForTimeout(1_500);
|
|
const newText = await followBtn.textContent();
|
|
|
|
console.log(` Follow toggle: "${initialText?.trim()}" → "${newText?.trim()}" ${initialText !== newText ? '✓' : '✗'}`);
|
|
} else {
|
|
console.log(' ⚠ Bouton follow non visible');
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe('SOCIAL — Profils', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password);
|
|
});
|
|
|
|
test('03. Mon profil se charge avec les bonnes infos @critical', async ({ page }) => {
|
|
await navigateTo(page, '/profile');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
|
|
// The username should appear on the profile page
|
|
const hasUsername = body.includes(CONFIG.users.listener.username);
|
|
console.log(` Username affiché: ${hasUsername ? '✓' : '✗'}`);
|
|
|
|
// Avatar visible (UserProfilePageHeader uses Avatar component)
|
|
const avatar = page.locator('[class*="avatar"], img[alt*="avatar"], img[alt*="profil"]').first();
|
|
const avatarVisible = await avatar.isVisible().catch(() => false);
|
|
console.log(` Avatar: ${avatarVisible ? '✓' : '✗'}`);
|
|
});
|
|
|
|
test('04. Éditer mon profil (bio, display name)', async ({ page }) => {
|
|
await navigateTo(page, '/settings');
|
|
|
|
const bioField = page.getByLabel(/bio/i).first()
|
|
.or(page.locator('textarea[name*="bio"]').first());
|
|
const nameField = page.getByLabel(/nom.*affichage|display.*name|nom/i).first();
|
|
|
|
const hasBio = await bioField.isVisible().catch(() => false);
|
|
const hasName = await nameField.isVisible().catch(() => false);
|
|
|
|
console.log(` Champ bio: ${hasBio ? '✓' : '✗'}`);
|
|
console.log(` Champ display name: ${hasName ? '✓' : '✗'}`);
|
|
});
|
|
|
|
test('05. L\'historique d\'écoute est privé (pas visible par d\'autres)', async ({ page }) => {
|
|
// Navigate to another user's public profile at /u/:username
|
|
await navigateTo(page, `/u/${CONFIG.users.creator.username}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Listening history must NOT be visible on someone else's public profile
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/historique.*écoute|listening.*history|recently.*played/i);
|
|
});
|
|
|
|
test('06. Profil artiste affiche les stats (tracks, followers)', async ({ page }) => {
|
|
await navigateTo(page, `/u/${CONFIG.users.creator.username}`);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
|
|
// UserProfilePageHeader displays stats: Tracks, Playlists, Followers, Following
|
|
const hasTracksLabel = body.includes('Tracks');
|
|
const hasFollowersLabel = body.includes('Followers');
|
|
|
|
console.log(` Stats Tracks: ${hasTracksLabel ? '✓' : '✗'}`);
|
|
console.log(` Stats Followers: ${hasFollowersLabel ? '✓' : '✗'}`);
|
|
|
|
// Username should be visible (displayed as @username)
|
|
const hasUsername = body.includes(CONFIG.users.creator.username);
|
|
console.log(` Username visible: ${hasUsername ? '✓' : '✗'}`);
|
|
});
|
|
});
|
|
|
|
test.describe('SOCIAL — Social Hub', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password);
|
|
});
|
|
|
|
test('07. Page social se charge @critical', async ({ page }) => {
|
|
await navigateTo(page, '/social');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
expect(body.length).toBeGreaterThan(100);
|
|
|
|
console.log(' Page /social chargée avec succès');
|
|
});
|
|
|
|
test('08. Social sidebar tabs (Fresh Tracks, Explore, Communities)', async ({ page }) => {
|
|
await navigateTo(page, '/social');
|
|
|
|
// SocialViewSidebar has buttons: "Fresh Tracks", "Explore", "Communities"
|
|
const freshTracksBtn = page.getByRole('button', { name: /fresh tracks/i });
|
|
const exploreBtn = page.getByRole('button', { name: /explore/i });
|
|
const communitiesBtn = page.getByRole('button', { name: /communities/i });
|
|
|
|
const hasFreshTracks = await freshTracksBtn.isVisible().catch(() => false);
|
|
const hasExplore = await exploreBtn.isVisible().catch(() => false);
|
|
const hasCommunities = await communitiesBtn.isVisible().catch(() => false);
|
|
|
|
console.log(` Tab Fresh Tracks: ${hasFreshTracks ? '✓' : '✗'}`);
|
|
console.log(` Tab Explore: ${hasExplore ? '✓' : '✗'}`);
|
|
console.log(` Tab Communities: ${hasCommunities ? '✓' : '✗'}`);
|
|
});
|
|
|
|
test('09. Page feed se charge', async ({ page }) => {
|
|
await navigateTo(page, '/feed');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
expect(body.length).toBeGreaterThan(100);
|
|
|
|
console.log(' Page /feed chargée avec succès');
|
|
});
|
|
});
|