From 71246df874c62a67dd4419b911d08edb87ec88e6 Mon Sep 17 00:00:00 2001 From: wnvko Date: Mon, 3 Dec 2018 15:41:59 +0200 Subject: [PATCH 01/11] refactor(igxOverlay): change positioning to use transform translate --- .../src/lib/grids/grid.common.ts | 4 +- .../src/lib/services/overlay/overlay.spec.ts | 72 ++++++++----------- .../position/auto-position-strategy.ts | 8 +-- .../connected-positioning-strategy.ts | 6 +- 4 files changed, 41 insertions(+), 49 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid.common.ts b/projects/igniteui-angular/src/lib/grids/grid.common.ts index 7931c738c29..d0ec7f954e3 100644 --- a/projects/igniteui-angular/src/lib/grids/grid.common.ts +++ b/projects/igniteui-angular/src/lib/grids/grid.common.ts @@ -613,7 +613,9 @@ export class ContainerPositioningStrategy extends ConnectedPositioningStrategy { target.offsetTop + target.getBoundingClientRect().height + contentElement.getBoundingClientRect().height; this.settings.verticalStartPoint = this.isTop ? VerticalAlignment.Top : VerticalAlignment.Bottom; const startPoint = getPointFromPositionsSettings(this.settings, contentElement.parentElement); - contentElement.style.top = startPoint.y + (this.isTop ? VerticalAlignment.Top : VerticalAlignment.Bottom) * size.height + 'px'; + const translateY = startPoint.y + (this.isTop ? VerticalAlignment.Top : VerticalAlignment.Bottom) * size.height; + const translateYString = `translateY(${translateY}px)`; + contentElement.style.transform = contentElement.style.transform.replace(/translateY\(\d+px\)/g, translateYString); contentElement.style.width = target.clientWidth + 'px'; } } diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts index 54bdacf30b7..558cae47862 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts @@ -367,18 +367,15 @@ describe('igxOverlay', () => { }; const connectedStrat1 = new ConnectedPositioningStrategy(mockPositioningSettings1); connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('0px'); - expect(mockItem.style.left).toEqual('-200px'); + expect(mockItem.style.transform).toEqual('translateX(-200px) translateY(0px)'); connectedStrat1.settings.horizontalStartPoint = HorizontalAlignment.Center; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('0px'); - expect(mockItem.style.left).toEqual('-100px'); + expect(mockItem.style.transform).toEqual('translateX(-100px) translateY(0px)'); connectedStrat1.settings.horizontalStartPoint = HorizontalAlignment.Right; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('0px'); - expect(mockItem.style.left).toEqual('0px'); + expect(mockItem.style.transform).toEqual('translateX(0px) translateY(0px)'); right = 0; bottom = 0; @@ -386,18 +383,14 @@ describe('igxOverlay', () => { height = 200; connectedStrat1.settings.verticalStartPoint = VerticalAlignment.Top; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('-200px'); - expect(mockItem.style.left).toEqual('0px'); - + expect(mockItem.style.transform).toEqual('translateX(0px) translateY(-200px)'); connectedStrat1.settings.verticalStartPoint = VerticalAlignment.Middle; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('-100px'); - expect(mockItem.style.left).toEqual('0px'); + expect(mockItem.style.transform).toEqual('translateX(0px) translateY(-100px)'); connectedStrat1.settings.verticalStartPoint = VerticalAlignment.Bottom; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('0px'); - expect(mockItem.style.left).toEqual('0px'); + expect(mockItem.style.transform).toEqual('translateX(0px) translateY(0px)'); right = 0; bottom = 0; @@ -405,18 +398,15 @@ describe('igxOverlay', () => { height = 0; connectedStrat1.settings.verticalDirection = VerticalAlignment.Top; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('-200px'); - expect(mockItem.style.left).toEqual('0px'); + expect(mockItem.style.transform).toEqual('translateX(0px) translateY(-200px)'); connectedStrat1.settings.verticalDirection = VerticalAlignment.Middle; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('-100px'); - expect(mockItem.style.left).toEqual('0px'); + expect(mockItem.style.transform).toEqual('translateX(0px) translateY(-100px)'); connectedStrat1.settings.verticalDirection = VerticalAlignment.Bottom; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('0px'); - expect(mockItem.style.left).toEqual('0px'); + expect(mockItem.style.transform).toEqual('translateX(0px) translateY(0px)'); right = 0; bottom = 0; @@ -424,34 +414,29 @@ describe('igxOverlay', () => { height = 0; connectedStrat1.settings.horizontalDirection = HorizontalAlignment.Left; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('0px'); - expect(mockItem.style.left).toEqual('-200px'); + expect(mockItem.style.transform).toEqual('translateX(-200px) translateY(0px)'); connectedStrat1.settings.horizontalDirection = HorizontalAlignment.Center; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('0px'); - expect(mockItem.style.left).toEqual('-100px'); + expect(mockItem.style.transform).toEqual('translateX(-100px) translateY(0px)'); connectedStrat1.settings.horizontalDirection = HorizontalAlignment.Right; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('0px'); - expect(mockItem.style.left).toEqual('0px'); + expect(mockItem.style.transform).toEqual('translateX(0px) translateY(0px)'); // If target is Point connectedStrat1.settings.target = new Point(0, 0); connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('0px'); - expect(mockItem.style.left).toEqual('0px'); + expect(mockItem.style.transform).toEqual('translateX(0px) translateY(0px)'); // If target is not point or html element, should fallback to new Point(0,0) connectedStrat1.settings.target = 'g'; connectedStrat1.position(mockItem, { width: 200, height: 200 }); - expect(mockItem.style.top).toEqual('0px'); - expect(mockItem.style.left).toEqual('0px'); + expect(mockItem.style.transform).toEqual('translateX(0px) translateY(0px)'); }); it('Should properly call position method - AutoPosition.', () => { - const mockParent = jasmine.createSpyObj('parentElement', ['style', 'lastElementChild']); + const mockParent = jasmine.createSpyObj('parentElement', ['style', 'lastElementChild', 'getBoundingClientRect']); const mockItem = { parentElement: mockParent, clientHeight: 0, clientWidth: 0 } as HTMLElement; spyOn(mockItem, 'parentElement').and.returnValue(mockParent); const mockPositioningSettings1: PositionSettings = { @@ -464,6 +449,7 @@ describe('igxOverlay', () => { const autoStrat1 = new AutoPositionStrategy(mockPositioningSettings1); spyOn(autoStrat1, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); spyOn(ConnectedPositioningStrategy.prototype, 'position'); + mockParent.getBoundingClientRect.and.returnValue(jasmine.createSpyObj('obj', ['left', 'top'])); autoStrat1.position(mockItem.parentElement, null, null, true); expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(2); @@ -1320,8 +1306,8 @@ describe('igxOverlay', () => { const strategy = new ConnectedPositioningStrategy(positionSettings2); strategy.position(contentWrapper, size); fixture.detectChanges(); - expect(contentWrapper.style.top).toBe(expectedTopForPoint[j]); - expect(contentWrapper.style.left).toBe(expectedLeftForPoint[i]); + const transform = `translateX(${expectedLeftForPoint[i]}) translateY(${expectedTopForPoint[j]})`; + expect(contentWrapper.style.transform).toBe(transform); } } document.body.removeChild(contentWrapper); @@ -1368,8 +1354,10 @@ describe('igxOverlay', () => { const strategy = new ConnectedPositioningStrategy(positionSettings2); strategy.position(contentWrapper, size); fixture.detectChanges(); - expect(contentWrapper.style.top).toBe((expectedTopForPoint[j] + 30 * tsp) + 'px'); - expect(contentWrapper.style.left).toBe((expectedLeftForPoint[i] + 50 * lsp) + 'px'); + const translateY = (expectedTopForPoint[j] + 30 * tsp) + 'px'; + const translateX = (expectedLeftForPoint[i] + 50 * lsp) + 'px'; + const transform = `translateX(${translateX}) translateY(${translateY})`; + expect(contentWrapper.style.transform).toBe(transform); } } } @@ -1483,8 +1471,8 @@ describe('igxOverlay', () => { const buttonTop = buttonElement.offsetTop; const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; const expectedTop = buttonTop - wrapperContent.lastElementChild.lastElementChild.clientHeight; - const wrapperLeft = wrapperContent.offsetLeft; - const wrapperTop = wrapperContent.offsetTop; + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; expect(wrapperTop).toEqual(expectedTop); expect(wrapperLeft).toEqual(expectedLeft); })); @@ -2146,8 +2134,8 @@ describe('igxOverlay', () => { const buttonTop = buttonElement.offsetTop; const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.offsetLeft; - const wrapperTop = wrapperContent.offsetTop; + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; expect(wrapperTop).toEqual(expectedTop); expect(wrapperLeft).toEqual(expectedLeft); })); @@ -2194,8 +2182,8 @@ describe('igxOverlay', () => { const buttonTop = buttonElement.offsetTop; const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; // To the left of the button const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.offsetLeft; - const wrapperTop = wrapperContent.offsetTop; + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; expect(wrapperTop).toEqual(expectedTop); expect(wrapperLeft).toEqual(expectedLeft); })); @@ -2242,8 +2230,8 @@ describe('igxOverlay', () => { const buttonTop = buttonElement.offsetTop; const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button const expectedTop = buttonTop - wrapperContent.lastElementChild.clientHeight; // On top of the button - const wrapperLeft = wrapperContent.offsetLeft; - const wrapperTop = wrapperContent.offsetTop; + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; expect(wrapperTop).toEqual(expectedTop); expect(wrapperLeft).toEqual(expectedLeft); })); diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/auto-position-strategy.ts b/projects/igniteui-angular/src/lib/services/overlay/position/auto-position-strategy.ts index 52988b323d1..d8cc893d3d5 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/position/auto-position-strategy.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/position/auto-position-strategy.ts @@ -41,8 +41,8 @@ export class AutoPositionStrategy extends ConnectedPositioningStrategy implement const viewPort = this.getViewPort(document); super.position(contentElement, size); const checkIfMoveHorizontal = (elem: HTMLElement) => { - const leftBound = elem.offsetLeft; - const rightBound = elem.offsetLeft + elem.lastElementChild.clientWidth; + const leftBound = elem.getBoundingClientRect().left; + const rightBound = elem.getBoundingClientRect().right; switch (this.settings.horizontalDirection) { case HorizontalAlignment.Left: if (leftBound < viewPort.left) { @@ -61,8 +61,8 @@ export class AutoPositionStrategy extends ConnectedPositioningStrategy implement } }; const checkIfMoveVertical = (elem: HTMLElement) => { - const topBound = elem.offsetTop; - const bottomBound = elem.offsetTop + elem.lastElementChild.clientHeight; + const topBound = elem.getBoundingClientRect().top; + const bottomBound = elem.getBoundingClientRect().bottom; switch (this.settings.verticalDirection) { case VerticalAlignment.Top: if (topBound < viewPort.top) { diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts b/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts index 5b9f2e4cbc7..04aa5f9c91f 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts @@ -23,8 +23,10 @@ export class ConnectedPositioningStrategy implements IPositionStrategy { position(contentElement: HTMLElement, size: { width: number, height: number}, document?: Document, initialCall?: boolean): void { const startPoint = getPointFromPositionsSettings(this.settings, contentElement.parentElement); - contentElement.style.top = startPoint.y + this.settings.verticalDirection * size.height + 'px'; - contentElement.style.left = startPoint.x + this.settings.horizontalDirection * size.width + 'px'; + let transformString = ''; + transformString += `translateX(${startPoint.x + this.settings.horizontalDirection * size.width}px) `; + transformString += `translateY(${startPoint.y + this.settings.verticalDirection * size.height}px)`; + contentElement.style.transform = transformString.trim(); } } From 3c770ba412decdbb784e787cf48111eae34dad0c Mon Sep 17 00:00:00 2001 From: wnvko Date: Thu, 6 Dec 2018 10:04:05 +0200 Subject: [PATCH 02/11] test(igxOverlay): add tests for Elastic position strategy, #2697 --- .../src/lib/services/overlay/overlay.spec.ts | 915 +++++++++++++++--- .../overlay/position/IPositionStrategy.ts | 5 +- .../lib/services/overlay/position/README.md | 19 +- .../position/auto-position-strategy.ts | 106 +- .../position/base-fit-position-strategy.ts | 71 ++ .../connected-positioning-strategy.ts | 5 +- .../position/elastic-position-strategy.ts | 12 + .../lib/services/overlay/position/index.ts | 1 + .../src/lib/services/overlay/utilities.ts | 8 + 9 files changed, 915 insertions(+), 227 deletions(-) create mode 100644 projects/igniteui-angular/src/lib/services/overlay/position/base-fit-position-strategy.ts create mode 100644 projects/igniteui-angular/src/lib/services/overlay/position/elastic-position-strategy.ts diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts index 558cae47862..9d8e63776dd 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts @@ -15,6 +15,7 @@ import { IgxToggleDirective, IgxToggleModule, IgxOverlayOutletDirective } from ' import { AutoPositionStrategy } from './position/auto-position-strategy'; import { ConnectedPositioningStrategy } from './position/connected-positioning-strategy'; import { GlobalPositionStrategy } from './position/global-position-strategy'; +import { ElasticPositionStrategy } from './position/elastic-position-strategy'; import { PositionSettings, HorizontalAlignment, @@ -36,6 +37,7 @@ import { configureTestSuite } from '../../test-utils/configure-suite'; import { IgxCalendarComponent, IgxCalendarModule } from '../../calendar/index'; import { IgxAvatarComponent, IgxAvatarModule } from '../../avatar/avatar.component'; import { IgxDatePickerComponent, IgxDatePickerModule } from '../../date-picker/date-picker.component'; +import { IPositionStrategy } from './position/IPositionStrategy'; const CLASS_OVERLAY_CONTENT = 'igx-overlay__content'; const CLASS_OVERLAY_CONTENT_MODAL = 'igx-overlay__content--modal'; @@ -112,7 +114,7 @@ function getExpectedLeftPosition(horizontalAlignment: HorizontalAlignment, eleme return expectedLeft; } -describe('igxOverlay', () => { +fdescribe('igxOverlay', () => { beforeEach(async(() => { UIInteractions.clearOverlay(); })); @@ -487,6 +489,58 @@ describe('igxOverlay', () => { expect(autoStrat3.getViewPort).toHaveBeenCalledTimes(0); }); + it('Should properly call position method - ElasticPosition.', () => { + const mockParent = jasmine.createSpyObj('parentElement', ['style', 'lastElementChild', 'getBoundingClientRect']); + const mockItem = { parentElement: mockParent, clientHeight: 0, clientWidth: 0 } as HTMLElement; + spyOn(mockItem, 'parentElement').and.returnValue(mockParent); + const mockPositioningSettings1: PositionSettings = { + horizontalDirection: HorizontalAlignment.Right, + verticalDirection: VerticalAlignment.Bottom, + target: mockItem, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + const autoStrat1 = new ElasticPositionStrategy(mockPositioningSettings1); + spyOn(autoStrat1, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); + spyOn(ConnectedPositioningStrategy.prototype, 'position'); + mockParent.getBoundingClientRect.and.returnValue(jasmine.createSpyObj('obj', ['left', 'top'])); + + autoStrat1.position(mockItem.parentElement, null, null, true); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(2); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledWith(mockItem.parentElement, null); + expect(autoStrat1.getViewPort).toHaveBeenCalledWith(null); + expect(autoStrat1.getViewPort).toHaveBeenCalledTimes(1); + + const mockPositioningSettings2: PositionSettings = { + horizontalDirection: HorizontalAlignment.Left, + verticalDirection: VerticalAlignment.Top, + target: mockItem, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + const autoStrat2 = new ElasticPositionStrategy(mockPositioningSettings2); + spyOn(autoStrat2, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); + + autoStrat2.position(mockItem.parentElement, null, null, true); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(4); + expect(autoStrat2.getViewPort).toHaveBeenCalledWith(null); + expect(autoStrat2.getViewPort).toHaveBeenCalledTimes(1); + + const mockPositioningSettings3: PositionSettings = { + horizontalDirection: HorizontalAlignment.Center, + verticalDirection: VerticalAlignment.Middle, + target: mockItem, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + const autoStrat3 = new ElasticPositionStrategy(mockPositioningSettings3); + spyOn(autoStrat3, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); + + autoStrat3.position(mockItem.parentElement, null, null); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(5); + expect(autoStrat3.getViewPort).toHaveBeenCalledTimes(0); + }); + it('Should properly call AutoPosition getViewPort.', () => { const autoStrat1 = new AutoPositionStrategy(); const docSpy = { @@ -625,7 +679,7 @@ describe('igxOverlay', () => { expect(fix.componentInstance.customComponent.nativeElement.getBoundingClientRect().left).toBe(400); })); - it('fix for @2798 - Allow canceling of open and close of IgxDropDown through onOpening and onClosing events', fakeAsync(() => { + it('fix for #2798 - Allow canceling of open and close of IgxDropDown through onOpening and onClosing events', fakeAsync(() => { const fix = TestBed.createComponent(SimpleRefComponent); fix.detectChanges(); const overlayInstance = fix.componentInstance.overlay; @@ -1450,6 +1504,8 @@ describe('igxOverlay', () => { it('Should show the component inside of the viewport if it would normally be outside of bounds, BOTTOM + RIGHT.', fakeAsync(() => { const fix = TestBed.createComponent(DownRightButtonComponent); fix.detectChanges(); + + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); const currentElement = fix.componentInstance; const buttonElement = fix.componentInstance.buttonElement.nativeElement; fix.detectChanges(); @@ -1789,152 +1845,579 @@ describe('igxOverlay', () => { expect(overlay.hide).toHaveBeenCalledTimes(0); })); - // 3. Interaction - // 3.1 Modal - it('Should apply a greyed-out mask layers when is modal.', fakeAsync(() => { - const fixture = TestBed.createComponent(EmptyPageComponent); + // 1.4 ElasticPosition (resize shown component to fit into visible window) + it('Should render igx-overlay on top of all other views/components (any previously existing html on the page) etc.', + fakeAsync(() => { + const fix = TestBed.createComponent(EmptyPageComponent); + fix.detectChanges(); const overlaySettings: OverlaySettings = { - modal: true, + positionStrategy: new ElasticPositionStrategy(), + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false }; - fixture.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - const overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0]; - tick(); - const styles = css(overlayWrapper); - const expectedBackgroundColor = 'background-color: rgba(0, 0, 0, 0.38)'; - const appliedBackgroundStyles = styles[3]; - expect(appliedBackgroundStyles).toContain(expectedBackgroundColor); - })); - - it('Should allow interaction only for the shown component when is modal.', fakeAsync(() => { - - // Utility handler meant for later detachment - // TO DO replace Spies with css class and/or getBoundingClientRect. - function _handler(event) { - if (event.which === 1) { - fixture.detectChanges(); - tick(); - expect(button.click).toHaveBeenCalledTimes(0); - expect(button.onclick).toHaveBeenCalledTimes(0); - document.removeEventListener('click', _handler); - dummy.remove(); - } - - return event; - } - const fixture = TestBed.createComponent(EmptyPageComponent); - const overlay = fixture.componentInstance.overlay; - const overlaySettings: OverlaySettings = { - modal: true, - closeOnOutsideClick: false, - positionStrategy: new GlobalPositionStrategy() + const positionSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Right, + verticalDirection: VerticalAlignment.Bottom, + target: fix.componentInstance.buttonElement.nativeElement, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top }; - const dummy = document.createElement('button'); - dummy.setAttribute('id', 'dummyButton'); - document.body.appendChild(dummy); - const button = document.getElementById('dummyButton'); - - button.addEventListener('click', _handler); - - spyOn(button, 'click').and.callThrough(); - spyOn(button, 'onclick').and.callThrough(); - spyOn(overlay, 'show').and.callThrough(); - spyOn(overlay, 'hide').and.callThrough(); - - overlay.show(SimpleDynamicComponent, overlaySettings); + overlaySettings.positionStrategy = new ElasticPositionStrategy(positionSettings); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); tick(); - expect(overlay.show).toHaveBeenCalledTimes(1); - expect(overlay.hide).toHaveBeenCalledTimes(0); - - button.dispatchEvent(new MouseEvent('click')); + fix.detectChanges(); + const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; + expect(wrapper).toBeDefined(); + expect(wrapper.classList).toContain(CLASS_OVERLAY_WRAPPER); })); - it('Should closes the component when esc key is pressed.', fakeAsync(() => { - const fixture = TestBed.createComponent(EmptyPageComponent); - const overlay = fixture.componentInstance.overlay; + it('Should cover the whole window 100% width and height.', fakeAsync(() => { + const fix = TestBed.createComponent(EmptyPageComponent); + fix.detectChanges(); const overlaySettings: OverlaySettings = { - modal: true, - positionStrategy: new GlobalPositionStrategy() + positionStrategy: new GlobalPositionStrategy(), + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false }; - - const targetButton = 'Escape'; - const escEvent = new KeyboardEvent('keydown', { - key: targetButton - }); - - overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - - let overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0]; - overlayWrapper.addEventListener('keydown', (event: KeyboardEvent) => { - if (event.key === targetButton) { - overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0]; - } - }); - tick(); - expect(overlayWrapper).toBeTruthy(); - overlayWrapper.dispatchEvent(escEvent); + const positionSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Right, + verticalDirection: VerticalAlignment.Bottom, + target: fix.componentInstance.buttonElement.nativeElement, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + overlaySettings.positionStrategy = new ElasticPositionStrategy(positionSettings); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); tick(); + fix.detectChanges(); + const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; + const body = document.getElementsByTagName('body')[0]; + expect(wrapper.clientHeight).toEqual(body.clientHeight); + expect(wrapper.clientWidth).toEqual(body.clientWidth); })); - // Test fix for #1883 #1820 - it('It should close the component when esc key is pressed and there were other keys pressed prior to esc.', fakeAsync(() => { - const fixture = TestBed.createComponent(EmptyPageComponent); - const overlay = fixture.componentInstance.overlay; + it('Should append the shown component inside the igx-overlay as a last child.', fakeAsync(() => { + const fix = TestBed.createComponent(EmptyPageComponent); + fix.detectChanges(); const overlaySettings: OverlaySettings = { - modal: true, - positionStrategy: new GlobalPositionStrategy() + positionStrategy: new GlobalPositionStrategy(), + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false }; - - const escEvent = new KeyboardEvent('keydown', { - key: 'Escape' - }); - const enterEvent = new KeyboardEvent('keydown', { - key: 'Enter' - }); - const arrowUpEvent = new KeyboardEvent('keydown', { - key: 'ArrowUp' - }); - const aEvent = new KeyboardEvent('keydown', { - key: 'a' - }); - - overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - - let overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0]; - overlayWrapper.addEventListener('keydown', (event: KeyboardEvent) => { - if (event.key === 'Escape') { - overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0]; - expect(overlayWrapper).toBeFalsy(); - } - }); + const positionSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Right, + verticalDirection: VerticalAlignment.Bottom, + target: fix.componentInstance.buttonElement.nativeElement, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + overlaySettings.positionStrategy = new ElasticPositionStrategy(positionSettings); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); tick(); - expect(overlayWrapper).toBeTruthy(); - overlayWrapper.dispatchEvent(enterEvent); - overlayWrapper.dispatchEvent(aEvent); - overlayWrapper.dispatchEvent(arrowUpEvent); - overlayWrapper.dispatchEvent(escEvent); + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1].lastElementChild; // wrapped in NG-COMPONENT + expect(wrapperContent.children.length).toEqual(1); + expect(wrapperContent.lastElementChild.getAttribute('style')) + .toEqual('position: absolute; width:100px; height: 100px; background-color: red'); })); - // 3.2 Non - Modal - it('Should not apply a greyed-out mask layer when is not modal', fakeAsync(() => { - const fixture = TestBed.createComponent(EmptyPageComponent); - const overlaySettings: OverlaySettings = { - modal: false, - }; + it('Should show the component inside of the viewport if it would normally be outside of bounds, BOTTOM + RIGHT.', fakeAsync(() => { + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fixture.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - const overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + fix.componentInstance.positionStrategy.minSize = {width: '80px', height: '80px'}; + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); tick(); - const styles = css(overlayWrapper); - const expectedBackgroundColor = 'background-color: rgba(0, 0, 0, 0.38)'; - const appliedBackgroundStyles = styles[3]; - expect(appliedBackgroundStyles).not.toContain(expectedBackgroundColor); - })); - it('Should not close when esc key is pressed and is not modal (DropDown, Dialog, etc.).', fakeAsync(() => { + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapped in NG-COMPONENT + const expectedStyle = 'position: absolute; width:80px; height: 80px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft; + const expectedTop = buttonTop; + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); + + it('Should display each shown component based on the options specified if the component fits into the visible window.', + fakeAsync(() => { + const fix = TestBed.createComponent(EmptyPageComponent); + fix.detectChanges(); + const button = fix.componentInstance.buttonElement.nativeElement; + const positionSettings: PositionSettings = { + target: button + }; + const overlaySettings: OverlaySettings = { + positionStrategy: new ElasticPositionStrategy(positionSettings), + modal: false, + closeOnOutsideClick: false + }; + const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); + const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); + vAlignmentArray.forEach(function (vAlignment) { + verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Left, VerticalAlignment.Bottom, + HorizontalAlignment.Right, VerticalAlignment[vAlignment]); + hAlignmentArray.forEach(function (hAlignment) { + verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Right, VerticalAlignment.Bottom, + HorizontalAlignment[hAlignment], VerticalAlignment[vAlignment]); + }); + }); + + // TODO: refactor this function and use it in all tests when needed + function verifyOverlayBoundingSizeAndPosition(horizontalDirection, verticalDirection, + horizontalAlignment, verticalAlignment) { + positionSettings.horizontalDirection = horizontalDirection; + positionSettings.verticalDirection = verticalDirection; + positionSettings.horizontalStartPoint = horizontalAlignment; + positionSettings.verticalStartPoint = verticalAlignment; + overlaySettings.positionStrategy = new ElasticPositionStrategy(positionSettings); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + const buttonRect = button.getBoundingClientRect(); + const overlayElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; + const overlayRect = overlayElement.getBoundingClientRect(); + const expectedTop = getExpectedTopPosition(verticalAlignment, buttonRect); + const expectedLeft = horizontalDirection === HorizontalAlignment.Left ? + buttonRect.right - overlayRect.width : + getExpectedLeftPosition(horizontalAlignment, buttonRect); + expect(overlayRect.top.toFixed(1)).toEqual(expectedTop.toFixed(1)); + expect(overlayRect.bottom.toFixed(1)).toEqual((overlayRect.top + overlayRect.height).toFixed(1)); + expect(overlayRect.left.toFixed(1)).toEqual(expectedLeft.toFixed(1)); + expect(overlayRect.right.toFixed(1)).toEqual((overlayRect.left + overlayRect.width).toFixed(1)); + fix.componentInstance.overlay.hideAll(); + } + })); + + it(`Should reposition the component and render it correctly in the window, even when the rendering options passed + should result in otherwise a partially hidden component. No scrollbars should appear.`, + fakeAsync(() => { + const fix = TestBed.createComponent(EmptyPageComponent); + fix.detectChanges(); + const button = fix.componentInstance.buttonElement.nativeElement; + const positionSettings: PositionSettings = { + target: button + }; + const overlaySettings: OverlaySettings = { + positionStrategy: new ElasticPositionStrategy(positionSettings), + modal: false, + closeOnOutsideClick: false + }; + const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); + const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); + hAlignmentArray.forEach(function (hAlignment) { + vAlignmentArray.forEach(function (vAlignment) { + if (hAlignment === 'Center') { + verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Left, VerticalAlignment.Bottom, + HorizontalAlignment.Center, VerticalAlignment[vAlignment]); + } + if (vAlignment !== 'Top') { + verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Right, VerticalAlignment.Top, + HorizontalAlignment[hAlignment], VerticalAlignment[vAlignment]); + if (hAlignment !== 'Left') { + verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Left, VerticalAlignment.Top, + HorizontalAlignment[hAlignment], VerticalAlignment[vAlignment]); + } + } + }); + }); + + // TODO: refactor this function and use it in all tests when needed + function verifyOverlayBoundingSizeAndPosition(horizontalDirection, verticalDirection, + horizontalAlignment, verticalAlignment) { + positionSettings.horizontalDirection = horizontalDirection; + positionSettings.verticalDirection = verticalDirection; + positionSettings.horizontalStartPoint = horizontalAlignment; + positionSettings.verticalStartPoint = verticalAlignment; + overlaySettings.positionStrategy = new ElasticPositionStrategy(positionSettings); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + fix.detectChanges(); + const buttonRect = button.getBoundingClientRect(); + const overlayElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; + const overlayRect = overlayElement.getBoundingClientRect(); + const expectedTop = verticalDirection === VerticalAlignment.Top ? + buttonRect.top + buttonRect.height : + getExpectedTopPosition(verticalAlignment, buttonRect); + const expectedLeft = (horizontalDirection === HorizontalAlignment.Left && + verticalDirection === VerticalAlignment.Top && + horizontalAlignment === HorizontalAlignment.Right) ? + buttonRect.right - overlayRect.width : + (horizontalDirection === HorizontalAlignment.Right && + verticalDirection === VerticalAlignment.Top) ? + getExpectedLeftPosition(horizontalAlignment, buttonRect) : + buttonRect.right; + expect(overlayRect.top.toFixed(1)).toEqual(expectedTop.toFixed(1)); + expect(overlayRect.bottom.toFixed(1)).toEqual((overlayRect.top + overlayRect.height).toFixed(1)); + expect(overlayRect.left.toFixed(1)).toEqual(expectedLeft.toFixed(1)); + expect(overlayRect.right.toFixed(1)).toEqual((overlayRect.left + overlayRect.width).toFixed(1)); + expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar + fix.componentInstance.overlay.hideAll(); + } + })); + + it('Should render margins correctly.', fakeAsync(() => { + const expectedMargin = '0px'; + const fix = TestBed.createComponent(EmptyPageComponent); + fix.detectChanges(); + const button = fix.componentInstance.buttonElement.nativeElement; + const positionSettings: PositionSettings = { + target: button + }; + const overlaySettings: OverlaySettings = { + positionStrategy: new ElasticPositionStrategy(positionSettings), + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false + }; + const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); + const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); + + hAlignmentArray.forEach(function (hDirection) { + vAlignmentArray.forEach(function (vDirection) { + hAlignmentArray.forEach(function (hAlignment) { + vAlignmentArray.forEach(function (vAlignment) { + verifyOverlayMargins(hDirection, vDirection, hAlignment, vAlignment); + }); + }); + }); + }); + + function verifyOverlayMargins(horizontalDirection, verticalDirection, horizontalAlignment, verticalAlignment) { + positionSettings.horizontalDirection = horizontalDirection; + positionSettings.verticalDirection = verticalDirection; + positionSettings.horizontalStartPoint = horizontalAlignment; + positionSettings.verticalStartPoint = verticalAlignment; + overlaySettings.positionStrategy = new ElasticPositionStrategy(positionSettings); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + fix.detectChanges(); + const overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; + const overlayContent = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; + const overlayElement = overlayContent.children[0]; + const wrapperMargin = window.getComputedStyle(overlayWrapper, null).getPropertyValue('margin'); + const contentMargin = window.getComputedStyle(overlayContent, null).getPropertyValue('margin'); + const elementMargin = window.getComputedStyle(overlayElement, null).getPropertyValue('margin'); + expect(wrapperMargin).toEqual(expectedMargin); + expect(contentMargin).toEqual(expectedMargin); + expect(elementMargin).toEqual(expectedMargin); + fix.componentInstance.overlay.hideAll(); + } + })); + + // When adding more than one component to show in igx-overlay: + it('When the options used to fit the component in the window - adding a new instance of the component with the ' + + ' same options will render it on top of the previous one.', fakeAsync(() => { + const fix = TestBed.createComponent(EmptyPageComponent); + fix.detectChanges(); + const button = fix.componentInstance.buttonElement.nativeElement; + const positionSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Right, + verticalDirection: VerticalAlignment.Bottom, + target: button, + horizontalStartPoint: HorizontalAlignment.Center, + verticalStartPoint: VerticalAlignment.Bottom + }; + const overlaySettings: OverlaySettings = { + positionStrategy: new ElasticPositionStrategy(positionSettings), + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false + }; + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + fix.detectChanges(); + tick(); + + const buttonRect = button.getBoundingClientRect(); + const overlayWrapper_1 = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; + const componentEl_1 = overlayWrapper_1.children[0].children[0]; + const overlayWrapper_2 = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[1]; + const componentEl_2 = overlayWrapper_2.children[0].children[0]; + const componentRect_1 = componentEl_1.getBoundingClientRect(); + const componentRect_2 = componentEl_2.getBoundingClientRect(); + expect(componentRect_1.left.toFixed(1)).toEqual((buttonRect.left + buttonRect.width / 2).toFixed(1)); + expect(componentRect_1.left.toFixed(1)).toEqual(componentRect_2.left.toFixed(1)); + expect(componentRect_1.top.toFixed(1)).toEqual((buttonRect.top + buttonRect.height).toFixed(1)); + expect(componentRect_1.top.toFixed(1)).toEqual(componentRect_2.top.toFixed(1)); + expect(componentRect_1.width.toFixed(1)).toEqual(componentRect_2.width.toFixed(1)); + expect(componentRect_1.height.toFixed(1)).toEqual(componentRect_2.height.toFixed(1)); + })); + + // When adding more than one component to show in igx-overlay and the options used will not fit the component in the + // window, so AutoPosition is used. + it('When adding a new instance of the component with the same options, will render it on top of the previous one.', + fakeAsync(() => { + const fix = TestBed.createComponent(EmptyPageComponent); + fix.detectChanges(); + const button = fix.componentInstance.buttonElement.nativeElement; + const positionSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Left, + verticalDirection: VerticalAlignment.Top, + target: button, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + const overlaySettings: OverlaySettings = { + positionStrategy: new ElasticPositionStrategy(positionSettings), + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false + }; + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + fix.detectChanges(); + tick(); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + fix.detectChanges(); + tick(); + const buttonRect = button.getBoundingClientRect(); + const overlayWrapper_1 = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; + const componentEl_1 = overlayWrapper_1.children[0].children[0]; + const overlayWrapper_2 = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[1]; + const componentEl_2 = overlayWrapper_2.children[0].children[0]; + const componentRect_1 = componentEl_1.getBoundingClientRect(); + const componentRect_2 = componentEl_2.getBoundingClientRect(); + expect(componentRect_1.left).toEqual(buttonRect.right); // Will be positioned on the right of the button + expect(componentRect_1.left).toEqual(componentRect_2.left); // Are on the same spot + // expect(componentRect_1.top).toEqual(buttonRect.top - componentEl_1.clientHeight); // Will be positioned on top of button + expect(componentRect_1.top).toEqual(componentRect_2.top); // Will have the same top + expect(componentRect_1.width).toEqual(componentRect_2.width); // Will have the same width + expect(componentRect_1.height).toEqual(componentRect_2.height); // Will have the same height + })); + + it(`Should persist the component's open state when scrolling, when scrolling and noOP scroll strategy is used + (expanded DropDown remains expanded).`, fakeAsync(() => { + // TO DO replace Spies with css class and/or getBoundingClientRect. + const fixture = TestBed.createComponent(EmptyPageComponent); + const scrollTolerance = 10; + const scrollStrategy = new BlockScrollStrategy(); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + modal: false, + scrollStrategy: scrollStrategy, + positionStrategy: new ElasticPositionStrategy() + }; + + spyOn(scrollStrategy, 'initialize').and.callThrough(); + spyOn(scrollStrategy, 'attach').and.callThrough(); + spyOn(scrollStrategy, 'detach').and.callThrough(); + spyOn(overlay, 'hide').and.callThrough(); + + const scrollSpy = spyOn(scrollStrategy, 'onScroll').and.callThrough(); + + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + expect(scrollStrategy.initialize).toHaveBeenCalledTimes(1); + expect(scrollStrategy.attach).toHaveBeenCalledTimes(1); + expect(scrollStrategy.detach).toHaveBeenCalledTimes(0); + expect(overlay.hide).toHaveBeenCalledTimes(0); + document.documentElement.scrollTop += scrollTolerance; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(scrollSpy).toHaveBeenCalledTimes(1); + expect(overlay.hide).toHaveBeenCalledTimes(0); + expect(scrollStrategy.detach).toHaveBeenCalledTimes(0); + })); + + it('Should persist the component open state when scrolling and absolute scroll strategy is used.', fakeAsync(() => { + // TO DO replace Spies with css class and/or getBoundingClientRect. + const fixture = TestBed.createComponent(EmptyPageComponent); + const scrollTolerance = 10; + const scrollStrategy = new AbsoluteScrollStrategy(); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + closeOnOutsideClick: false, + modal: false, + positionStrategy: new ElasticPositionStrategy(), + scrollStrategy: scrollStrategy + }; + + spyOn(scrollStrategy, 'initialize').and.callThrough(); + spyOn(scrollStrategy, 'attach').and.callThrough(); + spyOn(scrollStrategy, 'detach').and.callThrough(); + spyOn(overlay, 'hide').and.callThrough(); + + const scrollSpy = spyOn(scrollStrategy, 'onScroll').and.callThrough(); + + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + expect(scrollStrategy.initialize).toHaveBeenCalledTimes(1); + expect(scrollStrategy.attach).toHaveBeenCalledTimes(1); + + document.documentElement.scrollTop += scrollTolerance; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(scrollSpy).toHaveBeenCalledTimes(1); + expect(scrollStrategy.detach).toHaveBeenCalledTimes(0); + expect(overlay.hide).toHaveBeenCalledTimes(0); + })); + + // 3. Interaction + // 3.1 Modal + it('Should apply a greyed-out mask layers when is modal.', fakeAsync(() => { + const fixture = TestBed.createComponent(EmptyPageComponent); + const overlaySettings: OverlaySettings = { + modal: true, + }; + + fixture.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + const overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0]; + tick(); + const styles = css(overlayWrapper); + const expectedBackgroundColor = 'background-color: rgba(0, 0, 0, 0.38)'; + const appliedBackgroundStyles = styles[3]; + expect(appliedBackgroundStyles).toContain(expectedBackgroundColor); + })); + + it('Should allow interaction only for the shown component when is modal.', fakeAsync(() => { + + // Utility handler meant for later detachment + // TO DO replace Spies with css class and/or getBoundingClientRect. + function _handler(event) { + if (event.which === 1) { + fixture.detectChanges(); + tick(); + expect(button.click).toHaveBeenCalledTimes(0); + expect(button.onclick).toHaveBeenCalledTimes(0); + document.removeEventListener('click', _handler); + dummy.remove(); + } + + return event; + } + const fixture = TestBed.createComponent(EmptyPageComponent); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + modal: true, + closeOnOutsideClick: false, + positionStrategy: new GlobalPositionStrategy() + }; + const dummy = document.createElement('button'); + dummy.setAttribute('id', 'dummyButton'); + document.body.appendChild(dummy); + const button = document.getElementById('dummyButton'); + + button.addEventListener('click', _handler); + + spyOn(button, 'click').and.callThrough(); + spyOn(button, 'onclick').and.callThrough(); + spyOn(overlay, 'show').and.callThrough(); + spyOn(overlay, 'hide').and.callThrough(); + + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + expect(overlay.show).toHaveBeenCalledTimes(1); + expect(overlay.hide).toHaveBeenCalledTimes(0); + + button.dispatchEvent(new MouseEvent('click')); + })); + + it('Should closes the component when esc key is pressed.', fakeAsync(() => { + const fixture = TestBed.createComponent(EmptyPageComponent); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + modal: true, + positionStrategy: new GlobalPositionStrategy() + }; + + const targetButton = 'Escape'; + const escEvent = new KeyboardEvent('keydown', { + key: targetButton + }); + + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + + let overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0]; + overlayWrapper.addEventListener('keydown', (event: KeyboardEvent) => { + if (event.key === targetButton) { + overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0]; + } + }); + tick(); + expect(overlayWrapper).toBeTruthy(); + overlayWrapper.dispatchEvent(escEvent); + tick(); + })); + + // Test fix for #1883 #1820 + it('It should close the component when esc key is pressed and there were other keys pressed prior to esc.', fakeAsync(() => { + const fixture = TestBed.createComponent(EmptyPageComponent); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + modal: true, + positionStrategy: new GlobalPositionStrategy() + }; + + const escEvent = new KeyboardEvent('keydown', { + key: 'Escape' + }); + const enterEvent = new KeyboardEvent('keydown', { + key: 'Enter' + }); + const arrowUpEvent = new KeyboardEvent('keydown', { + key: 'ArrowUp' + }); + const aEvent = new KeyboardEvent('keydown', { + key: 'a' + }); + + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + + let overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0]; + overlayWrapper.addEventListener('keydown', (event: KeyboardEvent) => { + if (event.key === 'Escape') { + overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER_MODAL)[0]; + expect(overlayWrapper).toBeFalsy(); + } + }); + tick(); + expect(overlayWrapper).toBeTruthy(); + + overlayWrapper.dispatchEvent(enterEvent); + overlayWrapper.dispatchEvent(aEvent); + overlayWrapper.dispatchEvent(arrowUpEvent); + overlayWrapper.dispatchEvent(escEvent); + })); + + // 3.2 Non - Modal + it('Should not apply a greyed-out mask layer when is not modal', fakeAsync(() => { + const fixture = TestBed.createComponent(EmptyPageComponent); + const overlaySettings: OverlaySettings = { + modal: false, + }; + + fixture.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + const overlayWrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; + tick(); + const styles = css(overlayWrapper); + const expectedBackgroundColor = 'background-color: rgba(0, 0, 0, 0.38)'; + const appliedBackgroundStyles = styles[3]; + expect(appliedBackgroundStyles).not.toContain(expectedBackgroundColor); + })); + + it('Should not close when esc key is pressed and is not modal (DropDown, Dialog, etc.).', fakeAsync(() => { // Utility handler meant for later detachment function _handler(event) { @@ -2091,8 +2574,8 @@ describe('igxOverlay', () => { scrollStrat.detach(); })); - it('Should show the component inside of the viewport if it would normally be outside of bounds, TOP + LEFT.', - fakeAsync(async () => { + it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, + TOP + LEFT.`, fakeAsync(async () => { TestBed.overrideComponent(DownRightButtonComponent, { set: { styles: [`button { @@ -2111,6 +2594,7 @@ describe('igxOverlay', () => { const fix = TestBed.createComponent(DownRightButtonComponent); fix.detectChanges(); + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); UIInteractions.clearOverlay(); fix.detectChanges(); const currentElement = fix.componentInstance; @@ -2140,8 +2624,8 @@ describe('igxOverlay', () => { expect(wrapperLeft).toEqual(expectedLeft); })); - it('Should show the component inside of the viewport if it would normally be outside of bounds, TOP + RIGHT.', - fakeAsync(async () => { + it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, + TOP + RIGHT.`, fakeAsync(async () => { TestBed.overrideComponent(DownRightButtonComponent, { set: { styles: [`button { @@ -2159,6 +2643,8 @@ describe('igxOverlay', () => { await TestBed.compileComponents(); const fix = TestBed.createComponent(DownRightButtonComponent); fix.detectChanges(); + + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); UIInteractions.clearOverlay(); fix.detectChanges(); const currentElement = fix.componentInstance; @@ -2188,8 +2674,158 @@ describe('igxOverlay', () => { expect(wrapperLeft).toEqual(expectedLeft); })); - it('Should show the component inside of the viewport if it would normally be outside of bounds, BOTTOM + LEFT.', - fakeAsync(async () => { + it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, + BOTTOM + LEFT.`, fakeAsync(async () => { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { + position: absolute; + bottom: 16px; + left: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + }`] + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); + + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); + + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button + const expectedTop = buttonTop - wrapperContent.lastElementChild.clientHeight; // On top of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); + + it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, + TOP + LEFT.`, fakeAsync(async () => { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { + position: absolute; + top: 16px; + left: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + }`] + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); + + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); + + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button + const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); + + it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, + TOP + RIGHT.`, fakeAsync(async () => { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { + position: absolute; + top: 16px; + right: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + }`] + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); + + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); + + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapper in NG-COMPONENT + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; // To the left of the button + const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); + + it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, + BOTTOM + LEFT.`, fakeAsync(async () => { TestBed.overrideComponent(DownRightButtonComponent, { set: { styles: [`button { @@ -2207,6 +2843,8 @@ describe('igxOverlay', () => { await TestBed.compileComponents(); const fix = TestBed.createComponent(DownRightButtonComponent); fix.detectChanges(); + + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); UIInteractions.clearOverlay(); fix.detectChanges(); const currentElement = fix.componentInstance; @@ -2539,6 +3177,7 @@ describe('igxOverlay', () => { })); }); + describe('Integration tests p3 (IgniteUI components): ', () => { beforeAll(() => { TestBed.resetTestingModule(); @@ -2678,7 +3317,7 @@ export class EmptyPageComponent { } @Component({ - template: ``, + template: ``, styles: [`button { position: absolute; bottom: 0px; @@ -2693,6 +3332,8 @@ export class EmptyPageComponent { export class DownRightButtonComponent { constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } + public positionStrategy: IPositionStrategy; + @ViewChild('button') buttonElement: ElementRef; public ButtonPositioningSettings: PositionSettings = { @@ -2702,10 +3343,11 @@ export class DownRightButtonComponent { horizontalStartPoint: HorizontalAlignment.Left, verticalStartPoint: VerticalAlignment.Top }; + click(event) { - const positionStrategy = new AutoPositionStrategy(this.ButtonPositioningSettings); + this.positionStrategy.settings = this.ButtonPositioningSettings; this.overlay.show(SimpleDynamicComponent, { - positionStrategy: positionStrategy, + positionStrategy: this.positionStrategy, scrollStrategy: new NoOpScrollStrategy(), modal: false, closeOnOutsideClick: false @@ -2729,7 +3371,6 @@ export class TopLeftOffsetComponent { @ViewChild('button') buttonElement: ElementRef; click(event) { - const positionStrategy = new ConnectedPositioningStrategy(); this.overlay.show(SimpleDynamicComponent); } } diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/IPositionStrategy.ts b/projects/igniteui-angular/src/lib/services/overlay/position/IPositionStrategy.ts index 3153051d1f6..7c04f9c61b4 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/position/IPositionStrategy.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/position/IPositionStrategy.ts @@ -1,4 +1,4 @@ -import { PositionSettings } from './../utilities'; +import { PositionSettings, Size } from './../utilities'; /** * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/overlay_position.html) @@ -13,9 +13,10 @@ export interface IPositionStrategy { * @param size Size of the element * @param document reference to the Document object * @param initialCall should be true if this is the initial call to the method + * @param minSize the size up to which element could be reduced * ```typescript * settings.positionStrategy.position(content, size, document, true); * ``` */ - position(contentElement: HTMLElement, size?: {}, document?: Document, initialCall?: boolean): void; + position(contentElement: HTMLElement, size?: Size, document?: Document, initialCall?: boolean, minSize?: Size): void; } diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/README.md b/projects/igniteui-angular/src/lib/services/overlay/position/README.md index 6ea3d8b90fe..bd78ecf9d8f 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/position/README.md +++ b/projects/igniteui-angular/src/lib/services/overlay/position/README.md @@ -14,7 +14,13 @@ Position strategies determine where to display the component in the provided Igx |:----------------|:--------------------------|:-------------------------|:-------------------------|:-------------------------| | new Point(0, 0) | HorizontalAlignment.Right | VerticalAlignment.Bottom | HorizontalAlignment.Left | VerticalAlignment.Bottom | -3) **Auto** - Positions the element as in **Connected** positioning strategy and re-positions the element in the view port (calculating a different start point) in case the element is partially getting out of view, adding an offsetPadding. Defaults to: +3) **Auto** - Positions the element as in **Connected** positioning strategy and re-positions the element in the view port (calculating a different start point) in case the element is partially getting out of view. Defaults to: + +| target | horizontalDirection | verticalDirection | horizontalStartPoint | verticalStartPoint | +|:----------------|:--------------------------|:-------------------------|:-------------------------|:-------------------------| +| new Point(0, 0) | HorizontalAlignment.Right | VerticalAlignment.Bottom | HorizontalAlignment.Left | VerticalAlignment.Bottom | + +4) **Elastic** - Positions the element as in **Connected** positioning strategy and resize the element to fit in the view port in case the element is partially getting out of view. Defaults to: | target | horizontalDirection | verticalDirection | horizontalStartPoint | verticalStartPoint | |:----------------|:--------------------------|:-------------------------|:-------------------------|:-------------------------| @@ -48,11 +54,12 @@ import {AutoPositionStrategy, GlobalPositionStrategy, ConnectedPositioningStrate ## API ##### Methods -| Position Strategy | Name | Description | -|:------------------|:---------------------------------------------|:------------------------------------------------| -| Global | `position(contentElement)` | Positions the element, based on the horizontal and vertical directions. | -| Connected | `position(contentElement, size{})` | Positions the element, based on the position strategy used and the size passed in.| -| Auto | `position(contentElement, size{}, document?)`| Positions the element, based on the position strategy used and the size passed in.| +| Position Strategy | Name | Description | +|:------------------|:-------------------------------------------------------|:----------------------------------------------------------------------------------| +| Global | `position(contentElement)` | Positions the element, based on the horizontal and vertical directions. | +| Connected | `position(contentElement, size{})` | Positions the element, based on the position strategy used and the size passed in.| +| Auto | `position(contentElement, size{}, document?)` | Positions the element, based on the position strategy used and the size passed in.| +| Elastic | `position(contentElement, size{}, document?, minSize?)`| Positions the element, based on the position strategy used and the size passed in.| ###### PositionSettings | Name | Type | Description | diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/auto-position-strategy.ts b/projects/igniteui-angular/src/lib/services/overlay/position/auto-position-strategy.ts index d8cc893d3d5..f778dae77d7 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/position/auto-position-strategy.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/position/auto-position-strategy.ts @@ -1,87 +1,35 @@ -import { PositionSettings, VerticalAlignment, HorizontalAlignment, Point } from './../utilities'; +import { VerticalAlignment, HorizontalAlignment, PositionSettings, Size } from './../utilities'; import { IPositionStrategy } from './IPositionStrategy'; -import { ConnectedPositioningStrategy } from './connected-positioning-strategy'; +import { BaseFitPositionStrategy } from './base-fit-position-strategy'; -enum Axis { - X = 1, - Y = 0 -} -export class AutoPositionStrategy extends ConnectedPositioningStrategy implements IPositionStrategy { - public offsetPadding = 16; - private _initialSettings; - getViewPort(document) { // Material Design implementation - const clientRect = document.documentElement.getBoundingClientRect(); - const scrollPosition = { - top: -clientRect.top, - left: -clientRect.left - }; - const width = window.innerWidth; - const height = window.innerHeight; - - return { - top: scrollPosition.top, - left: scrollPosition.left, - bottom: scrollPosition.top + height, - right: scrollPosition.left + width, - height, - width - }; +export class AutoPositionStrategy extends BaseFitPositionStrategy implements IPositionStrategy { + fitHorizontal(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size) { + switch (settings.horizontalDirection) { + case HorizontalAlignment.Left: + settings.horizontalDirection = HorizontalAlignment.Right; + settings.horizontalStartPoint = HorizontalAlignment.Right; + break; + case HorizontalAlignment.Right: + settings.horizontalDirection = HorizontalAlignment.Left; + settings.horizontalStartPoint = HorizontalAlignment.Left; + break; + } + super.position(element, this._initialSize); } - - // The position method should return a
container that will host the component - position(contentElement: HTMLElement, size: { width: number, height: number }, document?: Document, initialCall?: boolean): void { - if (!initialCall) { - super.position(contentElement, size); - return; + fitVertical(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size) { + switch (settings.verticalDirection) { + case VerticalAlignment.Top: + settings.verticalDirection = VerticalAlignment.Bottom; + settings.verticalStartPoint = VerticalAlignment.Bottom; + break; + case VerticalAlignment.Bottom: + settings.verticalDirection = VerticalAlignment.Top; + settings.verticalStartPoint = VerticalAlignment.Top; + break; } - this._initialSettings = this._initialSettings || Object.assign({}, this._initialSettings, this.settings); - this.settings = this._initialSettings ? Object.assign({}, this.settings, this._initialSettings) : this.settings; - const viewPort = this.getViewPort(document); - super.position(contentElement, size); - const checkIfMoveHorizontal = (elem: HTMLElement) => { - const leftBound = elem.getBoundingClientRect().left; - const rightBound = elem.getBoundingClientRect().right; - switch (this.settings.horizontalDirection) { - case HorizontalAlignment.Left: - if (leftBound < viewPort.left) { - this.settings.horizontalDirection = HorizontalAlignment.Right; - this.settings.horizontalStartPoint = HorizontalAlignment.Right; - } - break; - case HorizontalAlignment.Right: - if (rightBound > viewPort.right) { - this.settings.horizontalDirection = HorizontalAlignment.Left; - this.settings.horizontalStartPoint = HorizontalAlignment.Left; - } - break; - default: - return; - } - }; - const checkIfMoveVertical = (elem: HTMLElement) => { - const topBound = elem.getBoundingClientRect().top; - const bottomBound = elem.getBoundingClientRect().bottom; - switch (this.settings.verticalDirection) { - case VerticalAlignment.Top: - if (topBound < viewPort.top) { - this.settings.verticalDirection = VerticalAlignment.Bottom; - this.settings.verticalStartPoint = VerticalAlignment.Bottom; - } - break; - case VerticalAlignment.Bottom: - if (bottomBound > viewPort.bottom) { - this.settings.verticalDirection = VerticalAlignment.Top; - this.settings.verticalStartPoint = VerticalAlignment.Top; - } - break; - default: - return; - } - }; - checkIfMoveVertical(contentElement); - checkIfMoveHorizontal(contentElement); - super.position(contentElement, size); + + super.position(element, this._initialSize); } } diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/base-fit-position-strategy.ts b/projects/igniteui-angular/src/lib/services/overlay/position/base-fit-position-strategy.ts new file mode 100644 index 00000000000..f24cee99912 --- /dev/null +++ b/projects/igniteui-angular/src/lib/services/overlay/position/base-fit-position-strategy.ts @@ -0,0 +1,71 @@ +import { ConnectedPositioningStrategy } from './connected-positioning-strategy'; +import { IPositionStrategy } from './IPositionStrategy'; +import { HorizontalAlignment, VerticalAlignment, PositionSettings, Size } from '../utilities'; + +export abstract class BaseFitPositionStrategy extends ConnectedPositioningStrategy implements IPositionStrategy { + protected _initialSettings: PositionSettings; + protected _initialSize: Size; + + position(contentElement: HTMLElement, size: Size, document?: Document, initialCall?: boolean, minSize?: Size): void { + this._initialSize = size; + super.position(contentElement, size); + if (!initialCall) { + return; + } + this._initialSettings = this._initialSettings || Object.assign({}, this._initialSettings, this.settings); + this.settings = this._initialSettings ? Object.assign({}, this.settings, this._initialSettings) : this.settings; + const elementRect: ClientRect = contentElement.getBoundingClientRect(); + const viewPort: ClientRect = { + left: 0, + top: 0, + right: window.innerWidth, + bottom: window.innerHeight, + width: window.innerWidth, + height: window.innerHeight, + }; + if (this.shouldFitHorizontal(this.settings, elementRect, viewPort)) { + this.fitHorizontal(contentElement, this.settings, elementRect, viewPort, minSize); + } + + if (this.shouldFitVertical(this.settings, elementRect, viewPort)) { + this.fitVertical(contentElement, this.settings, elementRect, viewPort, minSize); + } + } + + protected shouldFitHorizontal(settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect): boolean { + switch (settings.horizontalDirection) { + case HorizontalAlignment.Left: + if (innerRect.left < outerRect.left) { + return true; + } + break; + case HorizontalAlignment.Right: + if (innerRect.right > outerRect.right) { + return true; + } + break; + } + + return false; + } + + protected shouldFitVertical(settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect): boolean { + switch (settings.verticalDirection) { + case VerticalAlignment.Top: + if (innerRect.top < outerRect.top) { + return true; + } + break; + case VerticalAlignment.Bottom: + if (innerRect.bottom > outerRect.bottom) { + return true; + } + break; + } + + return false; + } + + abstract fitHorizontal(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size); + abstract fitVertical(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size); +} diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts b/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts index 04aa5f9c91f..3968cfd4321 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts @@ -1,5 +1,5 @@ import { IPositionStrategy } from './IPositionStrategy'; -import { PositionSettings, Point, HorizontalAlignment, VerticalAlignment, getPointFromPositionsSettings } from './../utilities'; +import { PositionSettings, Point, HorizontalAlignment, VerticalAlignment, getPointFromPositionsSettings, Size } from './../utilities'; import { scaleInVerTop, scaleOutVerTop } from '../../../animations/main'; export class ConnectedPositioningStrategy implements IPositionStrategy { @@ -19,8 +19,7 @@ export class ConnectedPositioningStrategy implements IPositionStrategy { this.settings = Object.assign({}, this._defaultSettings, settings); } - // we no longer use the element inside the position() as its dimensions are cached in rect - position(contentElement: HTMLElement, size: { width: number, height: number}, document?: Document, initialCall?: boolean): void { + position(contentElement: HTMLElement, size: Size, document?: Document, initialCall?: boolean, minSize?: Size): void { const startPoint = getPointFromPositionsSettings(this.settings, contentElement.parentElement); let transformString = ''; diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/elastic-position-strategy.ts b/projects/igniteui-angular/src/lib/services/overlay/position/elastic-position-strategy.ts new file mode 100644 index 00000000000..fd5d1728f7e --- /dev/null +++ b/projects/igniteui-angular/src/lib/services/overlay/position/elastic-position-strategy.ts @@ -0,0 +1,12 @@ +import { IPositionStrategy } from './IPositionStrategy'; +import { BaseFitPositionStrategy } from './base-fit-position-strategy'; +import { Size, HorizontalAlignment, VerticalAlignment, PositionSettings } from '../utilities'; + +export class ElasticPositionStrategy extends BaseFitPositionStrategy implements IPositionStrategy { + fitHorizontal(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size) { + } + + fitVertical(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size) { + } + } +} diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/index.ts b/projects/igniteui-angular/src/lib/services/overlay/position/index.ts index e419860412f..1c3dc6ae418 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/position/index.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/position/index.ts @@ -3,3 +3,4 @@ export * from './IPositionStrategy'; export * from './global-position-strategy'; export * from './connected-positioning-strategy'; export * from './auto-position-strategy'; +export * from './elastic-position-strategy'; diff --git a/projects/igniteui-angular/src/lib/services/overlay/utilities.ts b/projects/igniteui-angular/src/lib/services/overlay/utilities.ts index 797546f0857..66a87713654 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/utilities.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/utilities.ts @@ -60,6 +60,13 @@ export interface OverlayAnimationEventArgs { animationType: 'open' | 'close'; } +export interface Size { + /** Gets or sets the horizontal component of Size */ + width: number; + /** Gets or sets the vertical component of Size */ + height: number; +} + /** @hidden */ export function getPointFromPositionsSettings(settings: PositionSettings, overlayWrapper: HTMLElement): Point { let result: Point = new Point(0, 0); @@ -96,4 +103,5 @@ export interface OverlayInfo { closeAnimationPlayer?: AnimationPlayer; openAnimationInnerPlayer?: any; closeAnimationInnerPlayer?: any; + originalElementStyle?: string; } From da947915e552d466da42f1cd6baa48a4564be05b Mon Sep 17 00:00:00 2001 From: wnvko Date: Thu, 6 Dec 2018 13:36:30 +0200 Subject: [PATCH 03/11] feat(igxOverlay): add elastic position strategy, #2697 --- .../src/lib/grids/grid.common.ts | 4 +- .../src/lib/services/overlay/overlay.spec.ts | 2 +- .../src/lib/services/overlay/overlay.ts | 26 +++--- .../lib/services/overlay/position/README.md | 10 ++- .../connected-positioning-strategy.ts | 12 +-- .../position/elastic-position-strategy.ts | 41 ++++++++++ .../position/global-position-strategy.ts | 7 +- .../src/lib/services/overlay/utilities.ts | 1 + src/app/overlay/overlay.sample.ts | 80 ++++++++++++------- 9 files changed, 130 insertions(+), 53 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid.common.ts b/projects/igniteui-angular/src/lib/grids/grid.common.ts index b7d31199c88..76585bdd1f3 100644 --- a/projects/igniteui-angular/src/lib/grids/grid.common.ts +++ b/projects/igniteui-angular/src/lib/grids/grid.common.ts @@ -614,9 +614,11 @@ export class ContainerPositioningStrategy extends ConnectedPositioningStrategy { this.settings.verticalStartPoint = this.isTop ? VerticalAlignment.Top : VerticalAlignment.Bottom; this.settings.openAnimation = this.isTop ? scaleInVerBottom : scaleInVerTop; const startPoint = getPointFromPositionsSettings(this.settings, contentElement.parentElement); + + // TODO: extract transform setting in util function const translateY = startPoint.y + (this.isTop ? VerticalAlignment.Top : VerticalAlignment.Bottom) * size.height; const translateYString = `translateY(${translateY}px)`; - contentElement.style.transform = contentElement.style.transform.replace(/translateY\(\d+px\)/g, translateYString); + contentElement.style.transform = contentElement.style.transform.replace(/translateY\([.-\d]+px\)/g, translateYString); contentElement.style.width = target.clientWidth + 'px'; } } diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts index 9d8e63776dd..e51bc277d4b 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts @@ -114,7 +114,7 @@ function getExpectedLeftPosition(horizontalAlignment: HorizontalAlignment, eleme return expectedLeft; } -fdescribe('igxOverlay', () => { +describe('igxOverlay', () => { beforeEach(async(() => { UIInteractions.clearOverlay(); })); diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.ts index 4fa58e6c4f2..a9f5dafaaa2 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.ts @@ -116,7 +116,7 @@ export class IgxOverlayService implements OnDestroy { */ // tslint:disable-next-line:unified-signatures show(component: ElementRef | Type<{}>, settings?: OverlaySettings): string; - show(compOrId: string | ElementRef | Type<{}> , settings?: OverlaySettings): string { + show(compOrId: string | ElementRef | Type<{}>, settings?: OverlaySettings): string { let info: OverlayInfo; let id: string; if (typeof compOrId === 'string') { @@ -165,7 +165,13 @@ export class IgxOverlayService implements OnDestroy { this.updateSize(info); this._overlayInfos.push(info); - settings.positionStrategy.position(info.elementRef.nativeElement.parentElement, info.initialSize, document, true); + info.originalElementStyle = info.elementRef.nativeElement.style; + settings.positionStrategy.position( + info.elementRef.nativeElement.parentElement, + { width: info.initialSize.width, height: info.initialSize.height }, + document, + true, + settings.positionStrategy.settings.minSize); settings.scrollStrategy.initialize(this._document, this, id); settings.scrollStrategy.attach(); } @@ -245,16 +251,18 @@ export class IgxOverlayService implements OnDestroy { * ``` */ reposition(id: string) { - const overlay = this.getOverlayById(id); - if (!overlay) { + const overlayInfo = this.getOverlayById(id); + if (!overlayInfo) { console.error('Wrong id provided in overlay.reposition method. Id: ' + id); return; } - overlay.settings.positionStrategy.position( - overlay.elementRef.nativeElement.parentElement, - overlay.initialSize, - this._document); + overlayInfo.settings.positionStrategy.position( + overlayInfo.elementRef.nativeElement.parentElement, + { width: overlayInfo.initialSize.width, height: overlayInfo.initialSize.height }, + this._document, + false, + overlayInfo.settings.positionStrategy.settings.minSize); } private getOverlayInfo(component: any): OverlayInfo { @@ -394,7 +402,7 @@ export class IgxOverlayService implements OnDestroy { this._overlayElement.parentElement.removeChild(this._overlayElement); this._overlayElement = null; } - + info.elementRef.nativeElement.style = info.originalElementStyle; this.onClosed.emit({ id: info.id, componentRef: info.componentRef }); } diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/README.md b/projects/igniteui-angular/src/lib/services/overlay/position/README.md index bd78ecf9d8f..d6791fcbe75 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/position/README.md +++ b/projects/igniteui-angular/src/lib/services/overlay/position/README.md @@ -22,9 +22,9 @@ Position strategies determine where to display the component in the provided Igx 4) **Elastic** - Positions the element as in **Connected** positioning strategy and resize the element to fit in the view port in case the element is partially getting out of view. Defaults to: -| target | horizontalDirection | verticalDirection | horizontalStartPoint | verticalStartPoint | -|:----------------|:--------------------------|:-------------------------|:-------------------------|:-------------------------| -| new Point(0, 0) | HorizontalAlignment.Right | VerticalAlignment.Bottom | HorizontalAlignment.Left | VerticalAlignment.Bottom | +| target | horizontalDirection | verticalDirection | horizontalStartPoint | verticalStartPoint | minSize | +|:----------------|:--------------------------|:-------------------------|:-------------------------|:-------------------------|-------------------------| +| new Point(0, 0) | HorizontalAlignment.Right | VerticalAlignment.Bottom | HorizontalAlignment.Left | VerticalAlignment.Bottom | { width: 0, height: 0 } | ## Usage Position an element based on an existing button as a target, so it's start point is the button's Bottom/Left corner. @@ -34,7 +34,8 @@ const positionSettings: PositionSettings = { horizontalDirection: HorizontalAlignment.Right, verticalDirection: VerticalAlignment.Bottom, horizontalStartPoint: HorizontalAlignment.Left, - verticalStartPoint: VerticalAlignment.Bottom + verticalStartPoint: VerticalAlignment.Bottom, + minSize: { width: 100, height: 300 } }; const strategy = new ConnectedPositioningStrategy(positionSettings); @@ -71,3 +72,4 @@ import {AutoPositionStrategy, GlobalPositionStrategy, ConnectedPositioningStrate |verticalStartPoint | VerticalAlignment | Target's starting point | |openAnimation | AnimationReferenceMetadata | Animation applied while overlay opens | |closeAnimation | AnimationReferenceMetadata | Animation applied while overlay closes | +|minSize | Size | The size up to which element could be reduced | diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts b/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts index 3968cfd4321..1023e0d542e 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/position/connected-positioning-strategy.ts @@ -11,7 +11,8 @@ export class ConnectedPositioningStrategy implements IPositionStrategy { horizontalStartPoint: HorizontalAlignment.Left, verticalStartPoint: VerticalAlignment.Bottom, openAnimation: scaleInVerTop, - closeAnimation: scaleOutVerTop + closeAnimation: scaleOutVerTop, + minSize: { width: 0, height: 0 } }; public settings: PositionSettings; @@ -22,10 +23,11 @@ export class ConnectedPositioningStrategy implements IPositionStrategy { position(contentElement: HTMLElement, size: Size, document?: Document, initialCall?: boolean, minSize?: Size): void { const startPoint = getPointFromPositionsSettings(this.settings, contentElement.parentElement); - let transformString = ''; - transformString += `translateX(${startPoint.x + this.settings.horizontalDirection * size.width}px) `; - transformString += `translateY(${startPoint.y + this.settings.verticalDirection * size.height}px)`; - contentElement.style.transform = transformString.trim(); + // TODO: extract transform setting in util function + let transformString = ''; + transformString += `translateX(${startPoint.x + this.settings.horizontalDirection * size.width}px) `; + transformString += `translateY(${startPoint.y + this.settings.verticalDirection * size.height}px)`; + contentElement.style.transform = transformString.trim(); } } diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/elastic-position-strategy.ts b/projects/igniteui-angular/src/lib/services/overlay/position/elastic-position-strategy.ts index fd5d1728f7e..d598b3aa881 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/position/elastic-position-strategy.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/position/elastic-position-strategy.ts @@ -4,9 +4,50 @@ import { Size, HorizontalAlignment, VerticalAlignment, PositionSettings } from ' export class ElasticPositionStrategy extends BaseFitPositionStrategy implements IPositionStrategy { fitHorizontal(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size) { + switch (settings.horizontalDirection) { + case HorizontalAlignment.Left: { + let extend = outerRect.left - innerRect.left; + if (extend > innerRect.width - minSize.width) { + extend = innerRect.width - minSize.width; + } + const translateX = `translateX(${innerRect.left + extend}px)`; + element.style.transform = element.style.transform.replace(/translateX\([.-\d]+px\)/g, translateX); + (element.firstChild).style.width = `${innerRect.width - extend}px`; + break; + } + case HorizontalAlignment.Right: { + let extend = innerRect.right - outerRect.right; + if (extend > innerRect.width - minSize.width) { + extend = innerRect.width - minSize.width; + } + + (element.firstChild).style.width = `${innerRect.width - extend}px`; + break; + } + } } fitVertical(element: HTMLElement, settings: PositionSettings, innerRect: ClientRect, outerRect: ClientRect, minSize: Size) { + switch (settings.verticalDirection) { + case VerticalAlignment.Top: { + let extend = outerRect.top - innerRect.top; + if (extend > innerRect.height - minSize.height) { + extend = innerRect.height - minSize.height; + } + const translateY = `translateY(${innerRect.top + extend}px)`; + element.style.transform = element.style.transform.replace(/translateY\([.-\d]+px\)/g, translateY); + (element.firstChild).style.height = `${innerRect.width - extend}px`; + break; + } + case VerticalAlignment.Bottom: { + let extend = innerRect.bottom - outerRect.bottom; + if (extend > innerRect.height - minSize.height) { + extend = innerRect.height - minSize.height; + } + + (element.firstChild).style.height = `${innerRect.height - extend}px`; + break; + } } } } diff --git a/projects/igniteui-angular/src/lib/services/overlay/position/global-position-strategy.ts b/projects/igniteui-angular/src/lib/services/overlay/position/global-position-strategy.ts index fb442d24d75..78cdddb6749 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/position/global-position-strategy.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/position/global-position-strategy.ts @@ -1,5 +1,5 @@ import { IPositionStrategy } from './IPositionStrategy'; -import { PositionSettings, Point, HorizontalAlignment, VerticalAlignment } from './../utilities'; +import { PositionSettings, Point, HorizontalAlignment, VerticalAlignment, Size } from './../utilities'; import { fadeIn, fadeOut } from '../../../animations/main'; export class GlobalPositionStrategy implements IPositionStrategy { @@ -9,7 +9,8 @@ export class GlobalPositionStrategy implements IPositionStrategy { horizontalStartPoint: HorizontalAlignment.Center, verticalStartPoint: VerticalAlignment.Middle, openAnimation: fadeIn, - closeAnimation: fadeOut + closeAnimation: fadeOut, + minSize: { width: 0, height: 0 } }; public settings: PositionSettings; @@ -17,7 +18,7 @@ export class GlobalPositionStrategy implements IPositionStrategy { this.settings = Object.assign({}, this._defaultSettings, settings); } - position(contentElement: HTMLElement, size?: { width: number, height: number}, document?: Document, initialCall?: boolean): void { + position(contentElement: HTMLElement, size?: Size, document?: Document, initialCall?: boolean, minSize?: Size): void { switch (this.settings.horizontalDirection) { case HorizontalAlignment.Left: contentElement.parentElement.style.justifyContent = 'flex-start'; diff --git a/projects/igniteui-angular/src/lib/services/overlay/utilities.ts b/projects/igniteui-angular/src/lib/services/overlay/utilities.ts index 66a87713654..c40453761ae 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/utilities.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/utilities.ts @@ -31,6 +31,7 @@ export interface PositionSettings { verticalStartPoint?: VerticalAlignment; openAnimation?: AnimationReferenceMetadata; closeAnimation?: AnimationReferenceMetadata; + minSize?: Size; } export interface OverlaySettings { diff --git a/src/app/overlay/overlay.sample.ts b/src/app/overlay/overlay.sample.ts index 987fa7eb72a..3e95037c2cf 100644 --- a/src/app/overlay/overlay.sample.ts +++ b/src/app/overlay/overlay.sample.ts @@ -9,7 +9,8 @@ import { BlockScrollStrategy, CloseScrollStrategy, NoOpScrollStrategy, - IgxInputGroupModule + IgxInputGroupModule, + ElasticPositionStrategy } from 'igniteui-angular'; import { templateJitUrl } from '@angular/compiler'; @@ -49,7 +50,7 @@ export class OverlaySampleComponent { verticalStartPoints = ['Top', 'Middle', 'Bottom']; verticalStartPoint = 'Top'; - positionStrategies = ['Auto', 'Connected', 'Global']; + positionStrategies = ['Auto', 'Connected', 'Global', 'Elastic']; positionStrategy = 'Auto'; scrollStrategies = ['Absolute', 'Block', 'Close', 'NoOp']; @@ -155,6 +156,22 @@ export class OverlaySampleComponent { this.closeOnOutsideClick = true; this.modal = true; break; + case 'Elastic': + this._overlaySettings = { + positionStrategy: new ElasticPositionStrategy({ + minSize: { width: 50, height: 50 } + }), + scrollStrategy: new NoOpScrollStrategy(), + modal: true, + closeOnOutsideClick: true + }; + this.horizontalDirection = 'Right'; + this.verticalDirection = 'Bottom'; + this.horizontalStartPoint = 'Left'; + this.verticalStartPoint = 'Bottom'; + this.closeOnOutsideClick = true; + this.modal = true; + break; default: break; } @@ -182,35 +199,38 @@ export class OverlaySampleComponent { onChange2() { // WIP const stringMapping = { 'ScrollStrategy': { - 'Absolute' : new AbsoluteScrollStrategy(), - 'Block' : new BlockScrollStrategy(), - 'Close' : new CloseScrollStrategy(), - 'NoOp' : new NoOpScrollStrategy() + 'Absolute': new AbsoluteScrollStrategy(), + 'Block': new BlockScrollStrategy(), + 'Close': new CloseScrollStrategy(), + 'NoOp': new NoOpScrollStrategy() }, - 'PositionStrategy' : { - 'Auto' : new AutoPositionStrategy(), - 'Connected' : new ConnectedPositioningStrategy(), - 'Global' : new GlobalPositionStrategy() + 'PositionStrategy': { + 'Auto': new AutoPositionStrategy(), + 'Connected': new ConnectedPositioningStrategy(), + 'Global': new GlobalPositionStrategy(), + 'Elastic': new ElasticPositionStrategy({ + minSize: { width: 50, height: 50 } + }), }, - 'VerticalDirection' : { - 'Top' : -1, - 'Middle' : -0.5, - 'Bottom' : 0 + 'VerticalDirection': { + 'Top': -1, + 'Middle': -0.5, + 'Bottom': 0 }, - 'VerticalStartPoint' : { - 'Top' : -1, - 'Middle' : -0.5, - 'Bottom' : 0 + 'VerticalStartPoint': { + 'Top': -1, + 'Middle': -0.5, + 'Bottom': 0 }, - 'HorizontalDirection' : { - 'Left' : -1, - 'Center' : -0.5, - 'Right' : 0 + 'HorizontalDirection': { + 'Left': -1, + 'Center': -0.5, + 'Right': 0 }, - 'HorizontalStartPoint' : { - 'Left' : -1, - 'Center' : -0.5, - 'Right' : 0 + 'HorizontalStartPoint': { + 'Left': -1, + 'Center': -0.5, + 'Right': 0 } }; @@ -221,13 +241,13 @@ export class OverlaySampleComponent { closeOnOutsideClick: this.closeOnOutsideClick }; this._overlaySettings.positionStrategy.settings.verticalDirection = - stringMapping['VerticalDirection'][this.verticalDirection]; + stringMapping['VerticalDirection'][this.verticalDirection]; this._overlaySettings.positionStrategy.settings.verticalStartPoint = - stringMapping['VerticalStartPoint'][this.verticalStartPoint]; + stringMapping['VerticalStartPoint'][this.verticalStartPoint]; this._overlaySettings.positionStrategy.settings.horizontalDirection = - stringMapping['HorizontalDirection'][this.horizontalDirection]; + stringMapping['HorizontalDirection'][this.horizontalDirection]; this._overlaySettings.positionStrategy.settings.horizontalStartPoint = - stringMapping['HorizontalStartPoint'][this.horizontalStartPoint]; + stringMapping['HorizontalStartPoint'][this.horizontalStartPoint]; } onSwitchChange(ev) { From d30b5013b07f6c4608055a5bd1e43e6bb218c3f5 Mon Sep 17 00:00:00 2001 From: wnvko Date: Fri, 7 Dec 2018 16:12:54 +0200 Subject: [PATCH 04/11] test(igxOverlay): fix some failing tests, #2697 --- .../src/lib/services/overlay/overlay.spec.ts | 982 ++++++++---------- 1 file changed, 435 insertions(+), 547 deletions(-) diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts index e51bc277d4b..31f63a64d67 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts @@ -276,6 +276,7 @@ describe('igxOverlay', () => { spyOn(overlayInstance.onClosing, 'emit'); spyOn(overlayInstance.onOpened, 'emit'); spyOn(overlayInstance.onOpening, 'emit'); + spyOn(overlayInstance.onAnimation, 'emit'); const firstCallId = overlayInstance.show(SimpleDynamicComponent); tick(); @@ -285,6 +286,7 @@ describe('igxOverlay', () => { .toHaveBeenCalledWith({ id: firstCallId, componentRef: jasmine.any(ComponentRef), cancel: false }); const args: OverlayEventArgs = (overlayInstance.onOpening.emit as jasmine.Spy).calls.mostRecent().args[0]; expect(args.componentRef.instance).toEqual(jasmine.any(SimpleDynamicComponent)); + expect(overlayInstance.onAnimation.emit).toHaveBeenCalledTimes(1); tick(); expect(overlayInstance.onOpened.emit).toHaveBeenCalledTimes(1); @@ -295,6 +297,7 @@ describe('igxOverlay', () => { expect(overlayInstance.onClosing.emit).toHaveBeenCalledTimes(1); expect(overlayInstance.onClosing.emit) .toHaveBeenCalledWith({ id: firstCallId, componentRef: jasmine.any(ComponentRef), cancel: false }); + expect(overlayInstance.onAnimation.emit).toHaveBeenCalledTimes(2); tick(); expect(overlayInstance.onClosed.emit).toHaveBeenCalledTimes(1); @@ -304,6 +307,7 @@ describe('igxOverlay', () => { tick(); expect(overlayInstance.onOpening.emit).toHaveBeenCalledTimes(2); expect(overlayInstance.onOpening.emit).toHaveBeenCalledWith({ componentRef: undefined, id: secondCallId, cancel: false }); + expect(overlayInstance.onAnimation.emit).toHaveBeenCalledTimes(3); tick(); expect(overlayInstance.onOpened.emit).toHaveBeenCalledTimes(2); @@ -313,13 +317,14 @@ describe('igxOverlay', () => { tick(); expect(overlayInstance.onClosing.emit).toHaveBeenCalledTimes(2); expect(overlayInstance.onClosing.emit).toHaveBeenCalledWith({ componentRef: undefined, id: secondCallId, cancel: false }); + expect(overlayInstance.onAnimation.emit).toHaveBeenCalledTimes(4); tick(); expect(overlayInstance.onClosed.emit).toHaveBeenCalledTimes(2); expect(overlayInstance.onClosed.emit).toHaveBeenCalledWith({ componentRef: undefined, id: secondCallId }); })); - it('Should properly call position method - GlobalPosition.', () => { + it('Should properly set style on position method call - GlobalPosition.', () => { const mockParent = document.createElement('div'); const mockItem = document.createElement('div'); mockParent.appendChild(mockItem); @@ -347,7 +352,7 @@ describe('igxOverlay', () => { } }); - it('Should properly call position method - ConnectedPosition.', () => { + it('Should properly set style on position method call - ConnectedPosition.', () => { const mockParent = jasmine.createSpyObj('parentElement', ['style', 'lastElementChild']); const mockItem = document.createElement('div'); let width = 200; @@ -449,15 +454,12 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat1 = new AutoPositionStrategy(mockPositioningSettings1); - spyOn(autoStrat1, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); spyOn(ConnectedPositioningStrategy.prototype, 'position'); mockParent.getBoundingClientRect.and.returnValue(jasmine.createSpyObj('obj', ['left', 'top'])); - autoStrat1.position(mockItem.parentElement, null, null, true); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(2); + autoStrat1.position(mockItem.parentElement, null, null, true, null); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(1); expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledWith(mockItem.parentElement, null); - expect(autoStrat1.getViewPort).toHaveBeenCalledWith(null); - expect(autoStrat1.getViewPort).toHaveBeenCalledTimes(1); const mockPositioningSettings2: PositionSettings = { horizontalDirection: HorizontalAlignment.Left, @@ -467,12 +469,9 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat2 = new AutoPositionStrategy(mockPositioningSettings2); - spyOn(autoStrat2, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); - autoStrat2.position(mockItem.parentElement, null, null, true); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(4); - expect(autoStrat2.getViewPort).toHaveBeenCalledWith(null); - expect(autoStrat2.getViewPort).toHaveBeenCalledTimes(1); + autoStrat2.position(mockItem.parentElement, null, null, true, null); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(2); const mockPositioningSettings3: PositionSettings = { horizontalDirection: HorizontalAlignment.Center, @@ -482,11 +481,9 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat3 = new AutoPositionStrategy(mockPositioningSettings3); - spyOn(autoStrat3, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); autoStrat3.position(mockItem.parentElement, null, null); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(5); - expect(autoStrat3.getViewPort).toHaveBeenCalledTimes(0); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(3); }); it('Should properly call position method - ElasticPosition.', () => { @@ -501,15 +498,12 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat1 = new ElasticPositionStrategy(mockPositioningSettings1); - spyOn(autoStrat1, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); spyOn(ConnectedPositioningStrategy.prototype, 'position'); mockParent.getBoundingClientRect.and.returnValue(jasmine.createSpyObj('obj', ['left', 'top'])); - autoStrat1.position(mockItem.parentElement, null, null, true); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(2); + autoStrat1.position(mockItem.parentElement, null, null, true, null); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(1); expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledWith(mockItem.parentElement, null); - expect(autoStrat1.getViewPort).toHaveBeenCalledWith(null); - expect(autoStrat1.getViewPort).toHaveBeenCalledTimes(1); const mockPositioningSettings2: PositionSettings = { horizontalDirection: HorizontalAlignment.Left, @@ -519,12 +513,9 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat2 = new ElasticPositionStrategy(mockPositioningSettings2); - spyOn(autoStrat2, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); - autoStrat2.position(mockItem.parentElement, null, null, true); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(4); - expect(autoStrat2.getViewPort).toHaveBeenCalledWith(null); - expect(autoStrat2.getViewPort).toHaveBeenCalledTimes(1); + autoStrat2.position(mockItem.parentElement, null, null, true, null); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(2); const mockPositioningSettings3: PositionSettings = { horizontalDirection: HorizontalAlignment.Center, @@ -534,34 +525,9 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat3 = new ElasticPositionStrategy(mockPositioningSettings3); - spyOn(autoStrat3, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); autoStrat3.position(mockItem.parentElement, null, null); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(5); - expect(autoStrat3.getViewPort).toHaveBeenCalledTimes(0); - }); - - it('Should properly call AutoPosition getViewPort.', () => { - const autoStrat1 = new AutoPositionStrategy(); - const docSpy = { - documentElement: { - getBoundingClientRect: () => { - return { - top: 1920, - left: 768 - }; - } - } - }; - spyOn(document, 'documentElement').and.returnValue(1); - expect(autoStrat1.getViewPort(docSpy)).toEqual({ - top: -1920, - left: -768, - bottom: -1920 + window.innerHeight, - right: -768 + + window.innerWidth, - height: window.innerHeight, - width: window.innerWidth - }); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(3); }); it('fix for #1690 - click on second filter does not close first one.', fakeAsync(() => { @@ -639,25 +605,25 @@ describe('igxOverlay', () => { })); it('fix for #2475 - An error is thrown for IgxOverlay when showing a component' + - 'instance that is not attached to the DOM', fakeAsync(() => { - const fix = TestBed.createComponent(SimpleRefComponent); - fix.detectChanges(); - fix.elementRef.nativeElement.parentElement.removeChild(fix.elementRef.nativeElement); - fix.componentInstance.overlay.show(fix.elementRef); - - tick(); - const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; - expect(overlayDiv).toBeDefined(); - expect(overlayDiv.children.length).toEqual(1); - const wrapperDiv = overlayDiv.children[0]; - expect(wrapperDiv).toBeDefined(); - expect(wrapperDiv.classList.contains(CLASS_OVERLAY_WRAPPER_MODAL)).toBeTruthy(); - expect(wrapperDiv.children[0].localName).toEqual('div'); + 'instance that is not attached to the DOM', fakeAsync(() => { + const fix = TestBed.createComponent(SimpleRefComponent); + fix.detectChanges(); + fix.elementRef.nativeElement.parentElement.removeChild(fix.elementRef.nativeElement); + fix.componentInstance.overlay.show(fix.elementRef); - const contentDiv = wrapperDiv.children[0]; - expect(contentDiv).toBeDefined(); - expect(contentDiv.classList.contains(CLASS_OVERLAY_CONTENT_MODAL)).toBeTruthy(); - })); + tick(); + const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; + expect(overlayDiv).toBeDefined(); + expect(overlayDiv.children.length).toEqual(1); + const wrapperDiv = overlayDiv.children[0]; + expect(wrapperDiv).toBeDefined(); + expect(wrapperDiv.classList.contains(CLASS_OVERLAY_WRAPPER_MODAL)).toBeTruthy(); + expect(wrapperDiv.children[0].localName).toEqual('div'); + + const contentDiv = wrapperDiv.children[0]; + expect(contentDiv).toBeDefined(); + expect(contentDiv.classList.contains(CLASS_OVERLAY_CONTENT_MODAL)).toBeTruthy(); + })); it('fix for #2486 - filtering dropdown is not correctly positioned', fakeAsync(() => { const fix = TestBed.createComponent(WidthTestOverlayComponent); @@ -717,7 +683,8 @@ describe('igxOverlay', () => { })); }); - describe('Unit Tests p2 (overrides): ', () => { + describe('Unit Tests - Scroll Strategies: ', () => { + configureTestSuite(); beforeEach(async(() => { TestBed.configureTestingModule({ imports: [IgxToggleModule, DynamicModule, NoopAnimationsModule], @@ -727,7 +694,7 @@ describe('igxOverlay', () => { afterAll(() => { TestBed.resetTestingModule(); }); - it('Should properly initialize Scroll Strategy - Block.', fakeAsync( async () => { + it('Should properly initialize Scroll Strategy - Block.', fakeAsync(async () => { TestBed.overrideComponent(EmptyPageComponent, { set: { styles: [`button { @@ -858,31 +825,30 @@ describe('igxOverlay', () => { // 1. Positioning Strategies // 1.1 Global (show components in the window center - default). - it('Should render igx-overlay on top of all other views/components (any previously existing html on the page) etc.', - fakeAsync(() => { - const fixture = TestBed.createComponent(EmptyPageComponent); - fixture.detectChanges(); - const overlaySettings: OverlaySettings = { - positionStrategy: new GlobalPositionStrategy(), - scrollStrategy: new NoOpScrollStrategy(), - modal: false, - closeOnOutsideClick: false - }; - const positionSettings: PositionSettings = { - horizontalDirection: HorizontalAlignment.Right, - verticalDirection: VerticalAlignment.Bottom, - target: fixture.componentInstance.buttonElement.nativeElement, - horizontalStartPoint: HorizontalAlignment.Left, - verticalStartPoint: VerticalAlignment.Top - }; - overlaySettings.positionStrategy = new GlobalPositionStrategy(positionSettings); - fixture.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - fixture.detectChanges(); - const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; - const wrapper = overlayDiv.children[0]; - expect(wrapper.classList).toContain(CLASS_OVERLAY_WRAPPER); - })); + it('Should correctly render igx-overlay', fakeAsync(() => { + const fixture = TestBed.createComponent(EmptyPageComponent); + fixture.detectChanges(); + const overlaySettings: OverlaySettings = { + positionStrategy: new GlobalPositionStrategy(), + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false + }; + const positionSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Right, + verticalDirection: VerticalAlignment.Bottom, + target: fixture.componentInstance.buttonElement.nativeElement, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + overlaySettings.positionStrategy = new GlobalPositionStrategy(positionSettings); + fixture.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + fixture.detectChanges(); + const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; + const wrapper = overlayDiv.children[0]; + expect(wrapper.classList).toContain(CLASS_OVERLAY_WRAPPER); + })); it('Should cover the whole window 100% width and height.', fakeAsync(() => { const fixture = TestBed.createComponent(EmptyPageComponent); @@ -895,11 +861,10 @@ describe('igxOverlay', () => { const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; const overlayWrapper = overlayDiv.children[0]; const overlayRect = overlayWrapper.getBoundingClientRect(); - const windowRect = document.body.getBoundingClientRect(); - expect(overlayRect.width).toEqual(windowRect.width); - expect(overlayRect.height).toEqual(windowRect.height); - expect(overlayRect.left).toEqual(windowRect.left); - expect(overlayRect.top).toEqual(windowRect.top); + expect(overlayRect.width).toEqual(window.innerWidth); + expect(overlayRect.height).toEqual(window.innerHeight); + expect(overlayRect.left).toEqual(0); + expect(overlayRect.top).toEqual(0); })); it('Should show the component inside the igx-overlay wrapper as a content last child.', fakeAsync(() => { @@ -969,12 +934,9 @@ describe('igxOverlay', () => { const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; const overlayWrapper = overlayDiv.children[0] as HTMLElement; const componentEl = overlayWrapper.children[0].children[0]; - const wrapperRect = overlayWrapper.getBoundingClientRect(); const componentRect = componentEl.getBoundingClientRect(); - expect(wrapperRect.width / 2 - componentRect.width / 2).toEqual(componentRect.left); - expect(wrapperRect.height / 2 - componentRect.height / 2).toEqual(componentRect.top); - expect(componentRect.left).toEqual(componentRect.right - componentRect.width); - expect(componentRect.top).toEqual(componentRect.bottom - componentRect.height); + expect((window.innerWidth - componentRect.width) / 2).toEqual(componentRect.left); + expect((window.innerHeight - componentRect.height) / 2).toEqual(componentRect.top); })); it('Should display a new instance of the same component/options exactly on top of the previous one.', fakeAsync(() => { @@ -1057,7 +1019,7 @@ describe('igxOverlay', () => { })); // 1.2 ConnectedPositioningStrategy(show components based on a specified position base point, horizontal and vertical alignment) - it('Should render on top of all other views/components (any previously existing html on the page) etc.', fakeAsync(() => { + it('Should correctly render igx-overlay', fakeAsync(() => { const fixture = TestBed.createComponent(EmptyPageComponent); fixture.detectChanges(); const overlaySettings: OverlaySettings = { @@ -1101,9 +1063,8 @@ describe('igxOverlay', () => { fixture.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); tick(); const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; - const body = document.getElementsByTagName('body')[0]; - expect(wrapper.clientHeight).toEqual(body.clientHeight); - expect(wrapper.clientWidth).toEqual(body.clientWidth); + expect(wrapper.clientHeight).toEqual(window.innerHeight); + expect(wrapper.clientWidth).toEqual(window.innerWidth); })); it('It should position the shown component inside the igx-overlay wrapper as a content last child.', fakeAsync(() => { @@ -1143,13 +1104,14 @@ describe('igxOverlay', () => { horizontalStartPoint: HorizontalAlignment.Left, verticalStartPoint: VerticalAlignment.Bottom, openAnimation: scaleInVerTop, - closeAnimation: scaleOutVerTop + closeAnimation: scaleOutVerTop, + minSize: { width: 0, height: 0 } }; expect(strategy.settings).toEqual(expectedDefaults); }); - it(`Should use target: null StartPoint:Left/Bottom, Direction Right/Bottom and openAnimation: scaleInVerTop, + it(`Should use target: null StartPoint:Left/Bottom, Direction Right/Bottom and openAnimation: scaleInVerTop, closeAnimation: scaleOutVerTop as default options when using a ConnectedPositioningStrategy without passing options.`, () => { const strategy = new ConnectedPositioningStrategy(); @@ -1160,7 +1122,8 @@ describe('igxOverlay', () => { horizontalStartPoint: HorizontalAlignment.Left, verticalStartPoint: VerticalAlignment.Bottom, openAnimation: scaleInVerTop, - closeAnimation: scaleOutVerTop + closeAnimation: scaleOutVerTop, + minSize: { width: 0, height: 0 } }; expect(strategy.settings).toEqual(expectedDefaults); @@ -1420,32 +1383,31 @@ describe('igxOverlay', () => { }); // 1.3 AutoPosition (fit the shown component into the visible window.) - it('Should render igx-overlay on top of all other views/components (any previously existing html on the page) etc.', - fakeAsync(() => { - const fix = TestBed.createComponent(EmptyPageComponent); - fix.detectChanges(); - const overlaySettings: OverlaySettings = { - positionStrategy: new GlobalPositionStrategy(), - scrollStrategy: new NoOpScrollStrategy(), - modal: false, - closeOnOutsideClick: false - }; + it('Should correctly render igx-overlay', fakeAsync(() => { + const fix = TestBed.createComponent(EmptyPageComponent); + fix.detectChanges(); + const overlaySettings: OverlaySettings = { + positionStrategy: new AutoPositionStrategy(), + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false + }; - const positionSettings: PositionSettings = { - horizontalDirection: HorizontalAlignment.Right, - verticalDirection: VerticalAlignment.Bottom, - target: fix.componentInstance.buttonElement.nativeElement, - horizontalStartPoint: HorizontalAlignment.Left, - verticalStartPoint: VerticalAlignment.Top - }; - overlaySettings.positionStrategy = new AutoPositionStrategy(positionSettings); - fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - fix.detectChanges(); - const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; - expect(wrapper).toBeDefined(); - expect(wrapper.classList).toContain(CLASS_OVERLAY_WRAPPER); - })); + const positionSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Right, + verticalDirection: VerticalAlignment.Bottom, + target: fix.componentInstance.buttonElement.nativeElement, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + overlaySettings.positionStrategy = new AutoPositionStrategy(positionSettings); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + fix.detectChanges(); + const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; + expect(wrapper).toBeDefined(); + expect(wrapper.classList).toContain(CLASS_OVERLAY_WRAPPER); + })); it('Should cover the whole window 100% width and height.', fakeAsync(() => { const fix = TestBed.createComponent(EmptyPageComponent); @@ -1468,9 +1430,8 @@ describe('igxOverlay', () => { tick(); fix.detectChanges(); const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; - const body = document.getElementsByTagName('body')[0]; - expect(wrapper.clientHeight).toEqual(body.clientHeight); - expect(wrapper.clientWidth).toEqual(body.clientWidth); + expect(wrapper.clientHeight).toEqual(window.innerHeight); + expect(wrapper.clientWidth).toEqual(window.innerWidth); })); it('Should append the shown component inside the igx-overlay as a last child.', fakeAsync(() => { @@ -1846,8 +1807,7 @@ describe('igxOverlay', () => { })); // 1.4 ElasticPosition (resize shown component to fit into visible window) - it('Should render igx-overlay on top of all other views/components (any previously existing html on the page) etc.', - fakeAsync(() => { + it('Should correctly render igx-overlay', fakeAsync(() => { const fix = TestBed.createComponent(EmptyPageComponent); fix.detectChanges(); const overlaySettings: OverlaySettings = { @@ -1894,16 +1854,15 @@ describe('igxOverlay', () => { tick(); fix.detectChanges(); const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; - const body = document.getElementsByTagName('body')[0]; - expect(wrapper.clientHeight).toEqual(body.clientHeight); - expect(wrapper.clientWidth).toEqual(body.clientWidth); + expect(wrapper.clientHeight).toEqual(window.innerHeight); + expect(wrapper.clientWidth).toEqual(window.innerWidth); })); it('Should append the shown component inside the igx-overlay as a last child.', fakeAsync(() => { const fix = TestBed.createComponent(EmptyPageComponent); fix.detectChanges(); const overlaySettings: OverlaySettings = { - positionStrategy: new GlobalPositionStrategy(), + positionStrategy: new ElasticPositionStrategy(), scrollStrategy: new NoOpScrollStrategy(), modal: false, closeOnOutsideClick: false @@ -1932,28 +1891,24 @@ describe('igxOverlay', () => { fix.detectChanges(); fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); - fix.componentInstance.positionStrategy.minSize = {width: '80px', height: '80px'}; - const currentElement = fix.componentInstance; + const component = fix.componentInstance; const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.target = buttonElement; + component.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; + component.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; + component.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; + component.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; + component.ButtonPositioningSettings.target = buttonElement; + component.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; buttonElement.click(); - fix.detectChanges(); tick(); - fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapped in NG-COMPONENT - const expectedStyle = 'position: absolute; width:80px; height: 80px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft; - const expectedTop = buttonTop; + expect(wrapperContent.lastElementChild.clientWidth).toEqual(80); + expect(wrapperContent.lastElementChild.clientHeight).toEqual(80); + const expectedLeft = buttonElement.offsetLeft + buttonElement.offsetWidth; + const expectedTop = buttonElement.offsetTop + buttonElement.offsetHeight; const wrapperLeft = wrapperContent.getBoundingClientRect().left; const wrapperTop = wrapperContent.getBoundingClientRect().top; expect(wrapperTop).toEqual(expectedTop); @@ -2009,73 +1964,6 @@ describe('igxOverlay', () => { } })); - it(`Should reposition the component and render it correctly in the window, even when the rendering options passed - should result in otherwise a partially hidden component. No scrollbars should appear.`, - fakeAsync(() => { - const fix = TestBed.createComponent(EmptyPageComponent); - fix.detectChanges(); - const button = fix.componentInstance.buttonElement.nativeElement; - const positionSettings: PositionSettings = { - target: button - }; - const overlaySettings: OverlaySettings = { - positionStrategy: new ElasticPositionStrategy(positionSettings), - modal: false, - closeOnOutsideClick: false - }; - const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); - const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); - hAlignmentArray.forEach(function (hAlignment) { - vAlignmentArray.forEach(function (vAlignment) { - if (hAlignment === 'Center') { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Left, VerticalAlignment.Bottom, - HorizontalAlignment.Center, VerticalAlignment[vAlignment]); - } - if (vAlignment !== 'Top') { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Right, VerticalAlignment.Top, - HorizontalAlignment[hAlignment], VerticalAlignment[vAlignment]); - if (hAlignment !== 'Left') { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Left, VerticalAlignment.Top, - HorizontalAlignment[hAlignment], VerticalAlignment[vAlignment]); - } - } - }); - }); - - // TODO: refactor this function and use it in all tests when needed - function verifyOverlayBoundingSizeAndPosition(horizontalDirection, verticalDirection, - horizontalAlignment, verticalAlignment) { - positionSettings.horizontalDirection = horizontalDirection; - positionSettings.verticalDirection = verticalDirection; - positionSettings.horizontalStartPoint = horizontalAlignment; - positionSettings.verticalStartPoint = verticalAlignment; - overlaySettings.positionStrategy = new ElasticPositionStrategy(positionSettings); - fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - fix.detectChanges(); - const buttonRect = button.getBoundingClientRect(); - const overlayElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; - const overlayRect = overlayElement.getBoundingClientRect(); - const expectedTop = verticalDirection === VerticalAlignment.Top ? - buttonRect.top + buttonRect.height : - getExpectedTopPosition(verticalAlignment, buttonRect); - const expectedLeft = (horizontalDirection === HorizontalAlignment.Left && - verticalDirection === VerticalAlignment.Top && - horizontalAlignment === HorizontalAlignment.Right) ? - buttonRect.right - overlayRect.width : - (horizontalDirection === HorizontalAlignment.Right && - verticalDirection === VerticalAlignment.Top) ? - getExpectedLeftPosition(horizontalAlignment, buttonRect) : - buttonRect.right; - expect(overlayRect.top.toFixed(1)).toEqual(expectedTop.toFixed(1)); - expect(overlayRect.bottom.toFixed(1)).toEqual((overlayRect.top + overlayRect.height).toFixed(1)); - expect(overlayRect.left.toFixed(1)).toEqual(expectedLeft.toFixed(1)); - expect(overlayRect.right.toFixed(1)).toEqual((overlayRect.left + overlayRect.width).toFixed(1)); - expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar - fix.componentInstance.overlay.hideAll(); - } - })); - it('Should render margins correctly.', fakeAsync(() => { const expectedMargin = '0px'; const fix = TestBed.createComponent(EmptyPageComponent); @@ -2165,7 +2053,7 @@ describe('igxOverlay', () => { })); // When adding more than one component to show in igx-overlay and the options used will not fit the component in the - // window, so AutoPosition is used. + // window, so element is resized. it('When adding a new instance of the component with the same options, will render it on top of the previous one.', fakeAsync(() => { const fix = TestBed.createComponent(EmptyPageComponent); @@ -2176,7 +2064,8 @@ describe('igxOverlay', () => { verticalDirection: VerticalAlignment.Top, target: button, horizontalStartPoint: HorizontalAlignment.Left, - verticalStartPoint: VerticalAlignment.Top + verticalStartPoint: VerticalAlignment.Top, + minSize: { width: 80, height: 80 } }; const overlaySettings: OverlaySettings = { positionStrategy: new ElasticPositionStrategy(positionSettings), @@ -2187,9 +2076,11 @@ describe('igxOverlay', () => { fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); fix.detectChanges(); tick(); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); fix.detectChanges(); tick(); + const buttonRect = button.getBoundingClientRect(); const overlayWrapper_1 = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; const componentEl_1 = overlayWrapper_1.children[0].children[0]; @@ -2197,12 +2088,11 @@ describe('igxOverlay', () => { const componentEl_2 = overlayWrapper_2.children[0].children[0]; const componentRect_1 = componentEl_1.getBoundingClientRect(); const componentRect_2 = componentEl_2.getBoundingClientRect(); - expect(componentRect_1.left).toEqual(buttonRect.right); // Will be positioned on the right of the button - expect(componentRect_1.left).toEqual(componentRect_2.left); // Are on the same spot - // expect(componentRect_1.top).toEqual(buttonRect.top - componentEl_1.clientHeight); // Will be positioned on top of button - expect(componentRect_1.top).toEqual(componentRect_2.top); // Will have the same top - expect(componentRect_1.width).toEqual(componentRect_2.width); // Will have the same width - expect(componentRect_1.height).toEqual(componentRect_2.height); // Will have the same height + expect(componentRect_1.left).toEqual(buttonRect.left - positionSettings.minSize.width); + expect(componentRect_1.left).toEqual(componentRect_2.left); + expect(componentRect_1.top).toEqual(componentRect_2.top); + expect(componentRect_1.width).toEqual(componentRect_2.width); + expect(componentRect_1.height).toEqual(componentRect_2.height); })); it(`Should persist the component's open state when scrolling, when scrolling and noOP scroll strategy is used @@ -2474,7 +2364,8 @@ describe('igxOverlay', () => { })); }); - describe('Integration tests p2 (overrides): ', () => { + describe('Integration tests - Scroll Strategies: ', () => { + configureTestSuite(); beforeEach(async(() => { TestBed.configureTestingModule({ imports: [IgxToggleModule, DynamicModule, NoopAnimationsModule], @@ -2483,7 +2374,7 @@ describe('igxOverlay', () => { })); // If adding a component near the visible window borders(left,right,up,down) // it should be partially hidden and based on scroll strategy: - it('Should not allow scrolling with scroll strategy is not passed.', fakeAsync( async () => { + it('Should not allow scrolling with scroll strategy is not passed.', fakeAsync(async () => { TestBed.overrideComponent(EmptyPageComponent, { set: { styles: [`button { @@ -2576,9 +2467,9 @@ describe('igxOverlay', () => { it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; top: 16px; left: 16px; @@ -2588,47 +2479,47 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new AutoPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button - const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button + const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + RIGHT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; top: 16px; right: 16px; @@ -2638,47 +2529,47 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); - - fix.componentInstance.positionStrategy = new AutoPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapper in NG-COMPONENT - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; // To the left of the button - const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); + + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapper in NG-COMPONENT + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; // To the left of the button + const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, BOTTOM + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; bottom: 16px; left: 16px; @@ -2688,47 +2579,47 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new AutoPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button - const expectedTop = buttonTop - wrapperContent.lastElementChild.clientHeight; // On top of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button + const expectedTop = buttonTop - wrapperContent.lastElementChild.clientHeight; // On top of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; top: 16px; left: 16px; @@ -2738,47 +2629,44 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + currentElement.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; + buttonElement.click(); + tick(); + fix.detectChanges(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button - const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button + const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + RIGHT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; top: 16px; right: 16px; @@ -2788,47 +2676,47 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapper in NG-COMPONENT - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; // To the left of the button - const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapper in NG-COMPONENT + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; // To the left of the button + const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, BOTTOM + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; bottom: 16px; left: 16px; @@ -2838,43 +2726,43 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button - const expectedTop = buttonTop - wrapperContent.lastElementChild.clientHeight; // On top of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button + const expectedTop = buttonTop - wrapperContent.lastElementChild.clientHeight; // On top of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); - // 2. Scroll Strategy (test with GlobalPositionStrategy(default)) + // 2. Scroll Strategy (test with GlobalPositionStrategy(default)) // 2.1. Scroll Strategy - None it('Should not scroll component, nor the window when none scroll strategy is passed. No scrolling happens.', fakeAsync(async () => { TestBed.overrideComponent(EmptyPageComponent, { @@ -2913,117 +2801,117 @@ describe('igxOverlay', () => { it(`Should not close the shown component when none scroll strategy is passed. (example: expanded DropDown stays expanded during a scrolling attempt.)`, - fakeAsync(async () => { - TestBed.overrideComponent(EmptyPageComponent, { - set: { - styles: [`button { + fakeAsync(async () => { + TestBed.overrideComponent(EmptyPageComponent, { + set: { + styles: [`button { position: absolute; top: 120%; left:120%; }`] - } - }); - await TestBed.compileComponents(); - const fixture = TestBed.createComponent(EmptyPageComponent); - fixture.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fixture = TestBed.createComponent(EmptyPageComponent); + fixture.detectChanges(); - const overlaySettings: OverlaySettings = { - modal: false, - }; - const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + modal: false, + }; + const overlay = fixture.componentInstance.overlay; - overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - const contentWrapper = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; - const element = contentWrapper.firstChild as HTMLElement; - const elementRect = element.getBoundingClientRect(); + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + const contentWrapper = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; + const element = contentWrapper.firstChild as HTMLElement; + const elementRect = element.getBoundingClientRect(); - document.documentElement.scrollTop = 40; - document.documentElement.scrollLeft = 30; - document.dispatchEvent(new Event('scroll')); - tick(); + document.documentElement.scrollTop = 40; + document.documentElement.scrollLeft = 30; + document.dispatchEvent(new Event('scroll')); + tick(); - expect(elementRect).toEqual(element.getBoundingClientRect()); - expect(document.documentElement.scrollTop).toEqual(40); - expect(document.documentElement.scrollLeft).toEqual(30); - expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); - })); + expect(elementRect).toEqual(element.getBoundingClientRect()); + expect(document.documentElement.scrollTop).toEqual(40); + expect(document.documentElement.scrollLeft).toEqual(30); + expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); + })); // 2.2 Scroll Strategy - Closing. (Uses a tolerance and closes an expanded component upon scrolling if the tolerance is exceeded.) // (example: DropDown or Dialog component collapse/closes after scrolling 10px.) it('Should scroll until the set threshold is exceeded, and closing scroll strategy is used.', - fakeAsync(async () => { - TestBed.overrideComponent(EmptyPageComponent, { - set: { - styles: [ - 'button { position: absolute; top: 100%; left: 90% }' - ] - } - }); - await TestBed.compileComponents(); - const fixture = TestBed.createComponent(EmptyPageComponent); - fixture.detectChanges(); + fakeAsync(async () => { + TestBed.overrideComponent(EmptyPageComponent, { + set: { + styles: [ + 'button { position: absolute; top: 100%; left: 90% }' + ] + } + }); + await TestBed.compileComponents(); + const fixture = TestBed.createComponent(EmptyPageComponent); + fixture.detectChanges(); - const scrollTolerance = 10; - const scrollStrategy = new CloseScrollStrategy(); - const overlay = fixture.componentInstance.overlay; - const overlaySettings: OverlaySettings = { - positionStrategy: new GlobalPositionStrategy(), - scrollStrategy: scrollStrategy, - modal: false - }; + const scrollTolerance = 10; + const scrollStrategy = new CloseScrollStrategy(); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + positionStrategy: new GlobalPositionStrategy(), + scrollStrategy: scrollStrategy, + modal: false + }; - overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); - document.documentElement.scrollTop = scrollTolerance; - document.dispatchEvent(new Event('scroll')); - tick(); - expect(document.documentElement.scrollTop).toEqual(scrollTolerance); - expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); + document.documentElement.scrollTop = scrollTolerance; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(document.documentElement.scrollTop).toEqual(scrollTolerance); + expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); - document.documentElement.scrollTop = scrollTolerance * 2; - document.dispatchEvent(new Event('scroll')); - tick(); - expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(0); + document.documentElement.scrollTop = scrollTolerance * 2; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(0); - })); + })); it(`Should not change the shown component shown state until it exceeds the scrolling tolerance set, and closing scroll strategy is used.`, - fakeAsync(async () => { - TestBed.overrideComponent(EmptyPageComponent, { - set: { - styles: [ - 'button { position: absolute; top: 200%; left: 90% }' - ] - } - }); - await TestBed.compileComponents(); - const fixture = TestBed.createComponent(EmptyPageComponent); - fixture.detectChanges(); + fakeAsync(async () => { + TestBed.overrideComponent(EmptyPageComponent, { + set: { + styles: [ + 'button { position: absolute; top: 200%; left: 90% }' + ] + } + }); + await TestBed.compileComponents(); + const fixture = TestBed.createComponent(EmptyPageComponent); + fixture.detectChanges(); - const scrollTolerance = 10; - const scrollStrategy = new CloseScrollStrategy(); - const overlay = fixture.componentInstance.overlay; - const overlaySettings: OverlaySettings = { - positionStrategy: new GlobalPositionStrategy(), - scrollStrategy: scrollStrategy, - closeOnOutsideClick: false, - modal: false - }; + const scrollTolerance = 10; + const scrollStrategy = new CloseScrollStrategy(); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + positionStrategy: new GlobalPositionStrategy(), + scrollStrategy: scrollStrategy, + closeOnOutsideClick: false, + modal: false + }; - overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - expect(document.documentElement.scrollTop).toEqual(0); + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + expect(document.documentElement.scrollTop).toEqual(0); - document.documentElement.scrollTop += scrollTolerance; - document.dispatchEvent(new Event('scroll')); - tick(); - expect(document.documentElement.scrollTop).toEqual(scrollTolerance); - expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); - fixture.destroy(); - })); + document.documentElement.scrollTop += scrollTolerance; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(document.documentElement.scrollTop).toEqual(scrollTolerance); + expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); + fixture.destroy(); + })); it(`Should close the shown component shown when it exceeds the scrolling threshold set, and closing scroll strategy is used. (an expanded DropDown, Menu, DatePicker, etc. collapses).`, fakeAsync(async () => { @@ -3106,7 +2994,7 @@ describe('igxOverlay', () => { it('Should scroll everything except component when scrolling and absolute scroll strategy is used.', fakeAsync(async () => { // Should behave as NoOpScrollStrategy - TestBed.overrideComponent(EmptyPageComponent, { + TestBed.overrideComponent(EmptyPageComponent, { set: { styles: [ 'button { position: absolute; top:200%; left: 100%; }', From 9bd28c8cba2e8d2dbd30df69242461be16011877 Mon Sep 17 00:00:00 2001 From: wnvko Date: Fri, 7 Dec 2018 16:12:54 +0200 Subject: [PATCH 05/11] test(igxOverlay): fix some failing tests, #2697 --- .../src/lib/services/overlay/overlay.spec.ts | 1055 ++++++++--------- 1 file changed, 466 insertions(+), 589 deletions(-) diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts index e51bc277d4b..2e940cd2ea8 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts @@ -114,7 +114,7 @@ function getExpectedLeftPosition(horizontalAlignment: HorizontalAlignment, eleme return expectedLeft; } -describe('igxOverlay', () => { +fdescribe('igxOverlay', () => { beforeEach(async(() => { UIInteractions.clearOverlay(); })); @@ -276,6 +276,7 @@ describe('igxOverlay', () => { spyOn(overlayInstance.onClosing, 'emit'); spyOn(overlayInstance.onOpened, 'emit'); spyOn(overlayInstance.onOpening, 'emit'); + spyOn(overlayInstance.onAnimation, 'emit'); const firstCallId = overlayInstance.show(SimpleDynamicComponent); tick(); @@ -285,6 +286,7 @@ describe('igxOverlay', () => { .toHaveBeenCalledWith({ id: firstCallId, componentRef: jasmine.any(ComponentRef), cancel: false }); const args: OverlayEventArgs = (overlayInstance.onOpening.emit as jasmine.Spy).calls.mostRecent().args[0]; expect(args.componentRef.instance).toEqual(jasmine.any(SimpleDynamicComponent)); + expect(overlayInstance.onAnimation.emit).toHaveBeenCalledTimes(1); tick(); expect(overlayInstance.onOpened.emit).toHaveBeenCalledTimes(1); @@ -295,6 +297,7 @@ describe('igxOverlay', () => { expect(overlayInstance.onClosing.emit).toHaveBeenCalledTimes(1); expect(overlayInstance.onClosing.emit) .toHaveBeenCalledWith({ id: firstCallId, componentRef: jasmine.any(ComponentRef), cancel: false }); + expect(overlayInstance.onAnimation.emit).toHaveBeenCalledTimes(2); tick(); expect(overlayInstance.onClosed.emit).toHaveBeenCalledTimes(1); @@ -304,6 +307,7 @@ describe('igxOverlay', () => { tick(); expect(overlayInstance.onOpening.emit).toHaveBeenCalledTimes(2); expect(overlayInstance.onOpening.emit).toHaveBeenCalledWith({ componentRef: undefined, id: secondCallId, cancel: false }); + expect(overlayInstance.onAnimation.emit).toHaveBeenCalledTimes(3); tick(); expect(overlayInstance.onOpened.emit).toHaveBeenCalledTimes(2); @@ -313,13 +317,14 @@ describe('igxOverlay', () => { tick(); expect(overlayInstance.onClosing.emit).toHaveBeenCalledTimes(2); expect(overlayInstance.onClosing.emit).toHaveBeenCalledWith({ componentRef: undefined, id: secondCallId, cancel: false }); + expect(overlayInstance.onAnimation.emit).toHaveBeenCalledTimes(4); tick(); expect(overlayInstance.onClosed.emit).toHaveBeenCalledTimes(2); expect(overlayInstance.onClosed.emit).toHaveBeenCalledWith({ componentRef: undefined, id: secondCallId }); })); - it('Should properly call position method - GlobalPosition.', () => { + it('Should properly set style on position method call - GlobalPosition.', () => { const mockParent = document.createElement('div'); const mockItem = document.createElement('div'); mockParent.appendChild(mockItem); @@ -347,7 +352,7 @@ describe('igxOverlay', () => { } }); - it('Should properly call position method - ConnectedPosition.', () => { + it('Should properly set style on position method call - ConnectedPosition.', () => { const mockParent = jasmine.createSpyObj('parentElement', ['style', 'lastElementChild']); const mockItem = document.createElement('div'); let width = 200; @@ -449,15 +454,12 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat1 = new AutoPositionStrategy(mockPositioningSettings1); - spyOn(autoStrat1, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); spyOn(ConnectedPositioningStrategy.prototype, 'position'); mockParent.getBoundingClientRect.and.returnValue(jasmine.createSpyObj('obj', ['left', 'top'])); - autoStrat1.position(mockItem.parentElement, null, null, true); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(2); + autoStrat1.position(mockItem.parentElement, null, null, true, null); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(1); expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledWith(mockItem.parentElement, null); - expect(autoStrat1.getViewPort).toHaveBeenCalledWith(null); - expect(autoStrat1.getViewPort).toHaveBeenCalledTimes(1); const mockPositioningSettings2: PositionSettings = { horizontalDirection: HorizontalAlignment.Left, @@ -467,12 +469,9 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat2 = new AutoPositionStrategy(mockPositioningSettings2); - spyOn(autoStrat2, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); - autoStrat2.position(mockItem.parentElement, null, null, true); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(4); - expect(autoStrat2.getViewPort).toHaveBeenCalledWith(null); - expect(autoStrat2.getViewPort).toHaveBeenCalledTimes(1); + autoStrat2.position(mockItem.parentElement, null, null, true, null); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(2); const mockPositioningSettings3: PositionSettings = { horizontalDirection: HorizontalAlignment.Center, @@ -482,11 +481,9 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat3 = new AutoPositionStrategy(mockPositioningSettings3); - spyOn(autoStrat3, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); autoStrat3.position(mockItem.parentElement, null, null); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(5); - expect(autoStrat3.getViewPort).toHaveBeenCalledTimes(0); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(3); }); it('Should properly call position method - ElasticPosition.', () => { @@ -501,15 +498,12 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat1 = new ElasticPositionStrategy(mockPositioningSettings1); - spyOn(autoStrat1, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); spyOn(ConnectedPositioningStrategy.prototype, 'position'); mockParent.getBoundingClientRect.and.returnValue(jasmine.createSpyObj('obj', ['left', 'top'])); - autoStrat1.position(mockItem.parentElement, null, null, true); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(2); + autoStrat1.position(mockItem.parentElement, null, null, true, null); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(1); expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledWith(mockItem.parentElement, null); - expect(autoStrat1.getViewPort).toHaveBeenCalledWith(null); - expect(autoStrat1.getViewPort).toHaveBeenCalledTimes(1); const mockPositioningSettings2: PositionSettings = { horizontalDirection: HorizontalAlignment.Left, @@ -519,12 +513,9 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat2 = new ElasticPositionStrategy(mockPositioningSettings2); - spyOn(autoStrat2, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); - autoStrat2.position(mockItem.parentElement, null, null, true); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(4); - expect(autoStrat2.getViewPort).toHaveBeenCalledWith(null); - expect(autoStrat2.getViewPort).toHaveBeenCalledTimes(1); + autoStrat2.position(mockItem.parentElement, null, null, true, null); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(2); const mockPositioningSettings3: PositionSettings = { horizontalDirection: HorizontalAlignment.Center, @@ -534,34 +525,9 @@ describe('igxOverlay', () => { verticalStartPoint: VerticalAlignment.Top }; const autoStrat3 = new ElasticPositionStrategy(mockPositioningSettings3); - spyOn(autoStrat3, 'getViewPort').and.returnValue(jasmine.createSpyObj('obj', ['left', 'top', 'right', 'bottom'])); autoStrat3.position(mockItem.parentElement, null, null); - expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(5); - expect(autoStrat3.getViewPort).toHaveBeenCalledTimes(0); - }); - - it('Should properly call AutoPosition getViewPort.', () => { - const autoStrat1 = new AutoPositionStrategy(); - const docSpy = { - documentElement: { - getBoundingClientRect: () => { - return { - top: 1920, - left: 768 - }; - } - } - }; - spyOn(document, 'documentElement').and.returnValue(1); - expect(autoStrat1.getViewPort(docSpy)).toEqual({ - top: -1920, - left: -768, - bottom: -1920 + window.innerHeight, - right: -768 + + window.innerWidth, - height: window.innerHeight, - width: window.innerWidth - }); + expect(ConnectedPositioningStrategy.prototype.position).toHaveBeenCalledTimes(3); }); it('fix for #1690 - click on second filter does not close first one.', fakeAsync(() => { @@ -639,25 +605,25 @@ describe('igxOverlay', () => { })); it('fix for #2475 - An error is thrown for IgxOverlay when showing a component' + - 'instance that is not attached to the DOM', fakeAsync(() => { - const fix = TestBed.createComponent(SimpleRefComponent); - fix.detectChanges(); - fix.elementRef.nativeElement.parentElement.removeChild(fix.elementRef.nativeElement); - fix.componentInstance.overlay.show(fix.elementRef); - - tick(); - const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; - expect(overlayDiv).toBeDefined(); - expect(overlayDiv.children.length).toEqual(1); - const wrapperDiv = overlayDiv.children[0]; - expect(wrapperDiv).toBeDefined(); - expect(wrapperDiv.classList.contains(CLASS_OVERLAY_WRAPPER_MODAL)).toBeTruthy(); - expect(wrapperDiv.children[0].localName).toEqual('div'); + 'instance that is not attached to the DOM', fakeAsync(() => { + const fix = TestBed.createComponent(SimpleRefComponent); + fix.detectChanges(); + fix.elementRef.nativeElement.parentElement.removeChild(fix.elementRef.nativeElement); + fix.componentInstance.overlay.show(fix.elementRef); - const contentDiv = wrapperDiv.children[0]; - expect(contentDiv).toBeDefined(); - expect(contentDiv.classList.contains(CLASS_OVERLAY_CONTENT_MODAL)).toBeTruthy(); - })); + tick(); + const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; + expect(overlayDiv).toBeDefined(); + expect(overlayDiv.children.length).toEqual(1); + const wrapperDiv = overlayDiv.children[0]; + expect(wrapperDiv).toBeDefined(); + expect(wrapperDiv.classList.contains(CLASS_OVERLAY_WRAPPER_MODAL)).toBeTruthy(); + expect(wrapperDiv.children[0].localName).toEqual('div'); + + const contentDiv = wrapperDiv.children[0]; + expect(contentDiv).toBeDefined(); + expect(contentDiv.classList.contains(CLASS_OVERLAY_CONTENT_MODAL)).toBeTruthy(); + })); it('fix for #2486 - filtering dropdown is not correctly positioned', fakeAsync(() => { const fix = TestBed.createComponent(WidthTestOverlayComponent); @@ -717,7 +683,8 @@ describe('igxOverlay', () => { })); }); - describe('Unit Tests p2 (overrides): ', () => { + describe('Unit Tests - Scroll Strategies: ', () => { + configureTestSuite(); beforeEach(async(() => { TestBed.configureTestingModule({ imports: [IgxToggleModule, DynamicModule, NoopAnimationsModule], @@ -727,7 +694,7 @@ describe('igxOverlay', () => { afterAll(() => { TestBed.resetTestingModule(); }); - it('Should properly initialize Scroll Strategy - Block.', fakeAsync( async () => { + it('Should properly initialize Scroll Strategy - Block.', fakeAsync(async () => { TestBed.overrideComponent(EmptyPageComponent, { set: { styles: [`button { @@ -858,31 +825,30 @@ describe('igxOverlay', () => { // 1. Positioning Strategies // 1.1 Global (show components in the window center - default). - it('Should render igx-overlay on top of all other views/components (any previously existing html on the page) etc.', - fakeAsync(() => { - const fixture = TestBed.createComponent(EmptyPageComponent); - fixture.detectChanges(); - const overlaySettings: OverlaySettings = { - positionStrategy: new GlobalPositionStrategy(), - scrollStrategy: new NoOpScrollStrategy(), - modal: false, - closeOnOutsideClick: false - }; - const positionSettings: PositionSettings = { - horizontalDirection: HorizontalAlignment.Right, - verticalDirection: VerticalAlignment.Bottom, - target: fixture.componentInstance.buttonElement.nativeElement, - horizontalStartPoint: HorizontalAlignment.Left, - verticalStartPoint: VerticalAlignment.Top - }; - overlaySettings.positionStrategy = new GlobalPositionStrategy(positionSettings); - fixture.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - fixture.detectChanges(); - const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; - const wrapper = overlayDiv.children[0]; - expect(wrapper.classList).toContain(CLASS_OVERLAY_WRAPPER); - })); + it('Should correctly render igx-overlay', fakeAsync(() => { + const fixture = TestBed.createComponent(EmptyPageComponent); + fixture.detectChanges(); + const overlaySettings: OverlaySettings = { + positionStrategy: new GlobalPositionStrategy(), + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false + }; + const positionSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Right, + verticalDirection: VerticalAlignment.Bottom, + target: fixture.componentInstance.buttonElement.nativeElement, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + overlaySettings.positionStrategy = new GlobalPositionStrategy(positionSettings); + fixture.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + fixture.detectChanges(); + const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; + const wrapper = overlayDiv.children[0]; + expect(wrapper.classList).toContain(CLASS_OVERLAY_WRAPPER); + })); it('Should cover the whole window 100% width and height.', fakeAsync(() => { const fixture = TestBed.createComponent(EmptyPageComponent); @@ -895,11 +861,10 @@ describe('igxOverlay', () => { const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; const overlayWrapper = overlayDiv.children[0]; const overlayRect = overlayWrapper.getBoundingClientRect(); - const windowRect = document.body.getBoundingClientRect(); - expect(overlayRect.width).toEqual(windowRect.width); - expect(overlayRect.height).toEqual(windowRect.height); - expect(overlayRect.left).toEqual(windowRect.left); - expect(overlayRect.top).toEqual(windowRect.top); + expect(overlayRect.width).toEqual(window.innerWidth); + expect(overlayRect.height).toEqual(window.innerHeight); + expect(overlayRect.left).toEqual(0); + expect(overlayRect.top).toEqual(0); })); it('Should show the component inside the igx-overlay wrapper as a content last child.', fakeAsync(() => { @@ -969,12 +934,9 @@ describe('igxOverlay', () => { const overlayDiv = document.getElementsByClassName(CLASS_OVERLAY_MAIN)[0]; const overlayWrapper = overlayDiv.children[0] as HTMLElement; const componentEl = overlayWrapper.children[0].children[0]; - const wrapperRect = overlayWrapper.getBoundingClientRect(); const componentRect = componentEl.getBoundingClientRect(); - expect(wrapperRect.width / 2 - componentRect.width / 2).toEqual(componentRect.left); - expect(wrapperRect.height / 2 - componentRect.height / 2).toEqual(componentRect.top); - expect(componentRect.left).toEqual(componentRect.right - componentRect.width); - expect(componentRect.top).toEqual(componentRect.bottom - componentRect.height); + expect((window.innerWidth - componentRect.width) / 2).toEqual(componentRect.left); + expect((window.innerHeight - componentRect.height) / 2).toEqual(componentRect.top); })); it('Should display a new instance of the same component/options exactly on top of the previous one.', fakeAsync(() => { @@ -1057,7 +1019,7 @@ describe('igxOverlay', () => { })); // 1.2 ConnectedPositioningStrategy(show components based on a specified position base point, horizontal and vertical alignment) - it('Should render on top of all other views/components (any previously existing html on the page) etc.', fakeAsync(() => { + it('Should correctly render igx-overlay', fakeAsync(() => { const fixture = TestBed.createComponent(EmptyPageComponent); fixture.detectChanges(); const overlaySettings: OverlaySettings = { @@ -1101,9 +1063,8 @@ describe('igxOverlay', () => { fixture.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); tick(); const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; - const body = document.getElementsByTagName('body')[0]; - expect(wrapper.clientHeight).toEqual(body.clientHeight); - expect(wrapper.clientWidth).toEqual(body.clientWidth); + expect(wrapper.clientHeight).toEqual(window.innerHeight); + expect(wrapper.clientWidth).toEqual(window.innerWidth); })); it('It should position the shown component inside the igx-overlay wrapper as a content last child.', fakeAsync(() => { @@ -1143,13 +1104,14 @@ describe('igxOverlay', () => { horizontalStartPoint: HorizontalAlignment.Left, verticalStartPoint: VerticalAlignment.Bottom, openAnimation: scaleInVerTop, - closeAnimation: scaleOutVerTop + closeAnimation: scaleOutVerTop, + minSize: { width: 0, height: 0 } }; expect(strategy.settings).toEqual(expectedDefaults); }); - it(`Should use target: null StartPoint:Left/Bottom, Direction Right/Bottom and openAnimation: scaleInVerTop, + it(`Should use target: null StartPoint:Left/Bottom, Direction Right/Bottom and openAnimation: scaleInVerTop, closeAnimation: scaleOutVerTop as default options when using a ConnectedPositioningStrategy without passing options.`, () => { const strategy = new ConnectedPositioningStrategy(); @@ -1160,7 +1122,8 @@ describe('igxOverlay', () => { horizontalStartPoint: HorizontalAlignment.Left, verticalStartPoint: VerticalAlignment.Bottom, openAnimation: scaleInVerTop, - closeAnimation: scaleOutVerTop + closeAnimation: scaleOutVerTop, + minSize: { width: 0, height: 0 } }; expect(strategy.settings).toEqual(expectedDefaults); @@ -1420,32 +1383,31 @@ describe('igxOverlay', () => { }); // 1.3 AutoPosition (fit the shown component into the visible window.) - it('Should render igx-overlay on top of all other views/components (any previously existing html on the page) etc.', - fakeAsync(() => { - const fix = TestBed.createComponent(EmptyPageComponent); - fix.detectChanges(); - const overlaySettings: OverlaySettings = { - positionStrategy: new GlobalPositionStrategy(), - scrollStrategy: new NoOpScrollStrategy(), - modal: false, - closeOnOutsideClick: false - }; + it('Should correctly render igx-overlay', fakeAsync(() => { + const fix = TestBed.createComponent(EmptyPageComponent); + fix.detectChanges(); + const overlaySettings: OverlaySettings = { + positionStrategy: new AutoPositionStrategy(), + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false + }; - const positionSettings: PositionSettings = { - horizontalDirection: HorizontalAlignment.Right, - verticalDirection: VerticalAlignment.Bottom, - target: fix.componentInstance.buttonElement.nativeElement, - horizontalStartPoint: HorizontalAlignment.Left, - verticalStartPoint: VerticalAlignment.Top - }; - overlaySettings.positionStrategy = new AutoPositionStrategy(positionSettings); - fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - fix.detectChanges(); - const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; - expect(wrapper).toBeDefined(); - expect(wrapper.classList).toContain(CLASS_OVERLAY_WRAPPER); - })); + const positionSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Right, + verticalDirection: VerticalAlignment.Bottom, + target: fix.componentInstance.buttonElement.nativeElement, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + overlaySettings.positionStrategy = new AutoPositionStrategy(positionSettings); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + fix.detectChanges(); + const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; + expect(wrapper).toBeDefined(); + expect(wrapper.classList).toContain(CLASS_OVERLAY_WRAPPER); + })); it('Should cover the whole window 100% width and height.', fakeAsync(() => { const fix = TestBed.createComponent(EmptyPageComponent); @@ -1468,9 +1430,8 @@ describe('igxOverlay', () => { tick(); fix.detectChanges(); const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; - const body = document.getElementsByTagName('body')[0]; - expect(wrapper.clientHeight).toEqual(body.clientHeight); - expect(wrapper.clientWidth).toEqual(body.clientWidth); + expect(wrapper.clientHeight).toEqual(window.innerHeight); + expect(wrapper.clientWidth).toEqual(window.innerWidth); })); it('Should append the shown component inside the igx-overlay as a last child.', fakeAsync(() => { @@ -1846,8 +1807,7 @@ describe('igxOverlay', () => { })); // 1.4 ElasticPosition (resize shown component to fit into visible window) - it('Should render igx-overlay on top of all other views/components (any previously existing html on the page) etc.', - fakeAsync(() => { + it('Should correctly render igx-overlay', fakeAsync(() => { const fix = TestBed.createComponent(EmptyPageComponent); fix.detectChanges(); const overlaySettings: OverlaySettings = { @@ -1894,16 +1854,15 @@ describe('igxOverlay', () => { tick(); fix.detectChanges(); const wrapper = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; - const body = document.getElementsByTagName('body')[0]; - expect(wrapper.clientHeight).toEqual(body.clientHeight); - expect(wrapper.clientWidth).toEqual(body.clientWidth); + expect(wrapper.clientHeight).toEqual(window.innerHeight); + expect(wrapper.clientWidth).toEqual(window.innerWidth); })); it('Should append the shown component inside the igx-overlay as a last child.', fakeAsync(() => { const fix = TestBed.createComponent(EmptyPageComponent); fix.detectChanges(); const overlaySettings: OverlaySettings = { - positionStrategy: new GlobalPositionStrategy(), + positionStrategy: new ElasticPositionStrategy(), scrollStrategy: new NoOpScrollStrategy(), modal: false, closeOnOutsideClick: false @@ -1932,28 +1891,24 @@ describe('igxOverlay', () => { fix.detectChanges(); fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); - fix.componentInstance.positionStrategy.minSize = {width: '80px', height: '80px'}; - const currentElement = fix.componentInstance; + const component = fix.componentInstance; const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.target = buttonElement; + component.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; + component.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; + component.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; + component.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; + component.ButtonPositioningSettings.target = buttonElement; + component.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; buttonElement.click(); - fix.detectChanges(); tick(); - fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapped in NG-COMPONENT - const expectedStyle = 'position: absolute; width:80px; height: 80px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft; - const expectedTop = buttonTop; + expect(wrapperContent.lastElementChild.clientWidth).toEqual(80); + expect(wrapperContent.lastElementChild.clientHeight).toEqual(80); + const expectedLeft = buttonElement.offsetLeft + buttonElement.offsetWidth; + const expectedTop = buttonElement.offsetTop + buttonElement.offsetHeight; const wrapperLeft = wrapperContent.getBoundingClientRect().left; const wrapperTop = wrapperContent.getBoundingClientRect().top; expect(wrapperTop).toEqual(expectedTop); @@ -2009,73 +1964,6 @@ describe('igxOverlay', () => { } })); - it(`Should reposition the component and render it correctly in the window, even when the rendering options passed - should result in otherwise a partially hidden component. No scrollbars should appear.`, - fakeAsync(() => { - const fix = TestBed.createComponent(EmptyPageComponent); - fix.detectChanges(); - const button = fix.componentInstance.buttonElement.nativeElement; - const positionSettings: PositionSettings = { - target: button - }; - const overlaySettings: OverlaySettings = { - positionStrategy: new ElasticPositionStrategy(positionSettings), - modal: false, - closeOnOutsideClick: false - }; - const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); - const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); - hAlignmentArray.forEach(function (hAlignment) { - vAlignmentArray.forEach(function (vAlignment) { - if (hAlignment === 'Center') { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Left, VerticalAlignment.Bottom, - HorizontalAlignment.Center, VerticalAlignment[vAlignment]); - } - if (vAlignment !== 'Top') { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Right, VerticalAlignment.Top, - HorizontalAlignment[hAlignment], VerticalAlignment[vAlignment]); - if (hAlignment !== 'Left') { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Left, VerticalAlignment.Top, - HorizontalAlignment[hAlignment], VerticalAlignment[vAlignment]); - } - } - }); - }); - - // TODO: refactor this function and use it in all tests when needed - function verifyOverlayBoundingSizeAndPosition(horizontalDirection, verticalDirection, - horizontalAlignment, verticalAlignment) { - positionSettings.horizontalDirection = horizontalDirection; - positionSettings.verticalDirection = verticalDirection; - positionSettings.horizontalStartPoint = horizontalAlignment; - positionSettings.verticalStartPoint = verticalAlignment; - overlaySettings.positionStrategy = new ElasticPositionStrategy(positionSettings); - fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - fix.detectChanges(); - const buttonRect = button.getBoundingClientRect(); - const overlayElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; - const overlayRect = overlayElement.getBoundingClientRect(); - const expectedTop = verticalDirection === VerticalAlignment.Top ? - buttonRect.top + buttonRect.height : - getExpectedTopPosition(verticalAlignment, buttonRect); - const expectedLeft = (horizontalDirection === HorizontalAlignment.Left && - verticalDirection === VerticalAlignment.Top && - horizontalAlignment === HorizontalAlignment.Right) ? - buttonRect.right - overlayRect.width : - (horizontalDirection === HorizontalAlignment.Right && - verticalDirection === VerticalAlignment.Top) ? - getExpectedLeftPosition(horizontalAlignment, buttonRect) : - buttonRect.right; - expect(overlayRect.top.toFixed(1)).toEqual(expectedTop.toFixed(1)); - expect(overlayRect.bottom.toFixed(1)).toEqual((overlayRect.top + overlayRect.height).toFixed(1)); - expect(overlayRect.left.toFixed(1)).toEqual(expectedLeft.toFixed(1)); - expect(overlayRect.right.toFixed(1)).toEqual((overlayRect.left + overlayRect.width).toFixed(1)); - expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar - fix.componentInstance.overlay.hideAll(); - } - })); - it('Should render margins correctly.', fakeAsync(() => { const expectedMargin = '0px'; const fix = TestBed.createComponent(EmptyPageComponent); @@ -2165,7 +2053,7 @@ describe('igxOverlay', () => { })); // When adding more than one component to show in igx-overlay and the options used will not fit the component in the - // window, so AutoPosition is used. + // window, so element is resized. it('When adding a new instance of the component with the same options, will render it on top of the previous one.', fakeAsync(() => { const fix = TestBed.createComponent(EmptyPageComponent); @@ -2176,7 +2064,8 @@ describe('igxOverlay', () => { verticalDirection: VerticalAlignment.Top, target: button, horizontalStartPoint: HorizontalAlignment.Left, - verticalStartPoint: VerticalAlignment.Top + verticalStartPoint: VerticalAlignment.Top, + minSize: { width: 80, height: 80 } }; const overlaySettings: OverlaySettings = { positionStrategy: new ElasticPositionStrategy(positionSettings), @@ -2187,9 +2076,11 @@ describe('igxOverlay', () => { fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); fix.detectChanges(); tick(); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); fix.detectChanges(); tick(); + const buttonRect = button.getBoundingClientRect(); const overlayWrapper_1 = document.getElementsByClassName(CLASS_OVERLAY_WRAPPER)[0]; const componentEl_1 = overlayWrapper_1.children[0].children[0]; @@ -2197,12 +2088,11 @@ describe('igxOverlay', () => { const componentEl_2 = overlayWrapper_2.children[0].children[0]; const componentRect_1 = componentEl_1.getBoundingClientRect(); const componentRect_2 = componentEl_2.getBoundingClientRect(); - expect(componentRect_1.left).toEqual(buttonRect.right); // Will be positioned on the right of the button - expect(componentRect_1.left).toEqual(componentRect_2.left); // Are on the same spot - // expect(componentRect_1.top).toEqual(buttonRect.top - componentEl_1.clientHeight); // Will be positioned on top of button - expect(componentRect_1.top).toEqual(componentRect_2.top); // Will have the same top - expect(componentRect_1.width).toEqual(componentRect_2.width); // Will have the same width - expect(componentRect_1.height).toEqual(componentRect_2.height); // Will have the same height + expect(componentRect_1.left).toEqual(buttonRect.left - positionSettings.minSize.width); + expect(componentRect_1.left).toEqual(componentRect_2.left); + expect(componentRect_1.top).toEqual(componentRect_2.top); + expect(componentRect_1.width).toEqual(componentRect_2.width); + expect(componentRect_1.height).toEqual(componentRect_2.height); })); it(`Should persist the component's open state when scrolling, when scrolling and noOP scroll strategy is used @@ -2474,7 +2364,8 @@ describe('igxOverlay', () => { })); }); - describe('Integration tests p2 (overrides): ', () => { + describe('Integration tests - Scroll Strategies: ', () => { + configureTestSuite(); beforeEach(async(() => { TestBed.configureTestingModule({ imports: [IgxToggleModule, DynamicModule, NoopAnimationsModule], @@ -2483,7 +2374,7 @@ describe('igxOverlay', () => { })); // If adding a component near the visible window borders(left,right,up,down) // it should be partially hidden and based on scroll strategy: - it('Should not allow scrolling with scroll strategy is not passed.', fakeAsync( async () => { + it('Should not allow scrolling with scroll strategy is not passed.', fakeAsync(async () => { TestBed.overrideComponent(EmptyPageComponent, { set: { styles: [`button { @@ -2576,109 +2467,109 @@ describe('igxOverlay', () => { it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { + position: absolute; + top: 16px; + left: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + }`] + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); + + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); + + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button + const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); + + it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, + TOP + RIGHT.`, fakeAsync(async () => { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; top: 16px; - left: 16px; + right: 16px; width: 84px; height: 84px; padding: 0px; margin: 0px; border: 0px; }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new AutoPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button - const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); - - it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, - TOP + RIGHT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { - position: absolute; - top: 16px; - right: 16px; - width: 84px; - height: 84px; - padding: 0px; - margin: 0px; - border: 0px; - }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); - - fix.componentInstance.positionStrategy = new AutoPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); - - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapper in NG-COMPONENT - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; // To the left of the button - const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapper in NG-COMPONENT + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; // To the left of the button + const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, BOTTOM + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; bottom: 16px; left: 16px; @@ -2688,193 +2579,179 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new AutoPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button - const expectedTop = buttonTop - wrapperContent.lastElementChild.clientHeight; // On top of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button + const expectedTop = buttonTop - wrapperContent.lastElementChild.clientHeight; // On top of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { - position: absolute; - top: 16px; - left: 16px; - width: 84px; - height: 84px; - padding: 0px; - margin: 0px; - border: 0px; - }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { + position: absolute; + top: 16px; + left: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + }`] + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + currentElement.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; + buttonElement.click(); + tick(); + fix.detectChanges(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button - const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1]; // wrapper in NG-COMPONENT + const expectedLeft = buttonElement.offsetLeft - currentElement.ButtonPositioningSettings.minSize.width; + const expectedTop = buttonElement.offsetTop - currentElement.ButtonPositioningSettings.minSize.height; + const componentRect = wrapperContent.lastElementChild.getBoundingClientRect(); + expect(componentRect.left).toEqual(expectedLeft); + expect(componentRect.top).toEqual(expectedTop); + })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + RIGHT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { - position: absolute; - top: 16px; - right: 16px; - width: 84px; - height: 84px; - padding: 0px; - margin: 0px; - border: 0px; - }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { + position: absolute; + top: 16px; + right: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + }`] + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.target = buttonElement; + currentElement.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; + buttonElement.click(); + fix.detectChanges(); + tick(); + fix.detectChanges(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapper in NG-COMPONENT - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; // To the left of the button - const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1]; // wrapper in NG-COMPONENT + const expectedLeft = buttonElement.offsetLeft + buttonElement.clientWidth; + const expectedTop = buttonElement.offsetTop - currentElement.ButtonPositioningSettings.minSize.height; + const componentRect = wrapperContent.lastElementChild.getBoundingClientRect(); + expect(componentRect.left).toEqual(expectedLeft); + expect(componentRect.top).toEqual(expectedTop); + })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, BOTTOM + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { - position: absolute; - bottom: 16px; - left: 16px; - width: 84px; - height: 84px; - padding: 0px; - margin: 0px; - border: 0px; - }`] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { + position: absolute; + bottom: 16px; + left: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + }`] + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + currentElement.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; + buttonElement.click(); + fix.detectChanges(); + tick(); + fix.detectChanges(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button - const expectedTop = buttonTop - wrapperContent.lastElementChild.clientHeight; // On top of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1]; // wrapper in NG-COMPONENT + const expectedLeft = buttonElement.offsetLeft - currentElement.ButtonPositioningSettings.minSize.width; + const expectedTop = buttonElement.offsetTop + buttonElement.offsetHeight; + const componentRect = wrapperContent.lastElementChild.getBoundingClientRect(); + expect(componentRect.left).toEqual(expectedLeft); + expect(componentRect.top).toEqual(expectedTop); + })); - // 2. Scroll Strategy (test with GlobalPositionStrategy(default)) + // 2. Scroll Strategy (test with GlobalPositionStrategy(default)) // 2.1. Scroll Strategy - None it('Should not scroll component, nor the window when none scroll strategy is passed. No scrolling happens.', fakeAsync(async () => { TestBed.overrideComponent(EmptyPageComponent, { @@ -2913,117 +2790,117 @@ describe('igxOverlay', () => { it(`Should not close the shown component when none scroll strategy is passed. (example: expanded DropDown stays expanded during a scrolling attempt.)`, - fakeAsync(async () => { - TestBed.overrideComponent(EmptyPageComponent, { - set: { - styles: [`button { + fakeAsync(async () => { + TestBed.overrideComponent(EmptyPageComponent, { + set: { + styles: [`button { position: absolute; top: 120%; left:120%; }`] - } - }); - await TestBed.compileComponents(); - const fixture = TestBed.createComponent(EmptyPageComponent); - fixture.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fixture = TestBed.createComponent(EmptyPageComponent); + fixture.detectChanges(); - const overlaySettings: OverlaySettings = { - modal: false, - }; - const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + modal: false, + }; + const overlay = fixture.componentInstance.overlay; - overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - const contentWrapper = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; - const element = contentWrapper.firstChild as HTMLElement; - const elementRect = element.getBoundingClientRect(); + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + const contentWrapper = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; + const element = contentWrapper.firstChild as HTMLElement; + const elementRect = element.getBoundingClientRect(); - document.documentElement.scrollTop = 40; - document.documentElement.scrollLeft = 30; - document.dispatchEvent(new Event('scroll')); - tick(); + document.documentElement.scrollTop = 40; + document.documentElement.scrollLeft = 30; + document.dispatchEvent(new Event('scroll')); + tick(); - expect(elementRect).toEqual(element.getBoundingClientRect()); - expect(document.documentElement.scrollTop).toEqual(40); - expect(document.documentElement.scrollLeft).toEqual(30); - expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); - })); + expect(elementRect).toEqual(element.getBoundingClientRect()); + expect(document.documentElement.scrollTop).toEqual(40); + expect(document.documentElement.scrollLeft).toEqual(30); + expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); + })); // 2.2 Scroll Strategy - Closing. (Uses a tolerance and closes an expanded component upon scrolling if the tolerance is exceeded.) // (example: DropDown or Dialog component collapse/closes after scrolling 10px.) it('Should scroll until the set threshold is exceeded, and closing scroll strategy is used.', - fakeAsync(async () => { - TestBed.overrideComponent(EmptyPageComponent, { - set: { - styles: [ - 'button { position: absolute; top: 100%; left: 90% }' - ] - } - }); - await TestBed.compileComponents(); - const fixture = TestBed.createComponent(EmptyPageComponent); - fixture.detectChanges(); + fakeAsync(async () => { + TestBed.overrideComponent(EmptyPageComponent, { + set: { + styles: [ + 'button { position: absolute; top: 100%; left: 90% }' + ] + } + }); + await TestBed.compileComponents(); + const fixture = TestBed.createComponent(EmptyPageComponent); + fixture.detectChanges(); - const scrollTolerance = 10; - const scrollStrategy = new CloseScrollStrategy(); - const overlay = fixture.componentInstance.overlay; - const overlaySettings: OverlaySettings = { - positionStrategy: new GlobalPositionStrategy(), - scrollStrategy: scrollStrategy, - modal: false - }; + const scrollTolerance = 10; + const scrollStrategy = new CloseScrollStrategy(); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + positionStrategy: new GlobalPositionStrategy(), + scrollStrategy: scrollStrategy, + modal: false + }; - overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); - document.documentElement.scrollTop = scrollTolerance; - document.dispatchEvent(new Event('scroll')); - tick(); - expect(document.documentElement.scrollTop).toEqual(scrollTolerance); - expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); + document.documentElement.scrollTop = scrollTolerance; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(document.documentElement.scrollTop).toEqual(scrollTolerance); + expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); - document.documentElement.scrollTop = scrollTolerance * 2; - document.dispatchEvent(new Event('scroll')); - tick(); - expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(0); + document.documentElement.scrollTop = scrollTolerance * 2; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(0); - })); + })); it(`Should not change the shown component shown state until it exceeds the scrolling tolerance set, and closing scroll strategy is used.`, - fakeAsync(async () => { - TestBed.overrideComponent(EmptyPageComponent, { - set: { - styles: [ - 'button { position: absolute; top: 200%; left: 90% }' - ] - } - }); - await TestBed.compileComponents(); - const fixture = TestBed.createComponent(EmptyPageComponent); - fixture.detectChanges(); + fakeAsync(async () => { + TestBed.overrideComponent(EmptyPageComponent, { + set: { + styles: [ + 'button { position: absolute; top: 200%; left: 90% }' + ] + } + }); + await TestBed.compileComponents(); + const fixture = TestBed.createComponent(EmptyPageComponent); + fixture.detectChanges(); - const scrollTolerance = 10; - const scrollStrategy = new CloseScrollStrategy(); - const overlay = fixture.componentInstance.overlay; - const overlaySettings: OverlaySettings = { - positionStrategy: new GlobalPositionStrategy(), - scrollStrategy: scrollStrategy, - closeOnOutsideClick: false, - modal: false - }; + const scrollTolerance = 10; + const scrollStrategy = new CloseScrollStrategy(); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + positionStrategy: new GlobalPositionStrategy(), + scrollStrategy: scrollStrategy, + closeOnOutsideClick: false, + modal: false + }; - overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - expect(document.documentElement.scrollTop).toEqual(0); + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + expect(document.documentElement.scrollTop).toEqual(0); - document.documentElement.scrollTop += scrollTolerance; - document.dispatchEvent(new Event('scroll')); - tick(); - expect(document.documentElement.scrollTop).toEqual(scrollTolerance); - expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); - fixture.destroy(); - })); + document.documentElement.scrollTop += scrollTolerance; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(document.documentElement.scrollTop).toEqual(scrollTolerance); + expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); + fixture.destroy(); + })); it(`Should close the shown component shown when it exceeds the scrolling threshold set, and closing scroll strategy is used. (an expanded DropDown, Menu, DatePicker, etc. collapses).`, fakeAsync(async () => { @@ -3106,7 +2983,7 @@ describe('igxOverlay', () => { it('Should scroll everything except component when scrolling and absolute scroll strategy is used.', fakeAsync(async () => { // Should behave as NoOpScrollStrategy - TestBed.overrideComponent(EmptyPageComponent, { + TestBed.overrideComponent(EmptyPageComponent, { set: { styles: [ 'button { position: absolute; top:200%; left: 100%; }', From e8ebd09dade83a4a58076e10753200af620702a8 Mon Sep 17 00:00:00 2001 From: wnvko Date: Mon, 10 Dec 2018 13:59:53 +0200 Subject: [PATCH 06/11] test(igxOverlay): all tests pass now, #2697 --- .../src/lib/services/overlay/overlay.spec.ts | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts index 87f6827ba47..120af786f3c 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts @@ -114,8 +114,8 @@ function getExpectedLeftPosition(horizontalAlignment: HorizontalAlignment, eleme return expectedLeft; } -fdescribe('igxOverlay', () => { - beforeEach(async(() => { +describe('igxOverlay', () => { + beforeEach(async(() => { UIInteractions.clearOverlay(); })); @@ -684,7 +684,6 @@ fdescribe('igxOverlay', () => { }); describe('Unit Tests - Scroll Strategies: ', () => { - configureTestSuite(); beforeEach(async(() => { TestBed.configureTestingModule({ imports: [IgxToggleModule, DynamicModule, NoopAnimationsModule], @@ -2365,7 +2364,6 @@ fdescribe('igxOverlay', () => { }); describe('Integration tests - Scroll Strategies: ', () => { - configureTestSuite(); beforeEach(async(() => { TestBed.configureTestingModule({ imports: [IgxToggleModule, DynamicModule, NoopAnimationsModule], @@ -2557,12 +2555,12 @@ fdescribe('igxOverlay', () => { expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); const buttonLeft = buttonElement.offsetLeft; const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button + const expectedRight = buttonLeft; // To the left of the button const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperRight = wrapperContent.getBoundingClientRect().right; const wrapperTop = wrapperContent.getBoundingClientRect().top; expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); + expect(wrapperRight).toEqual(expectedRight); })); it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, @@ -3106,9 +3104,6 @@ fdescribe('igxOverlay', () => { }); describe('Integration tests p3 (IgniteUI components): ', () => { - beforeAll(() => { - TestBed.resetTestingModule(); - }); beforeEach(async(() => { TestBed.configureTestingModule({ imports: [IgxToggleModule, DynamicModule, NoopAnimationsModule, IgxComponentsModule], From a7df20cce780c8d23a7b2a277e341c4aeb0c2865 Mon Sep 17 00:00:00 2001 From: wnvko Date: Tue, 11 Dec 2018 16:58:58 +0200 Subject: [PATCH 07/11] chore(igxOverlay): update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d12e3a32af6..3c356d1606b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ All notable changes for each version of this project will be documented in this - Batch editing - an injectable transaction provider accumulates pending changes, which are not directly applied to the grid's data source. Those can later be inspected, manipulated and submitted at once. Changes are collected for individual cells or rows, depending on editing mode, and accumulated per data row/record. - You can now export the tree grid both to CSV and Excel. - The hierarchy and the records' expanded states would be reflected in the exported Excel worksheet. +- `IgxOverlayService`: + - `ElasticPositioningStrategy` added. This strategy positions the element as in **Connected** positioning strategy and resize the element to fit in the view port in case the element is partially getting out of view. ## 7.0.4 ### Bug fixes From 69f70d4b46b1b14878e645c18e8162c38afe7815 Mon Sep 17 00:00:00 2001 From: wnvko Date: Fri, 14 Dec 2018 12:38:04 +0200 Subject: [PATCH 08/11] test(igxOverlay): refactor tests, #3270 --- .../src/lib/services/overlay/overlay.spec.ts | 253 +++++++++++------- 1 file changed, 157 insertions(+), 96 deletions(-) diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts index 120af786f3c..2c36bb380f3 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts @@ -7,7 +7,7 @@ import { ComponentRef, HostBinding } from '@angular/core'; -import { async as asyncWrapper, TestBed, fakeAsync, tick, async } from '@angular/core/testing'; +import { async as asyncWrapper, TestBed, fakeAsync, tick, async, ComponentFixture } from '@angular/core/testing'; import { BrowserModule } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { IgxOverlayService } from './overlay'; @@ -114,8 +114,38 @@ function getExpectedLeftPosition(horizontalAlignment: HorizontalAlignment, eleme return expectedLeft; } +function getOverlayWrapperPosition( + positionSettings: PositionSettings, + targetRect: ClientRect, + wrapperRect: ClientRect, + screenRect: ClientRect): Point { + const location: Point = new Point(0, 0); + + location.x = + targetRect.left + + targetRect.width * (1 + positionSettings.horizontalStartPoint) + + wrapperRect.width * positionSettings.horizontalDirection; + if (location.x < screenRect.left) { + location.x = targetRect.right; + } else if (location.x > screenRect.right) { + location.x = targetRect.left - wrapperRect.width; + } + + location.y = + targetRect.top + + targetRect.height * (1 + positionSettings.verticalStartPoint) + + wrapperRect.height * positionSettings.verticalDirection; + if (location.y < screenRect.top) { + location.y = targetRect.bottom; + } else if (location.y > screenRect.bottom) { + location.y = targetRect.top - wrapperRect.height; + } + + return location; +} + describe('igxOverlay', () => { - beforeEach(async(() => { + beforeEach(async(() => { UIInteractions.clearOverlay(); })); @@ -1498,115 +1528,146 @@ describe('igxOverlay', () => { const fix = TestBed.createComponent(EmptyPageComponent); fix.detectChanges(); const button = fix.componentInstance.buttonElement.nativeElement; - const positionSettings: PositionSettings = { - target: button - }; - const overlaySettings: OverlaySettings = { - positionStrategy: new AutoPositionStrategy(positionSettings), - modal: false, - closeOnOutsideClick: false - }; + const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); - vAlignmentArray.forEach(function (vAlignment) { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Left, VerticalAlignment.Bottom, - HorizontalAlignment.Right, VerticalAlignment[vAlignment]); - hAlignmentArray.forEach(function (hAlignment) { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Right, VerticalAlignment.Bottom, - HorizontalAlignment[hAlignment], VerticalAlignment[vAlignment]); + hAlignmentArray.forEach(function (horizontalStartPoint) { + vAlignmentArray.forEach(function (verticalStartPoint) { + hAlignmentArray.forEach(function (horizontalDirection) { + // do not check Center as we do nothing here + if (horizontalDirection === 'Center') { return; } + vAlignmentArray.forEach(function (verticalDirection) { + // do not check Middle as we do nothing here + if (verticalDirection === 'Middle') { return; } + const positionSettings: PositionSettings = { + target: button + }; + positionSettings.horizontalStartPoint = HorizontalAlignment[horizontalStartPoint]; + positionSettings.verticalStartPoint = VerticalAlignment[verticalStartPoint]; + positionSettings.horizontalDirection = HorizontalAlignment[horizontalDirection]; + positionSettings.verticalDirection = VerticalAlignment[verticalDirection]; + + const overlaySettings: OverlaySettings = { + positionStrategy: new AutoPositionStrategy(positionSettings), + modal: false, + closeOnOutsideClick: false + }; + + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + fix.detectChanges(); + + const targetRect: ClientRect = (positionSettings.target).getBoundingClientRect() as ClientRect; + const overlayWrapperElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; + const overlayWrapperRect: ClientRect = overlayWrapperElement.getBoundingClientRect() as ClientRect; + const screenRect: ClientRect = { + left: 0, + top: 0, + right: window.innerWidth, + bottom: window.innerHeight, + width: window.innerWidth, + height: window.innerHeight, + }; + + const location = getOverlayWrapperPosition(positionSettings, targetRect, overlayWrapperRect, screenRect); + expect(overlayWrapperRect.top.toFixed(1)).toEqual(location.y.toFixed(1)); + expect(overlayWrapperRect.left.toFixed(1)).toEqual(location.x.toFixed(1)); + expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar + fix.componentInstance.overlay.hideAll(); + tick(); + fix.detectChanges(); + }); + }); }); }); - - // TODO: refactor this function and use it in all tests when needed - function verifyOverlayBoundingSizeAndPosition(horizontalDirection, verticalDirection, - horizontalAlignment, verticalAlignment) { - positionSettings.horizontalDirection = horizontalDirection; - positionSettings.verticalDirection = verticalDirection; - positionSettings.horizontalStartPoint = horizontalAlignment; - positionSettings.verticalStartPoint = verticalAlignment; - overlaySettings.positionStrategy = new AutoPositionStrategy(positionSettings); - fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - const buttonRect = button.getBoundingClientRect(); - const overlayElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; - const overlayRect = overlayElement.getBoundingClientRect(); - const expectedTop = getExpectedTopPosition(verticalAlignment, buttonRect); - const expectedLeft = horizontalDirection === HorizontalAlignment.Left ? - buttonRect.right - overlayRect.width : - getExpectedLeftPosition(horizontalAlignment, buttonRect); - expect(overlayRect.top.toFixed(1)).toEqual(expectedTop.toFixed(1)); - expect(overlayRect.bottom.toFixed(1)).toEqual((overlayRect.top + overlayRect.height).toFixed(1)); - expect(overlayRect.left.toFixed(1)).toEqual(expectedLeft.toFixed(1)); - expect(overlayRect.right.toFixed(1)).toEqual((overlayRect.left + overlayRect.width).toFixed(1)); - fix.componentInstance.overlay.hideAll(); - } })); - it(`Should reposition the component and render it correctly in the window, even when the rendering options passed + + // TODO: refactor this function and use it in all tests when needed + function verifyOverlayBoundingSizeAndPosition(positionSettings: PositionSettings, fix) { + const overlaySettings: OverlaySettings = { + positionStrategy: new AutoPositionStrategy(positionSettings), + modal: false, + closeOnOutsideClick: false + }; + overlaySettings.positionStrategy = new AutoPositionStrategy(positionSettings); + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + const buttonRect: DOMRect = (positionSettings.target).getBoundingClientRect() as DOMRect; + const overlayElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; + const overlayRect = overlayElement.getBoundingClientRect(); + const expectedTop = positionSettings.verticalStartPoint === VerticalAlignment.Top ? + buttonRect.top + buttonRect.height : + getExpectedTopPosition(positionSettings.verticalStartPoint, buttonRect); + const expectedLeft = positionSettings.horizontalDirection === HorizontalAlignment.Left ? + buttonRect.right - overlayRect.width : + getExpectedLeftPosition(positionSettings.horizontalStartPoint, buttonRect); + expect(overlayRect.top.toFixed(1)).toEqual(expectedTop.toFixed(1)); + expect(overlayRect.bottom.toFixed(1)).toEqual((overlayRect.top + overlayRect.height).toFixed(1)); + expect(overlayRect.left.toFixed(1)).toEqual(expectedLeft.toFixed(1)); + expect(overlayRect.right.toFixed(1)).toEqual((overlayRect.left + overlayRect.width).toFixed(1)); + expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar + fix.componentInstance.overlay.hideAll(); + } + + fit(`Should reposition the component and render it correctly in the window, even when the rendering options passed should result in otherwise a partially hidden component. No scrollbars should appear.`, fakeAsync(() => { const fix = TestBed.createComponent(EmptyPageComponent); fix.detectChanges(); const button = fix.componentInstance.buttonElement.nativeElement; - const positionSettings: PositionSettings = { - target: button - }; - const overlaySettings: OverlaySettings = { - positionStrategy: new AutoPositionStrategy(positionSettings), - modal: false, - closeOnOutsideClick: false - }; const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); - hAlignmentArray.forEach(function (hAlignment) { - vAlignmentArray.forEach(function (vAlignment) { - if (hAlignment === 'Center') { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Left, VerticalAlignment.Bottom, - HorizontalAlignment.Center, VerticalAlignment[vAlignment]); - } - if (vAlignment !== 'Top') { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Right, VerticalAlignment.Top, - HorizontalAlignment[hAlignment], VerticalAlignment[vAlignment]); - if (hAlignment !== 'Left') { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Left, VerticalAlignment.Top, - HorizontalAlignment[hAlignment], VerticalAlignment[vAlignment]); - } - } + hAlignmentArray.forEach(function (horizontalStartPoint) { + vAlignmentArray.forEach(function (verticalStartPoint) { + hAlignmentArray.forEach(function (horizontalDirection) { + // do not check Center as we do nothing here + if (horizontalDirection === 'Center') { return; } + vAlignmentArray.forEach(function (verticalDirection) { + // do not check Middle as we do nothing here + if (verticalDirection === 'Middle') { return; } + + const positionSettings: PositionSettings = { + target: button + }; + positionSettings.horizontalStartPoint = HorizontalAlignment[horizontalStartPoint]; + positionSettings.verticalStartPoint = VerticalAlignment[verticalStartPoint]; + positionSettings.horizontalDirection = HorizontalAlignment[horizontalDirection]; + positionSettings.verticalDirection = VerticalAlignment[verticalDirection]; + + const overlaySettings: OverlaySettings = { + positionStrategy: new AutoPositionStrategy(positionSettings), + modal: false, + closeOnOutsideClick: false + }; + + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + fix.detectChanges(); + + const targetRect: ClientRect = (positionSettings.target).getBoundingClientRect() as ClientRect; + const overlayWrapperElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; + const overlayWrapperRect: ClientRect = overlayWrapperElement.getBoundingClientRect() as ClientRect; + const screenRect: ClientRect = { + left: 0, + top: 0, + right: window.innerWidth, + bottom: window.innerHeight, + width: window.innerWidth, + height: window.innerHeight, + }; + + const location = getOverlayWrapperPosition(positionSettings, targetRect, overlayWrapperRect, screenRect); + expect(overlayWrapperRect.top.toFixed(1)).toEqual(location.y.toFixed(1)); + expect(overlayWrapperRect.left.toFixed(1)).toEqual(location.x.toFixed(1)); + expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar + fix.componentInstance.overlay.hideAll(); + tick(); + fix.detectChanges(); + }); + }); }); }); - - // TODO: refactor this function and use it in all tests when needed - function verifyOverlayBoundingSizeAndPosition(horizontalDirection, verticalDirection, - horizontalAlignment, verticalAlignment) { - positionSettings.horizontalDirection = horizontalDirection; - positionSettings.verticalDirection = verticalDirection; - positionSettings.horizontalStartPoint = horizontalAlignment; - positionSettings.verticalStartPoint = verticalAlignment; - overlaySettings.positionStrategy = new AutoPositionStrategy(positionSettings); - fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - fix.detectChanges(); - const buttonRect = button.getBoundingClientRect(); - const overlayElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; - const overlayRect = overlayElement.getBoundingClientRect(); - const expectedTop = verticalDirection === VerticalAlignment.Top ? - buttonRect.top + buttonRect.height : - getExpectedTopPosition(verticalAlignment, buttonRect); - const expectedLeft = (horizontalDirection === HorizontalAlignment.Left && - verticalDirection === VerticalAlignment.Top && - horizontalAlignment === HorizontalAlignment.Right) ? - buttonRect.right - overlayRect.width : - (horizontalDirection === HorizontalAlignment.Right && - verticalDirection === VerticalAlignment.Top) ? - getExpectedLeftPosition(horizontalAlignment, buttonRect) : - buttonRect.right; - expect(overlayRect.top.toFixed(1)).toEqual(expectedTop.toFixed(1)); - expect(overlayRect.bottom.toFixed(1)).toEqual((overlayRect.top + overlayRect.height).toFixed(1)); - expect(overlayRect.left.toFixed(1)).toEqual(expectedLeft.toFixed(1)); - expect(overlayRect.right.toFixed(1)).toEqual((overlayRect.left + overlayRect.width).toFixed(1)); - expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar - fix.componentInstance.overlay.hideAll(); - } })); it('Should render margins correctly.', fakeAsync(() => { From 3d3b902a0bf8223e93e9cce01ca61c639ce5f90a Mon Sep 17 00:00:00 2001 From: wnvko Date: Mon, 17 Dec 2018 11:31:23 +0200 Subject: [PATCH 09/11] test(igxOverlay): refactor tests and fix some TODO's, #2697 --- .../src/lib/core/utils.spec.ts | 8 + .../src/lib/services/overlay/overlay.spec.ts | 894 ++++++++++-------- 2 files changed, 501 insertions(+), 401 deletions(-) diff --git a/projects/igniteui-angular/src/lib/core/utils.spec.ts b/projects/igniteui-angular/src/lib/core/utils.spec.ts index 3454ba516b5..a1ab6e4a6b8 100644 --- a/projects/igniteui-angular/src/lib/core/utils.spec.ts +++ b/projects/igniteui-angular/src/lib/core/utils.spec.ts @@ -161,6 +161,14 @@ describe('Utils', () => { expect(clone.Null).toBeNull(); expect(clone.undefined).toBeUndefined(); }); + + it('Should correctly handle null and undefined values', () => { + const nullClone = cloneValue(null); + expect(nullClone).toBeNull(); + + const undefinedClone = cloneValue(undefined); + expect(undefinedClone).toBeUndefined(); + }); }); describe('Utils - mergeObjects() unit tests', () => { diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts index 2c36bb380f3..217d96daede 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts @@ -114,11 +114,12 @@ function getExpectedLeftPosition(horizontalAlignment: HorizontalAlignment, eleme return expectedLeft; } -function getOverlayWrapperPosition( +function getOverlayWrapperLocation( positionSettings: PositionSettings, targetRect: ClientRect, wrapperRect: ClientRect, - screenRect: ClientRect): Point { + screenRect: ClientRect, + elastic = false): Point { const location: Point = new Point(0, 0); location.x = @@ -126,8 +127,16 @@ function getOverlayWrapperPosition( targetRect.width * (1 + positionSettings.horizontalStartPoint) + wrapperRect.width * positionSettings.horizontalDirection; if (location.x < screenRect.left) { - location.x = targetRect.right; - } else if (location.x > screenRect.right) { + if (elastic) { + let offset = screenRect.left - location.x; + if (offset > wrapperRect.width - positionSettings.minSize.width) { + offset = wrapperRect.width - positionSettings.minSize.width; + } + location.x += offset; + } else { + location.x = targetRect.right; + } + } else if (location.x + wrapperRect.width > screenRect.right && !elastic) { location.x = targetRect.left - wrapperRect.width; } @@ -136,11 +145,18 @@ function getOverlayWrapperPosition( targetRect.height * (1 + positionSettings.verticalStartPoint) + wrapperRect.height * positionSettings.verticalDirection; if (location.y < screenRect.top) { - location.y = targetRect.bottom; - } else if (location.y > screenRect.bottom) { + if (elastic) { + let offset = screenRect.top - location.y; + if (offset > wrapperRect.height - positionSettings.minSize.height) { + offset = wrapperRect.height - positionSettings.minSize.height; + } + location.y += offset; + } else { + location.y = targetRect.bottom; + } + } else if (location.y + wrapperRect.height > screenRect.bottom && !elastic) { location.y = targetRect.top - wrapperRect.height; } - return location; } @@ -1528,6 +1544,9 @@ describe('igxOverlay', () => { const fix = TestBed.createComponent(EmptyPageComponent); fix.detectChanges(); const button = fix.componentInstance.buttonElement.nativeElement; + button.style.left = '150px'; + button.style.top = '150px'; + button.style.position = 'relative'; const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); @@ -1569,7 +1588,7 @@ describe('igxOverlay', () => { height: window.innerHeight, }; - const location = getOverlayWrapperPosition(positionSettings, targetRect, overlayWrapperRect, screenRect); + const location = getOverlayWrapperLocation(positionSettings, targetRect, overlayWrapperRect, screenRect); expect(overlayWrapperRect.top.toFixed(1)).toEqual(location.y.toFixed(1)); expect(overlayWrapperRect.left.toFixed(1)).toEqual(location.x.toFixed(1)); expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar @@ -1582,92 +1601,76 @@ describe('igxOverlay', () => { }); })); - - // TODO: refactor this function and use it in all tests when needed - function verifyOverlayBoundingSizeAndPosition(positionSettings: PositionSettings, fix) { - const overlaySettings: OverlaySettings = { - positionStrategy: new AutoPositionStrategy(positionSettings), - modal: false, - closeOnOutsideClick: false - }; - overlaySettings.positionStrategy = new AutoPositionStrategy(positionSettings); - fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - const buttonRect: DOMRect = (positionSettings.target).getBoundingClientRect() as DOMRect; - const overlayElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; - const overlayRect = overlayElement.getBoundingClientRect(); - const expectedTop = positionSettings.verticalStartPoint === VerticalAlignment.Top ? - buttonRect.top + buttonRect.height : - getExpectedTopPosition(positionSettings.verticalStartPoint, buttonRect); - const expectedLeft = positionSettings.horizontalDirection === HorizontalAlignment.Left ? - buttonRect.right - overlayRect.width : - getExpectedLeftPosition(positionSettings.horizontalStartPoint, buttonRect); - expect(overlayRect.top.toFixed(1)).toEqual(expectedTop.toFixed(1)); - expect(overlayRect.bottom.toFixed(1)).toEqual((overlayRect.top + overlayRect.height).toFixed(1)); - expect(overlayRect.left.toFixed(1)).toEqual(expectedLeft.toFixed(1)); - expect(overlayRect.right.toFixed(1)).toEqual((overlayRect.left + overlayRect.width).toFixed(1)); - expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar - fix.componentInstance.overlay.hideAll(); - } - - fit(`Should reposition the component and render it correctly in the window, even when the rendering options passed + it(`Should reposition the component and render it correctly in the window, even when the rendering options passed should result in otherwise a partially hidden component. No scrollbars should appear.`, fakeAsync(() => { const fix = TestBed.createComponent(EmptyPageComponent); fix.detectChanges(); const button = fix.componentInstance.buttonElement.nativeElement; + button.style.position = 'relative'; + button.style.width = '50px'; + button.style.height = '50px'; + const buttonLocations = [ + { left: `0px`, top: `0px` }, // topLeft + { left: `${window.innerWidth - 200}px`, top: `0px` }, // topRight + { left: `0px`, top: `${window.innerHeight - 200}px` }, // bottomLeft + { left: `${window.innerWidth - 200}px`, top: `${window.innerHeight - 200}px` } // bottomRight + ]; const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); - hAlignmentArray.forEach(function (horizontalStartPoint) { - vAlignmentArray.forEach(function (verticalStartPoint) { - hAlignmentArray.forEach(function (horizontalDirection) { - // do not check Center as we do nothing here - if (horizontalDirection === 'Center') { return; } - vAlignmentArray.forEach(function (verticalDirection) { - // do not check Middle as we do nothing here - if (verticalDirection === 'Middle') { return; } - - const positionSettings: PositionSettings = { - target: button - }; - positionSettings.horizontalStartPoint = HorizontalAlignment[horizontalStartPoint]; - positionSettings.verticalStartPoint = VerticalAlignment[verticalStartPoint]; - positionSettings.horizontalDirection = HorizontalAlignment[horizontalDirection]; - positionSettings.verticalDirection = VerticalAlignment[verticalDirection]; - - const overlaySettings: OverlaySettings = { - positionStrategy: new AutoPositionStrategy(positionSettings), - modal: false, - closeOnOutsideClick: false - }; - - fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - fix.detectChanges(); - - const targetRect: ClientRect = (positionSettings.target).getBoundingClientRect() as ClientRect; - const overlayWrapperElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; - const overlayWrapperRect: ClientRect = overlayWrapperElement.getBoundingClientRect() as ClientRect; - const screenRect: ClientRect = { - left: 0, - top: 0, - right: window.innerWidth, - bottom: window.innerHeight, - width: window.innerWidth, - height: window.innerHeight, - }; - - const location = getOverlayWrapperPosition(positionSettings, targetRect, overlayWrapperRect, screenRect); - expect(overlayWrapperRect.top.toFixed(1)).toEqual(location.y.toFixed(1)); - expect(overlayWrapperRect.left.toFixed(1)).toEqual(location.x.toFixed(1)); - expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar - fix.componentInstance.overlay.hideAll(); - tick(); - fix.detectChanges(); - }); - }); - }); - }); + for (const buttonLocation of buttonLocations) { + for (const horizontalStartPoint of hAlignmentArray) { + for (const verticalStartPoint of vAlignmentArray) { + for (const horizontalDirection of hAlignmentArray) { + if (horizontalDirection === 'Center') { continue; } + for (const verticalDirection of vAlignmentArray) { + if (verticalDirection === 'Middle') { continue; } + + const positionSettings: PositionSettings = { + target: button + }; + button.style.left = buttonLocation.left; + button.style.top = buttonLocation.top; + + positionSettings.horizontalStartPoint = HorizontalAlignment[horizontalStartPoint]; + positionSettings.verticalStartPoint = VerticalAlignment[verticalStartPoint]; + positionSettings.horizontalDirection = HorizontalAlignment[horizontalDirection]; + positionSettings.verticalDirection = VerticalAlignment[verticalDirection]; + + const overlaySettings: OverlaySettings = { + positionStrategy: new AutoPositionStrategy(positionSettings), + modal: false, + closeOnOutsideClick: false + }; + + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + fix.detectChanges(); + + const targetRect = (positionSettings.target).getBoundingClientRect() as ClientRect; + const overlayWrapperElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; + const overlayWrapperRect = overlayWrapperElement.getBoundingClientRect() as ClientRect; + const screenRect: ClientRect = { + left: 0, + top: 0, + right: window.innerWidth, + bottom: window.innerHeight, + width: window.innerWidth, + height: window.innerHeight, + }; + + const loc = getOverlayWrapperLocation(positionSettings, targetRect, overlayWrapperRect, screenRect); + expect(overlayWrapperRect.top.toFixed(1)).toEqual(loc.y.toFixed(1)); + expect(overlayWrapperRect.left.toFixed(1)).toEqual(loc.x.toFixed(1)); + expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar + fix.componentInstance.overlay.hideAll(); + tick(); + fix.detectChanges(); + } + } + } + } + } })); it('Should render margins correctly.', fakeAsync(() => { @@ -1980,47 +1983,136 @@ describe('igxOverlay', () => { const fix = TestBed.createComponent(EmptyPageComponent); fix.detectChanges(); const button = fix.componentInstance.buttonElement.nativeElement; - const positionSettings: PositionSettings = { - target: button - }; - const overlaySettings: OverlaySettings = { - positionStrategy: new ElasticPositionStrategy(positionSettings), - modal: false, - closeOnOutsideClick: false - }; + button.style.left = '150px'; + button.style.top = '150px'; + button.style.position = 'relative'; + const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); - vAlignmentArray.forEach(function (vAlignment) { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Left, VerticalAlignment.Bottom, - HorizontalAlignment.Right, VerticalAlignment[vAlignment]); - hAlignmentArray.forEach(function (hAlignment) { - verifyOverlayBoundingSizeAndPosition(HorizontalAlignment.Right, VerticalAlignment.Bottom, - HorizontalAlignment[hAlignment], VerticalAlignment[vAlignment]); + hAlignmentArray.forEach(function (horizontalStartPoint) { + vAlignmentArray.forEach(function (verticalStartPoint) { + hAlignmentArray.forEach(function (horizontalDirection) { + // do not check Center as we do nothing here + if (horizontalDirection === 'Center') { return; } + vAlignmentArray.forEach(function (verticalDirection) { + // do not check Middle as we do nothing here + if (verticalDirection === 'Middle') { return; } + + const positionSettings: PositionSettings = { + target: button + }; + positionSettings.horizontalStartPoint = HorizontalAlignment[horizontalStartPoint]; + positionSettings.verticalStartPoint = VerticalAlignment[verticalStartPoint]; + positionSettings.horizontalDirection = HorizontalAlignment[horizontalDirection]; + positionSettings.verticalDirection = VerticalAlignment[verticalDirection]; + positionSettings.minSize = { width: 80, height: 80 }; + + const overlaySettings: OverlaySettings = { + positionStrategy: new ElasticPositionStrategy(positionSettings), + modal: false, + closeOnOutsideClick: false + }; + + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + fix.detectChanges(); + + const targetRect: ClientRect = (positionSettings.target).getBoundingClientRect() as ClientRect; + const overlayWrapperElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; + const overlayWrapperRect: ClientRect = overlayWrapperElement.getBoundingClientRect() as ClientRect; + const screenRect: ClientRect = { + left: 0, + top: 0, + right: window.innerWidth, + bottom: window.innerHeight, + width: window.innerWidth, + height: window.innerHeight, + }; + + const location = + getOverlayWrapperLocation(positionSettings, targetRect, overlayWrapperRect, screenRect, true); + expect(overlayWrapperRect.top.toFixed(1)).toEqual(location.y.toFixed(1)); + expect(overlayWrapperRect.left.toFixed(1)).toEqual(location.x.toFixed(1)); + fix.componentInstance.overlay.hideAll(); + tick(); + fix.detectChanges(); + }); + }); }); }); + })); - // TODO: refactor this function and use it in all tests when needed - function verifyOverlayBoundingSizeAndPosition(horizontalDirection, verticalDirection, - horizontalAlignment, verticalAlignment) { - positionSettings.horizontalDirection = horizontalDirection; - positionSettings.verticalDirection = verticalDirection; - positionSettings.horizontalStartPoint = horizontalAlignment; - positionSettings.verticalStartPoint = verticalAlignment; - overlaySettings.positionStrategy = new ElasticPositionStrategy(positionSettings); - fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - const buttonRect = button.getBoundingClientRect(); - const overlayElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; - const overlayRect = overlayElement.getBoundingClientRect(); - const expectedTop = getExpectedTopPosition(verticalAlignment, buttonRect); - const expectedLeft = horizontalDirection === HorizontalAlignment.Left ? - buttonRect.right - overlayRect.width : - getExpectedLeftPosition(horizontalAlignment, buttonRect); - expect(overlayRect.top.toFixed(1)).toEqual(expectedTop.toFixed(1)); - expect(overlayRect.bottom.toFixed(1)).toEqual((overlayRect.top + overlayRect.height).toFixed(1)); - expect(overlayRect.left.toFixed(1)).toEqual(expectedLeft.toFixed(1)); - expect(overlayRect.right.toFixed(1)).toEqual((overlayRect.left + overlayRect.width).toFixed(1)); - fix.componentInstance.overlay.hideAll(); + it(`Should reposition the component and render it correctly in the window, even when the rendering options passed + should result in otherwise a partially hidden component.No scrollbars should appear.`, + fakeAsync(() => { + const fix = TestBed.createComponent(EmptyPageComponent); + fix.detectChanges(); + const button = fix.componentInstance.buttonElement.nativeElement; + button.style.position = 'relative'; + button.style.width = '50px'; + button.style.height = '50px'; + const buttonLocations = [ + { left: `0px`, top: `0px` }, // topLeft + { left: `${ window.innerWidth - 200 } px`, top: `0px` }, // topRight + { left: `0px`, top: `${ window.innerHeight - 200 } px` }, // bottomLeft + { left: `${ window.innerWidth - 200 } px`, top: `${ window.innerHeight - 200 } px` } // bottomRight + ]; + const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); + const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); + for (const buttonLocation of buttonLocations) { + for (const horizontalStartPoint of hAlignmentArray) { + for (const verticalStartPoint of vAlignmentArray) { + for (const horizontalDirection of hAlignmentArray) { + if (horizontalDirection === 'Center') { continue; } + for (const verticalDirection of vAlignmentArray) { + if (verticalDirection === 'Middle') { continue; } + + const positionSettings: PositionSettings = { + target: button + }; + button.style.left = buttonLocation.left; + button.style.top = buttonLocation.top; + + positionSettings.horizontalStartPoint = HorizontalAlignment[horizontalStartPoint]; + positionSettings.verticalStartPoint = VerticalAlignment[verticalStartPoint]; + positionSettings.horizontalDirection = HorizontalAlignment[horizontalDirection]; + positionSettings.verticalDirection = VerticalAlignment[verticalDirection]; + positionSettings.minSize = { width: 80, height: 80 }; + + const overlaySettings: OverlaySettings = { + positionStrategy: new ElasticPositionStrategy(positionSettings), + modal: false, + closeOnOutsideClick: false + }; + + fix.componentInstance.overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + fix.detectChanges(); + + const targetRect = (positionSettings.target).getBoundingClientRect() as ClientRect; + const overlayWrapperElement = document.getElementsByClassName(CLASS_OVERLAY_CONTENT)[0]; + const overlayWrapperRect = overlayWrapperElement.getBoundingClientRect() as ClientRect; + const screenRect: ClientRect = { + left: 0, + top: 0, + right: window.innerWidth, + bottom: window.innerHeight, + width: window.innerWidth, + height: window.innerHeight, + }; + + const loc = + getOverlayWrapperLocation(positionSettings, targetRect, overlayWrapperRect, screenRect, true); + expect(overlayWrapperRect.top.toFixed(1)).toEqual(loc.y.toFixed(1)); + expect(overlayWrapperRect.left.toFixed(1)).toEqual(loc.x.toFixed(1)); + expect(document.body.scrollHeight > document.body.clientHeight).toBeFalsy(); // check scrollbar + fix.componentInstance.overlay.hideAll(); + tick(); + fix.detectChanges(); + } + } + } + } } })); @@ -2156,7 +2248,7 @@ describe('igxOverlay', () => { })); it(`Should persist the component's open state when scrolling, when scrolling and noOP scroll strategy is used - (expanded DropDown remains expanded).`, fakeAsync(() => { + (expanded DropDown remains expanded).`, fakeAsync(() => { // TO DO replace Spies with css class and/or getBoundingClientRect. const fixture = TestBed.createComponent(EmptyPageComponent); const scrollTolerance = 10; @@ -2437,12 +2529,12 @@ describe('igxOverlay', () => { TestBed.overrideComponent(EmptyPageComponent, { set: { styles: [`button { - position: absolute; - top: 850px; - left: -30px; - width: 100px; - height: 60px; - }`] + position: absolute; + top: 850px; + left: -30px; + width: 100px; + height: 60px; + } `] } }); await TestBed.compileComponents(); @@ -2488,7 +2580,7 @@ describe('igxOverlay', () => { it('Should retain the component state when scrolling and block scroll strategy is used.', fakeAsync(async () => { TestBed.overrideComponent(EmptyPageComponent, { set: { - styles: [`button { position: absolute, bottom: -2000px; }`] + styles: [`button { position: absolute, bottom: -2000px; } `] } }); await TestBed.compileComponents(); @@ -2525,19 +2617,19 @@ describe('igxOverlay', () => { })); it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, - TOP + LEFT.`, fakeAsync(async () => { + TOP + LEFT.`, fakeAsync(async () => { TestBed.overrideComponent(DownRightButtonComponent, { set: { styles: [`button { - position: absolute; - top: 16px; - left: 16px; - width: 84px; - height: 84px; - padding: 0px; - margin: 0px; - border: 0px; - }`] + position: absolute; + top: 16px; + left: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + } `] } }); await TestBed.compileComponents(); @@ -2575,19 +2667,19 @@ describe('igxOverlay', () => { })); it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, - TOP + RIGHT.`, fakeAsync(async () => { + TOP + RIGHT.`, fakeAsync(async () => { TestBed.overrideComponent(DownRightButtonComponent, { set: { styles: [`button { - position: absolute; - top: 16px; - right: 16px; - width: 84px; - height: 84px; - padding: 0px; - margin: 0px; - border: 0px; - }`] + position: absolute; + top: 16px; + right: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + } `] } }); await TestBed.compileComponents(); @@ -2625,19 +2717,19 @@ describe('igxOverlay', () => { })); it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, - TOP + RIGHT.`, fakeAsync(async () => { + TOP + RIGHT.`, fakeAsync(async () => { TestBed.overrideComponent(DownRightButtonComponent, { set: { styles: [`button { - position: absolute; - top: 16px; - right: 16px; - width: 84px; - height: 84px; - padding: 0px; - margin: 0px; - border: 0px; - }`] + position: absolute; + top: 16px; + right: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + } `] } }); await TestBed.compileComponents(); @@ -2675,19 +2767,19 @@ describe('igxOverlay', () => { })); it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, - BOTTOM + LEFT.`, fakeAsync(async () => { + BOTTOM + LEFT.`, fakeAsync(async () => { TestBed.overrideComponent(DownRightButtonComponent, { set: { styles: [`button { - position: absolute; - bottom: 16px; - left: 16px; - width: 84px; - height: 84px; - padding: 0px; - margin: 0px; - border: 0px; - }`] + position: absolute; + bottom: 16px; + left: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + } `] } }); await TestBed.compileComponents(); @@ -2725,19 +2817,19 @@ describe('igxOverlay', () => { })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, - TOP + LEFT.`, fakeAsync(async () => { + TOP + LEFT.`, fakeAsync(async () => { TestBed.overrideComponent(DownRightButtonComponent, { set: { styles: [`button { - position: absolute; - top: 16px; - left: 16px; - width: 84px; - height: 84px; - padding: 0px; - margin: 0px; - border: 0px; - }`] + position: absolute; + top: 16px; + left: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + } `] } }); await TestBed.compileComponents(); @@ -2769,19 +2861,19 @@ describe('igxOverlay', () => { })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, - TOP + RIGHT.`, fakeAsync(async () => { + TOP + RIGHT.`, fakeAsync(async () => { TestBed.overrideComponent(DownRightButtonComponent, { set: { styles: [`button { - position: absolute; - top: 16px; - right: 16px; - width: 84px; - height: 84px; - padding: 0px; - margin: 0px; - border: 0px; - }`] + position: absolute; + top: 16px; + right: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + } `] } }); await TestBed.compileComponents(); @@ -2815,19 +2907,19 @@ describe('igxOverlay', () => { })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, - BOTTOM + LEFT.`, fakeAsync(async () => { + BOTTOM + LEFT.`, fakeAsync(async () => { TestBed.overrideComponent(DownRightButtonComponent, { set: { styles: [`button { - position: absolute; - bottom: 16px; - left: 16px; - width: 84px; - height: 84px; - padding: 0px; - margin: 0px; - border: 0px; - }`] + position: absolute; + bottom: 16px; + left: 16px; + width: 84px; + height: 84px; + padding: 0px; + margin: 0px; + border: 0px; + } `] } }); await TestBed.compileComponents(); @@ -2866,10 +2958,10 @@ describe('igxOverlay', () => { TestBed.overrideComponent(EmptyPageComponent, { set: { styles: [`button { - position: absolute; - top: 120%; - left:120%; - }`] + position: absolute; + top: 120 %; + left: 120 %; + } `] } }); await TestBed.compileComponents(); @@ -2903,10 +2995,10 @@ describe('igxOverlay', () => { TestBed.overrideComponent(EmptyPageComponent, { set: { styles: [`button { - position: absolute; - top: 120%; - left:120%; - }`] + position: absolute; + top: 120 %; + left: 120 %; + } `] } }); await TestBed.compileComponents(); @@ -2976,7 +3068,7 @@ describe('igxOverlay', () => { })); it(`Should not change the shown component shown state until it exceeds the scrolling tolerance set, - and closing scroll strategy is used.`, + and closing scroll strategy is used.`, fakeAsync(async () => { TestBed.overrideComponent(EmptyPageComponent, { set: { @@ -3012,7 +3104,7 @@ describe('igxOverlay', () => { })); it(`Should close the shown component shown when it exceeds the scrolling threshold set, and closing scroll strategy is used. - (an expanded DropDown, Menu, DatePicker, etc. collapses).`, fakeAsync(async () => { + (an expanded DropDown, Menu, DatePicker, etc.collapses).`, fakeAsync(async () => { TestBed.overrideComponent(EmptyPageComponent, { set: { styles: [ @@ -3171,12 +3263,12 @@ describe('igxOverlay', () => { declarations: DIRECTIVE_COMPONENTS }).compileComponents(); })); - it(`Should properly be able to render components that have no initial content (IgxCalendar, IgxAvatar)`, fakeAsync(() => { + it(`Should properly be able to render components that have no initial content(IgxCalendar, IgxAvatar)`, fakeAsync(() => { const fixture = TestBed.createComponent(SimpleRefComponent); fixture.detectChanges(); - const IGX_CALENDAR_CLASS = `.igx-calendar`; - const IGX_AVATAR_CLASS = `.igx-avatar`; - const IGX_DATEPICKER_CLASS = `.igx-date-picker`; + const IGX_CALENDAR_CLASS = `.igx - calendar`; + const IGX_AVATAR_CLASS = `.igx - avatar`; + const IGX_DATEPICKER_CLASS = `.igx - date - picker`; const overlay = fixture.componentInstance.overlay; expect(document.querySelectorAll((IGX_CALENDAR_CLASS)).length).toEqual(0); expect(document.querySelectorAll((IGX_AVATAR_CLASS)).length).toEqual(0); @@ -3211,7 +3303,7 @@ describe('igxOverlay', () => { }); @Component({ // tslint:disable-next-line:component-selector - selector: `simple-dynamic-component`, + selector: `simple - dynamic - component`, template: '
' }) export class SimpleDynamicComponent { @@ -3250,58 +3342,58 @@ export class SimpleBigSizeComponent { @Component({ template: ` -
-
-

AAAAA

-

AAAAA

-

AAAAA

-

AAAAA

-

AAAAA

-

AAAAA

-

AAAAA

-

AAAAA

-

AAAAA

-
-
` -}) -export class SimpleDynamicWithDirectiveComponent { - public visible = false; - - @ViewChild(IgxToggleDirective) - private _overlay: IgxToggleDirective; - - public get overlay(): IgxToggleDirective { - return this._overlay; - } + < div igxToggle > +
+ < p > AAAAA < /p> + < p > AAAAA < /p> + < p > AAAAA < /p> + < p > AAAAA < /p> + < p > AAAAA < /p> + < p > AAAAA < /p> + < p > AAAAA < /p> + < p > AAAAA < /p> + < p > AAAAA < /p> + < /div> + < /div>` + }) + export class SimpleDynamicWithDirectiveComponent { + public visible = false; + + @ViewChild(IgxToggleDirective) + private _overlay: IgxToggleDirective; + + public get overlay(): IgxToggleDirective { + return this._overlay; + } - show(overlaySettings?: OverlaySettings) { - this.visible = true; - this.overlay.open(overlaySettings); - } + show(overlaySettings?: OverlaySettings) { + this.visible = true; + this.overlay.open(overlaySettings); + } - hide() { - this.visible = false; - this.overlay.close(); + hide() { + this.visible = false; + this.overlay.close(); + } } -} -@Component({ - template: `` -}) -export class EmptyPageComponent { - constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } + @Component({ + template: `` + }) + export class EmptyPageComponent { + constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } - @ViewChild('button') buttonElement: ElementRef; + @ViewChild('button') buttonElement: ElementRef; - click(event) { - this.overlay.show(SimpleDynamicComponent); + click(event) { + this.overlay.show(SimpleDynamicComponent); + } } -} -@Component({ - template: ``, - styles: [`button { + @Component({ + template: ``, + styles: [`button { position: absolute; bottom: 0px; right: 0px; @@ -3311,35 +3403,35 @@ export class EmptyPageComponent { margin: 0px; border: 0px; }`] -}) -export class DownRightButtonComponent { - constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } - - public positionStrategy: IPositionStrategy; - - @ViewChild('button') buttonElement: ElementRef; - - public ButtonPositioningSettings: PositionSettings = { - horizontalDirection: HorizontalAlignment.Right, - verticalDirection: VerticalAlignment.Bottom, - target: null, - horizontalStartPoint: HorizontalAlignment.Left, - verticalStartPoint: VerticalAlignment.Top - }; - - click(event) { - this.positionStrategy.settings = this.ButtonPositioningSettings; - this.overlay.show(SimpleDynamicComponent, { - positionStrategy: this.positionStrategy, - scrollStrategy: new NoOpScrollStrategy(), - modal: false, - closeOnOutsideClick: false - }); + }) + export class DownRightButtonComponent { + constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } + + public positionStrategy: IPositionStrategy; + + @ViewChild('button') buttonElement: ElementRef; + + public ButtonPositioningSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Right, + verticalDirection: VerticalAlignment.Bottom, + target: null, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + + click(event) { + this.positionStrategy.settings = this.ButtonPositioningSettings; + this.overlay.show(SimpleDynamicComponent, { + positionStrategy: this.positionStrategy, + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false + }); + } } -} -@Component({ - template: ``, - styles: [`button { + @Component({ + template: ``, + styles: [`button { position: absolute; top: 300px; left: 300px; @@ -3347,52 +3439,52 @@ export class DownRightButtonComponent { height: 60px; border: 0px; }`] -}) -export class TopLeftOffsetComponent { + }) + export class TopLeftOffsetComponent { - constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } + constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } - @ViewChild('button') buttonElement: ElementRef; - click(event) { - this.overlay.show(SimpleDynamicComponent); + @ViewChild('button') buttonElement: ElementRef; + click(event) { + this.overlay.show(SimpleDynamicComponent); + } } -} -@Component({ - template: ` + @Component({ + template: `
` -}) -export class TwoButtonsComponent { - private _setting: OverlaySettings = { modal: false }; + }) + export class TwoButtonsComponent { + private _setting: OverlaySettings = { modal: false }; - constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } + constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } - clickOne() { - this.overlay.show(SimpleDynamicComponent, this._setting); - } + clickOne() { + this.overlay.show(SimpleDynamicComponent, this._setting); + } - clickTwo() { - this.overlay.show(SimpleDynamicComponent, this._setting); - } + clickTwo() { + this.overlay.show(SimpleDynamicComponent, this._setting); + } - divClick(ev: Event) { - ev.stopPropagation(); + divClick(ev: Event) { + ev.stopPropagation(); + } } -} -@Component({ - template: `
+ @Component({ + template: `
Some Content
`, - styles: [`button { + styles: [`button { position: absolute; top: 300px; left: 300px; @@ -3400,30 +3492,30 @@ export class TwoButtonsComponent { height: 60px; border: 0px; }`] -}) -export class WidthTestOverlayComponent { - - constructor( - @Inject(IgxOverlayService) public overlay: IgxOverlayService, - public elementRef: ElementRef - ) { } - - @ViewChild('button') buttonElement: ElementRef; - @ViewChild('myCustomComponent') customComponent: ElementRef; - public overlaySettings: OverlaySettings = {}; - click(event) { - this.overlaySettings.positionStrategy = new ConnectedPositioningStrategy(); - this.overlaySettings.scrollStrategy = new NoOpScrollStrategy(); - this.overlaySettings.closeOnOutsideClick = true; - this.overlaySettings.modal = false; - - this.overlaySettings.positionStrategy.settings.target = this.buttonElement.nativeElement; - this.overlay.show(this.customComponent, this.overlaySettings); + }) + export class WidthTestOverlayComponent { + + constructor( + @Inject(IgxOverlayService) public overlay: IgxOverlayService, + public elementRef: ElementRef + ) { } + + @ViewChild('button') buttonElement: ElementRef; + @ViewChild('myCustomComponent') customComponent: ElementRef; + public overlaySettings: OverlaySettings = {}; + click(event) { + this.overlaySettings.positionStrategy = new ConnectedPositioningStrategy(); + this.overlaySettings.scrollStrategy = new NoOpScrollStrategy(); + this.overlaySettings.closeOnOutsideClick = true; + this.overlaySettings.modal = false; + + this.overlaySettings.positionStrategy.settings.target = this.buttonElement.nativeElement; + this.overlay.show(this.customComponent, this.overlaySettings); + } } -} -@Component({ - template: ` + @Component({ + template: `

AAAAA

@@ -3437,83 +3529,83 @@ export class WidthTestOverlayComponent {

AAAAA

` -}) -export class ScrollableComponent { - public visible = false; + }) + export class ScrollableComponent { + public visible = false; - @ViewChild(IgxToggleDirective) - private _toggle: IgxToggleDirective; + @ViewChild(IgxToggleDirective) + private _toggle: IgxToggleDirective; - public get toggle(): IgxToggleDirective { - return this._toggle; - } + public get toggle(): IgxToggleDirective { + return this._toggle; + } - show() { - this.visible = true; - const settings: OverlaySettings = { scrollStrategy: new CloseScrollStrategy() }; - this.toggle.open(settings); - } + show() { + this.visible = true; + const settings: OverlaySettings = { scrollStrategy: new CloseScrollStrategy() }; + this.toggle.open(settings); + } - hide() { - this.toggle.close(); - this.visible = false; - } + hide() { + this.toggle.close(); + this.visible = false; + } -} + } -@Component({ - template: ` + @Component({ + template: `
` -}) -export class FlexContainerComponent { - public overlaySettings: OverlaySettings = {}; - constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } - - @ViewChild('button') buttonElement: ElementRef; - click(event) { - this.overlay.show(SimpleDynamicComponent, this.overlaySettings); + }) + export class FlexContainerComponent { + public overlaySettings: OverlaySettings = {}; + constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } + + @ViewChild('button') buttonElement: ElementRef; + click(event) { + this.overlay.show(SimpleDynamicComponent, this.overlaySettings); + } } -} - -const DYNAMIC_COMPONENTS = [ - EmptyPageComponent, - SimpleRefComponent, - SimpleDynamicComponent, - SimpleBigSizeComponent, - DownRightButtonComponent, - TopLeftOffsetComponent, - TwoButtonsComponent, - WidthTestOverlayComponent, - ScrollableComponent, - FlexContainerComponent -]; - -const IgniteUIComponents = [ - IgxCalendarComponent, - IgxAvatarComponent, - IgxDatePickerComponent -]; - -const DIRECTIVE_COMPONENTS = [ - SimpleDynamicWithDirectiveComponent -]; - -@NgModule({ - imports: [BrowserModule], - declarations: [DYNAMIC_COMPONENTS], - exports: [DYNAMIC_COMPONENTS], - entryComponents: [DYNAMIC_COMPONENTS] -}) -export class DynamicModule { } -@NgModule({ - imports: [IgxCalendarModule, IgxAvatarModule, IgxDatePickerModule], - entryComponents: IgniteUIComponents -}) -export class IgxComponentsModule { -} + const DYNAMIC_COMPONENTS = [ + EmptyPageComponent, + SimpleRefComponent, + SimpleDynamicComponent, + SimpleBigSizeComponent, + DownRightButtonComponent, + TopLeftOffsetComponent, + TwoButtonsComponent, + WidthTestOverlayComponent, + ScrollableComponent, + FlexContainerComponent + ]; + + const IgniteUIComponents = [ + IgxCalendarComponent, + IgxAvatarComponent, + IgxDatePickerComponent + ]; + + const DIRECTIVE_COMPONENTS = [ + SimpleDynamicWithDirectiveComponent + ]; + + @NgModule({ + imports: [BrowserModule], + declarations: [DYNAMIC_COMPONENTS], + exports: [DYNAMIC_COMPONENTS], + entryComponents: [DYNAMIC_COMPONENTS] + }) + export class DynamicModule { } + + @NgModule({ + imports: [IgxCalendarModule, IgxAvatarModule, IgxDatePickerModule], + entryComponents: IgniteUIComponents + }) + export class IgxComponentsModule { + } From d6928ab6ce54f953351fe34615b38dec7cabbb47 Mon Sep 17 00:00:00 2001 From: wnvko Date: Tue, 18 Dec 2018 12:05:18 +0200 Subject: [PATCH 10/11] test(igxOverlay): fix failing tests in overlay.spec.ts, #2697 --- .../src/lib/services/overlay/overlay.spec.ts | 1040 ++++++++--------- 1 file changed, 520 insertions(+), 520 deletions(-) diff --git a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts index 217d96daede..fb9a5c92c8d 100644 --- a/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts +++ b/projects/igniteui-angular/src/lib/services/overlay/overlay.spec.ts @@ -1804,37 +1804,37 @@ describe('igxOverlay', () => { it(`Should persist the component's open state when scrolling, when scrolling and noOP scroll strategy is used (expanded DropDown remains expanded).`, fakeAsync(() => { - // TO DO replace Spies with css class and/or getBoundingClientRect. - const fixture = TestBed.createComponent(EmptyPageComponent); - const scrollTolerance = 10; - const scrollStrategy = new BlockScrollStrategy(); - const overlay = fixture.componentInstance.overlay; - const overlaySettings: OverlaySettings = { - modal: false, - scrollStrategy: scrollStrategy, - positionStrategy: new GlobalPositionStrategy() - }; + // TO DO replace Spies with css class and/or getBoundingClientRect. + const fixture = TestBed.createComponent(EmptyPageComponent); + const scrollTolerance = 10; + const scrollStrategy = new BlockScrollStrategy(); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + modal: false, + scrollStrategy: scrollStrategy, + positionStrategy: new GlobalPositionStrategy() + }; - spyOn(scrollStrategy, 'initialize').and.callThrough(); - spyOn(scrollStrategy, 'attach').and.callThrough(); - spyOn(scrollStrategy, 'detach').and.callThrough(); - spyOn(overlay, 'hide').and.callThrough(); + spyOn(scrollStrategy, 'initialize').and.callThrough(); + spyOn(scrollStrategy, 'attach').and.callThrough(); + spyOn(scrollStrategy, 'detach').and.callThrough(); + spyOn(overlay, 'hide').and.callThrough(); - const scrollSpy = spyOn(scrollStrategy, 'onScroll').and.callThrough(); + const scrollSpy = spyOn(scrollStrategy, 'onScroll').and.callThrough(); - overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - expect(scrollStrategy.initialize).toHaveBeenCalledTimes(1); - expect(scrollStrategy.attach).toHaveBeenCalledTimes(1); - expect(scrollStrategy.detach).toHaveBeenCalledTimes(0); - expect(overlay.hide).toHaveBeenCalledTimes(0); - document.documentElement.scrollTop += scrollTolerance; - document.dispatchEvent(new Event('scroll')); - tick(); - expect(scrollSpy).toHaveBeenCalledTimes(1); - expect(overlay.hide).toHaveBeenCalledTimes(0); - expect(scrollStrategy.detach).toHaveBeenCalledTimes(0); - })); + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + expect(scrollStrategy.initialize).toHaveBeenCalledTimes(1); + expect(scrollStrategy.attach).toHaveBeenCalledTimes(1); + expect(scrollStrategy.detach).toHaveBeenCalledTimes(0); + expect(overlay.hide).toHaveBeenCalledTimes(0); + document.documentElement.scrollTop += scrollTolerance; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(scrollSpy).toHaveBeenCalledTimes(1); + expect(overlay.hide).toHaveBeenCalledTimes(0); + expect(scrollStrategy.detach).toHaveBeenCalledTimes(0); + })); it('Should persist the component open state when scrolling and absolute scroll strategy is used.', fakeAsync(() => { // TO DO replace Spies with css class and/or getBoundingClientRect. @@ -2053,9 +2053,9 @@ describe('igxOverlay', () => { button.style.height = '50px'; const buttonLocations = [ { left: `0px`, top: `0px` }, // topLeft - { left: `${ window.innerWidth - 200 } px`, top: `0px` }, // topRight - { left: `0px`, top: `${ window.innerHeight - 200 } px` }, // bottomLeft - { left: `${ window.innerWidth - 200 } px`, top: `${ window.innerHeight - 200 } px` } // bottomRight + { left: `${window.innerWidth - 200} px`, top: `0px` }, // topRight + { left: `0px`, top: `${window.innerHeight - 200} px` }, // bottomLeft + { left: `${window.innerWidth - 200} px`, top: `${window.innerHeight - 200} px` } // bottomRight ]; const hAlignmentArray = Object.keys(HorizontalAlignment).filter(key => !isNaN(Number(HorizontalAlignment[key]))); const vAlignmentArray = Object.keys(VerticalAlignment).filter(key => !isNaN(Number(VerticalAlignment[key]))); @@ -2249,37 +2249,37 @@ describe('igxOverlay', () => { it(`Should persist the component's open state when scrolling, when scrolling and noOP scroll strategy is used (expanded DropDown remains expanded).`, fakeAsync(() => { - // TO DO replace Spies with css class and/or getBoundingClientRect. - const fixture = TestBed.createComponent(EmptyPageComponent); - const scrollTolerance = 10; - const scrollStrategy = new BlockScrollStrategy(); - const overlay = fixture.componentInstance.overlay; - const overlaySettings: OverlaySettings = { - modal: false, - scrollStrategy: scrollStrategy, - positionStrategy: new ElasticPositionStrategy() - }; + // TO DO replace Spies with css class and/or getBoundingClientRect. + const fixture = TestBed.createComponent(EmptyPageComponent); + const scrollTolerance = 10; + const scrollStrategy = new BlockScrollStrategy(); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + modal: false, + scrollStrategy: scrollStrategy, + positionStrategy: new ElasticPositionStrategy() + }; - spyOn(scrollStrategy, 'initialize').and.callThrough(); - spyOn(scrollStrategy, 'attach').and.callThrough(); - spyOn(scrollStrategy, 'detach').and.callThrough(); - spyOn(overlay, 'hide').and.callThrough(); + spyOn(scrollStrategy, 'initialize').and.callThrough(); + spyOn(scrollStrategy, 'attach').and.callThrough(); + spyOn(scrollStrategy, 'detach').and.callThrough(); + spyOn(overlay, 'hide').and.callThrough(); - const scrollSpy = spyOn(scrollStrategy, 'onScroll').and.callThrough(); + const scrollSpy = spyOn(scrollStrategy, 'onScroll').and.callThrough(); - overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - expect(scrollStrategy.initialize).toHaveBeenCalledTimes(1); - expect(scrollStrategy.attach).toHaveBeenCalledTimes(1); - expect(scrollStrategy.detach).toHaveBeenCalledTimes(0); - expect(overlay.hide).toHaveBeenCalledTimes(0); - document.documentElement.scrollTop += scrollTolerance; - document.dispatchEvent(new Event('scroll')); - tick(); - expect(scrollSpy).toHaveBeenCalledTimes(1); - expect(overlay.hide).toHaveBeenCalledTimes(0); - expect(scrollStrategy.detach).toHaveBeenCalledTimes(0); - })); + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + expect(scrollStrategy.initialize).toHaveBeenCalledTimes(1); + expect(scrollStrategy.attach).toHaveBeenCalledTimes(1); + expect(scrollStrategy.detach).toHaveBeenCalledTimes(0); + expect(overlay.hide).toHaveBeenCalledTimes(0); + document.documentElement.scrollTop += scrollTolerance; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(scrollSpy).toHaveBeenCalledTimes(1); + expect(overlay.hide).toHaveBeenCalledTimes(0); + expect(scrollStrategy.detach).toHaveBeenCalledTimes(0); + })); it('Should persist the component open state when scrolling and absolute scroll strategy is used.', fakeAsync(() => { // TO DO replace Spies with css class and/or getBoundingClientRect. @@ -2618,9 +2618,9 @@ describe('igxOverlay', () => { it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; top: 16px; left: 16px; @@ -2630,47 +2630,47 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; } `] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new AutoPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button - const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button + const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + RIGHT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; top: 16px; right: 16px; @@ -2680,47 +2680,47 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; } `] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new AutoPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedRight = buttonLeft; // To the left of the button - const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperRight = wrapperContent.getBoundingClientRect().right; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperRight).toEqual(expectedRight); - })); + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedRight = buttonLeft; // To the left of the button + const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button + const wrapperRight = wrapperContent.getBoundingClientRect().right; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperRight).toEqual(expectedRight); + })); it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + RIGHT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; top: 16px; right: 16px; @@ -2730,47 +2730,47 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; } `] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new AutoPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapper in NG-COMPONENT - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; // To the left of the button - const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; // wrapper in NG-COMPONENT + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft - wrapperContent.lastElementChild.lastElementChild.clientWidth; // To the left of the button + const expectedTop = buttonTop + buttonElement.clientHeight; // Bottom of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); it(`Should show the component, AutoPositionStrategy, inside of the viewport if it would normally be outside of bounds, BOTTOM + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; bottom: 16px; left: 16px; @@ -2780,47 +2780,47 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; } `] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new AutoPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - buttonElement.click(); - fix.detectChanges(); - tick(); + fix.componentInstance.positionStrategy = new AutoPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + buttonElement.click(); + fix.detectChanges(); + tick(); - fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; - const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; - expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); - const buttonLeft = buttonElement.offsetLeft; - const buttonTop = buttonElement.offsetTop; - const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button - const expectedTop = buttonTop - wrapperContent.lastElementChild.clientHeight; // On top of the button - const wrapperLeft = wrapperContent.getBoundingClientRect().left; - const wrapperTop = wrapperContent.getBoundingClientRect().top; - expect(wrapperTop).toEqual(expectedTop); - expect(wrapperLeft).toEqual(expectedLeft); - })); + fix.detectChanges(); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1] as HTMLElement; + const expectedStyle = 'position: absolute; width:100px; height: 100px; background-color: red'; + expect(wrapperContent.lastElementChild.lastElementChild.getAttribute('style')).toEqual(expectedStyle); + const buttonLeft = buttonElement.offsetLeft; + const buttonTop = buttonElement.offsetTop; + const expectedLeft = buttonLeft + buttonElement.clientWidth; // To the right of the button + const expectedTop = buttonTop - wrapperContent.lastElementChild.clientHeight; // On top of the button + const wrapperLeft = wrapperContent.getBoundingClientRect().left; + const wrapperTop = wrapperContent.getBoundingClientRect().top; + expect(wrapperTop).toEqual(expectedTop); + expect(wrapperLeft).toEqual(expectedLeft); + })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; top: 16px; left: 16px; @@ -2830,41 +2830,41 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; } `] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - currentElement.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; - buttonElement.click(); - tick(); - fix.detectChanges(); + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + currentElement.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; + buttonElement.click(); + tick(); + fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1]; // wrapper in NG-COMPONENT - const expectedLeft = buttonElement.offsetLeft - currentElement.ButtonPositioningSettings.minSize.width; - const expectedTop = buttonElement.offsetTop - currentElement.ButtonPositioningSettings.minSize.height; - const componentRect = wrapperContent.lastElementChild.getBoundingClientRect(); - expect(componentRect.left).toEqual(expectedLeft); - expect(componentRect.top).toEqual(expectedTop); - })); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1]; // wrapper in NG-COMPONENT + const expectedLeft = buttonElement.offsetLeft - currentElement.ButtonPositioningSettings.minSize.width; + const expectedTop = buttonElement.offsetTop - currentElement.ButtonPositioningSettings.minSize.height; + const componentRect = wrapperContent.lastElementChild.getBoundingClientRect(); + expect(componentRect.left).toEqual(expectedLeft); + expect(componentRect.top).toEqual(expectedTop); + })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, TOP + RIGHT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; top: 16px; right: 16px; @@ -2874,43 +2874,43 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; } `] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; - currentElement.ButtonPositioningSettings.target = buttonElement; - currentElement.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; - buttonElement.click(); - fix.detectChanges(); - tick(); - fix.detectChanges(); + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Top; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Right; + currentElement.ButtonPositioningSettings.target = buttonElement; + currentElement.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; + buttonElement.click(); + fix.detectChanges(); + tick(); + fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1]; // wrapper in NG-COMPONENT - const expectedLeft = buttonElement.offsetLeft + buttonElement.clientWidth; - const expectedTop = buttonElement.offsetTop - currentElement.ButtonPositioningSettings.minSize.height; - const componentRect = wrapperContent.lastElementChild.getBoundingClientRect(); - expect(componentRect.left).toEqual(expectedLeft); - expect(componentRect.top).toEqual(expectedTop); - })); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1]; // wrapper in NG-COMPONENT + const expectedLeft = buttonElement.offsetLeft + buttonElement.clientWidth; + const expectedTop = buttonElement.offsetTop - currentElement.ButtonPositioningSettings.minSize.height; + const componentRect = wrapperContent.lastElementChild.getBoundingClientRect(); + expect(componentRect.left).toEqual(expectedLeft); + expect(componentRect.top).toEqual(expectedTop); + })); it(`Should show the component, ElasticPositionStrategy, inside of the viewport if it would normally be outside of bounds, BOTTOM + LEFT.`, fakeAsync(async () => { - TestBed.overrideComponent(DownRightButtonComponent, { - set: { - styles: [`button { + TestBed.overrideComponent(DownRightButtonComponent, { + set: { + styles: [`button { position: absolute; bottom: 16px; left: 16px; @@ -2920,37 +2920,37 @@ describe('igxOverlay', () => { margin: 0px; border: 0px; } `] - } - }); - await TestBed.compileComponents(); - const fix = TestBed.createComponent(DownRightButtonComponent); - fix.detectChanges(); + } + }); + await TestBed.compileComponents(); + const fix = TestBed.createComponent(DownRightButtonComponent); + fix.detectChanges(); - fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); - UIInteractions.clearOverlay(); - fix.detectChanges(); - const currentElement = fix.componentInstance; - const buttonElement = fix.componentInstance.buttonElement.nativeElement; - fix.detectChanges(); - currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; - currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; - currentElement.ButtonPositioningSettings.target = buttonElement; - currentElement.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; - buttonElement.click(); - fix.detectChanges(); - tick(); - fix.detectChanges(); + fix.componentInstance.positionStrategy = new ElasticPositionStrategy(); + UIInteractions.clearOverlay(); + fix.detectChanges(); + const currentElement = fix.componentInstance; + const buttonElement = fix.componentInstance.buttonElement.nativeElement; + fix.detectChanges(); + currentElement.ButtonPositioningSettings.horizontalDirection = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.verticalDirection = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.verticalStartPoint = VerticalAlignment.Bottom; + currentElement.ButtonPositioningSettings.horizontalStartPoint = HorizontalAlignment.Left; + currentElement.ButtonPositioningSettings.target = buttonElement; + currentElement.ButtonPositioningSettings.minSize = { width: 80, height: 80 }; + buttonElement.click(); + fix.detectChanges(); + tick(); + fix.detectChanges(); - const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); - const wrapperContent = wrappers[wrappers.length - 1]; // wrapper in NG-COMPONENT - const expectedLeft = buttonElement.offsetLeft - currentElement.ButtonPositioningSettings.minSize.width; - const expectedTop = buttonElement.offsetTop + buttonElement.offsetHeight; - const componentRect = wrapperContent.lastElementChild.getBoundingClientRect(); - expect(componentRect.left).toEqual(expectedLeft); - expect(componentRect.top).toEqual(expectedTop); - })); + const wrappers = document.getElementsByClassName(CLASS_OVERLAY_CONTENT); + const wrapperContent = wrappers[wrappers.length - 1]; // wrapper in NG-COMPONENT + const expectedLeft = buttonElement.offsetLeft - currentElement.ButtonPositioningSettings.minSize.width; + const expectedTop = buttonElement.offsetTop + buttonElement.offsetHeight; + const componentRect = wrapperContent.lastElementChild.getBoundingClientRect(); + expect(componentRect.left).toEqual(expectedLeft); + expect(componentRect.top).toEqual(expectedTop); + })); // 2. Scroll Strategy (test with GlobalPositionStrategy(default)) // 2.1. Scroll Strategy - None @@ -2959,8 +2959,8 @@ describe('igxOverlay', () => { set: { styles: [`button { position: absolute; - top: 120 %; - left: 120 %; + top: 120%; + left: 120%; } `] } }); @@ -2996,8 +2996,8 @@ describe('igxOverlay', () => { set: { styles: [`button { position: absolute; - top: 120 %; - left: 120 %; + top: 120%; + left: 120%; } `] } }); @@ -3105,41 +3105,41 @@ describe('igxOverlay', () => { it(`Should close the shown component shown when it exceeds the scrolling threshold set, and closing scroll strategy is used. (an expanded DropDown, Menu, DatePicker, etc.collapses).`, fakeAsync(async () => { - TestBed.overrideComponent(EmptyPageComponent, { - set: { - styles: [ - 'button { position: absolute; top: 100%; left: 90% }' - ] - } - }); - await TestBed.compileComponents(); - const fixture = TestBed.createComponent(EmptyPageComponent); - fixture.detectChanges(); + TestBed.overrideComponent(EmptyPageComponent, { + set: { + styles: [ + 'button { position: absolute; top: 100%; left: 90% }' + ] + } + }); + await TestBed.compileComponents(); + const fixture = TestBed.createComponent(EmptyPageComponent); + fixture.detectChanges(); - const scrollTolerance = 10; - const scrollStrategy = new CloseScrollStrategy(); - const overlay = fixture.componentInstance.overlay; - const overlaySettings: OverlaySettings = { - positionStrategy: new GlobalPositionStrategy(), - scrollStrategy: scrollStrategy, - modal: false - }; + const scrollTolerance = 10; + const scrollStrategy = new CloseScrollStrategy(); + const overlay = fixture.componentInstance.overlay; + const overlaySettings: OverlaySettings = { + positionStrategy: new GlobalPositionStrategy(), + scrollStrategy: scrollStrategy, + modal: false + }; - overlay.show(SimpleDynamicComponent, overlaySettings); - tick(); - expect(document.documentElement.scrollTop).toEqual(0); + overlay.show(SimpleDynamicComponent, overlaySettings); + tick(); + expect(document.documentElement.scrollTop).toEqual(0); - document.documentElement.scrollTop += scrollTolerance; - document.dispatchEvent(new Event('scroll')); - tick(); - expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); - expect(document.documentElement.scrollTop).toEqual(scrollTolerance); + document.documentElement.scrollTop += scrollTolerance; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(1); + expect(document.documentElement.scrollTop).toEqual(scrollTolerance); - document.documentElement.scrollTop += scrollTolerance * 2; - document.dispatchEvent(new Event('scroll')); - tick(); - expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(0); - })); + document.documentElement.scrollTop += scrollTolerance * 2; + document.dispatchEvent(new Event('scroll')); + tick(); + expect(document.getElementsByClassName(CLASS_OVERLAY_WRAPPER).length).toEqual(0); + })); // 2.3 Scroll Strategy - NoOp. it('Should retain the component static and only the background scrolls, when scrolling and noOP scroll strategy is used.', @@ -3266,9 +3266,9 @@ describe('igxOverlay', () => { it(`Should properly be able to render components that have no initial content(IgxCalendar, IgxAvatar)`, fakeAsync(() => { const fixture = TestBed.createComponent(SimpleRefComponent); fixture.detectChanges(); - const IGX_CALENDAR_CLASS = `.igx - calendar`; - const IGX_AVATAR_CLASS = `.igx - avatar`; - const IGX_DATEPICKER_CLASS = `.igx - date - picker`; + const IGX_CALENDAR_CLASS = `.igx-calendar`; + const IGX_AVATAR_CLASS = `.igx-avatar`; + const IGX_DATEPICKER_CLASS = `.igx-date-picker`; const overlay = fixture.componentInstance.overlay; expect(document.querySelectorAll((IGX_CALENDAR_CLASS)).length).toEqual(0); expect(document.querySelectorAll((IGX_AVATAR_CLASS)).length).toEqual(0); @@ -3342,58 +3342,58 @@ export class SimpleBigSizeComponent { @Component({ template: ` - < div igxToggle > -
- < p > AAAAA < /p> - < p > AAAAA < /p> - < p > AAAAA < /p> - < p > AAAAA < /p> - < p > AAAAA < /p> - < p > AAAAA < /p> - < p > AAAAA < /p> - < p > AAAAA < /p> - < p > AAAAA < /p> - < /div> - < /div>` - }) - export class SimpleDynamicWithDirectiveComponent { - public visible = false; - - @ViewChild(IgxToggleDirective) - private _overlay: IgxToggleDirective; - - public get overlay(): IgxToggleDirective { - return this._overlay; - } +
+
+

AAAAA

+

AAAAA

+

AAAAA

+

AAAAA

+

AAAAA

+

AAAAA

+

AAAAA

+

AAAAA

+

AAAAA

+
+
` +}) +export class SimpleDynamicWithDirectiveComponent { + public visible = false; - show(overlaySettings?: OverlaySettings) { - this.visible = true; - this.overlay.open(overlaySettings); - } + @ViewChild(IgxToggleDirective) + private _overlay: IgxToggleDirective; - hide() { - this.visible = false; - this.overlay.close(); - } + public get overlay(): IgxToggleDirective { + return this._overlay; } - @Component({ - template: `` - }) - export class EmptyPageComponent { - constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } + show(overlaySettings?: OverlaySettings) { + this.visible = true; + this.overlay.open(overlaySettings); + } - @ViewChild('button') buttonElement: ElementRef; + hide() { + this.visible = false; + this.overlay.close(); + } +} - click(event) { - this.overlay.show(SimpleDynamicComponent); - } +@Component({ + template: `` +}) +export class EmptyPageComponent { + constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } + + @ViewChild('button') buttonElement: ElementRef; + + click(event) { + this.overlay.show(SimpleDynamicComponent); } +} - @Component({ - template: ``, - styles: [`button { +@Component({ + template: ``, + styles: [`button { position: absolute; bottom: 0px; right: 0px; @@ -3403,35 +3403,35 @@ export class SimpleBigSizeComponent { margin: 0px; border: 0px; }`] - }) - export class DownRightButtonComponent { - constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } - - public positionStrategy: IPositionStrategy; - - @ViewChild('button') buttonElement: ElementRef; - - public ButtonPositioningSettings: PositionSettings = { - horizontalDirection: HorizontalAlignment.Right, - verticalDirection: VerticalAlignment.Bottom, - target: null, - horizontalStartPoint: HorizontalAlignment.Left, - verticalStartPoint: VerticalAlignment.Top - }; - - click(event) { - this.positionStrategy.settings = this.ButtonPositioningSettings; - this.overlay.show(SimpleDynamicComponent, { - positionStrategy: this.positionStrategy, - scrollStrategy: new NoOpScrollStrategy(), - modal: false, - closeOnOutsideClick: false - }); - } +}) +export class DownRightButtonComponent { + constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } + + public positionStrategy: IPositionStrategy; + + @ViewChild('button') buttonElement: ElementRef; + + public ButtonPositioningSettings: PositionSettings = { + horizontalDirection: HorizontalAlignment.Right, + verticalDirection: VerticalAlignment.Bottom, + target: null, + horizontalStartPoint: HorizontalAlignment.Left, + verticalStartPoint: VerticalAlignment.Top + }; + + click(event) { + this.positionStrategy.settings = this.ButtonPositioningSettings; + this.overlay.show(SimpleDynamicComponent, { + positionStrategy: this.positionStrategy, + scrollStrategy: new NoOpScrollStrategy(), + modal: false, + closeOnOutsideClick: false + }); } - @Component({ - template: ``, - styles: [`button { +} +@Component({ + template: ``, + styles: [`button { position: absolute; top: 300px; left: 300px; @@ -3439,52 +3439,52 @@ export class SimpleBigSizeComponent { height: 60px; border: 0px; }`] - }) - export class TopLeftOffsetComponent { +}) +export class TopLeftOffsetComponent { - constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } + constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } - @ViewChild('button') buttonElement: ElementRef; - click(event) { - this.overlay.show(SimpleDynamicComponent); - } + @ViewChild('button') buttonElement: ElementRef; + click(event) { + this.overlay.show(SimpleDynamicComponent); } +} - @Component({ - template: ` +@Component({ + template: `
` - }) - export class TwoButtonsComponent { - private _setting: OverlaySettings = { modal: false }; +}) +export class TwoButtonsComponent { + private _setting: OverlaySettings = { modal: false }; - constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } + constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } - clickOne() { - this.overlay.show(SimpleDynamicComponent, this._setting); - } + clickOne() { + this.overlay.show(SimpleDynamicComponent, this._setting); + } - clickTwo() { - this.overlay.show(SimpleDynamicComponent, this._setting); - } + clickTwo() { + this.overlay.show(SimpleDynamicComponent, this._setting); + } - divClick(ev: Event) { - ev.stopPropagation(); - } + divClick(ev: Event) { + ev.stopPropagation(); } +} - @Component({ - template: `
+@Component({ + template: `
Some Content
`, - styles: [`button { + styles: [`button { position: absolute; top: 300px; left: 300px; @@ -3492,30 +3492,30 @@ export class SimpleBigSizeComponent { height: 60px; border: 0px; }`] - }) - export class WidthTestOverlayComponent { - - constructor( - @Inject(IgxOverlayService) public overlay: IgxOverlayService, - public elementRef: ElementRef - ) { } - - @ViewChild('button') buttonElement: ElementRef; - @ViewChild('myCustomComponent') customComponent: ElementRef; - public overlaySettings: OverlaySettings = {}; - click(event) { - this.overlaySettings.positionStrategy = new ConnectedPositioningStrategy(); - this.overlaySettings.scrollStrategy = new NoOpScrollStrategy(); - this.overlaySettings.closeOnOutsideClick = true; - this.overlaySettings.modal = false; - - this.overlaySettings.positionStrategy.settings.target = this.buttonElement.nativeElement; - this.overlay.show(this.customComponent, this.overlaySettings); - } +}) +export class WidthTestOverlayComponent { + + constructor( + @Inject(IgxOverlayService) public overlay: IgxOverlayService, + public elementRef: ElementRef + ) { } + + @ViewChild('button') buttonElement: ElementRef; + @ViewChild('myCustomComponent') customComponent: ElementRef; + public overlaySettings: OverlaySettings = {}; + click(event) { + this.overlaySettings.positionStrategy = new ConnectedPositioningStrategy(); + this.overlaySettings.scrollStrategy = new NoOpScrollStrategy(); + this.overlaySettings.closeOnOutsideClick = true; + this.overlaySettings.modal = false; + + this.overlaySettings.positionStrategy.settings.target = this.buttonElement.nativeElement; + this.overlay.show(this.customComponent, this.overlaySettings); } +} - @Component({ - template: ` +@Component({ + template: `

AAAAA

@@ -3529,83 +3529,83 @@ export class SimpleBigSizeComponent {

AAAAA

` - }) - export class ScrollableComponent { - public visible = false; - - @ViewChild(IgxToggleDirective) - private _toggle: IgxToggleDirective; +}) +export class ScrollableComponent { + public visible = false; - public get toggle(): IgxToggleDirective { - return this._toggle; - } + @ViewChild(IgxToggleDirective) + private _toggle: IgxToggleDirective; - show() { - this.visible = true; - const settings: OverlaySettings = { scrollStrategy: new CloseScrollStrategy() }; - this.toggle.open(settings); - } + public get toggle(): IgxToggleDirective { + return this._toggle; + } - hide() { - this.toggle.close(); - this.visible = false; - } + show() { + this.visible = true; + const settings: OverlaySettings = { scrollStrategy: new CloseScrollStrategy() }; + this.toggle.open(settings); + } + hide() { + this.toggle.close(); + this.visible = false; } - @Component({ - template: ` +} + +@Component({ + template: `
` - }) - export class FlexContainerComponent { - public overlaySettings: OverlaySettings = {}; - constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } - - @ViewChild('button') buttonElement: ElementRef; - click(event) { - this.overlay.show(SimpleDynamicComponent, this.overlaySettings); - } - } +}) +export class FlexContainerComponent { + public overlaySettings: OverlaySettings = {}; + constructor(@Inject(IgxOverlayService) public overlay: IgxOverlayService) { } - const DYNAMIC_COMPONENTS = [ - EmptyPageComponent, - SimpleRefComponent, - SimpleDynamicComponent, - SimpleBigSizeComponent, - DownRightButtonComponent, - TopLeftOffsetComponent, - TwoButtonsComponent, - WidthTestOverlayComponent, - ScrollableComponent, - FlexContainerComponent - ]; - - const IgniteUIComponents = [ - IgxCalendarComponent, - IgxAvatarComponent, - IgxDatePickerComponent - ]; - - const DIRECTIVE_COMPONENTS = [ - SimpleDynamicWithDirectiveComponent - ]; - - @NgModule({ - imports: [BrowserModule], - declarations: [DYNAMIC_COMPONENTS], - exports: [DYNAMIC_COMPONENTS], - entryComponents: [DYNAMIC_COMPONENTS] - }) - export class DynamicModule { } - - @NgModule({ - imports: [IgxCalendarModule, IgxAvatarModule, IgxDatePickerModule], - entryComponents: IgniteUIComponents - }) - export class IgxComponentsModule { + @ViewChild('button') buttonElement: ElementRef; + click(event) { + this.overlay.show(SimpleDynamicComponent, this.overlaySettings); } +} + +const DYNAMIC_COMPONENTS = [ + EmptyPageComponent, + SimpleRefComponent, + SimpleDynamicComponent, + SimpleBigSizeComponent, + DownRightButtonComponent, + TopLeftOffsetComponent, + TwoButtonsComponent, + WidthTestOverlayComponent, + ScrollableComponent, + FlexContainerComponent +]; + +const IgniteUIComponents = [ + IgxCalendarComponent, + IgxAvatarComponent, + IgxDatePickerComponent +]; + +const DIRECTIVE_COMPONENTS = [ + SimpleDynamicWithDirectiveComponent +]; + +@NgModule({ + imports: [BrowserModule], + declarations: [DYNAMIC_COMPONENTS], + exports: [DYNAMIC_COMPONENTS], + entryComponents: [DYNAMIC_COMPONENTS] +}) +export class DynamicModule { } + +@NgModule({ + imports: [IgxCalendarModule, IgxAvatarModule, IgxDatePickerModule], + entryComponents: IgniteUIComponents +}) +export class IgxComponentsModule { +} From dd2a19cb4dee4a1fc2099c14bbdcf0076225bfb8 Mon Sep 17 00:00:00 2001 From: zdrawku Date: Wed, 2 Jan 2019 14:27:18 +0200 Subject: [PATCH 11/11] test(update): Modify firstMonth selector #3508 --- .../src/lib/grids/grid/grid-filtering-ui.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts index 775cc8bb78a..b6e858f7f6a 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts @@ -1293,7 +1293,7 @@ describe('IgxGrid - Filtering actions', () => { tick(); fix.detectChanges(); - const firstMonth = calendar.queryAll(By.css('.igx-calendar__month'))[0]; + const firstMonth = calendar.queryAll(By.css(`[class*='igx-calendar__month']`))[0]; firstMonth.nativeElement.click(); tick(); fix.detectChanges();