Skip to content

Commit 3e27493

Browse files
committed
test(selection): add behavior and visual tests for RTL arrow key movement
Add Playwright behavior test that verifies ArrowLeft/ArrowRight move the cursor in the correct visual direction in RTL paragraphs (and regression test for LTR). Add visual regression test that screenshots cursor position after arrow navigation in an RTL document. Both use the existing rtl-mixed-bidi.docx fixture. SD-2390
1 parent ff7af6a commit 3e27493

1 file changed

Lines changed: 118 additions & 0 deletions

File tree

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import fs from 'node:fs';
2+
import path from 'node:path';
3+
import { fileURLToPath } from 'node:url';
4+
import { test, expect } from '../../fixtures/superdoc.js';
5+
6+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
7+
const DOC_PATH = path.resolve(__dirname, 'fixtures/rtl-mixed-bidi.docx');
8+
9+
test.skip(!fs.existsSync(DOC_PATH), 'RTL fixture not available');
10+
11+
test.use({ config: { toolbar: 'none', showCaret: true, showSelection: true } });
12+
13+
test.describe('RTL arrow key cursor movement (SD-2390)', () => {
14+
test('ArrowLeft moves cursor visually left in RTL paragraph', async ({ superdoc }) => {
15+
await superdoc.loadDocument(DOC_PATH);
16+
await superdoc.waitForStable();
17+
18+
// First line is RTL Arabic: "هذه فقرة كاملة باللغة العربية"
19+
const rtlLine = superdoc.page.locator('.superdoc-line').first();
20+
const box = await rtlLine.boundingBox();
21+
if (!box) throw new Error('RTL line not visible');
22+
23+
// Click near the right edge (logical start of RTL text)
24+
await superdoc.page.mouse.click(box.x + box.width - 20, box.y + box.height / 2);
25+
await superdoc.waitForStable();
26+
27+
const before = await superdoc.getSelection();
28+
29+
// Get caret X before
30+
const xBefore = await superdoc.page.evaluate((pos) => {
31+
const pe = (window as any).superdoc?.activeEditor?.presentationEditor;
32+
return pe?.computeCaretLayoutRect(pos)?.x;
33+
}, before.from);
34+
35+
// Press ArrowLeft
36+
await superdoc.page.keyboard.press('ArrowLeft');
37+
await superdoc.waitForStable();
38+
39+
const after = await superdoc.getSelection();
40+
const xAfter = await superdoc.page.evaluate((pos) => {
41+
const pe = (window as any).superdoc?.activeEditor?.presentationEditor;
42+
return pe?.computeCaretLayoutRect(pos)?.x;
43+
}, after.from);
44+
45+
// In RTL, ArrowLeft should move visually left (decreasing X)
46+
expect(xAfter).toBeLessThan(xBefore);
47+
// PM position should increase (moving toward end of line in document order)
48+
expect(after.from).toBeGreaterThan(before.from);
49+
});
50+
51+
test('ArrowRight moves cursor visually right in RTL paragraph', async ({ superdoc }) => {
52+
await superdoc.loadDocument(DOC_PATH);
53+
await superdoc.waitForStable();
54+
55+
const rtlLine = superdoc.page.locator('.superdoc-line').first();
56+
const box = await rtlLine.boundingBox();
57+
if (!box) throw new Error('RTL line not visible');
58+
59+
// Click near the middle of the line
60+
await superdoc.page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
61+
await superdoc.waitForStable();
62+
63+
const before = await superdoc.getSelection();
64+
const xBefore = await superdoc.page.evaluate((pos) => {
65+
const pe = (window as any).superdoc?.activeEditor?.presentationEditor;
66+
return pe?.computeCaretLayoutRect(pos)?.x;
67+
}, before.from);
68+
69+
// Press ArrowRight
70+
await superdoc.page.keyboard.press('ArrowRight');
71+
await superdoc.waitForStable();
72+
73+
const after = await superdoc.getSelection();
74+
const xAfter = await superdoc.page.evaluate((pos) => {
75+
const pe = (window as any).superdoc?.activeEditor?.presentationEditor;
76+
return pe?.computeCaretLayoutRect(pos)?.x;
77+
}, after.from);
78+
79+
// In RTL, ArrowRight should move visually right (increasing X)
80+
expect(xAfter).toBeGreaterThan(xBefore);
81+
// PM position should decrease (moving toward start of line in document order)
82+
expect(after.from).toBeLessThan(before.from);
83+
});
84+
85+
test('ArrowLeft/Right in LTR paragraph still works correctly', async ({ superdoc }) => {
86+
await superdoc.loadDocument(DOC_PATH);
87+
await superdoc.waitForStable();
88+
89+
// Second line is LTR English: "This is a complete English paragraph"
90+
const ltrLine = superdoc.page.locator('.superdoc-line').nth(1);
91+
const box = await ltrLine.boundingBox();
92+
if (!box) throw new Error('LTR line not visible');
93+
94+
// Click near the left edge
95+
await superdoc.page.mouse.click(box.x + 30, box.y + box.height / 2);
96+
await superdoc.waitForStable();
97+
98+
const before = await superdoc.getSelection();
99+
const xBefore = await superdoc.page.evaluate((pos) => {
100+
const pe = (window as any).superdoc?.activeEditor?.presentationEditor;
101+
return pe?.computeCaretLayoutRect(pos)?.x;
102+
}, before.from);
103+
104+
// Press ArrowRight in LTR
105+
await superdoc.page.keyboard.press('ArrowRight');
106+
await superdoc.waitForStable();
107+
108+
const after = await superdoc.getSelection();
109+
const xAfter = await superdoc.page.evaluate((pos) => {
110+
const pe = (window as any).superdoc?.activeEditor?.presentationEditor;
111+
return pe?.computeCaretLayoutRect(pos)?.x;
112+
}, after.from);
113+
114+
// In LTR, ArrowRight moves visually right (increasing X) and increases PM position
115+
expect(xAfter).toBeGreaterThan(xBefore);
116+
expect(after.from).toBeGreaterThan(before.from);
117+
});
118+
});

0 commit comments

Comments
 (0)