UNPKG

ipsos-components

Version:

Material Design components for Angular

222 lines (168 loc) 8.41 kB
import {inject, TestBed, async, fakeAsync, ComponentFixture, tick} from '@angular/core/testing'; import {NgModule, Component, ViewChild, ElementRef} from '@angular/core'; import {CdkScrollable, ScrollDispatcher, ScrollDispatchModule} from './public-api'; import {dispatchFakeEvent} from '@angular/cdk/testing'; describe('Scroll Dispatcher', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ScrollTestModule], }); TestBed.compileComponents(); })); describe('Basic usage', () => { let scroll: ScrollDispatcher; let fixture: ComponentFixture<ScrollingComponent>; beforeEach(inject([ScrollDispatcher], (s: ScrollDispatcher) => { scroll = s; fixture = TestBed.createComponent(ScrollingComponent); fixture.detectChanges(); })); it('should be registered with the scrollable directive with the scroll service', () => { const componentScrollable = fixture.componentInstance.scrollable; expect(scroll.scrollContainers.has(componentScrollable)).toBe(true); }); it('should have the scrollable directive deregistered when the component is destroyed', () => { const componentScrollable = fixture.componentInstance.scrollable; expect(scroll.scrollContainers.has(componentScrollable)).toBe(true); fixture.destroy(); expect(scroll.scrollContainers.has(componentScrollable)).toBe(false); }); it('should notify through the directive and service that a scroll event occurred', fakeAsync(() => { // Listen for notifications from scroll directive const scrollable = fixture.componentInstance.scrollable; const directiveSpy = jasmine.createSpy('directive scroll callback'); scrollable.elementScrolled().subscribe(directiveSpy); // Listen for notifications from scroll service with a throttle of 100ms const throttleTime = 100; const serviceSpy = jasmine.createSpy('service scroll callback'); scroll.scrolled(throttleTime).subscribe(serviceSpy); // Emit a scroll event from the scrolling element in our component. // This event should be picked up by the scrollable directive and notify. // The notification should be picked up by the service. dispatchFakeEvent(fixture.componentInstance.scrollingElement.nativeElement, 'scroll', false); // The scrollable directive should have notified the service immediately. expect(directiveSpy).toHaveBeenCalled(); // Verify that the throttle is used, the service should wait for the throttle time until // sending the notification. expect(serviceSpy).not.toHaveBeenCalled(); // After the throttle time, the notification should be sent. tick(throttleTime); expect(serviceSpy).toHaveBeenCalled(); })); it('should not execute the global events in the Angular zone', () => { scroll.scrolled(0).subscribe(() => {}); dispatchFakeEvent(document, 'scroll', false); expect(fixture.ngZone!.isStable).toBe(true); }); it('should not execute the scrollable events in the Angular zone', () => { dispatchFakeEvent(fixture.componentInstance.scrollingElement.nativeElement, 'scroll'); expect(fixture.ngZone!.isStable).toBe(true); }); it('should be able to unsubscribe from the global scrollable', () => { const spy = jasmine.createSpy('global scroll callback'); const subscription = scroll.scrolled(0).subscribe(spy); dispatchFakeEvent(document, 'scroll', false); expect(spy).toHaveBeenCalledTimes(1); subscription.unsubscribe(); dispatchFakeEvent(document, 'scroll', false); expect(spy).toHaveBeenCalledTimes(1); }); }); describe('Nested scrollables', () => { let scroll: ScrollDispatcher; let fixture: ComponentFixture<NestedScrollingComponent>; let element: ElementRef; beforeEach(inject([ScrollDispatcher], (s: ScrollDispatcher) => { scroll = s; fixture = TestBed.createComponent(NestedScrollingComponent); fixture.detectChanges(); element = fixture.componentInstance.interestingElement; })); it('should be able to identify the containing scrollables of an element', () => { const scrollContainers = scroll.getAncestorScrollContainers(element); const scrollableElementIds = scrollContainers.map(scrollable => scrollable.getElementRef().nativeElement.id); expect(scrollableElementIds).toEqual(['scrollable-1', 'scrollable-1a']); }); it('should emit when one of the ancestor scrollable containers is scrolled', () => { const spy = jasmine.createSpy('scroll spy'); const subscription = scroll.ancestorScrolled(element, 0).subscribe(spy); const grandparent = fixture.debugElement.nativeElement.querySelector('#scrollable-1'); dispatchFakeEvent(grandparent, 'scroll', false); expect(spy).toHaveBeenCalledTimes(1); dispatchFakeEvent(window.document, 'scroll', false); expect(spy).toHaveBeenCalledTimes(2); subscription.unsubscribe(); }); it('should not emit when a non-ancestor is scrolled', () => { const spy = jasmine.createSpy('scroll spy'); const subscription = scroll.ancestorScrolled(element, 0).subscribe(spy); const stranger = fixture.debugElement.nativeElement.querySelector('#scrollable-2'); dispatchFakeEvent(stranger, 'scroll', false); expect(spy).not.toHaveBeenCalled(); subscription.unsubscribe(); }); }); describe('lazy subscription', () => { let scroll: ScrollDispatcher; beforeEach(inject([ScrollDispatcher], (s: ScrollDispatcher) => { scroll = s; })); it('should lazily add global listeners as service subscriptions are added and removed', () => { expect(scroll._globalSubscription).toBeNull('Expected no global listeners on init.'); const subscription = scroll.scrolled(0).subscribe(() => {}); expect(scroll._globalSubscription).toBeTruthy( 'Expected global listeners after a subscription has been added.'); subscription.unsubscribe(); expect(scroll._globalSubscription).toBeNull( 'Expected global listeners to have been removed after the subscription has stopped.'); }); it('should remove global listeners on unsubscribe, despite any other live scrollables', () => { const fixture = TestBed.createComponent(NestedScrollingComponent); fixture.detectChanges(); expect(scroll._globalSubscription).toBeNull('Expected no global listeners on init.'); expect(scroll.scrollContainers.size).toBe(4, 'Expected multiple scrollables'); const subscription = scroll.scrolled(0).subscribe(() => {}); expect(scroll._globalSubscription).toBeTruthy( 'Expected global listeners after a subscription has been added.'); subscription.unsubscribe(); expect(scroll._globalSubscription).toBeNull( 'Expected global listeners to have been removed after the subscription has stopped.'); expect(scroll.scrollContainers.size) .toBe(4, 'Expected scrollable count to stay the same'); }); }); }); /** Simple component that contains a large div and can be scrolled. */ @Component({ template: `<div #scrollingElement cdk-scrollable style="height: 9999px"></div>` }) class ScrollingComponent { @ViewChild(CdkScrollable) scrollable: CdkScrollable; @ViewChild('scrollingElement') scrollingElement: ElementRef; } /** Component containing nested scrollables. */ @Component({ template: ` <div id="scrollable-1" cdk-scrollable> <div id="scrollable-1a" cdk-scrollable> <div #interestingElement></div> </div> <div id="scrollable-1b" cdk-scrollable></div> </div> <div id="scrollable-2" cdk-scrollable></div> ` }) class NestedScrollingComponent { @ViewChild('interestingElement') interestingElement: ElementRef; } const TEST_COMPONENTS = [ScrollingComponent, NestedScrollingComponent]; @NgModule({ imports: [ScrollDispatchModule], providers: [ScrollDispatcher], exports: TEST_COMPONENTS, declarations: TEST_COMPONENTS, entryComponents: TEST_COMPONENTS, }) class ScrollTestModule { }