p19-bug-fixes
This commit is contained in:
233
e2e/tests/capabilities/responsive/breakpoints.spec.ts
Normal file
233
e2e/tests/capabilities/responsive/breakpoints.spec.ts
Normal file
@@ -0,0 +1,233 @@
|
||||
import { SELECTORS } from "../../fixtures/selectors";
|
||||
import { expect, test } from "../../fixtures/test";
|
||||
import {
|
||||
hasHorizontalOverflow,
|
||||
isClipped,
|
||||
VIEWPORT_SIZES,
|
||||
type ViewportSize,
|
||||
} from "../../fixtures/viewports";
|
||||
|
||||
test.describe("Responsive Breakpoint Tests @smoke", () => {
|
||||
for (const viewport of VIEWPORT_SIZES) {
|
||||
test.describe(`${viewport} viewport`, () => {
|
||||
test.beforeEach(async ({ gotoApp, waitForAppReady, setViewport }) => {
|
||||
await setViewport(viewport);
|
||||
await gotoApp();
|
||||
await waitForAppReady();
|
||||
});
|
||||
|
||||
test("page has no horizontal overflow", async ({ page }) => {
|
||||
// Check body for overflow
|
||||
const bodyOverflow = await hasHorizontalOverflow(page, "body");
|
||||
expect(bodyOverflow).toBe(false);
|
||||
|
||||
// Check main content
|
||||
const mainOverflow = await hasHorizontalOverflow(page, "main");
|
||||
expect(mainOverflow).toBe(false);
|
||||
|
||||
// Check hero section
|
||||
const heroOverflow = await hasHorizontalOverflow(
|
||||
page,
|
||||
SELECTORS.hero.root,
|
||||
);
|
||||
expect(heroOverflow).toBe(false);
|
||||
|
||||
// Check feed section
|
||||
const feedOverflow = await hasHorizontalOverflow(
|
||||
page,
|
||||
SELECTORS.feed.root,
|
||||
);
|
||||
expect(feedOverflow).toBe(false);
|
||||
});
|
||||
|
||||
test("hero section is not clipped", async ({ page, waitForHero }) => {
|
||||
const hero = await waitForHero();
|
||||
const isHeroClipped = await isClipped(page, SELECTORS.hero.root);
|
||||
expect(isHeroClipped).toBe(false);
|
||||
});
|
||||
|
||||
test("feed articles are not clipped", async ({ page, waitForFeed }) => {
|
||||
const feed = await waitForFeed();
|
||||
const isFeedClipped = await isClipped(page, SELECTORS.feed.root);
|
||||
expect(isFeedClipped).toBe(false);
|
||||
});
|
||||
|
||||
test("modal fits within viewport", async ({
|
||||
page,
|
||||
waitForHero,
|
||||
setViewport,
|
||||
}) => {
|
||||
// Open modal
|
||||
const hero = await waitForHero();
|
||||
await hero.locator(SELECTORS.hero.readButton).click();
|
||||
|
||||
const modal = page.locator(SELECTORS.summaryModal.root);
|
||||
await expect(modal).toBeVisible();
|
||||
|
||||
// Get viewport dimensions
|
||||
const viewport = await page.evaluate(() => ({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
}));
|
||||
|
||||
// Get modal dimensions
|
||||
const modalBox = await modal.boundingBox();
|
||||
expect(modalBox).not.toBeNull();
|
||||
|
||||
// Modal should fit within viewport (with some padding)
|
||||
expect(modalBox!.width).toBeLessThanOrEqual(viewport.width);
|
||||
expect(modalBox!.height).toBeLessThanOrEqual(viewport.height * 0.96); // max-h-[96vh]
|
||||
});
|
||||
|
||||
test("interactive controls are reachable", async ({
|
||||
page,
|
||||
waitForFeed,
|
||||
}) => {
|
||||
const feed = await waitForFeed();
|
||||
const firstArticle = feed.locator(SELECTORS.feed.articles).first();
|
||||
|
||||
// Check read button is visible and clickable
|
||||
const readButton = firstArticle.locator(
|
||||
SELECTORS.feed.articleReadButton,
|
||||
);
|
||||
await expect(readButton).toBeVisible();
|
||||
await expect(readButton).toBeEnabled();
|
||||
|
||||
// Check source link is visible if present
|
||||
const sourceLink = firstArticle.locator(SELECTORS.feed.articleSource);
|
||||
const hasSourceLink = (await sourceLink.count()) > 0;
|
||||
if (hasSourceLink) {
|
||||
await expect(sourceLink).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
test("header controls remain accessible", async ({ page }) => {
|
||||
// Check logo is visible
|
||||
const logo = page.locator(SELECTORS.header.logo);
|
||||
await expect(logo).toBeVisible();
|
||||
|
||||
// Check theme button is visible
|
||||
const themeButton = page.locator(SELECTORS.header.themeMenuButton);
|
||||
await expect(themeButton).toBeVisible();
|
||||
await expect(themeButton).toBeEnabled();
|
||||
|
||||
// Check language select is visible (may be hidden on very small screens)
|
||||
const languageSelect = page.locator(SELECTORS.header.languageSelect);
|
||||
const isVisible = await languageSelect.isVisible().catch(() => false);
|
||||
|
||||
if (isVisible) {
|
||||
await expect(languageSelect).toBeEnabled();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test.describe("Responsive Layout Adaptations", () => {
|
||||
test("mobile shows single column feed", async ({
|
||||
gotoApp,
|
||||
waitForAppReady,
|
||||
setViewport,
|
||||
waitForFeed,
|
||||
}) => {
|
||||
await setViewport("mobile");
|
||||
await gotoApp();
|
||||
await waitForAppReady();
|
||||
|
||||
const feed = await waitForFeed();
|
||||
const articles = feed.locator(SELECTORS.feed.articles);
|
||||
|
||||
// Articles should be in single column (full width)
|
||||
const firstArticle = articles.first();
|
||||
const articleBox = await firstArticle.boundingBox();
|
||||
|
||||
// Get feed container width
|
||||
const feedBox = await feed.boundingBox();
|
||||
|
||||
// Article should take most of the width (single column)
|
||||
expect(articleBox!.width).toBeGreaterThan(feedBox!.width * 0.8);
|
||||
});
|
||||
|
||||
test("tablet shows appropriate layout", async ({
|
||||
gotoApp,
|
||||
waitForAppReady,
|
||||
setViewport,
|
||||
waitForFeed,
|
||||
}) => {
|
||||
await setViewport("tablet");
|
||||
await gotoApp();
|
||||
await waitForAppReady();
|
||||
|
||||
const feed = await waitForFeed();
|
||||
const articles = feed.locator(SELECTORS.feed.articles);
|
||||
|
||||
// Should have multiple articles visible
|
||||
const count = await articles.count();
|
||||
expect(count).toBeGreaterThanOrEqual(2);
|
||||
|
||||
// Articles should be side by side (multi-column)
|
||||
const firstArticle = articles.first();
|
||||
const secondArticle = articles.nth(1);
|
||||
|
||||
const firstBox = await firstArticle.boundingBox();
|
||||
const secondBox = await secondArticle.boundingBox();
|
||||
|
||||
// Second article should be to the right of first (or below in some layouts)
|
||||
expect(secondBox!.x).not.toBe(firstBox!.x);
|
||||
});
|
||||
|
||||
test("desktop shows multi-column feed", async ({
|
||||
gotoApp,
|
||||
waitForAppReady,
|
||||
setViewport,
|
||||
waitForFeed,
|
||||
}) => {
|
||||
await setViewport("desktop");
|
||||
await gotoApp();
|
||||
await waitForAppReady();
|
||||
|
||||
const feed = await waitForFeed();
|
||||
const articles = feed.locator(SELECTORS.feed.articles);
|
||||
|
||||
// Should have multiple articles in a row
|
||||
const count = await articles.count();
|
||||
expect(count).toBeGreaterThanOrEqual(3);
|
||||
|
||||
// First three articles should be in a row
|
||||
const articleBoxes = await articles
|
||||
.slice(0, 3)
|
||||
.evaluateAll((els) => els.map((el) => el.getBoundingClientRect()));
|
||||
|
||||
// Articles should be at different x positions (side by side)
|
||||
const xPositions = articleBoxes.map((box) => box.x);
|
||||
const uniqueXPositions = [...new Set(xPositions)];
|
||||
expect(uniqueXPositions.length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
test("hero image maintains aspect ratio", async ({
|
||||
gotoApp,
|
||||
waitForAppReady,
|
||||
setViewport,
|
||||
waitForHero,
|
||||
}) => {
|
||||
for (const viewport of ["mobile", "tablet", "desktop"] as ViewportSize[]) {
|
||||
await setViewport(viewport);
|
||||
await gotoApp();
|
||||
await waitForAppReady();
|
||||
|
||||
const hero = await waitForHero();
|
||||
const image = hero.locator(SELECTORS.hero.image);
|
||||
|
||||
const box = await image.boundingBox();
|
||||
expect(box).not.toBeNull();
|
||||
|
||||
// Image should have reasonable dimensions
|
||||
expect(box!.width).toBeGreaterThan(0);
|
||||
expect(box!.height).toBeGreaterThan(0);
|
||||
|
||||
// Aspect ratio should be roughly maintained (wider than tall)
|
||||
expect(box!.width / box!.height).toBeGreaterThan(1);
|
||||
expect(box!.width / box!.height).toBeLessThan(5);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user