test(e2e): e2e_image_outcomes — fixture image host, per-image outcomes + notice band (SD-0002 §6.8)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
.backend.log
|
.backend.log
|
||||||
|
.objectstore/
|
||||||
test-results/
|
test-results/
|
||||||
playwright-report/
|
playwright-report/
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 184 B |
@@ -0,0 +1,4 @@
|
|||||||
|
Handle,Title,Image Src
|
||||||
|
good-lamp,Good Lamp,http://127.0.0.1:8799/good.png
|
||||||
|
tiny-lamp,Tiny Lamp,http://127.0.0.1:8799/tiny.png
|
||||||
|
gone-lamp,Gone Lamp,http://127.0.0.1:8799/missing.png
|
||||||
|
@@ -83,6 +83,16 @@ export async function importGoodCsv(page: Page) {
|
|||||||
await expect(page.getByRole("heading", { level: 1, name: "good.csv" })).toBeVisible();
|
await expect(page.getByRole("heading", { level: 1, name: "good.csv" })).toBeVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Import with-images.csv (3 products, each with one Image Src) and confirm it.
|
||||||
|
// Mirrors importGoodCsv; callers continue from the run-detail screen, where the
|
||||||
|
// background image fetch progresses fetching_images → terminal.
|
||||||
|
export async function importWithImages(page: Page) {
|
||||||
|
await uploadFixture(page, "with-images.csv");
|
||||||
|
await expect(page.getByRole("heading", { name: "Import preview — with-images.csv" })).toBeVisible();
|
||||||
|
await page.getByRole("button", { name: "Import 3 products" }).click();
|
||||||
|
await expect(page.getByRole("heading", { level: 1, name: "with-images.csv" })).toBeVisible();
|
||||||
|
}
|
||||||
|
|
||||||
// Click an Export status option and capture the downloaded CSV's text + path.
|
// Click an Export status option and capture the downloaded CSV's text + path.
|
||||||
export async function exportCatalog(page: Page, label: string): Promise<{ text: string; path: string }> {
|
export async function exportCatalog(page: Page, label: string): Promise<{ text: string; path: string }> {
|
||||||
// Open the <details> menu, then click the status option, capturing the download.
|
// Open the <details> menu, then click the status option, capturing the download.
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { createServer } from "node:http";
|
||||||
|
import { readFile } from "node:fs/promises";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
|
||||||
|
const dir = join(dirname(fileURLToPath(import.meta.url)), "fixtures", "images");
|
||||||
|
createServer(async (req, res) => {
|
||||||
|
const name = (req.url || "").replace(/^\//, "").split("?")[0];
|
||||||
|
if (name === "good.png" || name === "tiny.png") {
|
||||||
|
try {
|
||||||
|
const buf = await readFile(join(dir, name));
|
||||||
|
res.writeHead(200, { "Content-Type": "image/png" });
|
||||||
|
res.end(buf);
|
||||||
|
return;
|
||||||
|
} catch { /* fallthrough */ }
|
||||||
|
}
|
||||||
|
res.writeHead(404);
|
||||||
|
res.end();
|
||||||
|
}).listen(8799, "127.0.0.1");
|
||||||
@@ -18,6 +18,17 @@ PY
|
|||||||
|
|
||||||
export ECOMM_DATABASE_URL="postgresql://ecomm:ecomm@localhost:5432/ecomm_e2e"
|
export ECOMM_DATABASE_URL="postgresql://ecomm:ecomm@localhost:5432/ecomm_e2e"
|
||||||
export ECOMM_MAILER=log
|
export ECOMM_MAILER=log
|
||||||
|
|
||||||
|
# Image pipeline (SLICE-7): local objectstore + a fixture image host on :8799.
|
||||||
|
# ECOMM_IMAGE_FETCH_ALLOW_PRIVATE lets the SSRF guard reach 127.0.0.1 — TEST-ONLY,
|
||||||
|
# never set in the deployed overlay. The &-backgrounded node host is a child of
|
||||||
|
# this serve process; Playwright tears the whole webServer group down between runs.
|
||||||
|
export ECOMM_OBJECTSTORE_KIND=local
|
||||||
|
export ECOMM_OBJECTSTORE_DIR="$repo_root/e2e/.objectstore"
|
||||||
|
export ECOMM_IMAGE_FETCH_ALLOW_PRIVATE=1
|
||||||
|
rm -rf "$repo_root/e2e/.objectstore"
|
||||||
|
node "$repo_root/e2e/image-host.mjs" &
|
||||||
|
|
||||||
cd "$repo_root/backend"
|
cd "$repo_root/backend"
|
||||||
exec "$repo_root/.venv/bin/python" -m uvicorn app.main:app --port 8765 \
|
exec "$repo_root/.venv/bin/python" -m uvicorn app.main:app --port 8765 \
|
||||||
> "$repo_root/e2e/.backend.log" 2>&1
|
> "$repo_root/e2e/.backend.log" 2>&1
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { expect, test } from "@playwright/test";
|
||||||
|
import { gotoProducts, importWithImages, signUpWithStorefront } from "../helpers";
|
||||||
|
|
||||||
|
test("e2e_image_outcomes: per-image outcomes, problem rows, notice band", async ({ page }) => {
|
||||||
|
await signUpWithStorefront(page);
|
||||||
|
await gotoProducts(page);
|
||||||
|
await importWithImages(page);
|
||||||
|
// Run detail polls fetching_images → terminal; wait for the outcome summary.
|
||||||
|
await expect(page.getByText("1 fetched · 1 rejected · 1 failed")).toBeVisible({ timeout: 30_000 });
|
||||||
|
// Problem images listed in the outcomes table.
|
||||||
|
await expect(page.getByText("tiny-lamp")).toBeVisible();
|
||||||
|
await expect(page.getByText("gone-lamp")).toBeVisible();
|
||||||
|
// Products page surfaces the aggregate notice.
|
||||||
|
await gotoProducts(page);
|
||||||
|
await expect(page.getByText(/products have image problems/)).toBeVisible();
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user