Skip to content

Commit 80d69d7

Browse files
committed
test: add e2e tests for the scroll blocking
1 parent caaeb8d commit 80d69d7

File tree

11 files changed

+207
-2
lines changed

11 files changed

+207
-2
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import {browser, Key, element, by} from 'protractor';
2+
import {screenshot} from '../../screenshot';
3+
import {getScrollPosition} from '../../util/query';
4+
5+
6+
describe('scroll blocking', () => {
7+
beforeEach(() => browser.get('/block-scroll-strategy'));
8+
afterEach(() => clickOn('disable'));
9+
10+
it('should not be able to scroll programmatically along the x axis', async (done) => {
11+
scrollPage(0, 100);
12+
expect((await getScrollPosition()).y).toBe(100, 'Expected the page to be scrollable.');
13+
14+
clickOn('enable');
15+
scrollPage(0, 200);
16+
expect((await getScrollPosition()).y).toBe(100, 'Expected the page not to be scrollable.');
17+
18+
clickOn('disable');
19+
scrollPage(0, 300);
20+
expect((await getScrollPosition()).y).toBe(300, 'Exected page to be scrollable again.');
21+
22+
done();
23+
});
24+
25+
it('should not be able to scroll programmatically along the y axis', async (done) => {
26+
scrollPage(100, 0);
27+
expect((await getScrollPosition()).x).toBe(100, 'Expected the page to be scrollable.');
28+
29+
clickOn('enable');
30+
scrollPage(200, 0);
31+
expect((await getScrollPosition()).x).toBe(100, 'Expected the page not to be scrollable.');
32+
33+
clickOn('disable');
34+
scrollPage(300, 0);
35+
expect((await getScrollPosition()).x).toBe(300, 'Exected page to be scrollable again.');
36+
37+
done();
38+
});
39+
40+
it('should not be able to scroll via the keyboard along the y axis', async (done) => {
41+
const body = element(by.tagName('body'));
42+
43+
scrollPage(0, 100);
44+
expect((await getScrollPosition()).y).toBe(100, 'Expected the page to be scrollable.');
45+
46+
clickOn('enable');
47+
await body.sendKeys(Key.ARROW_DOWN);
48+
await body.sendKeys(Key.ARROW_DOWN);
49+
await body.sendKeys(Key.ARROW_DOWN);
50+
expect((await getScrollPosition()).y).toBe(100, 'Expected the page not to be scrollable.');
51+
52+
clickOn('disable');
53+
await body.sendKeys(Key.ARROW_DOWN);
54+
await body.sendKeys(Key.ARROW_DOWN);
55+
await body.sendKeys(Key.ARROW_DOWN);
56+
expect((await getScrollPosition()).y)
57+
.toBeGreaterThan(100, 'Expected the page to be scrollable again.');
58+
59+
done();
60+
});
61+
62+
it('should not be able to scroll via the keyboard along the x axis', async (done) => {
63+
const body = element(by.tagName('body'));
64+
65+
scrollPage(100, 0);
66+
expect((await getScrollPosition()).x).toBe(100, 'Expected the page to be scrollable.');
67+
68+
clickOn('enable');
69+
await body.sendKeys(Key.ARROW_RIGHT);
70+
await body.sendKeys(Key.ARROW_RIGHT);
71+
await body.sendKeys(Key.ARROW_RIGHT);
72+
expect((await getScrollPosition()).x).toBe(100, 'Expected the page not to be scrollable.');
73+
74+
clickOn('disable');
75+
await body.sendKeys(Key.ARROW_RIGHT);
76+
await body.sendKeys(Key.ARROW_RIGHT);
77+
await body.sendKeys(Key.ARROW_RIGHT);
78+
expect((await getScrollPosition()).x)
79+
.toBeGreaterThan(100, 'Expected the page to be scrollable again.');
80+
81+
done();
82+
});
83+
84+
it('should not be able to scroll the page after reaching the end of an element along the y axis',
85+
async (done) => {
86+
const scroller = element(by.id('scroller'));
87+
88+
browser.executeScript(`document.getElementById('scroller').scrollTop = 200;`);
89+
scrollPage(0, 100);
90+
expect((await getScrollPosition()).y).toBe(100, 'Expected the page to be scrollable.');
91+
92+
clickOn('enable');
93+
scroller.sendKeys(Key.ARROW_DOWN);
94+
scroller.sendKeys(Key.ARROW_DOWN);
95+
scroller.sendKeys(Key.ARROW_DOWN);
96+
expect((await getScrollPosition()).y).toBe(100, 'Expected the page not to have scrolled.');
97+
98+
done();
99+
});
100+
101+
it('should not be able to scroll the page after reaching the end of an element along the x axis',
102+
async (done) => {
103+
const scroller = element(by.id('scroller'));
104+
105+
browser.executeScript(`document.getElementById('scroller').scrollLeft = 200;`);
106+
scrollPage(100, 0);
107+
expect((await getScrollPosition()).x).toBe(100, 'Expected the page to be scrollable.');
108+
109+
clickOn('enable');
110+
scroller.sendKeys(Key.ARROW_RIGHT);
111+
scroller.sendKeys(Key.ARROW_RIGHT);
112+
scroller.sendKeys(Key.ARROW_RIGHT);
113+
expect((await getScrollPosition()).x).toBe(100, 'Expected the page not to have scrolled.');
114+
115+
done();
116+
});
117+
});
118+
119+
// Clicks on a button programmatically. Note that we can't use Protractor's `.click`, because
120+
// it performs a real click, which will scroll the button into view.
121+
function clickOn(id: string) {
122+
browser.executeScript(`document.getElementById('${id}').click()`);
123+
}
124+
125+
// Scrolls the page to the specified coordinates.
126+
function scrollPage(x: number, y: number) {
127+
return browser.executeScript(`window.scrollTo(${x}, ${y});`);
128+
}

e2e/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"emitDecoratorMetadata": true,
77
"experimentalDecorators": true,
88
"inlineSources": true,
9+
"lib": ["es2015"],
910
"module": "commonjs",
1011
"moduleResolution": "node",
1112
"noEmitOnError": true,

e2e/util/asserts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function expectFocusOn(element: FinderResult, expected = true): void {
2020
}
2121

2222
/**
23-
* Asserts that an element has a certan location.
23+
* Asserts that an element has a certain location.
2424
*/
2525
export function expectLocation(element: FinderResult, {x, y}: Point): void {
2626
getElement(element).getLocation().then((location: Point) => {

e2e/util/query.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {ElementFinder, by, element, ProtractorBy, browser} from 'protractor';
2+
import {Point} from './actions';
23

34
/**
45
* Normalizes either turning a selector into an
@@ -15,4 +16,21 @@ export function waitForElement(selector: string) {
1516
return browser.isElementPresent(by.css(selector) as ProtractorBy);
1617
}
1718

19+
/**
20+
* Determines the current scroll position of the page.
21+
*/
22+
export async function getScrollPosition(): Promise<Point> {
23+
const snippet = `
24+
var documentRect = document.documentElement.getBoundingClientRect();
25+
var x = -documentRect.left || document.body.scrollLeft || window.scrollX ||
26+
document.documentElement.scrollLeft || 0;
27+
var y = -documentRect.top || document.body.scrollTop || window.scrollY ||
28+
document.documentElement.scrollTop || 0;
29+
30+
return {x: x, y: y};
31+
`;
32+
33+
return await browser.executeScript<Point>(snippet);
34+
}
35+
1836
export type FinderResult = ElementFinder | string;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
.spacer {
2+
background: #3f51b5;
3+
margin-bottom: 10px;
4+
}
5+
6+
.spacer.vertical {
7+
width: 100px;
8+
height: 3000px;
9+
}
10+
11+
.spacer.horizontal {
12+
width: 3000px;
13+
height: 100px;
14+
}
15+
16+
.scroller {
17+
width: 100px;
18+
height: 100px;
19+
overflow: auto;
20+
position: absolute;
21+
top: 100px;
22+
left: 200px;
23+
}
24+
25+
.scroller-spacer {
26+
width: 200px;
27+
height: 200px;
28+
background: #ff4081;
29+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<p>
2+
<button id="enable" (click)="scrollStrategy.enable()">Enable scroll blocking</button>
3+
<button id="disable" (click)="scrollStrategy.disable()">Disable scroll blocking</button>
4+
</p>
5+
<div class="spacer vertical"></div>
6+
<!-- this one needs a tabindex so protractor can trigger key presses inside it -->
7+
<div class="scroller" id="scroller" tabindex="-1">
8+
<div class="scroller-spacer"></div>
9+
</div>
10+
<div class="spacer horizontal"></div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import {Component} from '@angular/core';
2+
import {BlockScrollStrategy, ViewportRuler} from '@angular/material';
3+
4+
@Component({
5+
moduleId: module.id,
6+
selector: 'block-scroll-strategy-e2e',
7+
templateUrl: 'block-scroll-strategy-e2e.html',
8+
styleUrls: ['block-scroll-strategy-e2e.css'],
9+
})
10+
export class BlockScrollStrategyE2E {
11+
constructor(private _viewportRuler: ViewportRuler) { }
12+
scrollStrategy = new BlockScrollStrategy(this._viewportRuler);
13+
}

src/e2e-app/e2e-app-module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {MaterialModule, OverlayContainer, FullscreenOverlayContainer} from '@ang
1919
import {E2E_APP_ROUTES} from './e2e-app/routes';
2020
import {SlideToggleE2E} from './slide-toggle/slide-toggle-e2e';
2121
import {InputE2E} from './input/input-e2e';
22+
import {BlockScrollStrategyE2E} from './block-scroll-strategy/block-scroll-strategy-e2e';
2223

2324
@NgModule({
2425
imports: [
@@ -45,7 +46,8 @@ import {InputE2E} from './input/input-e2e';
4546
SimpleRadioButtons,
4647
SlideToggleE2E,
4748
TestDialog,
48-
TestDialogFullScreen
49+
TestDialogFullScreen,
50+
BlockScrollStrategyE2E
4951
],
5052
bootstrap: [E2EApp],
5153
providers: [

src/e2e-app/e2e-app/e2e-app.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<button (click)="showLinks = !showLinks">Toggle Navigation Links</button>
22

33
<md-nav-list *ngIf="showLinks">
4+
<a md-list-item [routerLink]="['block-scroll-strategy']">Block scroll strategy</a>
45
<a md-list-item [routerLink]="['button']">Button</a>
56
<a md-list-item [routerLink]="['checkbox']">Checkbox</a>
67
<a md-list-item [routerLink]="['dialog']">Dialog</a>

src/e2e-app/e2e-app/routes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ import {ProgressSpinnerE2E} from '../progress-spinner/progress-spinner-e2e';
1414
import {SlideToggleE2E} from '../slide-toggle/slide-toggle-e2e';
1515
import {FullscreenE2E} from '../fullscreen/fullscreen-e2e';
1616
import {InputE2E} from '../input/input-e2e';
17+
import {BlockScrollStrategyE2E} from '../block-scroll-strategy/block-scroll-strategy-e2e';
1718

1819
export const E2E_APP_ROUTES: Routes = [
1920
{path: '', component: Home},
21+
{path: 'block-scroll-strategy', component: BlockScrollStrategyE2E},
2022
{path: 'button', component: ButtonE2E},
2123
{path: 'checkbox', component: SimpleCheckboxes},
2224
{path: 'dialog', component: DialogE2E},

src/lib/core/overlay/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export {OverlayRef} from './overlay-ref';
55
export {OverlayState} from './overlay-state';
66
export {ConnectedOverlayDirective, OverlayOrigin, OverlayModule} from './overlay-directives';
77
export {ScrollDispatcher} from './scroll/scroll-dispatcher';
8+
export {ViewportRuler} from './position/viewport-ruler';
89

910
export * from './position/connected-position';
1011

0 commit comments

Comments
 (0)