New tests/e2e/ suite covering: - Auth, navigation, player, tracks, playlists - Search, discover, social, marketplace, chat - Accessibility, API, workflows, edge cases - Routes coverage, forms validation, modals - Empty states, responsive, network errors - Error boundary, performance, visual regression - Cross-browser, profile, smoke, upload - Storybook, deep pages, visual bugs - Includes fixtures, helpers, global setup/teardown - Playwright config and coverage map Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
204 lines
7.8 KiB
TypeScript
204 lines
7.8 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { loginViaAPI, CONFIG, navigateTo } from './helpers';
|
|
|
|
test.describe('MARKETPLACE — Navigation', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password);
|
|
});
|
|
|
|
test('01. Page marketplace se charge @critical', async ({ page }) => {
|
|
await navigateTo(page, '/marketplace');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
expect(body.length).toBeGreaterThan(50);
|
|
|
|
// MarketplacePage renders heading "Marketplace"
|
|
const heading = page.locator('h1').filter({ hasText: /marketplace/i });
|
|
const hasHeading = await heading.isVisible().catch(() => false);
|
|
console.log(` Heading Marketplace: ${hasHeading ? '✓' : '✗'}`);
|
|
});
|
|
|
|
test('02. Les produits (beats/samples) s\'affichent', async ({ page }) => {
|
|
await navigateTo(page, '/marketplace');
|
|
|
|
// ProductCard wraps in <article aria-label="Product: ...">
|
|
const products = page.locator('article[aria-label^="Product:"]');
|
|
const count = await products.count();
|
|
console.log(` Produits affichés: ${count}`);
|
|
});
|
|
|
|
test('03. Filtres marketplace fonctionnent', async ({ page }) => {
|
|
await navigateTo(page, '/marketplace');
|
|
|
|
// Search input in the filters bar
|
|
const searchInput = page.getByPlaceholder(/search tracks|search/i).first();
|
|
const hasSearch = await searchInput.isVisible().catch(() => false);
|
|
console.log(` Champ recherche: ${hasSearch ? '✓' : '✗'}`);
|
|
|
|
// Filters button
|
|
const filtersBtn = page.getByRole('button', { name: /filters/i }).first();
|
|
const hasFilters = await filtersBtn.isVisible().catch(() => false);
|
|
console.log(` Bouton Filters: ${hasFilters ? '✓' : '✗'}`);
|
|
|
|
// Cart button
|
|
const cartBtn = page.getByRole('button', { name: /cart/i }).first();
|
|
const hasCart = await cartBtn.isVisible().catch(() => false);
|
|
console.log(` Bouton Cart: ${hasCart ? '✓' : '✗'}`);
|
|
});
|
|
|
|
test('04. Page détail d\'un produit se charge', async ({ page }) => {
|
|
await navigateTo(page, '/marketplace');
|
|
|
|
// ProductCard has "Buy Now" button — check if products exist first
|
|
const products = page.locator('article[aria-label^="Product:"]');
|
|
const count = await products.count();
|
|
|
|
if (count === 0) {
|
|
console.log(' ⚠ Aucun produit disponible');
|
|
return;
|
|
}
|
|
|
|
// Look for a link to product detail page
|
|
const productLink = page.locator('a[href*="/marketplace/products/"]').first();
|
|
if (await productLink.isVisible().catch(() => false)) {
|
|
await productLink.click();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
console.log(' Page détail produit chargée');
|
|
} else {
|
|
// Products exist but no detail links — the cards may use buy directly
|
|
console.log(' ⚠ Pas de liens vers page détail (achat direct sur carte)');
|
|
}
|
|
});
|
|
|
|
test('05. Bouton Buy Now et Add to Cart présents', async ({ page }) => {
|
|
await navigateTo(page, '/marketplace');
|
|
|
|
// ProductCard has "Buy Now" and "Add to Cart" buttons
|
|
const buyBtn = page.getByRole('button', { name: /buy now/i }).first();
|
|
const addToCartBtn = page.getByRole('button', { name: /add to cart/i }).first();
|
|
|
|
// Hover the first product card to reveal the Add to Cart button (it has opacity-0 by default)
|
|
const firstProduct = page.locator('article[aria-label^="Product:"]').first();
|
|
if (await firstProduct.isVisible().catch(() => false)) {
|
|
await firstProduct.hover();
|
|
await page.waitForTimeout(500);
|
|
}
|
|
|
|
const hasBuy = await buyBtn.isVisible().catch(() => false);
|
|
const hasAddToCart = await addToCartBtn.isVisible().catch(() => false);
|
|
|
|
console.log(` Bouton Buy Now: ${hasBuy ? '✓' : '✗'}`);
|
|
console.log(` Bouton Add to Cart: ${hasAddToCart ? '✓' : '✗'}`);
|
|
});
|
|
});
|
|
|
|
test.describe('MARKETPLACE — Dashboard vendeur', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, CONFIG.users.creator.email, CONFIG.users.creator.password);
|
|
});
|
|
|
|
test('06. Dashboard vendeur accessible @critical', async ({ page }) => {
|
|
// Seller dashboard is at /sell
|
|
await navigateTo(page, '/sell');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
expect(body.length).toBeGreaterThan(100);
|
|
|
|
console.log(' Dashboard vendeur chargé à /sell');
|
|
});
|
|
});
|
|
|
|
test.describe('MARKETPLACE — Wishlist', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password);
|
|
});
|
|
|
|
test('07. Page wishlist accessible @critical', async ({ page }) => {
|
|
// Wishlist is at /wishlist
|
|
await navigateTo(page, '/wishlist');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
expect(body.length).toBeGreaterThan(50);
|
|
|
|
console.log(' Page /wishlist chargée');
|
|
});
|
|
});
|
|
|
|
test.describe('MARKETPLACE — Purchases', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password);
|
|
});
|
|
|
|
test('08. Page purchases accessible', async ({ page }) => {
|
|
// Purchases page is at /purchases
|
|
await navigateTo(page, '/purchases');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
expect(body.length).toBeGreaterThan(50);
|
|
|
|
console.log(' Page /purchases chargée');
|
|
});
|
|
});
|
|
|
|
test.describe('MARKETPLACE — Cart (in-page)', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password);
|
|
});
|
|
|
|
test('09. Cart s\'ouvre via le bouton Cart sur marketplace', async ({ page }) => {
|
|
await navigateTo(page, '/marketplace');
|
|
|
|
// MarketplacePage has a Cart button that opens a slide-over Cart component
|
|
const cartBtn = page.getByRole('button', { name: /cart/i }).first();
|
|
if (await cartBtn.isVisible().catch(() => false)) {
|
|
await cartBtn.click();
|
|
await page.waitForTimeout(500);
|
|
|
|
// Cart component should be visible (it's a slide-over panel, not a separate page)
|
|
const body = await page.textContent('body') || '';
|
|
// Cart panel should show something (empty cart message or items)
|
|
console.log(' Cart panel ouvert');
|
|
} else {
|
|
console.log(' ⚠ Bouton Cart non visible');
|
|
}
|
|
});
|
|
|
|
test('10. Ajouter un produit au cart affiche un feedback', async ({ page }) => {
|
|
await navigateTo(page, '/marketplace');
|
|
|
|
const firstProduct = page.locator('article[aria-label^="Product:"]').first();
|
|
if (!(await firstProduct.isVisible().catch(() => false))) {
|
|
console.log(' ⚠ Aucun produit disponible');
|
|
return;
|
|
}
|
|
|
|
// Hover to reveal "Add to Cart" button (hidden by default with opacity-0)
|
|
await firstProduct.hover();
|
|
await page.waitForTimeout(500);
|
|
|
|
const addToCartBtn = firstProduct.getByRole('button', { name: /add to cart/i });
|
|
if (await addToCartBtn.isVisible().catch(() => false)) {
|
|
await addToCartBtn.click();
|
|
await page.waitForTimeout(1_000);
|
|
|
|
// Toast feedback: "{title} added to cart"
|
|
const toast = page.getByTestId('toast-alert').first();
|
|
const hasToast = await toast.isVisible().catch(() => false);
|
|
console.log(` Toast feedback: ${hasToast ? '✓' : '✗'}`);
|
|
|
|
// Cart badge should update
|
|
const cartBadge = page.locator('button').filter({ hasText: /cart/i }).locator('[class*="badge"], [class*="Badge"]').first();
|
|
const hasBadge = await cartBadge.isVisible().catch(() => false);
|
|
console.log(` Cart badge mis à jour: ${hasBadge ? '✓' : '✗'}`);
|
|
} else {
|
|
console.log(' ⚠ Bouton Add to Cart non visible après hover');
|
|
}
|
|
});
|
|
});
|