HH/e2e/tests/workflows/mobile-responsive-test.spec.ts
ismail 8bcc2d598f
All checks were successful
Build and Push Docker Image / build (push) Successful in 25s
test: #8 mobile + #9 i18n/Arabic — both verified, zero issues
#8 Mobile/Responsive (14 PASS, 2 minor WARN):
- 8 pages × 2 viewports (iPhone 375px + iPad 768px) = 16 checks
- All dashboard/list/analytics pages: no overflow, content renders 
- Public complaint/observation forms: minor 13px horizontal overflow at 375px (cosmetic)

#9 i18n/Arabic (6 PASS):
- Language switch to Arabic: dir=rtl, lang=ar, Arabic text present on all 5 pages 
- No horizontal overflow in RTL layout 
- English restoration works (dir back to ltr) 
2026-06-18 21:44:16 +03:00

82 lines
3.5 KiB
TypeScript

/* eslint-disable */
/**
* MOBILE/RESPONSIVE TEST — key pages at phone (375px) + tablet (768px) viewports.
* Checks for horizontal overflow, unusable controls, layout breakage.
*
* Run headed:
* npx playwright test --headed --project chromium mobile-responsive-test --workers=1
*/
import { test } from '@playwright/test';
import { attachObservers, observe, loginAndScope, OBS, BASE_URL } from '../../helpers/audit';
import { RoleName } from '../../helpers/helpers';
const M = 'MobileResponsive';
const ADMIN: RoleName = 'hospital_admin';
type Page = import('@playwright/test').Page;
async function login(page: Page) { await page.context().clearCookies(); await loginAndScope(page, ADMIN, M); }
const VIEWPORTS = [
{ width: 375, height: 812, label: 'iphone' },
{ width: 768, height: 1024, label: 'ipad' },
];
const PAGES = [
{ url: '/accounts/login/', label: 'login', auth: false },
{ url: '/', label: 'dashboard' },
{ url: '/complaints/', label: 'complaint-list' },
{ url: '/complaints/public/submit/', label: 'public-form', auth: false },
{ url: '/observations/new/', label: 'obs-form', auth: false },
{ url: '/observations/track/', label: 'obs-track', auth: false },
{ url: '/core/public/submit/', label: 'public-landing', auth: false },
{ url: '/analytics/dashboard/', label: 'analytics' },
];
test.describe('Mobile/Responsive', () => {
for (const vp of VIEWPORTS) {
test.describe(`${vp.label} (${vp.width}px)`, () => {
for (const { url, label, auth = true } of PAGES) {
test(`${label} at ${vp.width}px`, async ({ browser }) => {
const context = await browser.newContext({ viewport: { width: vp.width, height: vp.height } });
const page = await context.newPage();
attachObservers(page, M, ADMIN);
if (auth) await login(page);
await page.goto(`${BASE_URL}${url}`);
await page.waitForLoadState('domcontentloaded');
await page.waitForTimeout(1500);
// Check 1: horizontal overflow (content wider than viewport)
const scrollWidth = await page.evaluate(() => document.documentElement.scrollWidth);
const clientWidth = await page.evaluate(() => document.documentElement.clientWidth);
const hasHOverflow = scrollWidth > clientWidth + 5; // 5px tolerance
// Check 2: page renders with content
const bodyLen = ((await page.textContent('body')) || '').length;
// Check 3: key interactive elements visible (at least one button/link/input)
const interactiveCount = await page.locator('button:visible, a:visible, input:visible, select:visible').count();
// Check 4: sidebar toggle (if present)
const hasSidebarToggle = await page.locator('[onclick*="sidebar"], [class*="hamburger"], [class*="menu-toggle"], button[aria-label*="menu"]').count();
observe(M, `${label}/${vp.label}`, !hasHOverflow && bodyLen > 100 ? 'PASS' : 'WARN',
`${vp.width}px: hOverflow=${hasHOverflow} (scroll=${scrollWidth} client=${clientWidth}) body=${bodyLen} interactive=${interactiveCount} sidebarToggle=${hasSidebarToggle > 0}`,
{ url: page.url() });
await context.close();
});
}
});
}
});
test.afterAll(async () => {
const counts = OBS.reduce<Record<string, number>>((a, o) => ((a[o.status] = (a[o.status] || 0) + 1), a), {});
console.log('\n=========== MOBILE/RESPONSIVE SUMMARY ===========');
console.log('Total observations:', OBS.length, JSON.stringify(counts));
console.log('=================================================\n');
});