veza/tests/e2e/07-social.spec.ts
senke 85cd17f342 fix(e2e): add login token cache + fix selectors for real bug detection
- Cache login tokens in loginViaAPI() to avoid rate limit / account
  lockout (429/423) when running 100+ tests sequentially
- Add ACCOUNT_LOCKOUT_EXEMPT_EMAILS to playwright webServer config
- Fix French-only regexes: add English alternatives (follow/back/etc.)
- Fix Settings heading: "System Config" → include "Settings" alternative
- Fix upload button selector: include "new/nouveau" alternative
- Fix genre heading: include "by genre/genres" alternatives
- Fix drag handle selector: include cursor-grab class

Result: 57 passed, 36 failed (real bugs), 7 skipped

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 15:41:48 +02:00

117 lines
4.5 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 }) => {
await navigateTo(page, `/u/${CONFIG.users.creator.username}`);
await page.waitForLoadState('networkidle');
const followBtn = page.getByRole('button', { name: /suivre|abonné|abonnement|follow|following|unfollow/i }).first();
await expect(followBtn).toBeVisible();
});
test('02. Follow toggle fonctionne', async ({ page }) => {
await navigateTo(page, '/u/marcus_beats');
await page.waitForLoadState('networkidle');
const followBtn = page.getByRole('button', { name: /suivre|abonné|abonnement|désabonnement|follow|following|unfollow/i }).first();
await expect(followBtn).toBeVisible();
const initialText = await followBtn.textContent();
await followBtn.click();
await page.waitForTimeout(1_500);
const newText = await followBtn.textContent();
expect(newText?.trim()).not.toBe(initialText?.trim());
});
});
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/);
expect(body).toContain(CONFIG.users.listener.username);
const avatar = page.locator('[class*="avatar"], img[alt*="avatar"], img[alt*="profil"]').first();
await expect(avatar).toBeVisible();
});
test('04. Éditer mon profil (bio, display name)', async ({ page }) => {
// Profile edit fields may be on /settings or /profile/edit
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|first.*name|last.*name|nom/i).first();
// If not on /settings, try /profile/edit
const bioVisible = await bioField.isVisible().catch(() => false);
if (!bioVisible) {
await navigateTo(page, '/profile/edit');
}
await expect(page.getByLabel(/bio/i).first()
.or(page.locator('textarea[name*="bio"]').first())).toBeVisible();
});
test('05. L\'historique d\'écoute est privé (pas visible par d\'autres)', async ({ page }) => {
await navigateTo(page, `/u/${CONFIG.users.creator.username}`);
await page.waitForLoadState('networkidle');
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') || '';
expect(body).toContain('Tracks');
expect(body).toContain('Followers');
expect(body).toContain(CONFIG.users.creator.username);
});
});
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);
});
test('08. Social sidebar tabs (Fresh Tracks, Explore, Communities)', async ({ page }) => {
await navigateTo(page, '/social');
await expect(page.getByRole('button', { name: /fresh tracks/i })
.or(page.getByText(/fresh tracks/i))).toBeVisible();
await expect(page.getByRole('button', { name: /explore/i })
.or(page.getByText(/explore/i).first())).toBeVisible();
await expect(page.getByRole('button', { name: /communities/i })
.or(page.getByText(/communities/i))).toBeVisible();
});
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);
});
});