main ab6686c

performance.spec.js RawHistoryFolder

1import { test, expect } from '@playwright/test';
2import path from 'node:path';
3
4const root = process.cwd();
5
6/** @param {number} width @param {number} height @param {string} text */
7function snapshot(width, height, text) {
8  const cells = Array.from({ length: width }, (_, column) => ({ column, width: 1, text, style: 0 }));
9  return {
10    schemaVersion: 2,
11    width,
12    height,
13    snapshot: true,
14    styles: [{ foreground: { kind: 0 }, background: { kind: 0 }, underlineColor: { kind: 0 } }],
15    rows: Array.from({ length: height }, (_, row) => ({ row, cells })),
16    cursor: { row: 0, column: 0, visible: false, style: 0, styleSet: false }
17  };
18}
19
20test('keeps sustained snapshot and row replacement work bounded', async ({ page, browserName }, testInfo) => {
21  test.skip(browserName !== 'chromium', 'reference performance budget uses pinned Chromium');
22  await page.setContent('<div id="terminal"></div>');
23  await page.addStyleTag({ path: path.join(root, 'html/terminal.css') });
24  await page.addScriptTag({ path: path.join(root, 'html/browser/terminal.js') });
25
26  const metrics = await page.evaluate(async ({ first, second, large }) => {
27    const terminal = VevTerminal.mount(document.querySelector('#terminal'), { label: 'Performance terminal' });
28    const settle = async () => {
29      document.querySelector('.vev-terminal__viewport').getBoundingClientRect();
30      await new Promise(requestAnimationFrame);
31    };
32    terminal.apply(first);
33    await settle();
34    const snapshots = [];
35    for (let index = 0; index < 10; index += 1) {
36      const start = performance.now();
37      terminal.apply(index % 2 === 0 ? second : first);
38      await settle();
39      snapshots.push(performance.now() - start);
40    }
41
42    const rows = [];
43    for (let index = 0; index < 50; index += 1) {
44      // Alternate both rows so every timed apply performs a real replacement
45      // instead of re-applying the same row through the no-op reuse path.
46      const rowUpdate = {
47        ...(index % 2 === 0 ? first : second),
48        snapshot: false,
49        rows: [(index % 2 === 0 ? second : first).rows[20]]
50      };
51      const start = performance.now();
52      terminal.apply(rowUpdate);
53      await settle();
54      rows.push(performance.now() - start);
55    }
56    const percentile = (values, ratio) => [...values].sort((a, b) => a - b)[Math.ceil(values.length * ratio) - 1];
57    const largeStart = performance.now();
58    terminal.apply(large);
59    await settle();
60    const largeApply = performance.now() - largeStart;
61    return {
62      snapshotP95: percentile(snapshots, 0.95),
63      rowP95: percentile(rows, 0.95),
64      largeApply,
65      cells: document.querySelectorAll('.vev-terminal__cell').length,
66      rows: document.querySelectorAll('.vev-terminal__row').length
67    };
68  }, { first: snapshot(120, 40, 'A'), second: snapshot(120, 40, 'B'), large: snapshot(240, 80, 'C') });
69
70  testInfo.annotations.push({ type: 'performance', description: JSON.stringify(metrics) });
71  expect(metrics.snapshotP95).toBeLessThan(100);
72  expect(metrics.rowP95).toBeLessThan(33);
73  expect(metrics.largeApply).toBeLessThan(500);
74  expect(metrics.cells).toBe(240 * 80);
75  expect(metrics.rows).toBe(80);
76});

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 13

↑↓ moveenter openesc close