Skip to content
This repository was archived by the owner on Jan 3, 2019. It is now read-only.

Commit f4f32cf

Browse files
authored
fix(web): improve the reliability of the scroll-into-view method (#230)
The `scrollIntoView` method of the `WebComponent` class should not start to scroll until the page stops moving.
1 parent c8d4cb4 commit f4f32cf

File tree

2 files changed

+86
-2
lines changed

2 files changed

+86
-2
lines changed

@pageobject/web/src/WebComponent.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,29 @@ export abstract class WebComponent extends Component<WebNode, WebAdapter> {
127127
}
128128

129129
public scrollIntoView(): Effect<void> {
130-
return async () =>
131-
(await this.findUniqueNode()).execute(element => {
130+
const getRect = async () =>
131+
(await this.findUniqueNode()).execute(element =>
132+
element.getBoundingClientRect()
133+
);
134+
135+
const isPageMoving = async (lastRect: ClientRect) => {
136+
const currentRect = await getRect();
137+
138+
return (
139+
currentRect.left !== lastRect.left || currentRect.top !== lastRect.top
140+
);
141+
};
142+
143+
return async () => {
144+
let lastRect: ClientRect;
145+
146+
do {
147+
lastRect = await getRect();
148+
149+
await new Promise<void>(resolve => setTimeout(resolve, 10));
150+
} while (await isPageMoving(lastRect));
151+
152+
await (await this.findUniqueNode()).execute(element => {
132153
const {height, left, top, width} = element.getBoundingClientRect();
133154
const {innerHeight, innerWidth} = window;
134155

@@ -137,5 +158,6 @@ export abstract class WebComponent extends Component<WebNode, WebAdapter> {
137158
top - innerHeight / 2 + height / 2
138159
);
139160
});
161+
};
140162
}
141163
}

@pageobject/web/src/tests/WebComponent.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,5 +296,67 @@ describe('WebComponent', () => {
296296
expect(scrollBy).toHaveBeenCalledTimes(1);
297297
expect(scrollBy).toHaveBeenLastCalledWith(-475, -275);
298298
});
299+
300+
it('should not start to scroll until the page stops moving vertically', async () => {
301+
let top = 100;
302+
303+
element.getBoundingClientRect.mockImplementation(() => ({
304+
height: 0,
305+
left: 0,
306+
top,
307+
width: 0
308+
}));
309+
310+
scrollBy.mockImplementation(() => {
311+
if (top !== 0) {
312+
throw new Error('page is moving');
313+
}
314+
});
315+
316+
const intervalId = setInterval(() => {
317+
top -= 1;
318+
319+
if (top === 0) {
320+
clearInterval(intervalId);
321+
}
322+
}, 1);
323+
324+
await component.scrollIntoView()();
325+
326+
expect(scrollBy).toHaveBeenCalledTimes(1);
327+
});
328+
329+
it('should not start to scroll until the page stops moving horizontally', async () => {
330+
let left = 100;
331+
332+
element.getBoundingClientRect.mockImplementation(() => ({
333+
height: 0,
334+
left,
335+
top: 0,
336+
width: 0
337+
}));
338+
339+
scrollBy.mockImplementation(() => {
340+
if (left !== 0) {
341+
throw new Error('page is moving');
342+
}
343+
});
344+
345+
const intervalId = setInterval(() => {
346+
left -= 1;
347+
348+
if (left === 0) {
349+
clearInterval(intervalId);
350+
}
351+
}, 1);
352+
353+
await component.scrollIntoView()();
354+
355+
expect(scrollBy).toHaveBeenCalledTimes(1);
356+
357+
expect(element.getBoundingClientRect.mock.calls.length).toBeGreaterThan(
358+
1
359+
);
360+
});
299361
});
300362
});

0 commit comments

Comments
 (0)