Skip to content

Commit 16742da

Browse files
committed
add test for scroll dispatcher
1 parent a81faea commit 16742da

File tree

4 files changed

+85
-41
lines changed

4 files changed

+85
-41
lines changed

src/lib/core/overlay/position/connected-position-strategy.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ export class ConnectedPositionStrategy implements PositionStrategy {
3434
/** The offset in pixels for the overlay connection point on the y-axis */
3535
private _offsetY: number = 0;
3636

37-
/** The Scrollable containers that may cause the overlay's connectedTo element to be clipped */
38-
private scrollables: Scrollable[];
37+
/** The Scrollable containers used to check scrollable view properties on position change. */
38+
private scrollables: Scrollable[] = [];
3939

4040
/** Whether the we're dealing with an RTL context */
4141
get _isRtl() {
@@ -304,6 +304,7 @@ export class ConnectedPositionStrategy implements PositionStrategy {
304304
element.style.top = overlayPoint.y + 'px';
305305
}
306306

307+
/** Returns the bounding positions of the provided element with respect to the viewport. */
307308
private _getElementBounds(element: HTMLElement): ElementBoundingPositions {
308309
const boundingClientRect = element.getBoundingClientRect();
309310
return {

src/lib/core/overlay/position/connected-position.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/** Horizontal dimension of a connection point on the perimeter of the origin or overlay element. */
2+
import {Optional} from '@angular/core';
23
export type HorizontalConnectionPos = 'start' | 'center' | 'end';
34

45
/** Vertical dimension of a connection point on the perimeter of the origin or overlay element. */
@@ -42,5 +43,5 @@ export class ScrollableViewProperties {
4243
/** The change event emitted by the strategy when a fallback position is used. */
4344
export class ConnectedOverlayPositionChange {
4445
constructor(public connectionPair: ConnectionPositionPair,
45-
public scrollableViewProperties: ScrollableViewProperties) {}
46+
@Optional() public scrollableViewProperties: ScrollableViewProperties) {}
4647
}

src/lib/core/overlay/scroll/scroll-dispatcher.spec.ts

Lines changed: 79 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import {inject, TestBed, async, ComponentFixture} from '@angular/core/testing';
2-
import {NgModule, Component, ViewChild, ElementRef} from '@angular/core';
2+
import {NgModule, Component, ViewChild, ElementRef, QueryList, ViewChildren} from '@angular/core';
33
import {ScrollDispatcher} from './scroll-dispatcher';
44
import {OverlayModule} from '../overlay-directives';
55
import {Scrollable} from './scrollable';
66

77
describe('Scroll Dispatcher', () => {
8-
let scroll: ScrollDispatcher;
9-
let fixture: ComponentFixture<ScrollingComponent>;
108

119
beforeEach(async(() => {
1210
TestBed.configureTestingModule({
@@ -16,45 +14,71 @@ describe('Scroll Dispatcher', () => {
1614
TestBed.compileComponents();
1715
}));
1816

19-
beforeEach(inject([ScrollDispatcher], (s: ScrollDispatcher) => {
20-
scroll = s;
17+
describe('Basic usage', () => {
18+
let scroll: ScrollDispatcher;
19+
let fixture: ComponentFixture<ScrollingComponent>;
2120

22-
fixture = TestBed.createComponent(ScrollingComponent);
23-
fixture.detectChanges();
24-
}));
21+
beforeEach(inject([ScrollDispatcher], (s: ScrollDispatcher) => {
22+
scroll = s;
2523

26-
it('should be registered with the scrollable directive with the scroll service', () => {
27-
const componentScrollable = fixture.componentInstance.scrollable;
28-
expect(scroll.scrollableReferences.has(componentScrollable)).toBe(true);
29-
});
24+
fixture = TestBed.createComponent(ScrollingComponent);
25+
fixture.detectChanges();
26+
}));
27+
28+
it('should be registered with the scrollable directive with the scroll service', () => {
29+
const componentScrollable = fixture.componentInstance.scrollable;
30+
expect(scroll.scrollableReferences.has(componentScrollable)).toBe(true);
31+
});
32+
33+
it('should have the scrollable directive deregistered when the component is destroyed', () => {
34+
const componentScrollable = fixture.componentInstance.scrollable;
35+
expect(scroll.scrollableReferences.has(componentScrollable)).toBe(true);
3036

31-
it('should have the scrollable directive deregistered when the component is destroyed', () => {
32-
const componentScrollable = fixture.componentInstance.scrollable;
33-
expect(scroll.scrollableReferences.has(componentScrollable)).toBe(true);
37+
fixture.destroy();
38+
expect(scroll.scrollableReferences.has(componentScrollable)).toBe(false);
39+
});
40+
41+
it('should notify through the directive and service that a scroll event occurred', () => {
42+
let hasDirectiveScrollNotified = false;
43+
// Listen for notifications from scroll directive
44+
let scrollable = fixture.componentInstance.scrollable;
45+
scrollable.elementScrolled().subscribe(() => { hasDirectiveScrollNotified = true; });
46+
47+
// Listen for notifications from scroll service
48+
let hasServiceScrollNotified = false;
49+
scroll.scrolled().subscribe(() => { hasServiceScrollNotified = true; });
3450

35-
fixture.destroy();
36-
expect(scroll.scrollableReferences.has(componentScrollable)).toBe(false);
51+
// Emit a scroll event from the scrolling element in our component.
52+
// This event should be picked up by the scrollable directive and notify.
53+
// The notification should be picked up by the service.
54+
const scrollEvent = document.createEvent('UIEvents');
55+
scrollEvent.initUIEvent('scroll', true, true, window, 0);
56+
fixture.componentInstance.scrollingElement.nativeElement.dispatchEvent(scrollEvent);
57+
58+
expect(hasDirectiveScrollNotified).toBe(true);
59+
expect(hasServiceScrollNotified).toBe(true);
60+
});
3761
});
3862

39-
it('should notify through the directive and service that a scroll event occurred', () => {
40-
let hasDirectiveScrollNotified = false;
41-
// Listen for notifications from scroll directive
42-
let scrollable = fixture.componentInstance.scrollable;
43-
scrollable.elementScrolled().subscribe(() => { hasDirectiveScrollNotified = true; });
44-
45-
// Listen for notifications from scroll service
46-
let hasServiceScrollNotified = false;
47-
scroll.scrolled().subscribe(() => { hasServiceScrollNotified = true; });
48-
49-
// Emit a scroll event from the scrolling element in our component.
50-
// This event should be picked up by the scrollable directive and notify.
51-
// The notification should be picked up by the service.
52-
const scrollEvent = document.createEvent('UIEvents');
53-
scrollEvent.initUIEvent('scroll', true, true, window, 0);
54-
fixture.componentInstance.scrollingElement.nativeElement.dispatchEvent(scrollEvent);
55-
56-
expect(hasDirectiveScrollNotified).toBe(true);
57-
expect(hasServiceScrollNotified).toBe(true);
63+
fdescribe('Nested scrollables', () => {
64+
let scroll: ScrollDispatcher;
65+
let fixture: ComponentFixture<NestedScrollingComponent>;
66+
67+
beforeEach(inject([ScrollDispatcher], (s: ScrollDispatcher) => {
68+
scroll = s;
69+
70+
fixture = TestBed.createComponent(NestedScrollingComponent);
71+
fixture.detectChanges();
72+
}));
73+
74+
it('should be able to identify the containing scrollables of an element', () => {
75+
const interestingElement = fixture.componentInstance.interestingElement;
76+
const scrollContainers = scroll.getScrollContainers(interestingElement);
77+
const scrollableElementIds =
78+
scrollContainers.map(scrollable => scrollable.getElementRef().nativeElement.id);
79+
80+
expect(scrollableElementIds).toEqual(['scrollable-1', 'scrollable-1a']);
81+
});
5882
});
5983
});
6084

@@ -68,7 +92,25 @@ class ScrollingComponent {
6892
@ViewChild('scrollingElement') scrollingElement: ElementRef;
6993
}
7094

71-
const TEST_COMPONENTS = [ScrollingComponent];
95+
96+
/** Component containing nested scrollables. */
97+
@Component({
98+
template: `
99+
<div id="scrollable-1" cdk-scrollable>
100+
<div id="scrollable-1a" cdk-scrollable>
101+
<div #interestingElement></div>
102+
</div>
103+
<div id="scrollable-1b" cdk-scrollable></div>
104+
</div>
105+
<div id="scrollable-2" cdk-scrollable></div>
106+
`
107+
})
108+
class NestedScrollingComponent {
109+
@ViewChild('interestingElement') interestingElement: ElementRef;
110+
@ViewChildren(Scrollable) scrollables: QueryList<Scrollable>;
111+
}
112+
113+
const TEST_COMPONENTS = [ScrollingComponent, NestedScrollingComponent];
72114
@NgModule({
73115
imports: [OverlayModule],
74116
providers: [ScrollDispatcher],

src/lib/tooltip/tooltip.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ describe('MdTooltip', () => {
300300
});
301301

302302

303-
fdescribe('scrollable usage', () => {
303+
describe('scrollable usage', () => {
304304
let fixture: ComponentFixture<ScrollableTooltipDemo>;
305305
let buttonDebugElement: DebugElement;
306306
let buttonElement: HTMLButtonElement;

0 commit comments

Comments
 (0)