- perf/run-all.sh: масштабы 1 и 2, шаги reset -> gen -> verify -> stand -> preflight -> scroll -> coauthor -> grow -> modals -> modals_profiling -> memory -> memtrend -> [control4x] -> bench -> aggregate; лог и run-all.status.json, возобновление (PERF_STEPS, PERF_SKIP_RESET), сухой режим с оценкой длительности, PERF_S2_REPEATS/PERF_S2_TARGETS, контроль CPU 4x (PERF_CONTROL_TARGETS). - Основная метрика: main_thread_ms и main_thread_ms_per_step в скролле (CDP TaskDuration), frame_excess_ms; в summary.md первыми строками. - SQL-статистика по шагам: PERF_SQLSTATS_TAG -> sql/<шаг>/ (sqlstats --out). - netlog: тела /auth/ не пишутся, поля password/token/secret вырезаются. - scroll.spec: уникальные имена целей (лист ССП с суффиксом /ssp, год в отчёте проекта) - иначе Playwright не запускал файл из-за дублей. - PERF_TRACE=0 для прогонов с одним повтором. - README: scroll-coauthor, run-all, возобновление, без CPU 4/6 в матрицах. - design.md: уточнена формулировка R-2, решения Task 10a. Refs #202 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
59 lines
2.5 KiB
TypeScript
59 lines
2.5 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import path from 'node:path';
|
|
import { scrollThrough } from '../lib/scroll';
|
|
import { PROBE_SCRIPT, startProbe, perStep } from '../lib/probe';
|
|
|
|
const fx = (n: string) => 'file://' + path.resolve(__dirname, '../fixtures', n);
|
|
|
|
test('scrollThrough: длинный список y проходится до конца', async ({ page }) => {
|
|
await page.goto(fx('long-list.html'));
|
|
const r = await scrollThrough(page, '#box', 'y');
|
|
expect(r.complete).toBe(true);
|
|
expect(r.steps).toBeGreaterThanOrEqual(100);
|
|
// вернулись к началу
|
|
expect(await page.evaluate(() => document.querySelector('#box')!.scrollTop)).toBeLessThanOrEqual(2);
|
|
});
|
|
|
|
test('scrollThrough: ось x', async ({ page }) => {
|
|
await page.goto(fx('long-list.html'));
|
|
const r = await scrollThrough(page, '#box', 'x');
|
|
expect(r.complete).toBe(true);
|
|
});
|
|
|
|
test('scrollThrough: при исчерпании maxSteps complete === false', async ({ page }) => {
|
|
await page.goto(fx('clipped-list.html'));
|
|
const r = await scrollThrough(page, '#box', 'y', 200, 10);
|
|
expect(r.complete).toBe(false);
|
|
expect(r.steps).toBeLessThanOrEqual(10);
|
|
});
|
|
|
|
test('scrollThrough: контейнер без переполнения - complete === false, reason no_overflow, 0 шагов', async ({ page }) => {
|
|
await page.goto(fx('no-overflow.html'));
|
|
for (const axis of ['y', 'x'] as const) {
|
|
const r = await scrollThrough(page, '#box', axis);
|
|
expect(r.complete).toBe(false);
|
|
expect(r.steps).toBe(0);
|
|
expect(r.reason).toBe('no_overflow');
|
|
}
|
|
});
|
|
|
|
test('scrollThrough: ось x на длинном по высоте, но не по ширине контейнере - no_overflow', async ({ page }) => {
|
|
await page.goto(fx('clipped-list.html'));
|
|
const r = await scrollThrough(page, '#box', 'x');
|
|
expect(r.complete).toBe(false);
|
|
expect(r.reason).toBe('no_overflow');
|
|
});
|
|
|
|
test('scroll + probe: main_thread_ms_per_step = main_thread_ms / steps', async ({ page }) => {
|
|
await page.addInitScript(PROBE_SCRIPT);
|
|
await page.goto(fx('long-list.html'));
|
|
const p = await startProbe(page);
|
|
const r = await scrollThrough(page, '#box', 'y');
|
|
const m = await p.stop();
|
|
expect(r.steps).toBeGreaterThan(0);
|
|
expect(m.main_thread_ms).toBeGreaterThan(0);
|
|
const ps = perStep(m, r.steps);
|
|
expect(ps.main_thread_ms_per_step).toBeCloseTo(m.main_thread_ms / r.steps, 6);
|
|
expect(perStep(m, 0)).toEqual({}); // нет шагов (фильтр, no_overflow) - метрики на шаг нет
|
|
});
|