import { test as base, expect, Response } from "@playwright/test"; import { WCV3Product, WCV3Products, } from "../../web/app/themes/haiku-atelier-2024/src/scripts/lib/types/api/v3/products"; import { BackendHeaders, getBackendHeadersFromHtml } from "./utils.ts"; import { pipe } from "effect"; import { not } from "effect/Boolean"; /* * Faire un premier test simple où l'on clic sur la première carte du shop * On doit pouvoir naviguer sur la page * Le produit ne DOIT pas avoir de variations (pour l'instant) * Le bouton d'ajout du panier doit être visible * (Si le produit n'est pas en stock) On ne doit pas pouvoir ajouter le produit au panier * Le bouton doit afficher le texte "Out of stock" * Le bouton doit être désactivé */ type ProductsFixture = { products: ProductsKinds; }; type ProductsKinds = { allProducts: WCV3Products; simpleProducts: WCV3Products; simpleProductsWithStock: WCV3Products; simpleProductsWithoutStock: WCV3Products; }; export const test = base.extend({ products: async ({ page, request }, use) => { await page.goto("/shop"); const backendHeaders: BackendHeaders = await getBackendHeadersFromHtml(page); const response = await request.get("/wp-json/wc/v3/products?page=1&per_page=100&status=publish", { headers: { Nonce: backendHeaders.nonce, Authorization: `Basic ${backendHeaders.authString}` }, }); expect(response.ok(), "The API returned the list of every Product").toBeTruthy(); const isSimpleProduct = (product: WCV3Product) => product.type === "simple"; const hasStock = (product: WCV3Product) => (product.stock_quantity ?? 0) > 0; const hasNoStock = (product: WCV3Product) => pipe(hasStock(product), not); const allProducts = await response.json() as WCV3Products; const simpleProducts = allProducts.filter(isSimpleProduct); const simpleProductsWithStock = simpleProducts.filter(hasStock); const simpleProductsWithoutStock = simpleProducts.filter(hasNoStock); const kinds = { allProducts, simpleProducts, simpleProductsWithStock, simpleProductsWithoutStock, } satisfies ProductsKinds; await use(kinds); }, }); test("can add a Product without variation with stock to the Cart", async ({ products, page }) => { // Prend un produit au hasard. const randomProductIndex = getRandomIntInclusive(0, products.simpleProductsWithStock.length - 1); const randomProduct = products.simpleProductsWithStock.at(randomProductIndex); expect(randomProduct, "The selected random Product must exist").toBeTruthy(); if (randomProduct === undefined) { throw new Error("The random product can't be undefined"); } // Va à la page du Produit. await page.goto(randomProduct.permalink); // Vérifie le bon état du bouton de l'ajout au Panier. const addToCartButton = page.getByRole("button", { name: "Add to cart", disabled: false }); await addToCartButton.scrollIntoViewIfNeeded(); await expect(addToCartButton, "The add to cart button must be visible").toBeVisible(); await expect(addToCartButton, "The add to cart button must be enabled").toBeEnabled(); // Vérifie qu'au clic sur le bouton, l'ajout au Panier retourne un succès. const addToCartResponse: Promise = page.waitForResponse( new RegExp(".*/wp-json/wc/store/cart/add-item"), ); await addToCartButton.click(); const addToCartStatus = (await addToCartResponse).ok(); expect(addToCartStatus, "The cart addition must succeed").toBeTruthy(); // Vérifie que le bouton ait changé de texte. const addedToCartButton = page.getByRole("button", { name: "Added to cart!" }); expect(addedToCartButton, "The add to cart button's text has changed").toBeDefined(); // Vérifie que le compteur d'articles dans le Panier soit incrémenté. const cartLink = page.getByRole("link", { name: "cart (1)" }); expect(cartLink, "The cart items' indicator has been incremented").toBeDefined(); }); test("can't add a Product without variation without stock to the Cart", async ({ products, page }) => { // Prend un produit au hasard. const randomProductIndex = getRandomIntInclusive(0, products.simpleProductsWithoutStock.length - 1); const randomProduct = products.simpleProductsWithoutStock.at(randomProductIndex); expect(randomProduct, "The selected random Product must exist").toBeTruthy(); if (randomProduct === undefined) { throw new Error("The random product can't be undefined"); } // Va à la page du Produit. await page.goto(randomProduct.permalink); // Vérifie le bon état du bouton de l'ajout au Panier. const outOfStockButton = page.getByRole("button", { name: "Out of stock", disabled: true }); await outOfStockButton.scrollIntoViewIfNeeded(); await expect(outOfStockButton, "The add to cart button must be visible").toBeVisible(); await expect(outOfStockButton, "The add to cart button must be disabled").toBeDisabled(); }); const getRandomIntInclusive = (min: number, max: number): number => { const minCeiled = Math.ceil(min); const maxFloored = Math.floor(max); return Math.floor(Math.random() * (maxFloored - minCeiled + 1) + minCeiled); };