generated from bisco/codex-bootstrap
test: add functional portal suite
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
test-results/
|
||||
playwright-report/
|
||||
@@ -0,0 +1,13 @@
|
||||
FROM mcr.microsoft.com/playwright:v1.61.1-noble
|
||||
|
||||
WORKDIR /tests
|
||||
RUN chown pwuser:pwuser /tests
|
||||
|
||||
COPY --chown=pwuser:pwuser package.json package-lock.json ./
|
||||
RUN npm ci --no-audit --no-fund
|
||||
|
||||
COPY --chown=pwuser:pwuser . .
|
||||
|
||||
USER pwuser
|
||||
|
||||
CMD ["npm", "test"]
|
||||
Generated
+78
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"name": "azionelab-functional-tests",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "azionelab-functional-tests",
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.61.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.61.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.1.tgz",
|
||||
"integrity": "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright": "1.61.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.61.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz",
|
||||
"integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.61.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.61.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz",
|
||||
"integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "azionelab-functional-tests",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "playwright test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.61.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { defineConfig } from "@playwright/test";
|
||||
|
||||
export default defineConfig({
|
||||
testDir: "./tests",
|
||||
timeout: 30_000,
|
||||
expect: {
|
||||
timeout: 5_000,
|
||||
},
|
||||
fullyParallel: false,
|
||||
forbidOnly: true,
|
||||
retries: 0,
|
||||
workers: 1,
|
||||
reporter: "line",
|
||||
outputDir: "test-results",
|
||||
use: {
|
||||
baseURL: process.env.BASE_URL ?? "http://azionelab.org",
|
||||
browserName: "chromium",
|
||||
screenshot: "only-on-failure",
|
||||
trace: "retain-on-failure",
|
||||
video: "off",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,155 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
const sectionIds = [
|
||||
"inizio",
|
||||
"laboratorio",
|
||||
"maestro",
|
||||
"lezioni",
|
||||
"spettacoli",
|
||||
"galleria",
|
||||
"contatti",
|
||||
];
|
||||
|
||||
test("renders the seeded single page in the required order", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
|
||||
await expect(page).toHaveTitle(/Azione!Lab/);
|
||||
await expect(page.getByRole("heading", { level: 1 })).toHaveText(
|
||||
"Il teatro diventa presenza.",
|
||||
);
|
||||
await expect(page.getByText("Ernesto Estatico")).toBeVisible();
|
||||
await expect(
|
||||
page.getByText("Via dell'Epomeo 9999, Napoli", { exact: true }),
|
||||
).toBeVisible();
|
||||
await expect(page.locator(".feature-card")).toHaveCount(3);
|
||||
await expect(page.locator(".show-card")).toHaveCount(2);
|
||||
await expect(page.locator(".gallery-item")).toHaveCount(4);
|
||||
await expect(
|
||||
page.getByRole("link", { name: "Vieni a conoscerci" }).first(),
|
||||
).toHaveAttribute("href", "#contatti");
|
||||
await expect(page.getByRole("link", { name: "Guarda la galleria" })).toHaveAttribute(
|
||||
"href",
|
||||
"#galleria",
|
||||
);
|
||||
|
||||
const verticalPositions = await page.evaluate(
|
||||
(ids) =>
|
||||
ids.map((id) => {
|
||||
const element = document.getElementById(id);
|
||||
if (!element) throw new Error(`Missing section #${id}`);
|
||||
return element.getBoundingClientRect().top + window.scrollY;
|
||||
}),
|
||||
sectionIds,
|
||||
);
|
||||
|
||||
expect(verticalPositions).toEqual([...verticalPositions].sort((a, b) => a - b));
|
||||
});
|
||||
|
||||
test("exposes usable contact actions", async ({ page }) => {
|
||||
await page.goto("/#contatti");
|
||||
|
||||
await expect(page.getByRole("link", { name: /Scrivi una mail/ })).toHaveAttribute(
|
||||
"href",
|
||||
"mailto:ciao@laboratorioteatrale.it",
|
||||
);
|
||||
await expect(page.getByRole("link", { name: /Chiama/ })).toHaveAttribute(
|
||||
"href",
|
||||
"tel:+393331234567",
|
||||
);
|
||||
await expect(page.getByRole("link", { name: /WhatsApp/ })).toHaveAttribute(
|
||||
"href",
|
||||
"https://wa.me/393331234567",
|
||||
);
|
||||
});
|
||||
|
||||
test("supports mobile navigation without horizontal overflow", async ({ page }) => {
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await page.goto("/");
|
||||
|
||||
const menu = page.locator("details.mobile-menu");
|
||||
await menu.locator("summary").click();
|
||||
await expect(menu).toHaveAttribute("open", "");
|
||||
await menu.getByRole("link", { name: "Le lezioni" }).click();
|
||||
await expect(page).toHaveURL(/#lezioni$/);
|
||||
|
||||
const dimensions = await page.evaluate(() => ({
|
||||
clientWidth: document.documentElement.clientWidth,
|
||||
scrollWidth: document.documentElement.scrollWidth,
|
||||
}));
|
||||
expect(dimensions.scrollWidth).toBeLessThanOrEqual(dimensions.clientWidth + 1);
|
||||
});
|
||||
|
||||
test("provides semantic landmarks, image alternatives and keyboard access", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/");
|
||||
|
||||
await expect(page.getByRole("banner")).toHaveCount(1);
|
||||
await expect(page.getByRole("main")).toHaveCount(1);
|
||||
await expect(page.getByRole("contentinfo")).toHaveCount(1);
|
||||
await expect(page.getByRole("heading", { level: 1 })).toHaveCount(1);
|
||||
|
||||
const imageAlternatives = await page.locator("img").evaluateAll((images) =>
|
||||
images.map((image) => image.getAttribute("alt")?.trim() ?? ""),
|
||||
);
|
||||
expect(imageAlternatives.length).toBeGreaterThan(0);
|
||||
expect(imageAlternatives.every(Boolean)).toBe(true);
|
||||
|
||||
const images = page.locator("img");
|
||||
for (let index = 0; index < await images.count(); index += 1) {
|
||||
const image = images.nth(index);
|
||||
await image.scrollIntoViewIfNeeded();
|
||||
await expect
|
||||
.poll(() => image.evaluate((element) => element.naturalWidth))
|
||||
.toBeGreaterThan(0);
|
||||
}
|
||||
|
||||
await page.keyboard.press("Tab");
|
||||
await expect(page.getByRole("link", { name: "Vai al contenuto" })).toBeFocused();
|
||||
});
|
||||
|
||||
test("returns the aggregate API contract and serves CMS media", async ({ request }) => {
|
||||
const healthResponse = await request.get("/health/");
|
||||
expect(healthResponse.ok()).toBe(true);
|
||||
expect(await healthResponse.json()).toEqual({ status: "ok" });
|
||||
|
||||
const response = await request.get("/api/site/home/");
|
||||
expect(response.ok()).toBe(true);
|
||||
|
||||
const payload = await response.json();
|
||||
expect(Object.keys(payload).sort()).toEqual([
|
||||
"feature_cards",
|
||||
"gallery_items",
|
||||
"homepage",
|
||||
"lesson_info",
|
||||
"settings",
|
||||
"shows",
|
||||
"teacher",
|
||||
]);
|
||||
expect(payload.settings.laboratory_name).toBe("Azione!Lab");
|
||||
expect(payload.feature_cards).toHaveLength(3);
|
||||
expect(payload.shows).toHaveLength(2);
|
||||
expect(payload.gallery_items).toHaveLength(4);
|
||||
|
||||
const mediaPath = new URL(payload.homepage.hero_image.url).pathname;
|
||||
const mediaResponse = await request.get(mediaPath);
|
||||
expect(mediaResponse.ok()).toBe(true);
|
||||
expect(mediaResponse.headers()["content-type"]).toMatch(/^image\//);
|
||||
});
|
||||
|
||||
test("routes Wagtail admin and rejects unknown virtual hosts", async ({
|
||||
page,
|
||||
playwright,
|
||||
}) => {
|
||||
await page.goto("/admin/");
|
||||
await expect(page).toHaveURL(/\/admin\/login\/\?next=\/admin\/$/);
|
||||
await expect(page.locator('input[name="username"]')).toBeVisible();
|
||||
await expect(page.locator('input[name="password"]')).toBeVisible();
|
||||
|
||||
const invalidHostContext = await playwright.request.newContext({
|
||||
baseURL: process.env.INVALID_HOST_URL ?? "http://proxy",
|
||||
});
|
||||
const invalidHostResponse = await invalidHostContext.get("/");
|
||||
expect(invalidHostResponse.status()).toBe(404);
|
||||
await invalidHostContext.dispose();
|
||||
});
|
||||
Reference in New Issue
Block a user