Skip to content

Commit c861b21

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

File tree

11 files changed

+213
-2
lines changed

11 files changed

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

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)