admin/e2e/shared/performance.spec.ts
alisaza e1eaf5eff5 feat: initial ghabilee-admin backoffice app
Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js
app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
2026-09-05 13:12:59 +03:30

39 lines
1.9 KiB
TypeScript

import { expect, test } from '@playwright/test'
test.use({ viewport: { width: 390, height: 844 }, deviceScaleFactor: 2, isMobile: true })
test('public mobile route stays inside the lab Core Web Vitals budget', async ({ browserName, page }) => {
test.skip(browserName !== 'chromium', 'Chromium exposes the Event Timing/LCP observers used by this lab budget')
await page.addInitScript(() => {
const values = { cls: 0, inp: 0, lcp: 0 }
Object.assign(window, { __labVitals: values })
new PerformanceObserver((list) => {
const latest = list.getEntries().at(-1)
if (latest) values.lcp = latest.startTime
}).observe({ type: 'largest-contentful-paint', buffered: true })
new PerformanceObserver((list) => {
for (const entry of list.getEntries() as (PerformanceEntry & { hadRecentInput?: boolean; value?: number })[]) {
if (!entry.hadRecentInput) values.cls += entry.value ?? 0
}
}).observe({ type: 'layout-shift', buffered: true })
new PerformanceObserver((list) => {
for (const entry of list.getEntries() as (PerformanceEntry & { duration: number; interactionId?: number })[]) {
if (entry.interactionId) values.inp = Math.max(values.inp, entry.duration)
}
}).observe({ type: 'event', buffered: true, durationThreshold: 16 } as PerformanceObserverInit)
})
await page.route('**/api/v1/**', (route) => route.fulfill({ json: { success: true, data: { items: [], meta: {} } } }))
await page.goto('/')
await page.getByRole('tab', { name: 'دسته‌بندی' }).click()
await page.waitForTimeout(500)
const vitals = await page.evaluate(() => (window as unknown as { __labVitals: { cls: number; inp: number; lcp: number } }).__labVitals)
expect(vitals.lcp).toBeGreaterThan(0)
expect(vitals.lcp).toBeLessThanOrEqual(2500)
expect(vitals.cls).toBeLessThanOrEqual(0.1)
expect(vitals.inp).toBeLessThanOrEqual(200)
})