증거물 A-1 근거: 커밋 c4c8ced
커밋 시각 · c4c8cedbe2276d3e1160a4379f9cfc092c518e1e
휴대폰에서 예약 버튼이 화면 밖에 있었습니다
저장소 자체는 비공개입니다. 이 페이지에 커밋을 기록된 그대로 옮겼습니다.
커밋 메시지
헤더를 유동 폭으로 되돌려 390px 휴대폰에 예약 버튼이 들어오게 함
변경 내용
git에 기록된 텍스트 파일만 보여 줍니다. +로 시작하는 줄은 추가, −로 시작하는 줄은 삭제입니다.
바뀐 파일
---
e2e/tests/a1-mobile-layout.spec.ts | 43 +++++++++++++++++++++++++++++++++++++++++++
site/wp-content/themes/hollis-child/style.css | 20 --------------------
2 files changed, 43 insertions(+), 20 deletions(-)
diff --git a/e2e/tests/a1-mobile-layout.spec.ts b/e2e/tests/a1-mobile-layout.spec.ts
new file mode 100644
index 0000000..e2ad17d
--- /dev/null
+++ b/e2e/tests/a1-mobile-layout.spec.ts
@@ -0,0 +1,43 @@
+import { test, expect } from '@playwright/test';
+import { BEFORE, AFTER } from './helpers';
+
+// Exhibit A-1. On a 390px phone the BEFORE page scrolls sideways and the booking button sits off screen;
+// the AFTER page fits the screen, the button is in view and the menu opens behind its toggle.
+test.use({ viewport: { width: 390, height: 844 }, isMobile: true, hasTouch: true });
+
+async function layout(page: import('@playwright/test').Page) {
+ const cta = page.locator('.site-header .header-cta');
+ const box = await cta.boundingBox();
+ const width = await page.evaluate(() => document.documentElement.scrollWidth);
+ return { width, box };
+}
+
+test('A-1 before: the page is wider than the phone and the booking button is off screen', async ({ page }) => {
+ await page.goto(BEFORE + '/');
+ const { width, box } = await layout(page);
+ expect(width).toBeGreaterThan(390);
+ expect(box).not.toBeNull();
+ expect(box!.x + box!.width).toBeGreaterThan(390);
+});
+
+test('A-1 after: the page fits 390px, the booking button is in view and leads to the form', async ({ page }) => {
+ await page.goto(AFTER + '/');
+ const { width, box } = await layout(page);
+ expect(width).toBeLessThanOrEqual(390);
+ expect(box!.x).toBeGreaterThanOrEqual(0);
+ expect(box!.x + box!.width).toBeLessThanOrEqual(390);
+ await page.locator('.site-header .header-cta').click();
+ await expect(page.getByRole('heading', { level: 1, name: 'Request an appointment' })).toBeVisible();
+});
+
+test('A-1 after: the menu opens from its toggle and reaches the team page', async ({ page }) => {
+ await page.goto(AFTER + '/');
+ const toggle = page.getByRole('button', { name: 'Menu' });
+ await expect(toggle).toBeVisible();
+ await expect(page.getByRole('navigation', { name: 'Primary' }).getByRole('link', { name: 'Our team' })).toBeHidden();
+ await toggle.click();
+ await expect(toggle).toHaveAttribute('aria-expanded', 'true');
+ await page.getByRole('navigation', { name: 'Primary' }).getByRole('link', { name: 'Our team' }).click();
+ await expect(page.getByRole('heading', { level: 3, name: 'Grace Han' })).toBeVisible();
+ expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(390);
+});
diff --git a/site/wp-content/themes/hollis-child/style.css b/site/wp-content/themes/hollis-child/style.css
index 817d48d..b4fe857 100644
--- a/site/wp-content/themes/hollis-child/style.css
+++ b/site/wp-content/themes/hollis-child/style.css
@@ -10,26 +10,6 @@ Text Domain: hollis-child
@import url("../clinicpress/style.css");
-/* 2019: the header was widened to fit the new menu and the booking button on one line. */
-.site-header .header-inner {
- width: 1180px;
- max-width: none;
- flex-wrap: nowrap;
-}
-
-.main-nav ul {
- flex-wrap: nowrap;
- white-space: nowrap;
-}
-
-.main-nav.is-collapsible {
- display: block !important;
-}
-
-.menu-toggle {
- display: none !important;
-}
-
.main-nav a {
color: #8aa7a2;
font-weight: 400;
증명 테스트
e2e/tests/a1-mobile-layout.spec.ts
e2e/tests/a1-mobile-layout.spec.ts, 커밋된 그대로.
import { test, expect } from '@playwright/test';
import { BEFORE, AFTER } from './helpers';
// Exhibit A-1. On a 390px phone the BEFORE page scrolls sideways and the booking button sits off screen;
// the AFTER page fits the screen, the button is in view and the menu opens behind its toggle.
test.use({ viewport: { width: 390, height: 844 }, isMobile: true, hasTouch: true });
async function layout(page: import('@playwright/test').Page) {
const cta = page.locator('.site-header .header-cta');
const box = await cta.boundingBox();
const width = await page.evaluate(() => document.documentElement.scrollWidth);
return { width, box };
}
test('A-1 before: the page is wider than the phone and the booking button is off screen', async ({ page }) => {
await page.goto(BEFORE + '/');
const { width, box } = await layout(page);
expect(width).toBeGreaterThan(390);
expect(box).not.toBeNull();
expect(box!.x + box!.width).toBeGreaterThan(390);
});
test('A-1 after: the page fits 390px, the booking button is in view and leads to the form', async ({ page }) => {
await page.goto(AFTER + '/');
const { width, box } = await layout(page);
expect(width).toBeLessThanOrEqual(390);
expect(box!.x).toBeGreaterThanOrEqual(0);
expect(box!.x + box!.width).toBeLessThanOrEqual(390);
await page.locator('.site-header .header-cta').click();
await expect(page.getByRole('heading', { level: 1, name: 'Request an appointment' })).toBeVisible();
});
test('A-1 after: the menu opens from its toggle and reaches the team page', async ({ page }) => {
await page.goto(AFTER + '/');
const toggle = page.getByRole('button', { name: 'Menu' });
await expect(toggle).toBeVisible();
await expect(page.getByRole('navigation', { name: 'Primary' }).getByRole('link', { name: 'Our team' })).toBeHidden();
await toggle.click();
await expect(toggle).toHaveAttribute('aria-expanded', 'true');
await page.getByRole('navigation', { name: 'Primary' }).getByRole('link', { name: 'Our team' }).click();
await expect(page.getByRole('heading', { level: 3, name: 'Grace Han' })).toBeVisible();
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(390);
});
test('A-1 after: the header does not shift when the page finishes loading (CLS)', async ({ page }) => {
await page.addInitScript(() => {
(window as any).__cls = 0;
new PerformanceObserver((list) => {
for (const e of list.getEntries() as any[]) if (!e.hadRecentInput) (window as any).__cls += e.value;
}).observe({ type: 'layout-shift', buffered: true });
});
await page.goto(AFTER + '/', { waitUntil: 'networkidle' });
await page.waitForTimeout(500);
expect(await page.evaluate(() => (window as any).__cls)).toBeLessThan(0.01);
});