DFiP_Budget_planing/perf/e2e/scenarios/svod2-memory.spec.ts
Andrey Epifancev 3363291801 perf: сценарий памяти свода 2 (GO «все» → RF «все» → GO)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 00:30:12 +04:00

93 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Сценарий памяти свода 2 (Task 16): роль dfip, свежий контекст на каждый повтор, одна SPA-сессия внутри повтора.
* Точки (lib/svod2.ts memoryPoints): go (вкладка GO, «Все ССП/РФ», «Загрузить») -> rf (вкладка RF, то же)
* [-> rf_scrolled при PERF_SVOD2_MEM_SCROLL=1] -> final (возврат на GO, «Загрузить»).
* В каждой точке gc -> heapUsed, domCounters. Запись: scenario "svod2-memory", target "svod2/<point>".
* Env: PERF_SCALE, PERF_RUN_ID, PERF_REPEATS (3), PERF_SVOD2_MEM_SCROLL, PERF_LOAD_TIMEOUT_MS, PERF_MAX_STEPS,
* PERF_TEST_TIMEOUT_MS.
*/
import { test, type Page } from '@playwright/test';
import { loadManifest, scale } from '../lib/manifest';
import { loginAs, WEB } from '../lib/auth';
import { throttle, heapUsed, domCounters } from '../lib/cdp';
import { append } from '../lib/results';
import { scrollThrough } from '../lib/scroll';
import { SVOD2_DATA_ROW_SELECTOR, memoryPoints } from '../lib/svod2';
const CONTAINER = '.MuiTableContainer-root';
const MIN_ROWS = 20;
const REPEATS = Number(process.env.PERF_REPEATS ?? 3);
const LOAD_TIMEOUT = Number(process.env.PERF_LOAD_TIMEOUT_MS ?? 900_000);
const MAX_STEPS = Number(process.env.PERF_MAX_STEPS ?? 5000);
async function waitRows(page: Page, what: string): Promise<number> {
const t0 = Date.now();
for (;;) {
const n = await page.evaluate(([sel, rs]) => document.querySelectorAll(`${sel} ${rs}`).length, [CONTAINER, SVOD2_DATA_ROW_SELECTOR]);
if (n >= MIN_ROWS) return n;
if (Date.now() - t0 > LOAD_TIMEOUT) throw new Error(`${what}: rows<${MIN_ROWS} за ${LOAD_TIMEOUT} мс (rows=${n})`);
await page.waitForTimeout(500);
}
}
/** «Все ССП/РФ» + «Загрузить» (Svod2Page.jsx), как в scroll.spec.ts. */
async function loadAll(page: Page): Promise<void> {
await page.getByLabel('ССП/РФ').click();
await page.getByRole('option', { name: 'Все ССП/РФ' }).click();
await page.keyboard.press('Escape');
await page.getByRole('button', { name: 'Загрузить' }).click();
}
for (let repeat = 0; repeat < REPEATS; repeat++) {
test(`svod2-memory: dfip #${repeat}`, async ({ browser }) => {
test.setTimeout(Number(process.env.PERF_TEST_TIMEOUT_MS ?? 3600_000));
const user = loadManifest().users['dfip'];
if (!user) throw new Error('в манифесте нет пользователя dfip');
const points = memoryPoints(process.env);
const ctx = await browser.newContext({ viewport: { width: 1600, height: 900 } });
try {
await loginAs(ctx, user);
const page = await ctx.newPage();
page.on('pageerror', (e) => console.log('pageerror:', e.message));
await page.goto(WEB + '/svod/2');
await throttle(page, 1);
const sample = async (point: string, rows: number) => {
const heap = await heapUsed(page); // gc внутри
const dom = await domCounters(page);
append({
scenario: 'svod2-memory', target: `svod2/${point}`, role: 'dfip', scale: scale(), cpu_rate: 1, repeat,
metrics: { heap_used_mb: heap / 1048576, nodes: dom.nodes, documents: dom.documents, js_event_listeners: dom.jsEventListeners, rows_visible: rows },
artifacts: [],
});
console.log(`${point} #${repeat}: heap ${(heap / 1048576).toFixed(1)} MB, nodes ${dom.nodes}, listeners ${dom.jsEventListeners}`);
};
for (const point of points) {
let rows: number;
if (point === 'go') {
await page.getByRole('tab').nth(0).click();
await loadAll(page);
rows = await waitRows(page, point);
} else if (point === 'rf') {
await page.getByRole('tab').nth(1).click();
await loadAll(page);
rows = await waitRows(page, point);
} else if (point === 'rf_scrolled') {
const r = await scrollThrough(page, CONTAINER, 'y', 200, MAX_STEPS);
if (!r.complete) throw new Error(`rf_scrolled: скролл не дошёл до конца (${r.reason ?? 'incomplete'})`);
rows = await waitRows(page, point);
} else {
await page.getByRole('tab').nth(0).click();
await loadAll(page);
rows = await waitRows(page, point);
}
await page.waitForTimeout(500);
await sample(point, rows);
}
} finally {
await ctx.close();
}
});
}