diff --git a/.github/workflows/_reusable-lighthouse.yml b/.github/workflows/_reusable-lighthouse.yml index d1ed4f4..f2abe0d 100644 --- a/.github/workflows/_reusable-lighthouse.yml +++ b/.github/workflows/_reusable-lighthouse.yml @@ -10,7 +10,7 @@ on: project_path: required: true type: string - description: 'Path to the Next.js project (relative to repo root)' + description: 'Path to the Astro project (relative to repo root)' jobs: lighthouse: @@ -36,10 +36,10 @@ jobs: run: npm install -g @lhci/cli@0.13.x - name: Run Lighthouse CI working-directory: ${{ inputs.project_path }} - # Non-blocking: chatislam/web is an SSR app (output: 'server', Vercel - # adapter) with no static dist for LHCI's staticDistDir to serve. - # Tracked as follow-up to rewire LHCI to build + serve the SSR app. - continue-on-error: true + # Blocking gate. The app is SSR (output: 'server', Vercel adapter); the + # landing pages audited by lighthouserc.cjs are `export const prerender = + # true`, so `pnpm build` emits their static HTML into + # .vercel/output/static, which LHCI serves via staticDistDir. run: lhci autorun - name: Upload Lighthouse report if: always() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e93c3c9..c8f4ced 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,11 +73,6 @@ jobs: name: E2E Tests runs-on: ubuntu-latest needs: build - # Non-blocking: the Astro migration left pre-existing e2e failures (RTL - # dir/lang not applied in ar/ur locales, empty-state assertion, missing - # platform snapshot baselines). These are tracked as follow-up app/test - # work; the blocking gates are lint, type-check, unit tests, and build. - continue-on-error: true steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 diff --git a/web/.gitignore b/web/.gitignore index 9f5bed3..3282053 100644 --- a/web/.gitignore +++ b/web/.gitignore @@ -31,6 +31,7 @@ coverage/ playwright-report/ test-results/ __tests__/e2e/**/*-snapshots/ +.lighthouseci/ # Astro .astro/ diff --git a/web/__tests__/e2e/rtl.spec.ts b/web/__tests__/e2e/rtl.spec.ts index 55ceda4..2e6ede0 100644 --- a/web/__tests__/e2e/rtl.spec.ts +++ b/web/__tests__/e2e/rtl.spec.ts @@ -67,14 +67,31 @@ test.describe('RTL layout — Arabic locale', () => { expect(hasOverflow).toBe(false) }) - test('RTL baseline screenshot — homepage Arabic', async ({ page }) => { + // Visual PNG snapshots are platform-dependent — Arabic shaping/fonts render + // differently across OSes, so a baseline captured on one platform is not a + // reliable gate on CI (linux). Instead assert the RTL layout properties a + // baseline would protect: computed direction on the document + main region, + // translated (Arabic) content, and no horizontal overflow. + test('RTL layout renders correctly — homepage Arabic', async ({ page }) => { await page.goto('/') await page.waitForLoadState('networkidle') - // Baseline: run once with --update-snapshots to create; subsequent runs compare. - await expect(page).toHaveScreenshot('homepage-ar-rtl.png', { - fullPage: false, - animations: 'disabled', + + const htmlDir = await page.evaluate(() => getComputedStyle(document.documentElement).direction) + expect(htmlDir).toBe('rtl') + + const mainDir = await page.evaluate(() => { + const main = document.querySelector('#main-content') + return main ? getComputedStyle(main).direction : null }) + expect(mainDir).toBe('rtl') + + const bodyText = await page.evaluate(() => document.body.innerText) + expect(bodyText).toMatch(/[؀-ۿ]/) + + const hasOverflow = await page.evaluate( + () => document.documentElement.scrollWidth > window.innerWidth, + ) + expect(hasOverflow).toBe(false) }) }) @@ -110,13 +127,28 @@ test.describe('RTL layout — Urdu locale', () => { expect(hasOverflow).toBe(false) }) - test('RTL baseline screenshot — homepage Urdu', async ({ page }) => { + // See the Arabic case above — assert RTL layout properties rather than commit + // a platform-dependent PNG baseline. + test('RTL layout renders correctly — homepage Urdu', async ({ page }) => { await page.goto('/') await page.waitForLoadState('networkidle') - await expect(page).toHaveScreenshot('homepage-ur-rtl.png', { - fullPage: false, - animations: 'disabled', + + const htmlDir = await page.evaluate(() => getComputedStyle(document.documentElement).direction) + expect(htmlDir).toBe('rtl') + + const mainDir = await page.evaluate(() => { + const main = document.querySelector('#main-content') + return main ? getComputedStyle(main).direction : null }) + expect(mainDir).toBe('rtl') + + const bodyText = await page.evaluate(() => document.body.innerText) + expect(bodyText).toMatch(/[؀-ۿ]/) + + const hasOverflow = await page.evaluate( + () => document.documentElement.scrollWidth > window.innerWidth, + ) + expect(hasOverflow).toBe(false) }) }) diff --git a/web/astro.config.ts b/web/astro.config.ts index 459fc40..5a87c42 100644 --- a/web/astro.config.ts +++ b/web/astro.config.ts @@ -20,6 +20,10 @@ import tailwindcss from '@tailwindcss/vite' export default defineConfig({ site: 'https://chatislam.org', output: 'server', + // Dev-only overlay injects unlabeled