import { test, expect } from '@chromatic-com/playwright'; import { loginViaAPI, CONFIG, navigateTo } from './helpers'; /** * MARKETPLACE & CHECKOUT — Tests du flux d'achat * Sélecteurs basés sur MarketplacePage.tsx, ProductCard.tsx, Cart.tsx, CartStore.ts */ test.describe('MARKETPLACE & CHECKOUT @critical', () => { test.beforeEach(async ({ page }) => { await loginViaAPI(page, CONFIG.users.listener.email, CONFIG.users.listener.password); // Clear cart before each test await page.evaluate(() => { localStorage.removeItem('veza-cart-storage'); }); }); test('Marketplace — produits affichés avec prix et boutons @critical', async ({ page }) => { await navigateTo(page, '/marketplace'); // Wait for products grid to load const productCard = page.locator('[aria-label^="Product:"]').first() .or(page.locator('[class*="CardFooter"]').first()); const hasProducts = await productCard.isVisible({ timeout: 10_000 }).catch(() => false); if (hasProducts) { // Verify price is visible const price = page.locator('text=/\\$|€|USD/').first(); await expect(price).toBeVisible({ timeout: 3000 }); // Verify Buy button exists const buyBtn = page.getByRole('button', { name: /buy|acheter/i }).first(); await expect(buyBtn).toBeVisible({ timeout: 3000 }); } else { // Empty marketplace is valid — just check the page loaded without crash const body = await page.textContent('body') || ''; expect(body).not.toMatch(/500|Internal Server Error/); expect(body.length).toBeGreaterThan(50); } }); test('Recherche marketplace — filtrer les produits', async ({ page }) => { await navigateTo(page, '/marketplace'); const searchInput = page.locator('input[placeholder*="Search" i]').first() .or(page.locator('input[placeholder*="Recherch" i]').first()); const hasSearch = await searchInput.isVisible({ timeout: 5000 }).catch(() => false); if (!hasSearch) { test.skip(true, 'Search input not available on marketplace'); return; } await searchInput.fill('beat'); await page.waitForTimeout(1000); // Results should update (either products or empty state) const body = await page.textContent('body'); expect(body!.length).toBeGreaterThan(50); }); test('Ajout au panier → badge panier incrémente @critical', async ({ page }) => { await navigateTo(page, '/marketplace'); // Find a product card const productCard = page.locator('[aria-label^="Product:"]').first(); const hasProduct = await productCard.isVisible({ timeout: 10_000 }).catch(() => false); if (!hasProduct) { test.skip(true, 'No products available in marketplace'); return; } // Hover to reveal Add to Cart await productCard.hover(); await page.waitForTimeout(300); const addToCartBtn = productCard.getByRole('button', { name: /add to cart|ajouter/i }).first() .or(productCard.locator('button[class*="outline"]').first()); const hasAddBtn = await addToCartBtn.isVisible({ timeout: 3000 }).catch(() => false); if (!hasAddBtn) { test.skip(true, 'Add to cart button not available'); return; } await addToCartBtn.click(); await page.waitForTimeout(500); // Check cart badge updated const cartBadge = page.locator('text=/^1$|^[1-9]$/').first(); await expect(cartBadge).toBeVisible({ timeout: 3000 }); }); test('Ouvrir le panier — affiche les produits ajoutés @critical', async ({ page }) => { await navigateTo(page, '/marketplace'); // Add a product to cart first const productCard = page.locator('[aria-label^="Product:"]').first(); const hasProduct = await productCard.isVisible({ timeout: 10_000 }).catch(() => false); if (!hasProduct) { test.skip(true, 'No products available in marketplace'); return; } await productCard.hover(); await page.waitForTimeout(300); const addBtn = productCard.getByRole('button', { name: /add to cart|ajouter/i }).first() .or(productCard.locator('button[class*="outline"]').first()); const hasAddBtn = await addBtn.isVisible({ timeout: 3000 }).catch(() => false); if (!hasAddBtn) { test.skip(true, 'Add to cart button not available'); return; } await addBtn.click(); await page.waitForTimeout(500); // Open cart const cartBtn = page.getByRole('button', { name: /cart|panier/i }).first() .or(page.locator('button').filter({ has: page.locator('[class*="ShoppingCart"]') }).first()); const hasCartBtn = await cartBtn.isVisible({ timeout: 5000 }).catch(() => false); if (!hasCartBtn) { test.skip(true, 'Cart button not visible'); return; } await cartBtn.click(); await page.waitForTimeout(500); // Cart dialog should open const cartDialog = page.locator('[role="dialog"]').first(); await expect(cartDialog).toBeVisible({ timeout: 3000 }); // Should show cart title const cartTitle = cartDialog.locator('text=/shopping cart|panier/i').first(); await expect(cartTitle).toBeVisible({ timeout: 3000 }); }); test('Panier — supprimer un produit @critical', async ({ page }) => { await navigateTo(page, '/marketplace'); // Add product then open cart const productCard = page.locator('[aria-label^="Product:"]').first(); const hasProduct = await productCard.isVisible({ timeout: 10_000 }).catch(() => false); if (!hasProduct) { test.skip(true, 'No products available in marketplace'); return; } await productCard.hover(); const addBtn = productCard.getByRole('button', { name: /add to cart|ajouter/i }).first() .or(productCard.locator('button[class*="outline"]').first()); const hasAddBtn = await addBtn.isVisible({ timeout: 3000 }).catch(() => false); if (!hasAddBtn) { test.skip(true, 'Add to cart button not available'); return; } await addBtn.click(); await page.waitForTimeout(500); const cartBtn = page.getByRole('button', { name: /cart|panier/i }).first(); const hasCartBtn = await cartBtn.isVisible({ timeout: 3000 }).catch(() => false); if (!hasCartBtn) { test.skip(true, 'Cart button not visible'); return; } await cartBtn.click(); await page.waitForTimeout(500); const removeBtn = page.locator('[aria-label="Remove item"]').first(); const hasRemoveBtn = await removeBtn.isVisible({ timeout: 3000 }).catch(() => false); if (!hasRemoveBtn) { test.skip(true, 'Remove item button not visible in cart'); return; } await removeBtn.click(); await page.waitForTimeout(500); // Cart should now show empty const emptyCart = page.locator('text=/cart is empty|panier est vide/i').first(); await expect(emptyCart).toBeVisible({ timeout: 3000 }); }); test('Panier vide — message et CTA vers marketplace', async ({ page }) => { await navigateTo(page, '/marketplace'); // Open cart without adding anything const cartBtn = page.getByRole('button', { name: /cart|panier/i }).first(); const hasCartBtn = await cartBtn.isVisible({ timeout: 5000 }).catch(() => false); if (!hasCartBtn) { test.skip(true, 'Cart button not visible'); return; } await cartBtn.click(); await page.waitForTimeout(500); const emptyMsg = page.locator('text=/cart is empty|panier est vide/i').first(); await expect(emptyMsg).toBeVisible({ timeout: 3000 }); }); test('Checkout — le formulaire de paiement se charge @critical', async ({ page }) => { await navigateTo(page, '/marketplace'); // Add product and go to checkout const productCard = page.locator('[aria-label^="Product:"]').first(); const hasProduct = await productCard.isVisible({ timeout: 10_000 }).catch(() => false); if (!hasProduct) { test.skip(true, 'No products available in marketplace'); return; } await productCard.hover(); const addBtn = productCard.getByRole('button', { name: /add to cart|ajouter/i }).first() .or(productCard.locator('button[class*="outline"]').first()); const hasAddBtn = await addBtn.isVisible({ timeout: 3000 }).catch(() => false); if (!hasAddBtn) { test.skip(true, 'Add to cart button not available'); return; } await addBtn.click(); await page.waitForTimeout(500); const cartBtn = page.getByRole('button', { name: /cart|panier/i }).first(); const hasCartBtn = await cartBtn.isVisible({ timeout: 3000 }).catch(() => false); if (!hasCartBtn) { test.skip(true, 'Cart button not visible'); return; } await cartBtn.click(); await page.waitForTimeout(500); // Look for checkout/pay button const checkoutBtn = page.getByRole('button', { name: /checkout|payer|pay/i }).first(); const hasCheckout = await checkoutBtn.isVisible({ timeout: 3000 }).catch(() => false); if (!hasCheckout) { test.skip(true, 'Checkout button not visible in cart'); return; } await checkoutBtn.click(); await page.waitForTimeout(2000); // Verify payment form loads (Hyperswitch iframe or payment form) const paymentForm = page.locator('iframe').first() .or(page.locator('text=/complete payment|paiement/i').first()); await expect(paymentForm).toBeVisible({ timeout: 5000 }); }); });