diff --git a/src/components/button/button.spec.ts b/src/components/button/button.spec.ts index 8116e687600a..534fe93a458b 100644 --- a/src/components/button/button.spec.ts +++ b/src/components/button/button.spec.ts @@ -5,135 +5,132 @@ import {By} from '@angular/platform-browser'; import {MdButton, MdAnchor} from './button'; +describe('MdButton', () => { + let builder: TestComponentBuilder; + + beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + builder = tcb; + })); + + // General button tests + it('should apply class based on color attribute', (done: () => void) => { + return builder.createAsync(TestApp).then(fixture => { + let testComponent = fixture.debugElement.componentInstance; + let buttonDebugElement = fixture.debugElement.query(By.css('button')); + let aDebugElement = fixture.debugElement.query(By.css('a')); + + testComponent.buttonColor = 'primary'; + fixture.detectChanges(); + expect(buttonDebugElement.nativeElement.classList.contains('md-primary')).toBe(true); + expect(aDebugElement.nativeElement.classList.contains('md-primary')).toBe(true); + + testComponent.buttonColor = 'accent'; + fixture.detectChanges(); + expect(buttonDebugElement.nativeElement.classList.contains('md-accent')).toBe(true); + expect(aDebugElement.nativeElement.classList.contains('md-accent')).toBe(true); + done(); + }); + }); + + it('should should not clear previous defined classes', (done: () => void) => { + return builder.createAsync(TestApp).then(fixture => { + let testComponent = fixture.debugElement.componentInstance; + let buttonDebugElement = fixture.debugElement.query(By.css('button')); + + buttonDebugElement.nativeElement.classList.add('custom-class'); + + testComponent.buttonColor = 'primary'; + fixture.detectChanges(); -export function main() { - describe('MdButton', () => { - let builder: TestComponentBuilder; + expect(buttonDebugElement.nativeElement.classList.contains('md-primary')).toBe(true); + expect(buttonDebugElement.nativeElement.classList.contains('custom-class')).toBe(true); - beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { - builder = tcb; - })); + testComponent.buttonColor = 'accent'; + fixture.detectChanges(); - // General button tests - it('should apply class based on color attribute', (done: () => void) => { + expect(buttonDebugElement.nativeElement.classList.contains('md-primary')).toBe(false); + expect(buttonDebugElement.nativeElement.classList.contains('md-accent')).toBe(true); + expect(buttonDebugElement.nativeElement.classList.contains('custom-class')).toBe(true); + + done(); + }); + }); + + // Regular button tests + describe('button[md-button]', () => { + it('should handle a click on the button', (done: () => void) => { return builder.createAsync(TestApp).then(fixture => { let testComponent = fixture.debugElement.componentInstance; let buttonDebugElement = fixture.debugElement.query(By.css('button')); - let aDebugElement = fixture.debugElement.query(By.css('a')); - - testComponent.buttonColor = 'primary'; - fixture.detectChanges(); - expect(buttonDebugElement.nativeElement.classList.contains('md-primary')).toBe(true); - expect(aDebugElement.nativeElement.classList.contains('md-primary')).toBe(true); - testComponent.buttonColor = 'accent'; - fixture.detectChanges(); - expect(buttonDebugElement.nativeElement.classList.contains('md-accent')).toBe(true); - expect(aDebugElement.nativeElement.classList.contains('md-accent')).toBe(true); + buttonDebugElement.nativeElement.click(); + expect(testComponent.clickCount).toBe(1); done(); }); }); - it('should should not clear previous defined classes', (done: () => void) => { + it('should not increment if disabled', (done: () => void) => { return builder.createAsync(TestApp).then(fixture => { let testComponent = fixture.debugElement.componentInstance; let buttonDebugElement = fixture.debugElement.query(By.css('button')); - buttonDebugElement.nativeElement.classList.add('custom-class'); - - testComponent.buttonColor = 'primary'; - fixture.detectChanges(); - - expect(buttonDebugElement.nativeElement.classList.contains('md-primary')).toBe(true); - expect(buttonDebugElement.nativeElement.classList.contains('custom-class')).toBe(true); - - testComponent.buttonColor = 'accent'; + testComponent.isDisabled = true; fixture.detectChanges(); - expect(buttonDebugElement.nativeElement.classList.contains('md-primary')).toBe(false); - expect(buttonDebugElement.nativeElement.classList.contains('md-accent')).toBe(true); - expect(buttonDebugElement.nativeElement.classList.contains('custom-class')).toBe(true); + buttonDebugElement.nativeElement.click(); + expect(testComponent.clickCount).toBe(0); done(); }); }); - // Regular button tests - describe('button[md-button]', () => { - it('should handle a click on the button', (done: () => void) => { - return builder.createAsync(TestApp).then(fixture => { - let testComponent = fixture.debugElement.componentInstance; - let buttonDebugElement = fixture.debugElement.query(By.css('button')); - - buttonDebugElement.nativeElement.click(); - expect(testComponent.clickCount).toBe(1); - done(); - }); - }); - - it('should not increment if disabled', (done: () => void) => { - return builder.createAsync(TestApp).then(fixture => { - let testComponent = fixture.debugElement.componentInstance; - let buttonDebugElement = fixture.debugElement.query(By.css('button')); + }); - testComponent.isDisabled = true; - fixture.detectChanges(); + // Anchor button tests + describe('a[md-button]', () => { + it('should not redirect if disabled', (done: () => void) => { + return builder.createAsync(TestApp).then(fixture => { + let testComponent = fixture.debugElement.componentInstance; + let buttonDebugElement = fixture.debugElement.query(By.css('a')); - buttonDebugElement.nativeElement.click(); + testComponent.isDisabled = true; + fixture.detectChanges(); - expect(testComponent.clickCount).toBe(0); - done(); - }); + buttonDebugElement.nativeElement.click(); + // will error if page reloads + done(); }); - }); - // Anchor button tests - describe('a[md-button]', () => { - it('should not redirect if disabled', (done: () => void) => { - return builder.createAsync(TestApp).then(fixture => { - let testComponent = fixture.debugElement.componentInstance; - let buttonDebugElement = fixture.debugElement.query(By.css('a')); - - testComponent.isDisabled = true; - fixture.detectChanges(); + it('should remove tabindex if disabled', (done: () => void) => { + return builder.createAsync(TestApp).then(fixture => { + let testComponent = fixture.debugElement.componentInstance; + let buttonDebugElement = fixture.debugElement.query(By.css('a')); + expect(buttonDebugElement.nativeElement.getAttribute('tabIndex')).toBe(null); - buttonDebugElement.nativeElement.click(); - // will error if page reloads - done(); - }); + testComponent.isDisabled = true; + fixture.detectChanges(); + expect(buttonDebugElement.nativeElement.getAttribute('tabIndex')).toBe('-1'); + done(); }); + }); - it('should remove tabindex if disabled', (done: () => void) => { - return builder.createAsync(TestApp).then(fixture => { - let testComponent = fixture.debugElement.componentInstance; - let buttonDebugElement = fixture.debugElement.query(By.css('a')); - expect(buttonDebugElement.nativeElement.getAttribute('tabIndex')).toBe(null); - - testComponent.isDisabled = true; - fixture.detectChanges(); - expect(buttonDebugElement.nativeElement.getAttribute('tabIndex')).toBe('-1'); - done(); - }); - }); + it('should add aria-disabled attribute if disabled', (done: () => void) => { + return builder.createAsync(TestApp).then(fixture => { + let testComponent = fixture.debugElement.componentInstance; + let buttonDebugElement = fixture.debugElement.query(By.css('a')); + fixture.detectChanges(); + expect(buttonDebugElement.nativeElement.getAttribute('aria-disabled')).toBe('false'); - it('should add aria-disabled attribute if disabled', (done: () => void) => { - return builder.createAsync(TestApp).then(fixture => { - let testComponent = fixture.debugElement.componentInstance; - let buttonDebugElement = fixture.debugElement.query(By.css('a')); - fixture.detectChanges(); - expect(buttonDebugElement.nativeElement.getAttribute('aria-disabled')).toBe('false'); - - testComponent.isDisabled = true; - fixture.detectChanges(); - expect(buttonDebugElement.nativeElement.getAttribute('aria-disabled')).toBe('true'); - done(); - }); + testComponent.isDisabled = true; + fixture.detectChanges(); + expect(buttonDebugElement.nativeElement.getAttribute('aria-disabled')).toBe('true'); + done(); }); - }); + }); -} +}); /** Test component that contains an MdButton. */ @Component({ diff --git a/src/components/icon/icon.spec.ts b/src/components/icon/icon.spec.ts index 6390ff083137..0041d4aa1d6b 100644 --- a/src/components/icon/icon.spec.ts +++ b/src/components/icon/icon.spec.ts @@ -40,385 +40,383 @@ const verifyPathChildElement = (element: Element, attributeValue: string) => { expect(pathElement.getAttribute('id')).toBe(attributeValue); }; -export function main() { - describe('MdIcon', () => { - - beforeEachProviders(() => [ - MdIconRegistry, - HTTP_PROVIDERS, - MockBackend, - provide(XHRBackend, {useExisting: MockBackend}), - ]); - - let builder: TestComponentBuilder; - let mdIconRegistry: MdIconRegistry; - let httpRequestUrls: string[]; - - beforeEach( - inject([TestComponentBuilder, MdIconRegistry, MockBackend], - (tcb: TestComponentBuilder, mir: MdIconRegistry, mockBackend: MockBackend) => { - builder = tcb; - mdIconRegistry = mir; - // Keep track of requests so we can verify caching behavior. - // Return responses for the SVGs defined in fake-svgs.ts. - httpRequestUrls = []; - mockBackend.connections.subscribe((connection: any) => { - const url = connection.request.url; - httpRequestUrls.push(url); - connection.mockRespond(getFakeSvgHttpResponse(url)); - }); - })); - - describe('Ligature icons', () => { - it('should add material-icons class by default', (done: () => void) => { - return builder.createAsync(MdIconLigatureTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - testComponent.iconName = 'home'; - fixture.detectChanges(); - expect(sortedClassNames(mdIconElement)).toEqual(['material-icons']); - done(); - }); +describe('MdIcon', () => { + + beforeEachProviders(() => [ + MdIconRegistry, + HTTP_PROVIDERS, + MockBackend, + provide(XHRBackend, {useExisting: MockBackend}), + ]); + + let builder: TestComponentBuilder; + let mdIconRegistry: MdIconRegistry; + let httpRequestUrls: string[]; + + beforeEach( + inject([TestComponentBuilder, MdIconRegistry, MockBackend], + (tcb: TestComponentBuilder, mir: MdIconRegistry, mockBackend: MockBackend) => { + builder = tcb; + mdIconRegistry = mir; + // Keep track of requests so we can verify caching behavior. + // Return responses for the SVGs defined in fake-svgs.ts. + httpRequestUrls = []; + mockBackend.connections.subscribe((connection: any) => { + const url = connection.request.url; + httpRequestUrls.push(url); + connection.mockRespond(getFakeSvgHttpResponse(url)); + }); + })); + + describe('Ligature icons', () => { + it('should add material-icons class by default', (done: () => void) => { + return builder.createAsync(MdIconLigatureTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + testComponent.iconName = 'home'; + fixture.detectChanges(); + expect(sortedClassNames(mdIconElement)).toEqual(['material-icons']); + done(); }); + }); - it('should use alternate icon font if set', (done: () => void) => { - mdIconRegistry.setDefaultFontSetClass('myfont'); - return builder.createAsync(MdIconLigatureTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - testComponent.iconName = 'home'; - fixture.detectChanges(); - expect(sortedClassNames(mdIconElement)).toEqual(['myfont']); - done(); - }); + it('should use alternate icon font if set', (done: () => void) => { + mdIconRegistry.setDefaultFontSetClass('myfont'); + return builder.createAsync(MdIconLigatureTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + testComponent.iconName = 'home'; + fixture.detectChanges(); + expect(sortedClassNames(mdIconElement)).toEqual(['myfont']); + done(); }); }); + }); - describe('Icons from URLs', () => { - it('should fetch SVG icon from URL and inline the content', (done: () => void) => { - return builder.createAsync(MdIconFromSvgUrlTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - let svgElement: any; - - testComponent.iconUrl = 'cat.svg'; - fixture.detectChanges(); - // An element should have been added as a child of . - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - // Default attributes should be set. - expect(svgElement.getAttribute('height')).toBe('100%'); - expect(svgElement.getAttribute('height')).toBe('100%'); - // Make sure SVG content is taken from response. - verifyPathChildElement(svgElement, 'meow'); - - // Change the icon, and the SVG element should be replaced. - testComponent.iconUrl = 'dog.svg'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'woof'); - - expect(httpRequestUrls).toEqual(['cat.svg', 'dog.svg']); - // Using an icon from a previously loaded URL should not cause another HTTP request. - testComponent.iconUrl = 'cat.svg'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'meow'); - expect(httpRequestUrls).toEqual(['cat.svg', 'dog.svg']); - - done(); - }); + describe('Icons from URLs', () => { + it('should fetch SVG icon from URL and inline the content', (done: () => void) => { + return builder.createAsync(MdIconFromSvgUrlTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + let svgElement: any; + + testComponent.iconUrl = 'cat.svg'; + fixture.detectChanges(); + // An element should have been added as a child of . + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + // Default attributes should be set. + expect(svgElement.getAttribute('height')).toBe('100%'); + expect(svgElement.getAttribute('height')).toBe('100%'); + // Make sure SVG content is taken from response. + verifyPathChildElement(svgElement, 'meow'); + + // Change the icon, and the SVG element should be replaced. + testComponent.iconUrl = 'dog.svg'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'woof'); + + expect(httpRequestUrls).toEqual(['cat.svg', 'dog.svg']); + // Using an icon from a previously loaded URL should not cause another HTTP request. + testComponent.iconUrl = 'cat.svg'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'meow'); + expect(httpRequestUrls).toEqual(['cat.svg', 'dog.svg']); + + done(); }); + }); - it('should register icon URLs by name', (done: () => void) => { - mdIconRegistry.addSvgIcon('fluffy', 'cat.svg'); - mdIconRegistry.addSvgIcon('fido', 'dog.svg'); - return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - let svgElement: SVGElement; - - testComponent.iconName = 'fido'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'woof'); - // The aria label should be taken from the icon name. - expect(mdIconElement.getAttribute('aria-label')).toBe('fido'); - - // Change the icon, and the SVG element should be replaced. - testComponent.iconName = 'fluffy'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'meow'); - expect(mdIconElement.getAttribute('aria-label')).toBe('fluffy'); - - expect(httpRequestUrls).toEqual(['dog.svg', 'cat.svg']); - // Using an icon from a previously loaded URL should not cause another HTTP request. - testComponent.iconName = 'fido'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'woof'); - expect(httpRequestUrls).toEqual(['dog.svg', 'cat.svg']); - - done(); - }); + it('should register icon URLs by name', (done: () => void) => { + mdIconRegistry.addSvgIcon('fluffy', 'cat.svg'); + mdIconRegistry.addSvgIcon('fido', 'dog.svg'); + return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + let svgElement: SVGElement; + + testComponent.iconName = 'fido'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'woof'); + // The aria label should be taken from the icon name. + expect(mdIconElement.getAttribute('aria-label')).toBe('fido'); + + // Change the icon, and the SVG element should be replaced. + testComponent.iconName = 'fluffy'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'meow'); + expect(mdIconElement.getAttribute('aria-label')).toBe('fluffy'); + + expect(httpRequestUrls).toEqual(['dog.svg', 'cat.svg']); + // Using an icon from a previously loaded URL should not cause another HTTP request. + testComponent.iconName = 'fido'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'woof'); + expect(httpRequestUrls).toEqual(['dog.svg', 'cat.svg']); + + done(); }); + }); - it('should extract icon from SVG icon set', (done: () => void) => { - mdIconRegistry.addSvgIconSetInNamespace('farm', 'farm-set-1.svg'); - return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - let svgElement: any; - let svgChild: any; - - testComponent.iconName = 'farm:pig'; - fixture.detectChanges(); - - expect(mdIconElement.childNodes.length).toBe(1); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - expect(svgElement.childNodes.length).toBe(1); - svgChild = svgElement.childNodes[0]; - // The first child should be the element. - expect(svgChild.tagName.toLowerCase()).toBe('g'); - expect(svgChild.getAttribute('id')).toBe('pig'); - verifyPathChildElement(svgChild, 'oink'); - // The aria label should be taken from the icon name (without the icon set portion). - expect(mdIconElement.getAttribute('aria-label')).toBe('pig'); - - // Change the icon, and the SVG element should be replaced. - testComponent.iconName = 'farm:cow'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - svgChild = svgElement.childNodes[0]; - // The first child should be the element. - expect(svgChild.tagName.toLowerCase()).toBe('g'); - expect(svgChild.getAttribute('id')).toBe('cow'); - verifyPathChildElement(svgChild, 'moo'); - expect(mdIconElement.getAttribute('aria-label')).toBe('cow'); - - done(); - }); + it('should extract icon from SVG icon set', (done: () => void) => { + mdIconRegistry.addSvgIconSetInNamespace('farm', 'farm-set-1.svg'); + return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + let svgElement: any; + let svgChild: any; + + testComponent.iconName = 'farm:pig'; + fixture.detectChanges(); + + expect(mdIconElement.childNodes.length).toBe(1); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + expect(svgElement.childNodes.length).toBe(1); + svgChild = svgElement.childNodes[0]; + // The first child should be the element. + expect(svgChild.tagName.toLowerCase()).toBe('g'); + expect(svgChild.getAttribute('id')).toBe('pig'); + verifyPathChildElement(svgChild, 'oink'); + // The aria label should be taken from the icon name (without the icon set portion). + expect(mdIconElement.getAttribute('aria-label')).toBe('pig'); + + // Change the icon, and the SVG element should be replaced. + testComponent.iconName = 'farm:cow'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + svgChild = svgElement.childNodes[0]; + // The first child should be the element. + expect(svgChild.tagName.toLowerCase()).toBe('g'); + expect(svgChild.getAttribute('id')).toBe('cow'); + verifyPathChildElement(svgChild, 'moo'); + expect(mdIconElement.getAttribute('aria-label')).toBe('cow'); + + done(); }); + }); - it('should allow multiple icon sets in a namespace', (done: () => void) => { - mdIconRegistry.addSvgIconSetInNamespace('farm', 'farm-set-1.svg'); - mdIconRegistry.addSvgIconSetInNamespace('farm', 'farm-set-2.svg'); - mdIconRegistry.addSvgIconSetInNamespace('arrows', 'arrow-set.svg'); - return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - let svgElement: any; - let svgChild: any; - - testComponent.iconName = 'farm:pig'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - expect(svgElement.childNodes.length).toBe(1); - svgChild = svgElement.childNodes[0]; - // The child should be the element. - expect(svgChild.tagName.toLowerCase()).toBe('g'); - expect(svgChild.getAttribute('id')).toBe('pig'); - expect(svgChild.childNodes.length).toBe(1); - verifyPathChildElement(svgChild, 'oink'); - // The aria label should be taken from the icon name (without the namespace). - expect(mdIconElement.getAttribute('aria-label')).toBe('pig'); - - // Both icon sets registered in the 'farm' namespace should have been fetched. - expect(httpRequestUrls.sort()).toEqual(['farm-set-1.svg', 'farm-set-2.svg']); - - // Change the icon name to one that appears in both icon sets. The icon from the set that - // was registered last should be used (with id attribute of 'moo moo' instead of 'moo'), - // and no additional HTTP request should be made. - testComponent.iconName = 'farm:cow'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - svgChild = svgElement.childNodes[0]; - // The first child should be the element. - expect(svgChild.tagName.toLowerCase()).toBe('g'); - expect(svgChild.getAttribute('id')).toBe('cow'); - expect(svgChild.childNodes.length).toBe(1); - verifyPathChildElement(svgChild, 'moo moo'); - expect(mdIconElement.getAttribute('aria-label')).toBe('cow'); - expect(httpRequestUrls.sort()).toEqual(['farm-set-1.svg', 'farm-set-2.svg']); - - done(); - }); + it('should allow multiple icon sets in a namespace', (done: () => void) => { + mdIconRegistry.addSvgIconSetInNamespace('farm', 'farm-set-1.svg'); + mdIconRegistry.addSvgIconSetInNamespace('farm', 'farm-set-2.svg'); + mdIconRegistry.addSvgIconSetInNamespace('arrows', 'arrow-set.svg'); + return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + let svgElement: any; + let svgChild: any; + + testComponent.iconName = 'farm:pig'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + expect(svgElement.childNodes.length).toBe(1); + svgChild = svgElement.childNodes[0]; + // The child should be the element. + expect(svgChild.tagName.toLowerCase()).toBe('g'); + expect(svgChild.getAttribute('id')).toBe('pig'); + expect(svgChild.childNodes.length).toBe(1); + verifyPathChildElement(svgChild, 'oink'); + // The aria label should be taken from the icon name (without the namespace). + expect(mdIconElement.getAttribute('aria-label')).toBe('pig'); + + // Both icon sets registered in the 'farm' namespace should have been fetched. + expect(httpRequestUrls.sort()).toEqual(['farm-set-1.svg', 'farm-set-2.svg']); + + // Change the icon name to one that appears in both icon sets. The icon from the set that + // was registered last should be used (with id attribute of 'moo moo' instead of 'moo'), + // and no additional HTTP request should be made. + testComponent.iconName = 'farm:cow'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + svgChild = svgElement.childNodes[0]; + // The first child should be the element. + expect(svgChild.tagName.toLowerCase()).toBe('g'); + expect(svgChild.getAttribute('id')).toBe('cow'); + expect(svgChild.childNodes.length).toBe(1); + verifyPathChildElement(svgChild, 'moo moo'); + expect(mdIconElement.getAttribute('aria-label')).toBe('cow'); + expect(httpRequestUrls.sort()).toEqual(['farm-set-1.svg', 'farm-set-2.svg']); + + done(); }); + }); - it('should not wrap elements in icon sets in another svg tag', (done: () => void) => { - mdIconRegistry.addSvgIconSet('arrow-set.svg'); - return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - let svgElement: any; - - testComponent.iconName = 'left-arrow'; - fixture.detectChanges(); - // arrow-set.svg stores its icons as nested elements, so they should be used - // directly and not wrapped in an outer tag like the elements in other sets. - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'left'); - expect(mdIconElement.getAttribute('aria-label')).toBe('left-arrow'); - - done(); - }); + it('should not wrap elements in icon sets in another svg tag', (done: () => void) => { + mdIconRegistry.addSvgIconSet('arrow-set.svg'); + return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + let svgElement: any; + + testComponent.iconName = 'left-arrow'; + fixture.detectChanges(); + // arrow-set.svg stores its icons as nested elements, so they should be used + // directly and not wrapped in an outer tag like the elements in other sets. + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'left'); + expect(mdIconElement.getAttribute('aria-label')).toBe('left-arrow'); + + done(); }); + }); - it('should return unmodified copies of icons from URLs', (done: () => void) => { - return builder.createAsync(MdIconFromSvgUrlTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - let svgElement: any; - - testComponent.iconUrl = 'cat.svg'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'meow'); - // Modify the SVG element by setting a viewBox attribute. - svgElement.setAttribute('viewBox', '0 0 100 100'); - - // Switch to a different icon. - testComponent.iconUrl = 'dog.svg'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'woof'); - - // Switch back to the first icon. The viewBox attribute should not be present. - testComponent.iconUrl = 'cat.svg'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'meow'); - expect(svgElement.getAttribute('viewBox')).toBeFalsy(); - - done(); - }); + it('should return unmodified copies of icons from URLs', (done: () => void) => { + return builder.createAsync(MdIconFromSvgUrlTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + let svgElement: any; + + testComponent.iconUrl = 'cat.svg'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'meow'); + // Modify the SVG element by setting a viewBox attribute. + svgElement.setAttribute('viewBox', '0 0 100 100'); + + // Switch to a different icon. + testComponent.iconUrl = 'dog.svg'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'woof'); + + // Switch back to the first icon. The viewBox attribute should not be present. + testComponent.iconUrl = 'cat.svg'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'meow'); + expect(svgElement.getAttribute('viewBox')).toBeFalsy(); + + done(); }); + }); - it('should return unmodified copies of icons from icon sets', (done: () => void) => { - mdIconRegistry.addSvgIconSet('arrow-set.svg'); - return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - let svgElement: any; - - testComponent.iconName = 'left-arrow'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'left'); - // Modify the SVG element by setting a viewBox attribute. - svgElement.setAttribute('viewBox', '0 0 100 100'); - - // Switch to a different icon. - testComponent.iconName = 'right-arrow'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'right'); - - // Switch back to the first icon. The viewBox attribute should not be present. - testComponent.iconName = 'left-arrow'; - fixture.detectChanges(); - svgElement = verifyAndGetSingleSvgChild(mdIconElement); - verifyPathChildElement(svgElement, 'left'); - expect(svgElement.getAttribute('viewBox')).toBeFalsy(); - - done(); - }); + it('should return unmodified copies of icons from icon sets', (done: () => void) => { + mdIconRegistry.addSvgIconSet('arrow-set.svg'); + return builder.createAsync(MdIconFromSvgNameTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + let svgElement: any; + + testComponent.iconName = 'left-arrow'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'left'); + // Modify the SVG element by setting a viewBox attribute. + svgElement.setAttribute('viewBox', '0 0 100 100'); + + // Switch to a different icon. + testComponent.iconName = 'right-arrow'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'right'); + + // Switch back to the first icon. The viewBox attribute should not be present. + testComponent.iconName = 'left-arrow'; + fixture.detectChanges(); + svgElement = verifyAndGetSingleSvgChild(mdIconElement); + verifyPathChildElement(svgElement, 'left'); + expect(svgElement.getAttribute('viewBox')).toBeFalsy(); + + done(); }); }); + }); - describe('custom fonts', () => { - it('should apply CSS classes for custom font and icon', (done: () => void) => { - mdIconRegistry.registerFontClassAlias('f1', 'font1'); - mdIconRegistry.registerFontClassAlias('f2'); - return builder.createAsync(MdIconCustomFontCssTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - testComponent.fontSet = 'f1'; - testComponent.fontIcon = 'house'; - fixture.detectChanges(); - expect(sortedClassNames(mdIconElement)).toEqual(['font1', 'house']); - expect(mdIconElement.getAttribute('aria-label')).toBe('house'); - - testComponent.fontSet = 'f2'; - testComponent.fontIcon = 'igloo'; - fixture.detectChanges(); - expect(sortedClassNames(mdIconElement)).toEqual(['f2', 'igloo']); - expect(mdIconElement.getAttribute('aria-label')).toBe('igloo'); - - testComponent.fontSet = 'f3'; - testComponent.fontIcon = 'tent'; - fixture.detectChanges(); - expect(sortedClassNames(mdIconElement)).toEqual(['f3', 'tent']); - expect(mdIconElement.getAttribute('aria-label')).toBe('tent'); - - done(); - }); + describe('custom fonts', () => { + it('should apply CSS classes for custom font and icon', (done: () => void) => { + mdIconRegistry.registerFontClassAlias('f1', 'font1'); + mdIconRegistry.registerFontClassAlias('f2'); + return builder.createAsync(MdIconCustomFontCssTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + testComponent.fontSet = 'f1'; + testComponent.fontIcon = 'house'; + fixture.detectChanges(); + expect(sortedClassNames(mdIconElement)).toEqual(['font1', 'house']); + expect(mdIconElement.getAttribute('aria-label')).toBe('house'); + + testComponent.fontSet = 'f2'; + testComponent.fontIcon = 'igloo'; + fixture.detectChanges(); + expect(sortedClassNames(mdIconElement)).toEqual(['f2', 'igloo']); + expect(mdIconElement.getAttribute('aria-label')).toBe('igloo'); + + testComponent.fontSet = 'f3'; + testComponent.fontIcon = 'tent'; + fixture.detectChanges(); + expect(sortedClassNames(mdIconElement)).toEqual(['f3', 'tent']); + expect(mdIconElement.getAttribute('aria-label')).toBe('tent'); + + done(); }); }); + }); - describe('aria label', () => { - it('should set aria label from text content if not specified', (done: () => void) => { - return builder.createAsync(MdIconLigatureTestApp).then(fixture => { + describe('aria label', () => { + it('should set aria label from text content if not specified', (done: () => void) => { + return builder.createAsync(MdIconLigatureTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - testComponent.iconName = 'home'; + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + testComponent.iconName = 'home'; - fixture.detectChanges(); - expect(mdIconElement.getAttribute('aria-label')).toBe('home'); + fixture.detectChanges(); + expect(mdIconElement.getAttribute('aria-label')).toBe('home'); - testComponent.iconName = 'hand'; - fixture.detectChanges(); - expect(mdIconElement.getAttribute('aria-label')).toBe('hand'); + testComponent.iconName = 'hand'; + fixture.detectChanges(); + expect(mdIconElement.getAttribute('aria-label')).toBe('hand'); - done(); - }); + done(); }); + }); + + it('should use alt tag if aria label is not specified', (done: () => void) => { + return builder.createAsync(MdIconLigatureWithAriaBindingTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + testComponent.iconName = 'home'; + testComponent.altText = 'castle'; + fixture.detectChanges(); + expect(mdIconElement.getAttribute('aria-label')).toBe('castle'); - it('should use alt tag if aria label is not specified', (done: () => void) => { - return builder.createAsync(MdIconLigatureWithAriaBindingTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - testComponent.iconName = 'home'; - testComponent.altText = 'castle'; - fixture.detectChanges(); - expect(mdIconElement.getAttribute('aria-label')).toBe('castle'); - - testComponent.ariaLabel = 'house'; - fixture.detectChanges(); - expect(mdIconElement.getAttribute('aria-label')).toBe('house'); - - done(); - }); + testComponent.ariaLabel = 'house'; + fixture.detectChanges(); + expect(mdIconElement.getAttribute('aria-label')).toBe('house'); + + done(); }); + }); - it('should use provided aria label rather than icon name', (done: () => void) => { - return builder.createAsync(MdIconLigatureWithAriaBindingTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - testComponent.iconName = 'home'; - testComponent.ariaLabel = 'house'; - fixture.detectChanges(); - expect(mdIconElement.getAttribute('aria-label')).toBe('house'); - done(); - }); + it('should use provided aria label rather than icon name', (done: () => void) => { + return builder.createAsync(MdIconLigatureWithAriaBindingTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + testComponent.iconName = 'home'; + testComponent.ariaLabel = 'house'; + fixture.detectChanges(); + expect(mdIconElement.getAttribute('aria-label')).toBe('house'); + done(); }); + }); - it('should use provided aria label rather than font icon', (done: () => void) => { - return builder.createAsync(MdIconCustomFontCssTestApp).then(fixture => { - const testComponent = fixture.debugElement.componentInstance; - const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); - testComponent.fontSet = 'f1'; - testComponent.fontIcon = 'house'; - testComponent.ariaLabel = 'home'; - fixture.detectChanges(); - expect(mdIconElement.getAttribute('aria-label')).toBe('home'); - done(); - }); + it('should use provided aria label rather than font icon', (done: () => void) => { + return builder.createAsync(MdIconCustomFontCssTestApp).then(fixture => { + const testComponent = fixture.debugElement.componentInstance; + const mdIconElement = fixture.debugElement.nativeElement.querySelector('md-icon'); + testComponent.fontSet = 'f1'; + testComponent.fontIcon = 'house'; + testComponent.ariaLabel = 'home'; + fixture.detectChanges(); + expect(mdIconElement.getAttribute('aria-label')).toBe('home'); + done(); }); }); }); -} +}); /** Test components that contain an MdIcon. */ @Component({ diff --git a/src/components/input/input.spec.ts b/src/components/input/input.spec.ts index 3b7aeb167338..764d5a90335c 100644 --- a/src/components/input/input.spec.ts +++ b/src/components/input/input.spec.ts @@ -16,647 +16,645 @@ import { } from './input'; -export function main() { - describe('MdInput', function () { - var builder: TestComponentBuilder; +describe('MdInput', function () { + var builder: TestComponentBuilder; - beforeEach(inject([TestComponentBuilder], function (tcb: TestComponentBuilder) { - builder = tcb; - })); + beforeEach(inject([TestComponentBuilder], function (tcb: TestComponentBuilder) { + builder = tcb; + })); - it('creates a native @@ -46,18 +45,18 @@ export function main() { `; - return builder.overrideTemplate(TestList, template) - .createAsync(TestList).then((fixture) => { - fixture.detectChanges(); - let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item')); - expect(listItems[0].nativeElement.className).toBe('md-2-line'); - expect(listItems[1].nativeElement.className).toBe('md-2-line'); - done(); + return builder.overrideTemplate(TestList, template) + .createAsync(TestList).then((fixture) => { + fixture.detectChanges(); + let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item')); + expect(listItems[0].nativeElement.className).toBe('md-2-line'); + expect(listItems[1].nativeElement.className).toBe('md-2-line'); + done(); }); - }); + }); - it('should apply md-3-line class to lists with three lines', (done: () => void) => { - var template = ` + it('should apply md-3-line class to lists with three lines', (done: () => void) => { + var template = `

{{item.name}}

@@ -66,18 +65,18 @@ export function main() {
`; - return builder.overrideTemplate(TestList, template) - .createAsync(TestList).then((fixture) => { - fixture.detectChanges(); - let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item')); - expect(listItems[0].nativeElement.className).toBe('md-3-line'); - expect(listItems[1].nativeElement.className).toBe('md-3-line'); - done(); + return builder.overrideTemplate(TestList, template) + .createAsync(TestList).then((fixture) => { + fixture.detectChanges(); + let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item')); + expect(listItems[0].nativeElement.className).toBe('md-3-line'); + expect(listItems[1].nativeElement.className).toBe('md-3-line'); + done(); }); - }); + }); - it('should apply md-list-avatar class to list items with avatars', (done: () => void) => { - var template = ` + it('should apply md-list-avatar class to list items with avatars', (done: () => void) => { + var template = ` @@ -88,18 +87,18 @@ export function main() { `; - return builder.overrideTemplate(TestList, template) - .createAsync(TestList).then((fixture) => { - fixture.detectChanges(); - let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item')); - expect(listItems[0].nativeElement.className).toBe('md-list-avatar'); - expect(listItems[1].nativeElement.className).toBe(''); - done(); + return builder.overrideTemplate(TestList, template) + .createAsync(TestList).then((fixture) => { + fixture.detectChanges(); + let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item')); + expect(listItems[0].nativeElement.className).toBe('md-list-avatar'); + expect(listItems[1].nativeElement.className).toBe(''); + done(); }); - }); + }); - it('should not clear custom classes provided by user', (done: () => void) => { - var template = ` + it('should not clear custom classes provided by user', (done: () => void) => { + var template = `

{{item.name}}

@@ -107,17 +106,17 @@ export function main() {
`; - return builder.overrideTemplate(TestList, template) - .createAsync(TestList).then((fixture) => { - fixture.detectChanges(); - let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item')); - expect(listItems[0].nativeElement.classList.contains('test-class')).toBe(true); - done(); + return builder.overrideTemplate(TestList, template) + .createAsync(TestList).then((fixture) => { + fixture.detectChanges(); + let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item')); + expect(listItems[0].nativeElement.classList.contains('test-class')).toBe(true); + done(); }); - }); + }); - it('should update classes if number of lines change', (done: () => void) => { - var template = ` + it('should update classes if number of lines change', (done: () => void) => { + var template = `

{{item.name}}

@@ -126,43 +125,42 @@ export function main() {
`; - return builder.overrideTemplate(TestList, template) - .createAsync(TestList).then((fixture) => { - fixture.debugElement.componentInstance.showThirdLine = false; - fixture.detectChanges(); - let listItem = fixture.debugElement.children[0].query(By.css('md-list-item')); - expect(listItem.nativeElement.className).toBe('md-2-line'); + return builder.overrideTemplate(TestList, template) + .createAsync(TestList).then((fixture) => { + fixture.debugElement.componentInstance.showThirdLine = false; + fixture.detectChanges(); + let listItem = fixture.debugElement.children[0].query(By.css('md-list-item')); + expect(listItem.nativeElement.className).toBe('md-2-line'); - fixture.debugElement.componentInstance.showThirdLine = true; - fixture.detectChanges(); - setTimeout(() => { - expect(listItem.nativeElement.className).toBe('md-3-line'); - done(); - }); + fixture.debugElement.componentInstance.showThirdLine = true; + fixture.detectChanges(); + setTimeout(() => { + expect(listItem.nativeElement.className).toBe('md-3-line'); + done(); + }); }); - }); + }); - it('should add aria roles properly', (done: () => void) => { - var template = ` + it('should add aria roles properly', (done: () => void) => { + var template = ` {{item.name}} `; - return builder.overrideTemplate(TestList, template) - .createAsync(TestList).then((fixture) => { - fixture.detectChanges(); - let list = fixture.debugElement.children[0]; - let listItem = fixture.debugElement.children[0].query(By.css('md-list-item')); - expect(list.nativeElement.getAttribute('role')).toBe('list'); - expect(listItem.nativeElement.getAttribute('role')).toBe('listitem'); - done(); + return builder.overrideTemplate(TestList, template) + .createAsync(TestList).then((fixture) => { + fixture.detectChanges(); + let list = fixture.debugElement.children[0]; + let listItem = fixture.debugElement.children[0].query(By.css('md-list-item')); + expect(list.nativeElement.getAttribute('role')).toBe('list'); + expect(listItem.nativeElement.getAttribute('role')).toBe('listitem'); + done(); }); - }); - }); -} + +}); @Component({ selector: 'test-list', diff --git a/src/components/progress-bar/progress-bar.spec.ts b/src/components/progress-bar/progress-bar.spec.ts index 505f2b17483b..0db2bd2f3fc9 100644 --- a/src/components/progress-bar/progress-bar.spec.ts +++ b/src/components/progress-bar/progress-bar.spec.ts @@ -5,116 +5,114 @@ import {By} from '@angular/platform-browser'; import {MdProgressBar} from './progress-bar'; -export function main() { - describe('MdProgressBar', () => { - let builder: TestComponentBuilder; - - beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { - builder = tcb; - })); - - it('should apply a mode of "determinate" if no mode is provided.', (done: () => void) => { - builder - .overrideTemplate(TestApp, '') - .createAsync(TestApp) - .then((fixture) => { - fixture.detectChanges(); - let progressElement = fixture.debugElement.query(By.css('md-progress-bar')); - expect(progressElement.componentInstance.mode).toBe('determinate'); - done(); - }); - }); - - it('should not modify the mode if a valid mode is provided.', (done: () => void) => { - builder - .overrideTemplate(TestApp, '') - .createAsync(TestApp) - .then((fixture) => { - fixture.detectChanges(); - let progressElement = fixture.debugElement.query(By.css('md-progress-bar')); - expect(progressElement.componentInstance.mode).toBe('buffer'); - done(); - }); - }); - - it('should define default values for value and bufferValue attributes', (done: () => void) => { - builder - .overrideTemplate(TestApp, '') - .createAsync(TestApp) - .then((fixture) => { - fixture.detectChanges(); - let progressElement = fixture.debugElement.query(By.css('md-progress-bar')); - expect(progressElement.componentInstance.value).toBe(0); - expect(progressElement.componentInstance.bufferValue).toBe(0); - done(); - }); - }); - - it('should clamp value and bufferValue between 0 and 100', (done: () => void) => { - builder - .overrideTemplate(TestApp, '') - .createAsync(TestApp) - .then((fixture) => { - fixture.detectChanges(); - let progressElement = fixture.debugElement.query(By.css('md-progress-bar')); - let progressComponent = progressElement.componentInstance; - - progressComponent.value = 50; - expect(progressComponent.value).toBe(50); - - progressComponent.value = 999; - expect(progressComponent.value).toBe(100); - - progressComponent.value = -10; - expect(progressComponent.value).toBe(0); - - progressComponent.bufferValue = -29; - expect(progressComponent.bufferValue).toBe(0); - - progressComponent.bufferValue = 9; - expect(progressComponent.bufferValue).toBe(9); - - progressComponent.bufferValue = 1320; - expect(progressComponent.bufferValue).toBe(100); - done(); - }); - }); - - it('should return the transform attribute for bufferValue and mode', (done: () => void) => { - builder - .overrideTemplate(TestApp, '') - .createAsync(TestApp) - .then((fixture) => { - fixture.detectChanges(); - let progressElement = fixture.debugElement.query(By.css('md-progress-bar')); - let progressComponent = progressElement.componentInstance; - - expect(progressComponent.primaryTransform()).toBe('scaleX(0)'); - expect(progressComponent.bufferTransform()).toBe(undefined); - - progressComponent.value = 40; - expect(progressComponent.primaryTransform()).toBe('scaleX(0.4)'); - expect(progressComponent.bufferTransform()).toBe(undefined); - - progressComponent.value = 35; - progressComponent.bufferValue = 55; - expect(progressComponent.primaryTransform()).toBe('scaleX(0.35)'); - expect(progressComponent.bufferTransform()).toBe(undefined); - - progressComponent.mode = 'buffer'; - expect(progressComponent.primaryTransform()).toBe('scaleX(0.35)'); - expect(progressComponent.bufferTransform()).toBe('scaleX(0.55)'); - - - progressComponent.value = 60; - progressComponent.bufferValue = 60; - expect(progressComponent.primaryTransform()).toBe('scaleX(0.6)'); - expect(progressComponent.bufferTransform()).toBe('scaleX(0.6)'); - done(); - }); - }); +describe('MdProgressBar', () => { + let builder: TestComponentBuilder; + + beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + builder = tcb; + })); + + it('should apply a mode of "determinate" if no mode is provided.', (done: () => void) => { + builder + .overrideTemplate(TestApp, '') + .createAsync(TestApp) + .then((fixture) => { + fixture.detectChanges(); + let progressElement = fixture.debugElement.query(By.css('md-progress-bar')); + expect(progressElement.componentInstance.mode).toBe('determinate'); + done(); + }); }); -} + + it('should not modify the mode if a valid mode is provided.', (done: () => void) => { + builder + .overrideTemplate(TestApp, '') + .createAsync(TestApp) + .then((fixture) => { + fixture.detectChanges(); + let progressElement = fixture.debugElement.query(By.css('md-progress-bar')); + expect(progressElement.componentInstance.mode).toBe('buffer'); + done(); + }); + }); + + it('should define default values for value and bufferValue attributes', (done: () => void) => { + builder + .overrideTemplate(TestApp, '') + .createAsync(TestApp) + .then((fixture) => { + fixture.detectChanges(); + let progressElement = fixture.debugElement.query(By.css('md-progress-bar')); + expect(progressElement.componentInstance.value).toBe(0); + expect(progressElement.componentInstance.bufferValue).toBe(0); + done(); + }); + }); + + it('should clamp value and bufferValue between 0 and 100', (done: () => void) => { + builder + .overrideTemplate(TestApp, '') + .createAsync(TestApp) + .then((fixture) => { + fixture.detectChanges(); + let progressElement = fixture.debugElement.query(By.css('md-progress-bar')); + let progressComponent = progressElement.componentInstance; + + progressComponent.value = 50; + expect(progressComponent.value).toBe(50); + + progressComponent.value = 999; + expect(progressComponent.value).toBe(100); + + progressComponent.value = -10; + expect(progressComponent.value).toBe(0); + + progressComponent.bufferValue = -29; + expect(progressComponent.bufferValue).toBe(0); + + progressComponent.bufferValue = 9; + expect(progressComponent.bufferValue).toBe(9); + + progressComponent.bufferValue = 1320; + expect(progressComponent.bufferValue).toBe(100); + done(); + }); + }); + + it('should return the transform attribute for bufferValue and mode', (done: () => void) => { + builder + .overrideTemplate(TestApp, '') + .createAsync(TestApp) + .then((fixture) => { + fixture.detectChanges(); + let progressElement = fixture.debugElement.query(By.css('md-progress-bar')); + let progressComponent = progressElement.componentInstance; + + expect(progressComponent.primaryTransform()).toBe('scaleX(0)'); + expect(progressComponent.bufferTransform()).toBe(undefined); + + progressComponent.value = 40; + expect(progressComponent.primaryTransform()).toBe('scaleX(0.4)'); + expect(progressComponent.bufferTransform()).toBe(undefined); + + progressComponent.value = 35; + progressComponent.bufferValue = 55; + expect(progressComponent.primaryTransform()).toBe('scaleX(0.35)'); + expect(progressComponent.bufferTransform()).toBe(undefined); + + progressComponent.mode = 'buffer'; + expect(progressComponent.primaryTransform()).toBe('scaleX(0.35)'); + expect(progressComponent.bufferTransform()).toBe('scaleX(0.55)'); + + + progressComponent.value = 60; + progressComponent.bufferValue = 60; + expect(progressComponent.primaryTransform()).toBe('scaleX(0.6)'); + expect(progressComponent.bufferTransform()).toBe('scaleX(0.6)'); + done(); + }); + }); +}); /** Test component that contains an MdButton. */ @@ -122,4 +120,5 @@ export function main() { directives: [MdProgressBar], template: '', }) -class TestApp {} +class TestApp { +} diff --git a/src/components/progress-circle/progress-circle.spec.ts b/src/components/progress-circle/progress-circle.spec.ts index 2cb19b6c1d36..11b6a25a5b01 100644 --- a/src/components/progress-circle/progress-circle.spec.ts +++ b/src/components/progress-circle/progress-circle.spec.ts @@ -11,72 +11,70 @@ import {By} from '@angular/platform-browser'; import {MdProgressCircle} from './progress-circle'; -export function main() { - describe('MdProgressCircular', () => { - let builder: TestComponentBuilder; +describe('MdProgressCircular', () => { + let builder: TestComponentBuilder; - beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { - builder = tcb; - })); + beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + builder = tcb; + })); - it('should apply a mode of "determinate" if no mode is provided.', (done: () => void) => { - builder - .overrideTemplate(TestApp, '') - .createAsync(TestApp) - .then((fixture) => { - fixture.detectChanges(); - let progressElement = getChildDebugElement(fixture.debugElement, 'md-progress-circle'); - expect(progressElement.componentInstance.mode).toBe('determinate'); - done(); - }); - }); + it('should apply a mode of "determinate" if no mode is provided.', (done: () => void) => { + builder + .overrideTemplate(TestApp, '') + .createAsync(TestApp) + .then((fixture) => { + fixture.detectChanges(); + let progressElement = getChildDebugElement(fixture.debugElement, 'md-progress-circle'); + expect(progressElement.componentInstance.mode).toBe('determinate'); + done(); + }); + }); - it('should not modify the mode if a valid mode is provided.', (done: () => void) => { - builder - .overrideTemplate(TestApp, '') - .createAsync(TestApp) - .then((fixture) => { - fixture.detectChanges(); - let progressElement = getChildDebugElement(fixture.debugElement, 'md-progress-circle'); - expect(progressElement.componentInstance.mode).toBe('indeterminate'); - done(); - }); - }); + it('should not modify the mode if a valid mode is provided.', (done: () => void) => { + builder + .overrideTemplate(TestApp, '') + .createAsync(TestApp) + .then((fixture) => { + fixture.detectChanges(); + let progressElement = getChildDebugElement(fixture.debugElement, 'md-progress-circle'); + expect(progressElement.componentInstance.mode).toBe('indeterminate'); + done(); + }); + }); - it('should define a default value for the value attribute', (done: () => void) => { - builder - .overrideTemplate(TestApp, '') - .createAsync(TestApp) - .then((fixture) => { - fixture.detectChanges(); - let progressElement = getChildDebugElement(fixture.debugElement, 'md-progress-circle'); - expect(progressElement.componentInstance.value).toBe(0); - done(); - }); - }); + it('should define a default value for the value attribute', (done: () => void) => { + builder + .overrideTemplate(TestApp, '') + .createAsync(TestApp) + .then((fixture) => { + fixture.detectChanges(); + let progressElement = getChildDebugElement(fixture.debugElement, 'md-progress-circle'); + expect(progressElement.componentInstance.value).toBe(0); + done(); + }); + }); - it('should clamp the value of the progress between 0 and 100', (done: () => void) => { - builder - .overrideTemplate(TestApp, '') - .createAsync(TestApp) - .then((fixture) => { - fixture.detectChanges(); - let progressElement = getChildDebugElement(fixture.debugElement, 'md-progress-circle'); - let progressComponent = progressElement.componentInstance; + it('should clamp the value of the progress between 0 and 100', (done: () => void) => { + builder + .overrideTemplate(TestApp, '') + .createAsync(TestApp) + .then((fixture) => { + fixture.detectChanges(); + let progressElement = getChildDebugElement(fixture.debugElement, 'md-progress-circle'); + let progressComponent = progressElement.componentInstance; - progressComponent.value = 50; - expect(progressComponent.value).toBe(50); + progressComponent.value = 50; + expect(progressComponent.value).toBe(50); - progressComponent.value = 999; - expect(progressComponent.value).toBe(100); + progressComponent.value = 999; + expect(progressComponent.value).toBe(100); - progressComponent.value = -10; - expect(progressComponent.value).toBe(0); - done(); - }); - }); + progressComponent.value = -10; + expect(progressComponent.value).toBe(0); + done(); + }); }); -} +}); /** Gets a child DebugElement by tag name. */ @@ -85,10 +83,10 @@ function getChildDebugElement(parent: DebugElement, selector: string): DebugElem } - /** Test component that contains an MdButton. */ @Component({ - directives: [MdProgressCircle], - template: '', + directives: [MdProgressCircle], + template: '', }) -class TestApp {} +class TestApp { +} diff --git a/src/components/sidenav/sidenav.spec.ts b/src/components/sidenav/sidenav.spec.ts index be9b8385d006..bc748a314948 100644 --- a/src/components/sidenav/sidenav.spec.ts +++ b/src/components/sidenav/sidenav.spec.ts @@ -29,7 +29,7 @@ function fakeAsyncAdaptor(fn: () => void) { * Create a ComponentFixture from the builder. This takes a template and a style for sidenav. */ function createFixture(appType: Type, builder: TestComponentBuilder, - template: string, style: string): ComponentFixture { + template: string, style: string): ComponentFixture { let fixture: ComponentFixture = null; // Remove the styles (which remove the animations/transitions). builder @@ -38,7 +38,9 @@ function createFixture(appType: Type, builder: TestComponentBuilder, styles: [style], directives: [MdSidenav], })) - .createAsync(appType).then((f: ComponentFixture) => { fixture = f; }); + .createAsync(appType).then((f: ComponentFixture) => { + fixture = f; + }); tick(); return fixture; @@ -55,230 +57,244 @@ function endSidenavTransition(fixture: ComponentFixture) { } -export function main() { - describe('MdSidenav', () => { - let template: string; - let style: string; - let builder: TestComponentBuilder; - - /** - * We need to get the template and styles for the sidenav in an Async test. - * FakeAsync would block indefinitely on the XHR if we were to create the component async-ly. - * See https://github.com/angular/angular/issues/5601. - * We do some style verification so styles have to match. - * But we remove the transitions so we only set the regular `sidenav.css` styling. - */ - beforeEach(injectAsync([TestComponentBuilder, XHR], (tcb: TestComponentBuilder, xhr: XHR) => { - builder = tcb; - - return Promise.all([ - xhr.get('./components/sidenav/sidenav.html').then((t) => { template = t; }), - xhr.get('./components/sidenav/sidenav.css').then((css) => { style = css; }) - ]).catch((err: any) => { - console.error(err); - }); +describe('MdSidenav', () => { + let template: string; + let style: string; + let builder: TestComponentBuilder; + + /** + * We need to get the template and styles for the sidenav in an Async test. + * FakeAsync would block indefinitely on the XHR if we were to create the component async-ly. + * See https://github.com/angular/angular/issues/5601. + * We do some style verification so styles have to match. + * But we remove the transitions so we only set the regular `sidenav.css` styling. + */ + beforeEach(injectAsync([TestComponentBuilder, XHR], (tcb: TestComponentBuilder, xhr: XHR) => { + builder = tcb; + + return Promise.all([ + xhr.get('./components/sidenav/sidenav.html').then((t) => { + template = t; + }), + xhr.get('./components/sidenav/sidenav.css').then((css) => { + style = css; + }) + ]).catch((err: any) => { + console.error(err); + }); + })); + + describe('methods', () => { + it('should be able to open and close', fakeAsyncAdaptor(() => { + let fixture = createFixture(BasicTestApp, builder, template, style); + + let testComponent: BasicTestApp = fixture.debugElement.componentInstance; + let openButtonElement = fixture.debugElement.query(By.css('.open')); + openButtonElement.nativeElement.click(); + fixture.detectChanges(); + tick(); + + expect(testComponent.openStartCount).toBe(1); + expect(testComponent.openCount).toBe(0); + + endSidenavTransition(fixture); + tick(); + + expect(testComponent.openStartCount).toBe(1); + expect(testComponent.openCount).toBe(1); + expect(testComponent.closeStartCount).toBe(0); + expect(testComponent.closeCount).toBe(0); + + let sidenavElement = fixture.debugElement.query(By.css('md-sidenav')); + let sidenavBackdropElement = fixture.debugElement.query(By.css('.md-sidenav-backdrop')); + expect(getComputedStyle(sidenavElement.nativeElement).visibility).toEqual('visible'); + expect(getComputedStyle(sidenavBackdropElement.nativeElement).visibility) + .toEqual('visible'); + + // Close it. + let closeButtonElement = fixture.debugElement.query(By.css('.close')); + closeButtonElement.nativeElement.click(); + fixture.detectChanges(); + tick(); + + expect(testComponent.openStartCount).toBe(1); + expect(testComponent.openCount).toBe(1); + expect(testComponent.closeStartCount).toBe(1); + expect(testComponent.closeCount).toBe(0); + + endSidenavTransition(fixture); + tick(); + + expect(testComponent.openStartCount).toBe(1); + expect(testComponent.openCount).toBe(1); + expect(testComponent.closeStartCount).toBe(1); + expect(testComponent.closeCount).toBe(1); + + expect(getComputedStyle(sidenavElement.nativeElement).visibility).toEqual('hidden'); + expect(getComputedStyle(sidenavBackdropElement.nativeElement).visibility).toEqual('hidden'); })); - describe('methods', () => { - it('should be able to open and close', fakeAsyncAdaptor(() => { - let fixture = createFixture(BasicTestApp, builder, template, style); + it('open/close() return a promise that resolves after animation end', fakeAsyncAdaptor(() => { + let fixture = createFixture(BasicTestApp, builder, template, style); + let sidenav: MdSidenav = fixture.debugElement + .query(By.directive(MdSidenav)).componentInstance; + let called = false; - let testComponent: BasicTestApp = fixture.debugElement.componentInstance; - let openButtonElement = fixture.debugElement.query(By.css('.open')); - openButtonElement.nativeElement.click(); - fixture.detectChanges(); - tick(); + sidenav.open().then(() => { + called = true; + }); - expect(testComponent.openStartCount).toBe(1); - expect(testComponent.openCount).toBe(0); + expect(called).toBe(false); + endSidenavTransition(fixture); + tick(); + expect(called).toBe(true); - endSidenavTransition(fixture); - tick(); + called = false; + sidenav.close().then(() => { + called = true; + }); - expect(testComponent.openStartCount).toBe(1); - expect(testComponent.openCount).toBe(1); - expect(testComponent.closeStartCount).toBe(0); - expect(testComponent.closeCount).toBe(0); + expect(called).toBe(false); + endSidenavTransition(fixture); + tick(); + expect(called).toBe(true); - let sidenavElement = fixture.debugElement.query(By.css('md-sidenav')); - let sidenavBackdropElement = fixture.debugElement.query(By.css('.md-sidenav-backdrop')); - expect(getComputedStyle(sidenavElement.nativeElement).visibility).toEqual('visible'); - expect(getComputedStyle(sidenavBackdropElement.nativeElement).visibility) - .toEqual('visible'); + })); - // Close it. - let closeButtonElement = fixture.debugElement.query(By.css('.close')); - closeButtonElement.nativeElement.click(); - fixture.detectChanges(); - tick(); + it('open/close() twice returns the same promise', fakeAsyncAdaptor(() => { + let fixture = createFixture(BasicTestApp, builder, template, style); + let sidenav: MdSidenav = fixture.debugElement + .query(By.directive(MdSidenav)).componentInstance; - expect(testComponent.openStartCount).toBe(1); - expect(testComponent.openCount).toBe(1); - expect(testComponent.closeStartCount).toBe(1); - expect(testComponent.closeCount).toBe(0); + let promise = sidenav.open(); + expect(sidenav.open()).toBe(promise); + fixture.detectChanges(); + tick(); - endSidenavTransition(fixture); - tick(); + promise = sidenav.close(); + expect(sidenav.close()).toBe(promise); + tick(); + })); - expect(testComponent.openStartCount).toBe(1); - expect(testComponent.openCount).toBe(1); - expect(testComponent.closeStartCount).toBe(1); - expect(testComponent.closeCount).toBe(1); + it('open() then close() cancel animations when called too fast', fakeAsyncAdaptor(() => { + let fixture = createFixture(BasicTestApp, builder, template, style); + let sidenav: MdSidenav = fixture.debugElement + .query(By.directive(MdSidenav)).componentInstance; - expect(getComputedStyle(sidenavElement.nativeElement).visibility).toEqual('hidden'); - expect(getComputedStyle(sidenavBackdropElement.nativeElement).visibility).toEqual('hidden'); - })); + let openCalled = false; + let openCancelled = false; + let closeCalled = false; - it('open/close() return a promise that resolves after animation end', fakeAsyncAdaptor(() => { - let fixture = createFixture(BasicTestApp, builder, template, style); - let sidenav: MdSidenav = fixture.debugElement - .query(By.directive(MdSidenav)).componentInstance; - let called = false; + sidenav.open().then(() => { + openCalled = true; + }, () => { + openCancelled = true; + }); - sidenav.open().then(() => { - called = true; - }); + // We do not call transition end, close directly. + sidenav.close().then(() => { + closeCalled = true; + }); - expect(called).toBe(false); - endSidenavTransition(fixture); - tick(); - expect(called).toBe(true); + endSidenavTransition(fixture); + tick(); - called = false; - sidenav.close().then(() => { - called = true; - }); + expect(openCalled).toBe(false); + expect(openCancelled).toBe(true); + expect(closeCalled).toBe(true); + tick(); + })); - expect(called).toBe(false); - endSidenavTransition(fixture); - tick(); - expect(called).toBe(true); + it('close() then open() cancel animations when called too fast', fakeAsyncAdaptor(() => { + let fixture = createFixture(BasicTestApp, builder, template, style); + let sidenav: MdSidenav = fixture.debugElement + .query(By.directive(MdSidenav)).componentInstance; + + let closeCalled = false; + let closeCancelled = false; + let openCalled = false; + + // First, open the sidenav completely. + sidenav.open(); + endSidenavTransition(fixture); + tick(); + + // Then close and check behavior. + sidenav.close().then(() => { + closeCalled = true; + }, () => { + closeCancelled = true; + }); + // We do not call transition end, open directly. + sidenav.open().then(() => { + openCalled = true; + }); - })); + endSidenavTransition(fixture); + tick(); - it('open/close() twice returns the same promise', fakeAsyncAdaptor(() => { - let fixture = createFixture(BasicTestApp, builder, template, style); - let sidenav: MdSidenav = fixture.debugElement - .query(By.directive(MdSidenav)).componentInstance; + expect(closeCalled).toBe(false); + expect(closeCancelled).toBe(true); + expect(openCalled).toBe(true); + tick(); + })); - let promise = sidenav.open(); - expect(sidenav.open()).toBe(promise); + it('does not throw when created without a sidenav', fakeAsyncAdaptor(() => { + expect(() => { + let fixture = createFixture(SidenavLayoutNoSidenavTestApp, builder, template, style); fixture.detectChanges(); tick(); + }).not.toThrow(); + })); - promise = sidenav.close(); - expect(sidenav.close()).toBe(promise); - tick(); - })); - - it('open() then close() cancel animations when called too fast', fakeAsyncAdaptor(() => { - let fixture = createFixture(BasicTestApp, builder, template, style); - let sidenav: MdSidenav = fixture.debugElement - .query(By.directive(MdSidenav)).componentInstance; - - let openCalled = false; - let openCancelled = false; - let closeCalled = false; - - sidenav.open().then(() => { openCalled = true; }, () => { openCancelled = true; }); - - // We do not call transition end, close directly. - sidenav.close().then(() => { closeCalled = true; }); - - endSidenavTransition(fixture); - tick(); - - expect(openCalled).toBe(false); - expect(openCancelled).toBe(true); - expect(closeCalled).toBe(true); - tick(); - })); - - it('close() then open() cancel animations when called too fast', fakeAsyncAdaptor(() => { - let fixture = createFixture(BasicTestApp, builder, template, style); - let sidenav: MdSidenav = fixture.debugElement - .query(By.directive(MdSidenav)).componentInstance; - - let closeCalled = false; - let closeCancelled = false; - let openCalled = false; - - // First, open the sidenav completely. - sidenav.open(); - endSidenavTransition(fixture); - tick(); - - // Then close and check behavior. - sidenav.close().then(() => { closeCalled = true; }, () => { closeCancelled = true; }); - // We do not call transition end, open directly. - sidenav.open().then(() => { openCalled = true; }); - - endSidenavTransition(fixture); - tick(); - - expect(closeCalled).toBe(false); - expect(closeCancelled).toBe(true); - expect(openCalled).toBe(true); + it('does throw when created with two sidenav on the same side', fakeAsyncAdaptor(() => { + expect(() => { + let fixture = createFixture(SidenavLayoutTwoSidenavTestApp, builder, template, style); + fixture.detectChanges(); tick(); - })); - - it('does not throw when created without a sidenav', fakeAsyncAdaptor(() => { - expect(() => { - let fixture = createFixture(SidenavLayoutNoSidenavTestApp, builder, template, style); - fixture.detectChanges(); - tick(); - }).not.toThrow(); - })); - - it('does throw when created with two sidenav on the same side', fakeAsyncAdaptor(() => { - expect(() => { - let fixture = createFixture(SidenavLayoutTwoSidenavTestApp, builder, template, style); - fixture.detectChanges(); - tick(); - }).toThrow(); - })); - }); + }).toThrow(); + })); + }); - describe('attributes', () => { + describe('attributes', () => { - it('should correctly parse opened="false"', fakeAsyncAdaptor(() => { - let newBuilder = builder.overrideTemplate(BasicTestApp, ` + it('should correctly parse opened="false"', fakeAsyncAdaptor(() => { + let newBuilder = builder.overrideTemplate(BasicTestApp, ` Closed Sidenav. `); - let fixture = createFixture(BasicTestApp, newBuilder, template, style); - fixture.detectChanges(); + let fixture = createFixture(BasicTestApp, newBuilder, template, style); + fixture.detectChanges(); - let sidenavEl = fixture.debugElement.query(By.css('md-sidenav')).nativeElement; + let sidenavEl = fixture.debugElement.query(By.css('md-sidenav')).nativeElement; - expect(sidenavEl.classList).toContain('md-sidenav-closed'); - expect(sidenavEl.classList).not.toContain('md-sidenav-opened'); - })); + expect(sidenavEl.classList).toContain('md-sidenav-closed'); + expect(sidenavEl.classList).not.toContain('md-sidenav-opened'); + })); - it('should correctly parse opened="true"', fakeAsyncAdaptor(() => { - let newBuilder = builder.overrideTemplate(BasicTestApp, ` + it('should correctly parse opened="true"', fakeAsyncAdaptor(() => { + let newBuilder = builder.overrideTemplate(BasicTestApp, ` Closed Sidenav. `); - let fixture = createFixture(BasicTestApp, newBuilder, template, style); - fixture.detectChanges(); - - let sidenavEl = fixture.debugElement.query(By.css('md-sidenav')).nativeElement; + let fixture = createFixture(BasicTestApp, newBuilder, template, style); + fixture.detectChanges(); - expect(sidenavEl.classList).not.toContain('md-sidenav-closed'); - expect(sidenavEl.classList).toContain('md-sidenav-opened'); - })); + let sidenavEl = fixture.debugElement.query(By.css('md-sidenav')).nativeElement; - }); + expect(sidenavEl.classList).not.toContain('md-sidenav-closed'); + expect(sidenavEl.classList).toContain('md-sidenav-opened'); + })); }); -} + +}); /** Test component that contains an MdSidenavLayout but no MdSidenav. */ @@ -336,12 +352,15 @@ class BasicTestApp { openStart() { this.openStartCount++; } + open() { this.openCount++; } + closeStart() { this.closeStartCount++; } + close() { this.closeCount++; } diff --git a/src/components/slide-toggle/slide-toggle.spec.ts b/src/components/slide-toggle/slide-toggle.spec.ts index 9b03a95e852a..4f86c2ab9b29 100644 --- a/src/components/slide-toggle/slide-toggle.spec.ts +++ b/src/components/slide-toggle/slide-toggle.spec.ts @@ -12,234 +12,232 @@ import {Component} from '@angular/core'; import {MdSlideToggle} from './slide-toggle'; import {NgControl} from '@angular/common'; -export function main() { - describe('MdSlideToggle', () => { - let builder: TestComponentBuilder; +describe('MdSlideToggle', () => { + let builder: TestComponentBuilder; - beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { - builder = tcb; - })); - - describe('basic behavior', () => { - - let fixture: ComponentFixture; - - let testComponent: SlideToggleTestApp; - let slideToggle: MdSlideToggle; - let slideToggleElement: HTMLElement; - let slideToggleControl: NgControl; - let labelElement: HTMLLabelElement; - let inputElement: HTMLInputElement; + beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + builder = tcb; + })); - beforeEach(async(() => { - builder.createAsync(SlideToggleTestApp).then(f => { - fixture = f; - fixture.detectChanges(); + describe('basic behavior', () => { - let slideToggleDebug = fixture.debugElement.query(By.css('md-slide-toggle')); + let fixture: ComponentFixture; - testComponent = fixture.debugElement.componentInstance; - slideToggle = slideToggleDebug.componentInstance; - slideToggleElement = slideToggleDebug.nativeElement; - slideToggleControl = slideToggleDebug.injector.get(NgControl); - inputElement = fixture.debugElement.query(By.css('input')).nativeElement; - labelElement = fixture.debugElement.query(By.css('label')).nativeElement; - }); - })); + let testComponent: SlideToggleTestApp; + let slideToggle: MdSlideToggle; + let slideToggleElement: HTMLElement; + let slideToggleControl: NgControl; + let labelElement: HTMLLabelElement; + let inputElement: HTMLInputElement; - - it('should update the model correctly', () => { - expect(slideToggleElement.classList).not.toContain('md-checked'); - - testComponent.slideModel = true; + beforeEach(async(() => { + builder.createAsync(SlideToggleTestApp).then(f => { + fixture = f; fixture.detectChanges(); - expect(slideToggleElement.classList).toContain('md-checked'); - }); + let slideToggleDebug = fixture.debugElement.query(By.css('md-slide-toggle')); - it('should apply class based on color attribute', () => { - testComponent.slideColor = 'primary'; - fixture.detectChanges(); + testComponent = fixture.debugElement.componentInstance; + slideToggle = slideToggleDebug.componentInstance; + slideToggleElement = slideToggleDebug.nativeElement; + slideToggleControl = slideToggleDebug.injector.get(NgControl); + inputElement = fixture.debugElement.query(By.css('input')).nativeElement; + labelElement = fixture.debugElement.query(By.css('label')).nativeElement; + }); + })); - expect(slideToggleElement.classList).toContain('md-primary'); - testComponent.slideColor = 'accent'; - fixture.detectChanges(); + it('should update the model correctly', () => { + expect(slideToggleElement.classList).not.toContain('md-checked'); - expect(slideToggleElement.classList).toContain('md-accent'); - }); + testComponent.slideModel = true; + fixture.detectChanges(); - it('should correctly update the disabled property', () => { - expect(inputElement.disabled).toBeFalsy(); + expect(slideToggleElement.classList).toContain('md-checked'); + }); - testComponent.isDisabled = true; - fixture.detectChanges(); + it('should apply class based on color attribute', () => { + testComponent.slideColor = 'primary'; + fixture.detectChanges(); - expect(inputElement.disabled).toBeTruthy(); - }); + expect(slideToggleElement.classList).toContain('md-primary'); - it('should correctly update the checked property', () => { - expect(slideToggle.checked).toBeFalsy(); + testComponent.slideColor = 'accent'; + fixture.detectChanges(); - testComponent.slideChecked = true; - fixture.detectChanges(); - - expect(inputElement.checked).toBeTruthy(); - }); + expect(slideToggleElement.classList).toContain('md-accent'); + }); - it('should set the toggle to checked on click', () => { - expect(slideToggle.checked).toBe(false); - expect(slideToggleElement.classList).not.toContain('md-checked'); + it('should correctly update the disabled property', () => { + expect(inputElement.disabled).toBeFalsy(); - labelElement.click(); - fixture.detectChanges(); + testComponent.isDisabled = true; + fixture.detectChanges(); - expect(slideToggleElement.classList).toContain('md-checked'); - expect(slideToggle.checked).toBe(true); - }); + expect(inputElement.disabled).toBeTruthy(); + }); - it('should add a suffix to the inputs id', () => { - testComponent.slideId = 'myId'; - fixture.detectChanges(); + it('should correctly update the checked property', () => { + expect(slideToggle.checked).toBeFalsy(); - expect(inputElement.id).toBe('myId-input'); + testComponent.slideChecked = true; + fixture.detectChanges(); - testComponent.slideId = 'nextId'; - fixture.detectChanges(); + expect(inputElement.checked).toBeTruthy(); + }); - expect(inputElement.id).toBe('nextId-input'); + it('should set the toggle to checked on click', () => { + expect(slideToggle.checked).toBe(false); + expect(slideToggleElement.classList).not.toContain('md-checked'); - testComponent.slideId = null; - fixture.detectChanges(); + labelElement.click(); + fixture.detectChanges(); - // Once the id input is falsy, we use a default prefix with a incrementing unique number. - expect(inputElement.id).toMatch(/md-slide-toggle-[0-9]+-input/g); - }); + expect(slideToggleElement.classList).toContain('md-checked'); + expect(slideToggle.checked).toBe(true); + }); - it('should forward the specified name to the input', () => { - testComponent.slideName = 'myName'; - fixture.detectChanges(); + it('should add a suffix to the inputs id', () => { + testComponent.slideId = 'myId'; + fixture.detectChanges(); - expect(inputElement.name).toBe('myName'); + expect(inputElement.id).toBe('myId-input'); - testComponent.slideName = 'nextName'; - fixture.detectChanges(); + testComponent.slideId = 'nextId'; + fixture.detectChanges(); - expect(inputElement.name).toBe('nextName'); + expect(inputElement.id).toBe('nextId-input'); - testComponent.slideName = null; - fixture.detectChanges(); + testComponent.slideId = null; + fixture.detectChanges(); - expect(inputElement.name).toBe(''); - }); + // Once the id input is falsy, we use a default prefix with a incrementing unique number. + expect(inputElement.id).toMatch(/md-slide-toggle-[0-9]+-input/g); + }); - it('should forward the aria-label attribute to the input', () => { - testComponent.slideLabel = 'ariaLabel'; - fixture.detectChanges(); + it('should forward the specified name to the input', () => { + testComponent.slideName = 'myName'; + fixture.detectChanges(); - expect(inputElement.getAttribute('aria-label')).toBe('ariaLabel'); + expect(inputElement.name).toBe('myName'); - testComponent.slideLabel = null; - fixture.detectChanges(); + testComponent.slideName = 'nextName'; + fixture.detectChanges(); - expect(inputElement.hasAttribute('aria-label')).toBeFalsy(); - }); + expect(inputElement.name).toBe('nextName'); - it('should forward the aria-labelledby attribute to the input', () => { - testComponent.slideLabelledBy = 'ariaLabelledBy'; - fixture.detectChanges(); + testComponent.slideName = null; + fixture.detectChanges(); - expect(inputElement.getAttribute('aria-labelledby')).toBe('ariaLabelledBy'); + expect(inputElement.name).toBe(''); + }); - testComponent.slideLabelledBy = null; - fixture.detectChanges(); + it('should forward the aria-label attribute to the input', () => { + testComponent.slideLabel = 'ariaLabel'; + fixture.detectChanges(); - expect(inputElement.hasAttribute('aria-labelledby')).toBeFalsy(); - }); + expect(inputElement.getAttribute('aria-label')).toBe('ariaLabel'); - it('should be initially set to ng-pristine', () => { - expect(slideToggleElement.classList).toContain('ng-pristine'); - expect(slideToggleElement.classList).not.toContain('ng-dirty'); - }); + testComponent.slideLabel = null; + fixture.detectChanges(); - it('should emit the new values', () => { - expect(testComponent.changeCount).toBe(0); + expect(inputElement.hasAttribute('aria-label')).toBeFalsy(); + }); - labelElement.click(); - fixture.detectChanges(); + it('should forward the aria-labelledby attribute to the input', () => { + testComponent.slideLabelledBy = 'ariaLabelledBy'; + fixture.detectChanges(); - expect(testComponent.changeCount).toBe(1); - }); + expect(inputElement.getAttribute('aria-labelledby')).toBe('ariaLabelledBy'); - it('should support subscription on the change observable', () => { - slideToggle.change.subscribe(value => { - expect(value).toBe(true); - }); + testComponent.slideLabelledBy = null; + fixture.detectChanges(); - slideToggle.toggle(); - fixture.detectChanges(); - }); + expect(inputElement.hasAttribute('aria-labelledby')).toBeFalsy(); + }); - it('should have the correct ngControl state initially and after interaction', () => { - // The control should start off valid, pristine, and untouched. - expect(slideToggleControl.valid).toBe(true); - expect(slideToggleControl.pristine).toBe(true); - expect(slideToggleControl.touched).toBe(false); + it('should be initially set to ng-pristine', () => { + expect(slideToggleElement.classList).toContain('ng-pristine'); + expect(slideToggleElement.classList).not.toContain('ng-dirty'); + }); - // After changing the value programmatically, the control should - // become dirty (not pristine), but remain untouched. - slideToggle.checked = true; - fixture.detectChanges(); + it('should emit the new values', () => { + expect(testComponent.changeCount).toBe(0); - expect(slideToggleControl.valid).toBe(true); - expect(slideToggleControl.pristine).toBe(false); - expect(slideToggleControl.touched).toBe(false); + labelElement.click(); + fixture.detectChanges(); - // After a user interaction occurs (such as a click), the control should remain dirty and - // now also be touched. - labelElement.click(); - fixture.detectChanges(); + expect(testComponent.changeCount).toBe(1); + }); - expect(slideToggleControl.valid).toBe(true); - expect(slideToggleControl.pristine).toBe(false); - expect(slideToggleControl.touched).toBe(true); + it('should support subscription on the change observable', () => { + slideToggle.change.subscribe(value => { + expect(value).toBe(true); }); - it('should not set the ngControl to touched when changing the state programmatically', () => { - // The control should start off with being untouched. - expect(slideToggleControl.touched).toBe(false); + slideToggle.toggle(); + fixture.detectChanges(); + }); - testComponent.slideChecked = true; - fixture.detectChanges(); + it('should have the correct ngControl state initially and after interaction', () => { + // The control should start off valid, pristine, and untouched. + expect(slideToggleControl.valid).toBe(true); + expect(slideToggleControl.pristine).toBe(true); + expect(slideToggleControl.touched).toBe(false); + + // After changing the value programmatically, the control should + // become dirty (not pristine), but remain untouched. + slideToggle.checked = true; + fixture.detectChanges(); + + expect(slideToggleControl.valid).toBe(true); + expect(slideToggleControl.pristine).toBe(false); + expect(slideToggleControl.touched).toBe(false); + + // After a user interaction occurs (such as a click), the control should remain dirty and + // now also be touched. + labelElement.click(); + fixture.detectChanges(); + + expect(slideToggleControl.valid).toBe(true); + expect(slideToggleControl.pristine).toBe(false); + expect(slideToggleControl.touched).toBe(true); + }); - expect(slideToggleControl.touched).toBe(false); - expect(slideToggleElement.classList).toContain('md-checked'); + it('should not set the ngControl to touched when changing the state programmatically', () => { + // The control should start off with being untouched. + expect(slideToggleControl.touched).toBe(false); - // After a user interaction occurs (such as a click), the control should remain dirty and - // now also be touched. - inputElement.click(); - fixture.detectChanges(); + testComponent.slideChecked = true; + fixture.detectChanges(); - expect(slideToggleControl.touched).toBe(true); - expect(slideToggleElement.classList).not.toContain('md-checked'); - }); + expect(slideToggleControl.touched).toBe(false); + expect(slideToggleElement.classList).toContain('md-checked'); - it('should not set the ngControl to touched when changing the model', () => { - // The control should start off with being untouched. - expect(slideToggleControl.touched).toBe(false); + // After a user interaction occurs (such as a click), the control should remain dirty and + // now also be touched. + inputElement.click(); + fixture.detectChanges(); - testComponent.slideModel = true; - fixture.detectChanges(); + expect(slideToggleControl.touched).toBe(true); + expect(slideToggleElement.classList).not.toContain('md-checked'); + }); - expect(slideToggleControl.touched).toBe(false); - expect(slideToggle.checked).toBe(true); - expect(slideToggleElement.classList).toContain('md-checked'); - }); + it('should not set the ngControl to touched when changing the model', () => { + // The control should start off with being untouched. + expect(slideToggleControl.touched).toBe(false); + testComponent.slideModel = true; + fixture.detectChanges(); + + expect(slideToggleControl.touched).toBe(false); + expect(slideToggle.checked).toBe(true); + expect(slideToggleElement.classList).toContain('md-checked'); }); }); -} + +}); @Component({ selector: 'slide-toggle-test-app', diff --git a/src/components/toolbar/toolbar.spec.ts b/src/components/toolbar/toolbar.spec.ts index 0970fe713741..e08c1ea9bba8 100644 --- a/src/components/toolbar/toolbar.spec.ts +++ b/src/components/toolbar/toolbar.spec.ts @@ -10,42 +10,40 @@ import {TestComponentBuilder} from '@angular/compiler/testing'; import {By} from '@angular/platform-browser'; import {MdToolbar} from './toolbar'; -export function main() { - describe('MdToolbar', () => { - let builder: TestComponentBuilder; +describe('MdToolbar', () => { + let builder: TestComponentBuilder; - beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { - builder = tcb; - })); + beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + builder = tcb; + })); - it('should apply class based on color attribute', (done: () => void) => { - return builder.createAsync(TestApp).then((fixture) => { - let testComponent = fixture.debugElement.componentInstance; - let toolbarDebugElement = fixture.debugElement.query(By.css('md-toolbar')); + it('should apply class based on color attribute', (done: () => void) => { + return builder.createAsync(TestApp).then((fixture) => { + let testComponent = fixture.debugElement.componentInstance; + let toolbarDebugElement = fixture.debugElement.query(By.css('md-toolbar')); - testComponent.toolbarColor = 'primary'; - fixture.detectChanges(); + testComponent.toolbarColor = 'primary'; + fixture.detectChanges(); - expect(toolbarDebugElement.nativeElement.classList.contains('md-primary')).toBe(true); + expect(toolbarDebugElement.nativeElement.classList.contains('md-primary')).toBe(true); - testComponent.toolbarColor = 'accent'; - fixture.detectChanges(); + testComponent.toolbarColor = 'accent'; + fixture.detectChanges(); - expect(toolbarDebugElement.nativeElement.classList.contains('md-primary')).toBe(false); - expect(toolbarDebugElement.nativeElement.classList.contains('md-accent')).toBe(true); + expect(toolbarDebugElement.nativeElement.classList.contains('md-primary')).toBe(false); + expect(toolbarDebugElement.nativeElement.classList.contains('md-accent')).toBe(true); - testComponent.toolbarColor = 'warn'; - fixture.detectChanges(); + testComponent.toolbarColor = 'warn'; + fixture.detectChanges(); - expect(toolbarDebugElement.nativeElement.classList.contains('md-accent')).toBe(false); - expect(toolbarDebugElement.nativeElement.classList.contains('md-warn')).toBe(true); + expect(toolbarDebugElement.nativeElement.classList.contains('md-accent')).toBe(false); + expect(toolbarDebugElement.nativeElement.classList.contains('md-warn')).toBe(true); - done(); - }); + done(); }); - }); -} + +}); @Component({ selector: 'test-app', diff --git a/src/core/live-announcer/live-announcer.spec.ts b/src/core/live-announcer/live-announcer.spec.ts index 20fd3ba29a39..ce16d8b18133 100644 --- a/src/core/live-announcer/live-announcer.spec.ts +++ b/src/core/live-announcer/live-announcer.spec.ts @@ -15,107 +15,105 @@ import {Component, provide} from '@angular/core'; import {By} from '@angular/platform-browser'; import {MdLiveAnnouncer, LIVE_ANNOUNCER_ELEMENT_TOKEN} from './live-announcer'; -export function main() { - describe('MdLiveAnnouncer', () => { - let live: MdLiveAnnouncer; - let builder: TestComponentBuilder; - let liveEl: Element; - - beforeEachProviders(() => [MdLiveAnnouncer]); - - beforeEach(inject([TestComponentBuilder, MdLiveAnnouncer], - (tcb: TestComponentBuilder, _live: MdLiveAnnouncer) => { - builder = tcb; - live = _live; - liveEl = getLiveElement(); +describe('MdLiveAnnouncer', () => { + let live: MdLiveAnnouncer; + let builder: TestComponentBuilder; + let liveEl: Element; + + beforeEachProviders(() => [MdLiveAnnouncer]); + + beforeEach(inject([TestComponentBuilder, MdLiveAnnouncer], + (tcb: TestComponentBuilder, _live: MdLiveAnnouncer) => { + builder = tcb; + live = _live; + liveEl = getLiveElement(); })); - afterEach(() => { - // In our tests we always remove the current live element, because otherwise we would have - // multiple live elements due multiple service instantiations. - liveEl.parentNode.removeChild(liveEl); - }); + afterEach(() => { + // In our tests we always remove the current live element, because otherwise we would have + // multiple live elements due multiple service instantiations. + liveEl.parentNode.removeChild(liveEl); + }); - it('should correctly update the announce text', fakeAsyncTest(() => { - let appFixture: ComponentFixture = null; + it('should correctly update the announce text', fakeAsyncTest(() => { + let appFixture: ComponentFixture = null; - builder.createAsync(TestApp).then(fixture => { - appFixture = fixture; - }); + builder.createAsync(TestApp).then(fixture => { + appFixture = fixture; + }); - flushMicrotasks(); + flushMicrotasks(); - let buttonElement = appFixture.debugElement - .query(By.css('button')).nativeElement; + let buttonElement = appFixture.debugElement + .query(By.css('button')).nativeElement; - buttonElement.click(); + buttonElement.click(); - // This flushes our 100ms timeout for the screenreaders. - tick(100); + // This flushes our 100ms timeout for the screenreaders. + tick(100); - expect(liveEl.textContent).toBe('Test'); - })); + expect(liveEl.textContent).toBe('Test'); + })); - it('should correctly update the politeness attribute', fakeAsyncTest(() => { - let appFixture: ComponentFixture = null; + it('should correctly update the politeness attribute', fakeAsyncTest(() => { + let appFixture: ComponentFixture = null; - builder.createAsync(TestApp).then(fixture => { - appFixture = fixture; - }); + builder.createAsync(TestApp).then(fixture => { + appFixture = fixture; + }); - flushMicrotasks(); + flushMicrotasks(); - live.announce('Hey Google', 'assertive'); + live.announce('Hey Google', 'assertive'); - // This flushes our 100ms timeout for the screenreaders. - tick(100); + // This flushes our 100ms timeout for the screenreaders. + tick(100); - expect(liveEl.textContent).toBe('Hey Google'); - expect(liveEl.getAttribute('aria-live')).toBe('assertive'); - })); + expect(liveEl.textContent).toBe('Hey Google'); + expect(liveEl.getAttribute('aria-live')).toBe('assertive'); + })); - it('should apply the aria-live value polite by default', fakeAsyncTest(() => { - let appFixture: ComponentFixture = null; + it('should apply the aria-live value polite by default', fakeAsyncTest(() => { + let appFixture: ComponentFixture = null; - builder.createAsync(TestApp).then(fixture => { - appFixture = fixture; - }); + builder.createAsync(TestApp).then(fixture => { + appFixture = fixture; + }); - flushMicrotasks(); + flushMicrotasks(); - live.announce('Hey Google'); + live.announce('Hey Google'); - // This flushes our 100ms timeout for the screenreaders. - tick(100); + // This flushes our 100ms timeout for the screenreaders. + tick(100); - expect(liveEl.textContent).toBe('Hey Google'); - expect(liveEl.getAttribute('aria-live')).toBe('polite'); - })); + expect(liveEl.textContent).toBe('Hey Google'); + expect(liveEl.getAttribute('aria-live')).toBe('polite'); + })); - it('should allow to use a custom live element', fakeAsyncTest(() => { - let customLiveEl = document.createElement('div'); + it('should allow to use a custom live element', fakeAsyncTest(() => { + let customLiveEl = document.createElement('div'); - // We need to reset our test injector here, because it is already instantiated above. - getTestInjector().reset(); + // We need to reset our test injector here, because it is already instantiated above. + getTestInjector().reset(); - getTestInjector().addProviders([ - provide(LIVE_ANNOUNCER_ELEMENT_TOKEN, {useValue: customLiveEl}), - MdLiveAnnouncer - ]); + getTestInjector().addProviders([ + provide(LIVE_ANNOUNCER_ELEMENT_TOKEN, {useValue: customLiveEl}), + MdLiveAnnouncer + ]); - let injector = getTestInjector().createInjector(); - let liveService: MdLiveAnnouncer = injector.get(MdLiveAnnouncer); + let injector = getTestInjector().createInjector(); + let liveService: MdLiveAnnouncer = injector.get(MdLiveAnnouncer); - liveService.announce('Custom Element'); + liveService.announce('Custom Element'); - // This flushes our 100ms timeout for the screenreaders. - tick(100); + // This flushes our 100ms timeout for the screenreaders. + tick(100); - expect(customLiveEl.textContent).toBe('Custom Element'); - })); + expect(customLiveEl.textContent).toBe('Custom Element'); + })); - }); -} +}); function fakeAsyncTest(fn: () => void) { return inject([], fakeAsync(fn)); @@ -131,7 +129,8 @@ function getLiveElement(): Element { }) class TestApp { - constructor(private live: MdLiveAnnouncer) {}; + constructor(private live: MdLiveAnnouncer) { + }; announceText(message: string) { this.live.announce(message); diff --git a/src/core/overlay/overlay.spec.ts b/src/core/overlay/overlay.spec.ts index 6fd22e4952cd..f4138f2cb852 100644 --- a/src/core/overlay/overlay.spec.ts +++ b/src/core/overlay/overlay.spec.ts @@ -10,9 +10,9 @@ import { } from '@angular/core/testing'; import {TestComponentBuilder} from '@angular/compiler/testing'; import { - Component, - ViewChild, - provide, ViewContainerRef, + Component, + ViewChild, + provide, ViewContainerRef, } from '@angular/core'; import {TemplatePortalDirective} from '../portal/portal-directives'; import {TemplatePortal, ComponentPortal} from '../portal/portal'; @@ -24,124 +24,124 @@ import {OverlayPositionBuilder} from './position/overlay-position-builder'; import {ViewportRuler} from './position/viewport-ruler'; -export function main() { - describe('Overlay', () => { - let builder: TestComponentBuilder; - let overlay: Overlay; - let componentPortal: ComponentPortal; - let templatePortal: TemplatePortal; - let overlayContainerElement: HTMLElement; +describe('Overlay', () => { + let builder: TestComponentBuilder; + let overlay: Overlay; + let componentPortal: ComponentPortal; + let templatePortal: TemplatePortal; + let overlayContainerElement: HTMLElement; - beforeEachProviders(() => [ - Overlay, - OverlayPositionBuilder, - ViewportRuler, - provide(OVERLAY_CONTAINER_TOKEN, {useFactory: () => { + beforeEachProviders(() => [ + Overlay, + OverlayPositionBuilder, + ViewportRuler, + provide(OVERLAY_CONTAINER_TOKEN, { + useFactory: () => { overlayContainerElement = document.createElement('div'); return overlayContainerElement; - }}) - ]); - - let deps = [TestComponentBuilder, Overlay]; - beforeEach(inject(deps, fakeAsync((tcb: TestComponentBuilder, o: Overlay) => { - builder = tcb; - overlay = o; - - builder.createAsync(TestComponentWithTemplatePortals).then(fixture => { - fixture.detectChanges(); - templatePortal = fixture.componentInstance.templatePortal; - componentPortal = new ComponentPortal(PizzaMsg, fixture.componentInstance.viewContainerRef); - }); + } + }) + ]); + + let deps = [TestComponentBuilder, Overlay]; + beforeEach(inject(deps, fakeAsync((tcb: TestComponentBuilder, o: Overlay) => { + builder = tcb; + overlay = o; + + builder.createAsync(TestComponentWithTemplatePortals).then(fixture => { + fixture.detectChanges(); + templatePortal = fixture.componentInstance.templatePortal; + componentPortal = new ComponentPortal(PizzaMsg, fixture.componentInstance.viewContainerRef); + }); - flushMicrotasks(); - }))); + flushMicrotasks(); + }))); - it('should load a component into an overlay', fakeAsyncTest(() => { - let overlayRef: OverlayRef; + it('should load a component into an overlay', fakeAsyncTest(() => { + let overlayRef: OverlayRef; - overlay.create().then(ref => { - overlayRef = ref; - overlayRef.attach(componentPortal); - }); + overlay.create().then(ref => { + overlayRef = ref; + overlayRef.attach(componentPortal); + }); - flushMicrotasks(); + flushMicrotasks(); - expect(overlayContainerElement.textContent).toContain('Pizza'); + expect(overlayContainerElement.textContent).toContain('Pizza'); - overlayRef.dispose(); - expect(overlayContainerElement.childNodes.length).toBe(0); - expect(overlayContainerElement.textContent).toBe(''); - })); + overlayRef.dispose(); + expect(overlayContainerElement.childNodes.length).toBe(0); + expect(overlayContainerElement.textContent).toBe(''); + })); - it('should load a template portal into an overlay', fakeAsyncTest(() => { - let overlayRef: OverlayRef; + it('should load a template portal into an overlay', fakeAsyncTest(() => { + let overlayRef: OverlayRef; - overlay.create().then(ref => { - overlayRef = ref; - overlayRef.attach(templatePortal); - }); + overlay.create().then(ref => { + overlayRef = ref; + overlayRef.attach(templatePortal); + }); - flushMicrotasks(); + flushMicrotasks(); - expect(overlayContainerElement.textContent).toContain('Cake'); + expect(overlayContainerElement.textContent).toContain('Cake'); - overlayRef.dispose(); - expect(overlayContainerElement.childNodes.length).toBe(0); - expect(overlayContainerElement.textContent).toBe(''); - })); + overlayRef.dispose(); + expect(overlayContainerElement.childNodes.length).toBe(0); + expect(overlayContainerElement.textContent).toBe(''); + })); - it('should open multiple overlays', fakeAsyncTest(() => { - let pizzaOverlayRef: OverlayRef; - let cakeOverlayRef: OverlayRef; + it('should open multiple overlays', fakeAsyncTest(() => { + let pizzaOverlayRef: OverlayRef; + let cakeOverlayRef: OverlayRef; - overlay.create().then(ref => { - pizzaOverlayRef = ref; - pizzaOverlayRef.attach(componentPortal); - }); + overlay.create().then(ref => { + pizzaOverlayRef = ref; + pizzaOverlayRef.attach(componentPortal); + }); - flushMicrotasks(); + flushMicrotasks(); - overlay.create().then(ref => { - cakeOverlayRef = ref; - cakeOverlayRef.attach(templatePortal); - }); + overlay.create().then(ref => { + cakeOverlayRef = ref; + cakeOverlayRef.attach(templatePortal); + }); - flushMicrotasks(); + flushMicrotasks(); - expect(overlayContainerElement.childNodes.length).toBe(2); - expect(overlayContainerElement.textContent).toContain('Pizza'); - expect(overlayContainerElement.textContent).toContain('Cake'); + expect(overlayContainerElement.childNodes.length).toBe(2); + expect(overlayContainerElement.textContent).toContain('Pizza'); + expect(overlayContainerElement.textContent).toContain('Cake'); - pizzaOverlayRef.dispose(); - expect(overlayContainerElement.childNodes.length).toBe(1); - expect(overlayContainerElement.textContent).toContain('Cake'); + pizzaOverlayRef.dispose(); + expect(overlayContainerElement.childNodes.length).toBe(1); + expect(overlayContainerElement.textContent).toContain('Cake'); - cakeOverlayRef.dispose(); - expect(overlayContainerElement.childNodes.length).toBe(0); - expect(overlayContainerElement.textContent).toBe(''); - })); + cakeOverlayRef.dispose(); + expect(overlayContainerElement.childNodes.length).toBe(0); + expect(overlayContainerElement.textContent).toBe(''); + })); - describe('applyState', () => { - let state: OverlayState; + describe('applyState', () => { + let state: OverlayState; - beforeEach(() => { - state = new OverlayState(); - }); + beforeEach(() => { + state = new OverlayState(); + }); - it('should apply the positioning strategy', fakeAsyncTest(() => { - state.positionStrategy = new FakePositionStrategy(); + it('should apply the positioning strategy', fakeAsyncTest(() => { + state.positionStrategy = new FakePositionStrategy(); - overlay.create(state).then(ref => { - ref.attach(componentPortal); - }); + overlay.create(state).then(ref => { + ref.attach(componentPortal); + }); - flushMicrotasks(); + flushMicrotasks(); - expect(overlayContainerElement.querySelectorAll('.fake-positioned').length).toBe(1); - })); - }); + expect(overlayContainerElement.querySelectorAll('.fake-positioned').length).toBe(1); + })); }); -} +}); /** Simple component for testing ComponentPortal. */ @@ -149,7 +149,8 @@ export function main() { selector: 'pizza-msg', template: '

Pizza

', }) -class PizzaMsg {} +class PizzaMsg { +} /** Test-bed component that contains a TempatePortal and an ElementRef. */ @@ -160,7 +161,9 @@ class PizzaMsg {} }) class TestComponentWithTemplatePortals { @ViewChild(TemplatePortalDirective) templatePortal: TemplatePortalDirective; - constructor(public viewContainerRef: ViewContainerRef) { } + + constructor(public viewContainerRef: ViewContainerRef) { + } } class FakePositionStrategy implements PositionStrategy { diff --git a/src/core/overlay/position/connected-position-strategy.spec.ts b/src/core/overlay/position/connected-position-strategy.spec.ts index 1adaa17c3458..62d3d17e75f4 100644 --- a/src/core/overlay/position/connected-position-strategy.spec.ts +++ b/src/core/overlay/position/connected-position-strategy.spec.ts @@ -9,297 +9,294 @@ import {OverlayPositionBuilder} from './overlay-position-builder'; const DEFAULT_HEIGHT = 30; const DEFAULT_WIDTH = 60; -export function main() { - - // For all tests, we assume the browser window is 1024x786 (outerWidth x outerHeight). - // The karma config has been set to this for local tests, and it is the default size - // for tests on CI (both SauceLabs and Browserstack). +// For all tests, we assume the browser window is 1024x786 (outerWidth x outerHeight). +// The karma config has been set to this for local tests, and it is the default size +// for tests on CI (both SauceLabs and Browserstack). + +describe('ConnectedPositionStrategy', () => { + const ORIGIN_HEIGHT = DEFAULT_HEIGHT; + const ORIGIN_WIDTH = DEFAULT_WIDTH; + const OVERLAY_HEIGHT = DEFAULT_HEIGHT; + const OVERLAY_WIDTH = DEFAULT_WIDTH; + + let originElement: HTMLElement; + let overlayElement: HTMLElement; + let strategy: ConnectedPositionStrategy; + let fakeElementRef: ElementRef; + let fakeViewportRuler: FakeViewportRuler; + let positionBuilder: OverlayPositionBuilder; + + let originRect: ClientRect; + let originCenterX: number; + let originCenterY: number; + + beforeEach(() => { + fakeViewportRuler = new FakeViewportRuler(); + + // The origin and overlay elements need to be in the document body in order to have geometry. + originElement = createPositionedBlockElement(); + overlayElement = createPositionedBlockElement(); + document.body.appendChild(originElement); + document.body.appendChild(overlayElement); + + fakeElementRef = new FakeElementRef(originElement); + positionBuilder = new OverlayPositionBuilder(new ViewportRuler()); + }); - describe('ConnectedPositionStrategy', () => { - const ORIGIN_HEIGHT = DEFAULT_HEIGHT; - const ORIGIN_WIDTH = DEFAULT_WIDTH; - const OVERLAY_HEIGHT = DEFAULT_HEIGHT; - const OVERLAY_WIDTH = DEFAULT_WIDTH; + afterEach(() => { + document.body.removeChild(originElement); + document.body.removeChild(overlayElement); - let originElement: HTMLElement; - let overlayElement: HTMLElement; - let strategy: ConnectedPositionStrategy; - let fakeElementRef: ElementRef; - let fakeViewportRuler: FakeViewportRuler; - let positionBuilder: OverlayPositionBuilder; + // Reset the origin geometry after each test so we don't accidently keep state between tests. + originRect = null; + originCenterX = null; + originCenterY = null; + }); - let originRect: ClientRect; - let originCenterX: number; - let originCenterY: number; + describe('when not near viewport edge, not scrolled', () => { + // Place the original element close to the center of the window. + // (1024 / 2, 768 / 2). It's not exact, since outerWidth/Height includes browser + // chrome, but it doesn't really matter for these tests. + const ORIGIN_LEFT = 500; + const ORIGIN_TOP = 350; beforeEach(() => { - fakeViewportRuler = new FakeViewportRuler(); + originElement.style.left = `${ORIGIN_LEFT}px`; + originElement.style.top = `${ORIGIN_TOP}px`; - // The origin and overlay elements need to be in the document body in order to have geometry. - originElement = createPositionedBlockElement(); - overlayElement = createPositionedBlockElement(); - document.body.appendChild(originElement); - document.body.appendChild(overlayElement); + originRect = originElement.getBoundingClientRect(); + originCenterX = originRect.left + (ORIGIN_WIDTH / 2); + originCenterY = originRect.top + (ORIGIN_HEIGHT / 2); + }); + + // Preconditions are set, now just run the full set of simple position tests. + runSimplePositionTests(); + }); - fakeElementRef = new FakeElementRef(originElement); - positionBuilder = new OverlayPositionBuilder(new ViewportRuler()); + describe('when scrolled', () => { + // Place the original element decently far outside the unscrolled document (1024x768). + const ORIGIN_LEFT = 2500; + const ORIGIN_TOP = 2500; + + // Create a very large element that will make the page scrollable. + let veryLargeElement: HTMLElement = document.createElement('div'); + veryLargeElement.style.width = '4000px'; + veryLargeElement.style.height = '4000px'; + + beforeEach(() => { + // Scroll the page such that the origin element is roughly in the + // center of the visible viewport (2500 - 1024/2, 2500 - 768/2). + document.body.appendChild(veryLargeElement); + document.body.scrollTop = 2100; + document.body.scrollLeft = 2100; + + originElement.style.top = `${ORIGIN_TOP}px`; + originElement.style.left = `${ORIGIN_LEFT}px`; + + originRect = originElement.getBoundingClientRect(); + originCenterX = originRect.left + (ORIGIN_WIDTH / 2); + originCenterY = originRect.top + (ORIGIN_HEIGHT / 2); }); afterEach(() => { - document.body.removeChild(originElement); - document.body.removeChild(overlayElement); + document.body.removeChild(veryLargeElement); + document.body.scrollTop = 0; + document.body.scrollLeft = 0; + }); + + // Preconditions are set, now just run the full set of simple position tests. + runSimplePositionTests(); + }); + + describe('when near viewport edge', () => { + it('should reposition the overlay if it would go off the top of the screen', () => { + // We can use the real ViewportRuler in this test since we know that zero is + // always the top of the viewport. + + originElement.style.top = '5px'; + originElement.style.left = '200px'; + originRect = originElement.getBoundingClientRect(); - // Reset the origin geometry after each test so we don't accidently keep state between tests. - originRect = null; - originCenterX = null; - originCenterY = null; + strategy = positionBuilder.connectedTo( + fakeElementRef, + {originX: 'end', originY: 'top'}, + {overlayX: 'end', overlayY: 'bottom'}) + .withFallbackPosition( + {originX: 'start', originY: 'bottom'}, + {overlayX: 'start', overlayY: 'top'}); + + strategy.apply(overlayElement); + + let overlayRect = overlayElement.getBoundingClientRect(); + expect(overlayRect.top).toBe(originRect.bottom); + expect(overlayRect.left).toBe(originRect.left); }); - describe('when not near viewport edge, not scrolled', () => { - // Place the original element close to the center of the window. - // (1024 / 2, 768 / 2). It's not exact, since outerWidth/Height includes browser - // chrome, but it doesn't really matter for these tests. - const ORIGIN_LEFT = 500; - const ORIGIN_TOP = 350; + it('should reposition the overlay if it would go off the left of the screen', () => { + // We can use the real ViewportRuler in this test since we know that zero is + // always the left edge of the viewport. + + originElement.style.top = '200px'; + originElement.style.left = '5px'; + originRect = originElement.getBoundingClientRect(); + originCenterY = originRect.top + (ORIGIN_HEIGHT / 2); - beforeEach(() => { - originElement.style.left = `${ORIGIN_LEFT}px`; - originElement.style.top = `${ORIGIN_TOP}px`; + strategy = positionBuilder.connectedTo( + fakeElementRef, + {originX: 'start', originY: 'bottom'}, + {overlayX: 'end', overlayY: 'top'}) + .withFallbackPosition( + {originX: 'end', originY: 'center'}, + {overlayX: 'start', overlayY: 'center'}); - originRect = originElement.getBoundingClientRect(); - originCenterX = originRect.left + (ORIGIN_WIDTH / 2); - originCenterY = originRect.top + (ORIGIN_HEIGHT / 2); - }); + strategy.apply(overlayElement); - // Preconditions are set, now just run the full set of simple position tests. - runSimplePositionTests(); + let overlayRect = overlayElement.getBoundingClientRect(); + expect(overlayRect.top).toBe(originCenterY - (OVERLAY_HEIGHT / 2)); + expect(overlayRect.left).toBe(originRect.right); }); - describe('when scrolled', () => { - // Place the original element decently far outside the unscrolled document (1024x768). - const ORIGIN_LEFT = 2500; - const ORIGIN_TOP = 2500; - - // Create a very large element that will make the page scrollable. - let veryLargeElement: HTMLElement = document.createElement('div'); - veryLargeElement.style.width = '4000px'; - veryLargeElement.style.height = '4000px'; - - beforeEach(() => { - // Scroll the page such that the origin element is roughly in the - // center of the visible viewport (2500 - 1024/2, 2500 - 768/2). - document.body.appendChild(veryLargeElement); - document.body.scrollTop = 2100; - document.body.scrollLeft = 2100; - - originElement.style.top = `${ORIGIN_TOP}px`; - originElement.style.left = `${ORIGIN_LEFT}px`; - - originRect = originElement.getBoundingClientRect(); - originCenterX = originRect.left + (ORIGIN_WIDTH / 2); - originCenterY = originRect.top + (ORIGIN_HEIGHT / 2); - }); - - afterEach(() => { - document.body.removeChild(veryLargeElement); - document.body.scrollTop = 0; - document.body.scrollLeft = 0; - }); - - // Preconditions are set, now just run the full set of simple position tests. - runSimplePositionTests(); + it('should reposition the overlay if it would go off the bottom of the screen', () => { + // Use the fake viewport ruler because we don't know *exactly* how big the viewport is. + fakeViewportRuler.fakeRect = { + top: 0, left: 0, width: 500, height: 500, right: 500, bottom: 500 + }; + positionBuilder = new OverlayPositionBuilder(fakeViewportRuler); + + originElement.style.top = '475px'; + originElement.style.left = '200px'; + originRect = originElement.getBoundingClientRect(); + + strategy = positionBuilder.connectedTo( + fakeElementRef, + {originX: 'start', originY: 'bottom'}, + {overlayX: 'start', overlayY: 'top'}) + .withFallbackPosition( + {originX: 'end', originY: 'top'}, + {overlayX: 'end', overlayY: 'bottom'}); + + strategy.apply(overlayElement); + + let overlayRect = overlayElement.getBoundingClientRect(); + expect(overlayRect.bottom).toBe(originRect.top); + expect(overlayRect.right).toBe(originRect.right); }); - describe('when near viewport edge', () => { - it('should reposition the overlay if it would go off the top of the screen', () => { - // We can use the real ViewportRuler in this test since we know that zero is - // always the top of the viewport. - - originElement.style.top = '5px'; - originElement.style.left = '200px'; - originRect = originElement.getBoundingClientRect(); - - strategy = positionBuilder.connectedTo( - fakeElementRef, - {originX: 'end', originY: 'top'}, - {overlayX: 'end', overlayY: 'bottom'}) - .withFallbackPosition( - {originX: 'start', originY: 'bottom'}, - {overlayX: 'start', overlayY: 'top'}); - - strategy.apply(overlayElement); - - let overlayRect = overlayElement.getBoundingClientRect(); - expect(overlayRect.top).toBe(originRect.bottom); - expect(overlayRect.left).toBe(originRect.left); - }); - - it('should reposition the overlay if it would go off the left of the screen', () => { - // We can use the real ViewportRuler in this test since we know that zero is - // always the left edge of the viewport. - - originElement.style.top = '200px'; - originElement.style.left = '5px'; - originRect = originElement.getBoundingClientRect(); - originCenterY = originRect.top + (ORIGIN_HEIGHT / 2); - - strategy = positionBuilder.connectedTo( - fakeElementRef, - {originX: 'start', originY: 'bottom'}, - {overlayX: 'end', overlayY: 'top'}) - .withFallbackPosition( - {originX: 'end', originY: 'center'}, - {overlayX: 'start', overlayY: 'center'}); - - strategy.apply(overlayElement); - - let overlayRect = overlayElement.getBoundingClientRect(); - expect(overlayRect.top).toBe(originCenterY - (OVERLAY_HEIGHT / 2)); - expect(overlayRect.left).toBe(originRect.right); - }); - - it('should reposition the overlay if it would go off the bottom of the screen', () => { - // Use the fake viewport ruler because we don't know *exactly* how big the viewport is. - fakeViewportRuler.fakeRect = { - top: 0, left: 0, width: 500, height: 500, right: 500, bottom: 500 - }; - positionBuilder = new OverlayPositionBuilder(fakeViewportRuler); - - originElement.style.top = '475px'; - originElement.style.left = '200px'; - originRect = originElement.getBoundingClientRect(); - - strategy = positionBuilder.connectedTo( - fakeElementRef, - {originX: 'start', originY: 'bottom'}, - {overlayX: 'start', overlayY: 'top'}) - .withFallbackPosition( - {originX: 'end', originY: 'top'}, - {overlayX: 'end', overlayY: 'bottom'}); - - strategy.apply(overlayElement); - - let overlayRect = overlayElement.getBoundingClientRect(); - expect(overlayRect.bottom).toBe(originRect.top); - expect(overlayRect.right).toBe(originRect.right); - }); - - it('should reposition the overlay if it would go off the right of the screen', () => { - // Use the fake viewport ruler because we don't know *exactly* how big the viewport is. - fakeViewportRuler.fakeRect = { - top: 0, left: 0, width: 500, height: 500, right: 500, bottom: 500 - }; - positionBuilder = new OverlayPositionBuilder(fakeViewportRuler); - - originElement.style.top = '200px'; - originElement.style.left = '475px'; - originRect = originElement.getBoundingClientRect(); - - strategy = positionBuilder.connectedTo( - fakeElementRef, - {originX: 'end', originY: 'center'}, - {overlayX: 'start', overlayY: 'center'}) - .withFallbackPosition( - {originX: 'start', originY: 'bottom'}, - {overlayX: 'end', overlayY: 'top'}); - - strategy.apply(overlayElement); - - let overlayRect = overlayElement.getBoundingClientRect(); - expect(overlayRect.top).toBe(originRect.bottom); - expect(overlayRect.right).toBe(originRect.left); - }); + it('should reposition the overlay if it would go off the right of the screen', () => { + // Use the fake viewport ruler because we don't know *exactly* how big the viewport is. + fakeViewportRuler.fakeRect = { + top: 0, left: 0, width: 500, height: 500, right: 500, bottom: 500 + }; + positionBuilder = new OverlayPositionBuilder(fakeViewportRuler); + + originElement.style.top = '200px'; + originElement.style.left = '475px'; + originRect = originElement.getBoundingClientRect(); + + strategy = positionBuilder.connectedTo( + fakeElementRef, + {originX: 'end', originY: 'center'}, + {overlayX: 'start', overlayY: 'center'}) + .withFallbackPosition( + {originX: 'start', originY: 'bottom'}, + {overlayX: 'end', overlayY: 'top'}); + + strategy.apply(overlayElement); + + let overlayRect = overlayElement.getBoundingClientRect(); + expect(overlayRect.top).toBe(originRect.bottom); + expect(overlayRect.right).toBe(originRect.left); }); + }); - /** - * Run all tests for connecting the overlay to the origin such that first preferred - * position does not go off-screen. We do this because there are several cases where we - * want to run the exact same tests with different preconditions (e.g., not scroll, scrolled, - * different element sized, etc.). - */ - function runSimplePositionTests() { - it('should position a panel below, left-aligned', () => { - strategy = positionBuilder.connectedTo( - fakeElementRef, - {originX: 'start', originY: 'bottom'}, - {overlayX: 'start', overlayY: 'top'}); - - strategy.apply(overlayElement); - - let overlayRect = overlayElement.getBoundingClientRect(); - expect(overlayRect.top).toBe(originRect.bottom); - expect(overlayRect.left).toBe(originRect.left); - }); - - it('should position to the right, center aligned vertically', () => { - strategy = positionBuilder.connectedTo( - fakeElementRef, - {originX: 'end', originY: 'center'}, - {overlayX: 'start', overlayY: 'center'}); - - strategy.apply(overlayElement); - - let overlayRect = overlayElement.getBoundingClientRect(); - expect(overlayRect.top).toBe(originCenterY - (OVERLAY_HEIGHT / 2)); - expect(overlayRect.left).toBe(originRect.right); - }); - - it('should position to the left, below', () => { - strategy = positionBuilder.connectedTo( - fakeElementRef, - {originX: 'start', originY: 'bottom'}, - {overlayX: 'end', overlayY: 'top'}); - - strategy.apply(overlayElement); - - let overlayRect = overlayElement.getBoundingClientRect(); - expect(overlayRect.top).toBe(originRect.bottom); - expect(overlayRect.right).toBe(originRect.left); - }); - - it('should position above, right aligned', () => { - strategy = positionBuilder.connectedTo( - fakeElementRef, - {originX: 'end', originY: 'top'}, - {overlayX: 'end', overlayY: 'bottom'}); - - strategy.apply(overlayElement); - - let overlayRect = overlayElement.getBoundingClientRect(); - expect(overlayRect.bottom).toBe(originRect.top); - expect(overlayRect.right).toBe(originRect.right); - }); - - it('should position below, centered', () => { - strategy = positionBuilder.connectedTo( - fakeElementRef, - {originX: 'center', originY: 'bottom'}, - {overlayX: 'center', overlayY: 'top'}); - - strategy.apply(overlayElement); - - let overlayRect = overlayElement.getBoundingClientRect(); - expect(overlayRect.top).toBe(originRect.bottom); - expect(overlayRect.left).toBe(originCenterX - (OVERLAY_WIDTH / 2)); - }); - - it('should center the overlay on the origin', () => { - strategy = positionBuilder.connectedTo( - fakeElementRef, - {originX: 'center', originY: 'center'}, - {overlayX: 'center', overlayY: 'center'}); - - strategy.apply(overlayElement); - - let overlayRect = overlayElement.getBoundingClientRect(); - expect(overlayRect.top).toBe(originRect.top); - expect(overlayRect.left).toBe(originRect.left); - }); - } + /** + * Run all tests for connecting the overlay to the origin such that first preferred + * position does not go off-screen. We do this because there are several cases where we + * want to run the exact same tests with different preconditions (e.g., not scroll, scrolled, + * different element sized, etc.). + */ + function runSimplePositionTests() { + it('should position a panel below, left-aligned', () => { + strategy = positionBuilder.connectedTo( + fakeElementRef, + {originX: 'start', originY: 'bottom'}, + {overlayX: 'start', overlayY: 'top'}); + + strategy.apply(overlayElement); + + let overlayRect = overlayElement.getBoundingClientRect(); + expect(overlayRect.top).toBe(originRect.bottom); + expect(overlayRect.left).toBe(originRect.left); + }); - }); -} + it('should position to the right, center aligned vertically', () => { + strategy = positionBuilder.connectedTo( + fakeElementRef, + {originX: 'end', originY: 'center'}, + {overlayX: 'start', overlayY: 'center'}); + + strategy.apply(overlayElement); + + let overlayRect = overlayElement.getBoundingClientRect(); + expect(overlayRect.top).toBe(originCenterY - (OVERLAY_HEIGHT / 2)); + expect(overlayRect.left).toBe(originRect.right); + }); + + it('should position to the left, below', () => { + strategy = positionBuilder.connectedTo( + fakeElementRef, + {originX: 'start', originY: 'bottom'}, + {overlayX: 'end', overlayY: 'top'}); + + strategy.apply(overlayElement); + + let overlayRect = overlayElement.getBoundingClientRect(); + expect(overlayRect.top).toBe(originRect.bottom); + expect(overlayRect.right).toBe(originRect.left); + }); + + it('should position above, right aligned', () => { + strategy = positionBuilder.connectedTo( + fakeElementRef, + {originX: 'end', originY: 'top'}, + {overlayX: 'end', overlayY: 'bottom'}); + + strategy.apply(overlayElement); + + let overlayRect = overlayElement.getBoundingClientRect(); + expect(overlayRect.bottom).toBe(originRect.top); + expect(overlayRect.right).toBe(originRect.right); + }); + + it('should position below, centered', () => { + strategy = positionBuilder.connectedTo( + fakeElementRef, + {originX: 'center', originY: 'bottom'}, + {overlayX: 'center', overlayY: 'top'}); + + strategy.apply(overlayElement); + + let overlayRect = overlayElement.getBoundingClientRect(); + expect(overlayRect.top).toBe(originRect.bottom); + expect(overlayRect.left).toBe(originCenterX - (OVERLAY_WIDTH / 2)); + }); + + it('should center the overlay on the origin', () => { + strategy = positionBuilder.connectedTo( + fakeElementRef, + {originX: 'center', originY: 'center'}, + {overlayX: 'center', overlayY: 'center'}); + + strategy.apply(overlayElement); + + let overlayRect = overlayElement.getBoundingClientRect(); + expect(overlayRect.top).toBe(originRect.top); + expect(overlayRect.left).toBe(originRect.left); + }); + } + +}); /** Creates an absolutely positioned, display: block element with a default size. */ @@ -333,5 +330,6 @@ class FakeViewportRuler implements ViewportRuler { /** Fake implementation of ElementRef that is just a simple container for nativeElement. */ class FakeElementRef implements ElementRef { - constructor(public nativeElement: HTMLElement) { } + constructor(public nativeElement: HTMLElement) { + } } diff --git a/src/core/overlay/position/global-position-strategy.spec.ts b/src/core/overlay/position/global-position-strategy.spec.ts index c1c541030efc..8ed2d8255e60 100644 --- a/src/core/overlay/position/global-position-strategy.spec.ts +++ b/src/core/overlay/position/global-position-strategy.spec.ts @@ -10,103 +10,101 @@ import { import {GlobalPositionStrategy} from './global-position-strategy'; -export function main() { - describe('GlobalPositonStrategy', () => { - let element: HTMLElement; - let strategy: GlobalPositionStrategy; +describe('GlobalPositonStrategy', () => { + let element: HTMLElement; + let strategy: GlobalPositionStrategy; - beforeEach(() => { - element = document.createElement('div'); - strategy = new GlobalPositionStrategy(); - }); + beforeEach(() => { + element = document.createElement('div'); + strategy = new GlobalPositionStrategy(); + }); - it('should set explicit (top, left) position to the element', fakeAsyncTest(() => { - strategy.top('10px').left('40%').apply(element); + it('should set explicit (top, left) position to the element', fakeAsyncTest(() => { + strategy.top('10px').left('40%').apply(element); - flushMicrotasks(); + flushMicrotasks(); - expect(element.style.top).toBe('10px'); - expect(element.style.left).toBe('40%'); - expect(element.style.bottom).toBe(''); - expect(element.style.right).toBe(''); - })); + expect(element.style.top).toBe('10px'); + expect(element.style.left).toBe('40%'); + expect(element.style.bottom).toBe(''); + expect(element.style.right).toBe(''); + })); - it('should set explicit (bottom, right) position to the element', fakeAsyncTest(() => { - strategy.bottom('70px').right('15em').apply(element); + it('should set explicit (bottom, right) position to the element', fakeAsyncTest(() => { + strategy.bottom('70px').right('15em').apply(element); - flushMicrotasks(); + flushMicrotasks(); - expect(element.style.top).toBe(''); - expect(element.style.left).toBe(''); - expect(element.style.bottom).toBe('70px'); - expect(element.style.right).toBe('15em'); - })); + expect(element.style.top).toBe(''); + expect(element.style.left).toBe(''); + expect(element.style.bottom).toBe('70px'); + expect(element.style.right).toBe('15em'); + })); - it('should overwrite previously applied positioning', fakeAsyncTest(() => { - strategy.centerHorizontally().centerVertically().apply(element); - flushMicrotasks(); + it('should overwrite previously applied positioning', fakeAsyncTest(() => { + strategy.centerHorizontally().centerVertically().apply(element); + flushMicrotasks(); - strategy.top('10px').left('40%').apply(element); - flushMicrotasks(); + strategy.top('10px').left('40%').apply(element); + flushMicrotasks(); - expect(element.style.top).toBe('10px'); - expect(element.style.left).toBe('40%'); - expect(element.style.bottom).toBe(''); - expect(element.style.right).toBe(''); - expect(element.style.transform).not.toContain('translate'); + expect(element.style.top).toBe('10px'); + expect(element.style.left).toBe('40%'); + expect(element.style.bottom).toBe(''); + expect(element.style.right).toBe(''); + expect(element.style.transform).not.toContain('translate'); - strategy.bottom('70px').right('15em').apply(element); + strategy.bottom('70px').right('15em').apply(element); - flushMicrotasks(); + flushMicrotasks(); - expect(element.style.top).toBe(''); - expect(element.style.left).toBe(''); - expect(element.style.bottom).toBe('70px'); - expect(element.style.right).toBe('15em'); - expect(element.style.transform).not.toContain('translate'); - })); + expect(element.style.top).toBe(''); + expect(element.style.left).toBe(''); + expect(element.style.bottom).toBe('70px'); + expect(element.style.right).toBe('15em'); + expect(element.style.transform).not.toContain('translate'); + })); - it('should center the element', fakeAsyncTest(() => { - strategy.centerHorizontally().centerVertically().apply(element); + it('should center the element', fakeAsyncTest(() => { + strategy.centerHorizontally().centerVertically().apply(element); - flushMicrotasks(); + flushMicrotasks(); - expect(element.style.top).toBe('50%'); - expect(element.style.left).toBe('50%'); - expect(element.style.transform).toContain('translateX(-50%)'); - expect(element.style.transform).toContain('translateY(-50%)'); - })); + expect(element.style.top).toBe('50%'); + expect(element.style.left).toBe('50%'); + expect(element.style.transform).toContain('translateX(-50%)'); + expect(element.style.transform).toContain('translateY(-50%)'); + })); - it('should center the element with an offset', fakeAsyncTest(() => { - strategy.centerHorizontally('10px').centerVertically('15px').apply(element); + it('should center the element with an offset', fakeAsyncTest(() => { + strategy.centerHorizontally('10px').centerVertically('15px').apply(element); - flushMicrotasks(); + flushMicrotasks(); - expect(element.style.top).toBe('50%'); - expect(element.style.left).toBe('50%'); - expect(element.style.transform).toContain('translateX(-50%)'); - expect(element.style.transform).toContain('translateX(10px)'); - expect(element.style.transform).toContain('translateY(-50%)'); - expect(element.style.transform).toContain('translateY(15px)'); - })); + expect(element.style.top).toBe('50%'); + expect(element.style.left).toBe('50%'); + expect(element.style.transform).toContain('translateX(-50%)'); + expect(element.style.transform).toContain('translateX(10px)'); + expect(element.style.transform).toContain('translateY(-50%)'); + expect(element.style.transform).toContain('translateY(15px)'); + })); - it('should default the element to position: absolute', fakeAsyncTest(() => { - strategy.apply(element); + it('should default the element to position: absolute', fakeAsyncTest(() => { + strategy.apply(element); - flushMicrotasks(); + flushMicrotasks(); - expect(element.style.position).toBe('absolute'); - })); + expect(element.style.position).toBe('absolute'); + })); - it('should make the element position: fixed', fakeAsyncTest(() => { - strategy.fixed().apply(element); + it('should make the element position: fixed', fakeAsyncTest(() => { + strategy.fixed().apply(element); - flushMicrotasks(); + flushMicrotasks(); - expect(element.style.position).toBe('fixed'); - })); - }); -} + expect(element.style.position).toBe('fixed'); + })); +}); function fakeAsyncTest(fn: () => void) { return inject([], fakeAsync(fn)); diff --git a/src/core/overlay/position/viewport-ruler.spec.ts b/src/core/overlay/position/viewport-ruler.spec.ts index b66d266d212c..de1702f5ec70 100644 --- a/src/core/overlay/position/viewport-ruler.spec.ts +++ b/src/core/overlay/position/viewport-ruler.spec.ts @@ -2,92 +2,89 @@ import {it, describe, expect, beforeEach} from '@angular/core/testing'; import {ViewportRuler} from './viewport-ruler'; -export function main() { - - // For all tests, we assume the browser window is 1024x786 (outerWidth x outerHeight). - // The karma config has been set to this for local tests, and it is the default size - // for tests on CI (both SauceLabs and Browserstack). - - // While we know the *outer* window width/height, the innerWidth and innerHeight depend on the - // the size of the individual browser's chrome, so we have to use window.innerWidth and - // window.innerHeight in the unit test instead of hard-coded values. - - describe('ViewportRuler', () => { - let ruler: ViewportRuler; - - let startingWindowWidth = window.innerWidth; - let startingWindowHeight = window.innerHeight; - - // Create a very large element that will make the page scrollable. - let veryLargeElement: HTMLElement = document.createElement('div'); - veryLargeElement.style.width = '6000px'; - veryLargeElement.style.height = '6000px'; - - beforeEach(() => { - ruler = new ViewportRuler(); - scrollTo(0, 0); - }); - - it('should get the viewport bounds when the page is not scrolled', () => { - let bounds = ruler.getViewportRect(); - expect(bounds.top).toBe(0); - expect(bounds.left).toBe(0); - expect(bounds.bottom).toBe(window.innerHeight); - expect(bounds.right).toBe(window.innerWidth); - }); - - it('should get the viewport bounds when the page is scrolled', () => { - document.body.appendChild(veryLargeElement); - scrollTo(1500, 2000); - - let bounds = ruler.getViewportRect(); - - // In the iOS simulator (BrowserStack & SauceLabs), adding the content to the - // body causes karma's iframe for the test to stretch to fit that content once we attempt to - // scroll the page. Setting width / height / maxWidth / maxHeight on the iframe does not - // successfully constrain its size. As such, skip assertions in environments where the - // window size has changed since the start of the test. - if (window.innerWidth > startingWindowWidth || window.innerHeight > startingWindowHeight) { - return; - } - - expect(bounds.top).toBe(2000); - expect(bounds.left).toBe(1500); - expect(bounds.bottom).toBe(2000 + window.innerHeight); - expect(bounds.right).toBe(1500 + window.innerWidth); - - document.body.removeChild(veryLargeElement); - }); - - it('should get the bounds based on client coordinates when the page is pinch-zoomed', () => { - // There is no API to make the browser pinch-zoom, so there's no real way to automate - // tests for this behavior. Leaving this test here as documentation for the behavior. - }); - - it('should get the scroll position when the page is not scrolled', () => { - var scrollPos = ruler.getViewportScrollPosition(); - expect(scrollPos.top).toBe(0); - expect(scrollPos.left).toBe(0); - }); - - it('should get the scroll position when the page is scrolled', () => { - document.body.appendChild(veryLargeElement); - scrollTo(1500, 2000); - - // In the iOS simulator (BrowserStack & SauceLabs), adding the content to the - // body causes karma's iframe for the test to stretch to fit that content once we attempt to - // scroll the page. Setting width / height / maxWidth / maxHeight on the iframe does not - // successfully constrain its size. As such, skip assertions in environments where the - // window size has changed since the start of the test. - if (window.innerWidth > startingWindowWidth || window.innerHeight > startingWindowHeight) { - return; - } - - var scrollPos = ruler.getViewportScrollPosition(); - expect(scrollPos.top).toBe(2000); - expect(scrollPos.left).toBe(1500); - - document.body.removeChild(veryLargeElement); - }); +// For all tests, we assume the browser window is 1024x786 (outerWidth x outerHeight). +// The karma config has been set to this for local tests, and it is the default size +// for tests on CI (both SauceLabs and Browserstack). + +// While we know the *outer* window width/height, the innerWidth and innerHeight depend on the +// the size of the individual browser's chrome, so we have to use window.innerWidth and +// window.innerHeight in the unit test instead of hard-coded values. + +describe('ViewportRuler', () => { + let ruler: ViewportRuler; + + let startingWindowWidth = window.innerWidth; + let startingWindowHeight = window.innerHeight; + + // Create a very large element that will make the page scrollable. + let veryLargeElement: HTMLElement = document.createElement('div'); + veryLargeElement.style.width = '6000px'; + veryLargeElement.style.height = '6000px'; + + beforeEach(() => { + ruler = new ViewportRuler(); + scrollTo(0, 0); + }); + + it('should get the viewport bounds when the page is not scrolled', () => { + let bounds = ruler.getViewportRect(); + expect(bounds.top).toBe(0); + expect(bounds.left).toBe(0); + expect(bounds.bottom).toBe(window.innerHeight); + expect(bounds.right).toBe(window.innerWidth); + }); + + it('should get the viewport bounds when the page is scrolled', () => { + document.body.appendChild(veryLargeElement); + scrollTo(1500, 2000); + + let bounds = ruler.getViewportRect(); + + // In the iOS simulator (BrowserStack & SauceLabs), adding the content to the + // body causes karma's iframe for the test to stretch to fit that content once we attempt to + // scroll the page. Setting width / height / maxWidth / maxHeight on the iframe does not + // successfully constrain its size. As such, skip assertions in environments where the + // window size has changed since the start of the test. + if (window.innerWidth > startingWindowWidth || window.innerHeight > startingWindowHeight) { + return; + } + + expect(bounds.top).toBe(2000); + expect(bounds.left).toBe(1500); + expect(bounds.bottom).toBe(2000 + window.innerHeight); + expect(bounds.right).toBe(1500 + window.innerWidth); + + document.body.removeChild(veryLargeElement); + }); + + it('should get the bounds based on client coordinates when the page is pinch-zoomed', () => { + // There is no API to make the browser pinch-zoom, so there's no real way to automate + // tests for this behavior. Leaving this test here as documentation for the behavior. + }); + + it('should get the scroll position when the page is not scrolled', () => { + var scrollPos = ruler.getViewportScrollPosition(); + expect(scrollPos.top).toBe(0); + expect(scrollPos.left).toBe(0); + }); + + it('should get the scroll position when the page is scrolled', () => { + document.body.appendChild(veryLargeElement); + scrollTo(1500, 2000); + + // In the iOS simulator (BrowserStack & SauceLabs), adding the content to the + // body causes karma's iframe for the test to stretch to fit that content once we attempt to + // scroll the page. Setting width / height / maxWidth / maxHeight on the iframe does not + // successfully constrain its size. As such, skip assertions in environments where the + // window size has changed since the start of the test. + if (window.innerWidth > startingWindowWidth || window.innerHeight > startingWindowHeight) { + return; + } + + var scrollPos = ruler.getViewportScrollPosition(); + expect(scrollPos.top).toBe(2000); + expect(scrollPos.left).toBe(1500); + + document.body.removeChild(veryLargeElement); }); -} +}); diff --git a/src/core/portal/portal.spec.ts b/src/core/portal/portal.spec.ts index 29b22ea8a62d..561005af8b23 100644 --- a/src/core/portal/portal.spec.ts +++ b/src/core/portal/portal.spec.ts @@ -1,314 +1,312 @@ import { - it, - describe, - expect, - beforeEach, - inject, - fakeAsync, - flushMicrotasks + it, + describe, + expect, + beforeEach, + inject, + fakeAsync, + flushMicrotasks } from '@angular/core/testing'; import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing'; import { - Component, - ViewChildren, - QueryList, - ViewContainerRef, - DynamicComponentLoader + Component, + ViewChildren, + QueryList, + ViewContainerRef, + DynamicComponentLoader } from '@angular/core'; import {TemplatePortalDirective, PortalHostDirective} from './portal-directives'; import {Portal, ComponentPortal} from './portal'; import {DomPortalHost} from './dom-portal-host'; -export function main() { - describe('Portals', () => { - let builder: TestComponentBuilder; +describe('Portals', () => { + let builder: TestComponentBuilder; - beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { - builder = tcb; - })); + beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + builder = tcb; + })); - describe('PortalHostDirective', () => { - it('should load a component into the portal', fakeAsync(() => { - let appFixture: ComponentFixture; + describe('PortalHostDirective', () => { + it('should load a component into the portal', fakeAsync(() => { + let appFixture: ComponentFixture; - builder.createAsync(PortalTestApp).then(fixture => { - appFixture = fixture; - }); + builder.createAsync(PortalTestApp).then(fixture => { + appFixture = fixture; + }); - // Flush the async creation of the PortalTestApp. - flushMicrotasks(); + // Flush the async creation of the PortalTestApp. + flushMicrotasks(); - // Set the selectedHost to be a ComponentPortal. - let testAppComponent = appFixture.debugElement.componentInstance; - testAppComponent.selectedPortal = new ComponentPortal(PizzaMsg); - appFixture.detectChanges(); + // Set the selectedHost to be a ComponentPortal. + let testAppComponent = appFixture.debugElement.componentInstance; + testAppComponent.selectedPortal = new ComponentPortal(PizzaMsg); + appFixture.detectChanges(); - // Flush the attachment of the Portal. - flushMicrotasks(); + // Flush the attachment of the Portal. + flushMicrotasks(); - // Expect that the content of the attached portal is present. - let hostContainer = appFixture.nativeElement.querySelector('.portal-container'); - expect(hostContainer.textContent).toContain('Pizza'); - })); + // Expect that the content of the attached portal is present. + let hostContainer = appFixture.nativeElement.querySelector('.portal-container'); + expect(hostContainer.textContent).toContain('Pizza'); + })); - it('should load a