120 lines
5.1 KiB
TypeScript
120 lines
5.1 KiB
TypeScript
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<ProductsFixture>({
|
|
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<Response> = 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);
|
|
};
|