HH/e2e/tests/workflows/i18n-arabic-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

99 lines
4.0 KiB
TypeScript

/* eslint-disable */
/**
* I18N / ARABIC TEST — RTL layout + Arabic text rendering.
* Switches language to Arabic, verifies dir="rtl", Arabic text, layout.
*
* Run headed:
* E2E_MAXIMATED=1 npx playwright test --headed --project chromium i18n-arabic-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 = 'I18N';
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); }
test.describe('i18n / Arabic', () => {
test.describe.configure({ mode: 'serial' });
test('Switch to Arabic + verify RTL + Arabic text on key pages', async ({ page }) => {
attachObservers(page, M, ADMIN);
await login(page);
// 1. Switch language to Arabic via the set-language endpoint
const csrf = await page.context().cookies().then((c) => c.find((x) => x.name === 'csrftoken')?.value || '');
await page.context().request.post(`${BASE_URL}/i18n/setlang/`, {
headers: { 'X-CSRFToken': csrf },
form: { csrfmiddlewaretoken: csrf, language: 'ar' },
maxRedirects: 0,
}).catch(() => {});
// 2. Visit key pages and check RTL + Arabic
const pages = [
{ url: '/', label: 'dashboard' },
{ url: '/complaints/', label: 'complaint-list' },
{ url: '/complaints/public/submit/', label: 'public-form' },
{ url: '/observations/new/', label: 'obs-form' },
{ url: '/core/public/submit/', label: 'public-landing' },
];
for (const { url, label } of pages) {
try {
await page.goto(`${BASE_URL}${url}`);
await page.waitForLoadState('domcontentloaded');
await page.waitForTimeout(1000);
// Check dir attribute
const htmlDir = await page.evaluate(() => document.documentElement.dir);
const htmlLang = await page.evaluate(() => document.documentElement.lang);
// Check for Arabic text (basic Unicode range check)
const body = (await page.textContent('body')) || '';
const hasArabic = /[\u0600-\u06FF]/.test(body);
// Check for layout issues (horizontal scrollbar)
const scrollWidth = await page.evaluate(() => document.documentElement.scrollWidth);
const clientWidth = await page.evaluate(() => document.documentElement.clientWidth);
const hasOverflow = scrollWidth > clientWidth + 10;
const rtlOk = htmlDir === 'rtl';
const langOk = htmlLang === 'ar' || htmlLang.includes('ar');
const arabicOk = hasArabic;
const layoutOk = !hasOverflow;
const allOk = rtlOk && arabicOk && layoutOk;
observe(M, `${label}-arabic`, allOk ? 'PASS' : 'WARN',
`dir=${htmlDir} lang=${htmlLang} arabic=${hasArabic} overflow=${hasOverflow} body=${body.length}`,
{ url: page.url() });
} catch (e) {
observe(M, `${label}-arabic`, 'FAIL', `exception: ${(e as Error).message.slice(0, 100)}`, {});
}
}
// 3. Switch back to English
await page.context().request.post(`${BASE_URL}/i18n/setlang/`, {
headers: { 'X-CSRFToken': csrf },
form: { csrfmiddlewaretoken: csrf, language: 'en' },
maxRedirects: 0,
}).catch(() => {});
// Verify English restored
await page.goto(`${BASE_URL}/`);
await page.waitForLoadState('domcontentloaded');
const htmlDirEn = await page.evaluate(() => document.documentElement.dir);
observe(M, 'restore-english', htmlDirEn !== 'rtl' ? 'PASS' : 'WARN',
`after switching back to EN: dir=${htmlDirEn}`, {});
});
});
test.afterAll(async () => {
const counts = OBS.reduce<Record<string, number>>((a, o) => ((a[o.status] = (a[o.status] || 0) + 1), a), {});
console.log('\n=========== I18N / ARABIC SUMMARY ===========');
console.log('Total observations:', OBS.length, JSON.stringify(counts));
console.log('==============================================\n');
});