The cart toast was matching 3 elements (react-hot-toast renders both a wrapper and a role="status" div). Narrowed to the role="status" element with aria-live attribute. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
165 lines
6.3 KiB
TypeScript
165 lines
6.3 KiB
TypeScript
import { test, expect } from '@chromatic-com/playwright';
|
|
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);
|
|
|
|
const heading = page.locator('h1').filter({ hasText: /marketplace/i });
|
|
await expect(heading).toBeVisible({ timeout: 10_000 });
|
|
});
|
|
|
|
test('02. Les produits (beats/samples) s\'affichent', async ({ page }) => {
|
|
await navigateTo(page, '/marketplace');
|
|
|
|
const products = page.locator('article[aria-label^="Product:"]');
|
|
expect(await products.count()).toBeGreaterThan(0);
|
|
});
|
|
|
|
test('03. Filtres marketplace fonctionnent', async ({ page }) => {
|
|
await navigateTo(page, '/marketplace');
|
|
|
|
const searchInput = page.getByPlaceholder(/search tracks|search/i).first();
|
|
await expect(searchInput).toBeVisible();
|
|
|
|
const filtersBtn = page.getByRole('button', { name: /filters/i }).first();
|
|
await expect(filtersBtn).toBeVisible();
|
|
|
|
const cartBtn = page.getByRole('button', { name: /cart/i }).first();
|
|
await expect(cartBtn).toBeVisible();
|
|
});
|
|
|
|
test('04. Page détail d\'un produit se charge', async ({ page }) => {
|
|
await navigateTo(page, '/marketplace');
|
|
|
|
const products = page.locator('article[aria-label^="Product:"]');
|
|
const count = await products.count();
|
|
test.skip(count === 0, 'No products available in marketplace');
|
|
|
|
// The detail route /marketplace/products/:id exists in router, but ProductCard
|
|
// does NOT currently expose a link to it — navigate directly to test the route.
|
|
// Try to extract a product id from an existing link, else navigate to a seeded route.
|
|
const productLink = page.locator('a[href*="/marketplace/products/"]').first();
|
|
const hasLink = await productLink.isVisible({ timeout: 2_000 }).catch(() => false);
|
|
|
|
if (hasLink) {
|
|
await productLink.click();
|
|
} else {
|
|
// Known UX gap: ProductCard has no link to detail. Navigate via API to find an ID.
|
|
const productId = await page.evaluate(async () => {
|
|
const r = await fetch('/api/v1/marketplace/products?page=1&limit=1');
|
|
const d = await r.json();
|
|
return d?.data?.[0]?.id ?? d?.data?.products?.[0]?.id ?? null;
|
|
});
|
|
test.skip(!productId, 'No product ID available to navigate to detail page');
|
|
await page.goto(`/marketplace/products/${productId}`);
|
|
}
|
|
await page.waitForLoadState('networkidle').catch(() => {});
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
});
|
|
|
|
test('05. Bouton Buy Now et Add to Cart présents', async ({ page }) => {
|
|
await navigateTo(page, '/marketplace');
|
|
|
|
const firstProduct = page.locator('article[aria-label^="Product:"]').first();
|
|
await expect(firstProduct).toBeVisible();
|
|
await firstProduct.hover();
|
|
await page.waitForTimeout(500);
|
|
|
|
const buyBtn = page.getByRole('button', { name: /buy now/i }).first();
|
|
const addToCartBtn = page.getByRole('button', { name: /add to cart/i }).first();
|
|
|
|
await expect(buyBtn).toBeVisible();
|
|
await expect(addToCartBtn).toBeVisible();
|
|
});
|
|
});
|
|
|
|
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 }) => {
|
|
await navigateTo(page, '/sell');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
expect(body.length).toBeGreaterThan(100);
|
|
});
|
|
});
|
|
|
|
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 }) => {
|
|
await navigateTo(page, '/wishlist');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
expect(body.length).toBeGreaterThan(50);
|
|
});
|
|
});
|
|
|
|
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 }) => {
|
|
await navigateTo(page, '/purchases');
|
|
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).not.toMatch(/500|Internal Server Error/);
|
|
expect(body.length).toBeGreaterThan(50);
|
|
});
|
|
});
|
|
|
|
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');
|
|
|
|
const cartBtn = page.getByRole('button', { name: /cart/i }).first();
|
|
await expect(cartBtn).toBeVisible();
|
|
await cartBtn.click();
|
|
await page.waitForTimeout(500);
|
|
|
|
// Cart panel should show something (empty cart message or items)
|
|
const body = await page.textContent('body') || '';
|
|
expect(body).toMatch(/cart|panier|empty|vide|item/i);
|
|
});
|
|
|
|
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();
|
|
test.skip(!(await firstProduct.isVisible().catch(() => false)), 'No products available');
|
|
|
|
await firstProduct.hover();
|
|
await page.waitForTimeout(500);
|
|
|
|
const addToCartBtn = firstProduct.getByRole('button', { name: /add to cart/i });
|
|
await expect(addToCartBtn).toBeVisible();
|
|
await addToCartBtn.click();
|
|
await page.waitForTimeout(1_000);
|
|
|
|
// react-hot-toast renders with role="status" aria-live="polite" + text "added to cart"
|
|
const toast = page.locator('[role="status"][aria-live]').filter({ hasText: /added to cart/i }).first();
|
|
await expect(toast).toBeVisible();
|
|
});
|
|
});
|