-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Expand file tree
/
Copy pathundo_redo_scroll.spec.ts
More file actions
104 lines (85 loc) · 4.19 KB
/
Copy pathundo_redo_scroll.spec.ts
File metadata and controls
104 lines (85 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import {expect, test} from "@playwright/test";
import {clearPadContent, getPadBody, goToNewPad} from "../helper/padHelper";
test.beforeEach(async ({page}) => {
await goToNewPad(page);
});
// Regression test for https://github.com/ether/etherpad/issues/7007
//
// Pre-fix: after undo on a large pad, the viewport did not scroll to
// follow the caret. When the caret landed below the current viewport,
// src/static/js/scroll.ts's caretIsBelowOfViewport branch ran
// `outer.scrollTo(0, outer[0].innerHeight)` — a fixed offset, not the
// caret position — so the user couldn't see what had just been
// modified. That special-case was intended for "Enter at the very end
// of the pad" (PR #4639); it misbehaved whenever undo/redo or another
// path moved the caret to an arbitrary line below the viewport.
test.describe('Undo scroll-to-caret (#7007)', function () {
test.describe.configure({retries: 2});
// Use the Etherpad keyboard path so the undo module has real
// changesets to replay. 45 lines is enough to push the pad well past
// a typical CI headless viewport (~900px × ~20px per line).
const LINE_COUNT = 45;
test('Ctrl+Z scrolls viewport up when the caret lands above the view', async function ({page}) {
await (await getPadBody(page)).click();
await clearPadContent(page);
// Type LINE_COUNT short lines through the real editor (so every line
// lands in a changeset the undo module can reverse).
for (let i = 0; i < LINE_COUNT; i++) {
await page.keyboard.type(`line ${i + 1}`);
await page.keyboard.press('Enter');
}
await page.waitForTimeout(300);
// Move caret to the top, insert a single edit the undo will reverse.
await page.keyboard.down('Control');
await page.keyboard.press('Home');
await page.keyboard.up('Control');
await page.keyboard.type('X');
await page.waitForTimeout(300);
// Scroll the outer frame all the way down so the edit is out of view.
const outerFrame = page.frame('ace_outer')!;
await outerFrame.evaluate(() => {
window.scrollTo(0, document.body.scrollHeight);
});
await page.waitForTimeout(300);
const scrollBefore = await outerFrame.evaluate(
() => window.scrollY || document.scrollingElement?.scrollTop || 0);
expect(scrollBefore).toBeGreaterThan(0); // sanity: viewport actually scrolled
// Undo — caret returns to the top, viewport should follow.
await page.keyboard.press('Control+Z');
// scrollNodeVerticallyIntoView's caret-below branch uses a 150ms
// setTimeout; give it a generous budget for CI.
await page.waitForTimeout(800);
const scrollAfter = await outerFrame.evaluate(
() => window.scrollY || document.scrollingElement?.scrollTop || 0);
// Pre-fix: scrollAfter ≈ scrollBefore (no scroll).
// Fixed: scrollAfter < scrollBefore (viewport moved up toward the caret).
expect(scrollAfter).toBeLessThan(scrollBefore);
});
test('Ctrl+Z scrolls viewport down when the caret lands below the view', async function ({page}) {
await (await getPadBody(page)).click();
await clearPadContent(page);
for (let i = 0; i < LINE_COUNT; i++) {
await page.keyboard.type(`line ${i + 1}`);
await page.keyboard.press('Enter');
}
await page.waitForTimeout(300);
// Caret is already at the bottom (after the last Enter). Type an
// edit there, then scroll to top.
await page.keyboard.type('Y');
await page.waitForTimeout(300);
const outerFrame = page.frame('ace_outer')!;
await outerFrame.evaluate(() => window.scrollTo(0, 0));
await page.waitForTimeout(300);
const scrollBefore = await outerFrame.evaluate(
() => window.scrollY || document.scrollingElement?.scrollTop || 0);
expect(scrollBefore).toBe(0);
await page.keyboard.press('Control+Z');
await page.waitForTimeout(800);
const scrollAfter = await outerFrame.evaluate(
() => window.scrollY || document.scrollingElement?.scrollTop || 0);
// Pre-fix: scrollAfter was pinned to outer[0].innerHeight (a fixed
// offset) or stayed at 0; either way it was not the caret location.
// Fixed: the viewport scrolls down toward the caret at the bottom.
expect(scrollAfter).toBeGreaterThan(0);
});
});