ipsos-components
Version:
Material Design components for Angular
193 lines (144 loc) • 6.9 kB
text/typescript
import {Component, NgModule} from '@angular/core';
import {async, inject, TestBed} from '@angular/core/testing';
import {ComponentPortal, PortalModule} from '@angular/cdk/portal';
import {Platform} from '@angular/cdk/platform';
import {ViewportRuler} from '@angular/cdk/scrolling';
import {Overlay, OverlayContainer, OverlayModule, OverlayRef, OverlayConfig} from '../index';
describe('BlockScrollStrategy', () => {
let platform = new Platform();
let viewport: ViewportRuler;
let overlayRef: OverlayRef;
let componentPortal: ComponentPortal<FocacciaMsg>;
let forceScrollElement: HTMLElement;
beforeEach(async(() => {
// Ensure a clean state for every test.
document.documentElement.classList.remove('cdk-global-scrollblock');
TestBed.configureTestingModule({
imports: [OverlayModule, PortalModule, OverlayTestModule]
}).compileComponents();
}));
beforeEach(inject([Overlay, ViewportRuler], (overlay: Overlay, viewportRuler: ViewportRuler) => {
let overlayConfig = new OverlayConfig({scrollStrategy: overlay.scrollStrategies.block()});
overlayRef = overlay.create(overlayConfig);
componentPortal = new ComponentPortal(FocacciaMsg);
viewport = viewportRuler;
forceScrollElement = document.createElement('div');
document.body.appendChild(forceScrollElement);
forceScrollElement.style.width = '100px';
forceScrollElement.style.height = '3000px';
forceScrollElement.style.background = 'rebeccapurple';
}));
afterEach(inject([OverlayContainer], (container: OverlayContainer) => {
overlayRef.dispose();
document.body.removeChild(forceScrollElement);
window.scroll(0, 0);
container.getContainerElement().parentNode!.removeChild(container.getContainerElement());
}));
it('should toggle scroll blocking along the y axis', skipIOS(() => {
window.scroll(0, 100);
expect(viewport.getViewportScrollPosition().top)
.toBe(100, 'Expected viewport to be scrollable initially.');
overlayRef.attach(componentPortal);
expect(document.documentElement.style.top)
.toBe('-100px', 'Expected <html> element to be offset by the previous scroll amount.');
window.scroll(0, 300);
expect(viewport.getViewportScrollPosition().top)
.toBe(100, 'Expected the viewport not to scroll.');
overlayRef.detach();
expect(viewport.getViewportScrollPosition().top)
.toBe(100, 'Expected old scroll position to have bee restored after disabling.');
window.scroll(0, 300);
expect(viewport.getViewportScrollPosition().top)
.toBe(300, 'Expected user to be able to scroll after disabling.');
}));
it('should toggle scroll blocking along the x axis', skipIOS(() => {
forceScrollElement.style.height = '100px';
forceScrollElement.style.width = '3000px';
window.scroll(100, 0);
expect(viewport.getViewportScrollPosition().left)
.toBe(100, 'Expected viewport to be scrollable initially.');
overlayRef.attach(componentPortal);
expect(document.documentElement.style.left)
.toBe('-100px', 'Expected <html> element to be offset by the previous scroll amount.');
window.scroll(300, 0);
expect(viewport.getViewportScrollPosition().left)
.toBe(100, 'Expected the viewport not to scroll.');
overlayRef.detach();
expect(viewport.getViewportScrollPosition().left)
.toBe(100, 'Expected old scroll position to have bee restored after disabling.');
window.scroll(300, 0);
expect(viewport.getViewportScrollPosition().left)
.toBe(300, 'Expected user to be able to scroll after disabling.');
}));
it('should toggle the `cdk-global-scrollblock` class', skipIOS(() => {
expect(document.documentElement.classList).not.toContain('cdk-global-scrollblock');
overlayRef.attach(componentPortal);
expect(document.documentElement.classList).toContain('cdk-global-scrollblock');
overlayRef.detach();
expect(document.documentElement.classList).not.toContain('cdk-global-scrollblock');
}));
it('should restore any previously-set inline styles', skipIOS(() => {
const root = document.documentElement;
root.style.top = '13px';
root.style.left = '37px';
overlayRef.attach(componentPortal);
expect(root.style.top).not.toBe('13px');
expect(root.style.left).not.toBe('37px');
overlayRef.detach();
expect(root.style.top).toBe('13px');
expect(root.style.left).toBe('37px');
}));
it(`should't do anything if the page isn't scrollable`, skipIOS(() => {
forceScrollElement.style.display = 'none';
overlayRef.attach(componentPortal);
expect(document.documentElement.classList).not.toContain('cdk-global-scrollblock');
}));
it('should keep the content width', () => {
forceScrollElement.style.width = '100px';
const previousContentWidth = document.documentElement.getBoundingClientRect().width;
overlayRef.attach(componentPortal);
expect(document.documentElement.getBoundingClientRect().width).toBe(previousContentWidth);
});
it('should not clobber user-defined scroll-behavior', skipIOS(() => {
const root = document.documentElement;
const body = document.body;
root.style['scrollBehavior'] = body.style['scrollBehavior'] = 'smooth';
// Get the value via the style declaration in order to
// handle browsers that don't support the property yet.
const initialRootValue = root.style['scrollBehavior'];
const initialBodyValue = root.style['scrollBehavior'];
overlayRef.attach(componentPortal);
overlayRef.detach();
expect(root.style['scrollBehavior']).toBe(initialRootValue);
expect(body.style['scrollBehavior']).toBe(initialBodyValue);
// Avoid bleeding styles into other tests.
root.style['scrollBehavior'] = body.style['scrollBehavior'] = '';
}));
/**
* Skips the specified test, if it is being executed on iOS. This is necessary, because
* programmatic scrolling inside the Karma iframe doesn't work on iOS, which renders these
* tests unusable. For example, something as basic as the following won't work:
* ```
* window.scroll(0, 100);
* expect(viewport.getViewportScrollPosition().top).toBe(100);
* ```
* @param spec Test to be executed or skipped.
*/
function skipIOS(spec: Function) {
return () => {
if (!platform.IOS) {
spec();
}
};
}
});
/** Simple component that we can attach to the overlay. */
({template: '<p>Focaccia</p>'})
class FocacciaMsg { }
/** Test module to hold the component. */
({
imports: [OverlayModule, PortalModule],
declarations: [FocacciaMsg],
entryComponents: [FocacciaMsg],
})
class OverlayTestModule { }