diff --git a/src/components/grid-list/grid-list-errors.ts b/src/components/grid-list/grid-list-errors.ts index 6c15aba8b034..b9220f942aac 100644 --- a/src/components/grid-list/grid-list-errors.ts +++ b/src/components/grid-list/grid-list-errors.ts @@ -14,7 +14,7 @@ export class MdGridListColsError extends MdError { */ export class MdGridTileTooWideError extends MdError { constructor(cols: number, listLength: number) { - super(`Tile with colspan ${cols} is wider than grid with cols="${listLength}".`); + super(`md-grid-list: tile with colspan ${cols} is wider than grid with cols="${listLength}".`); } } diff --git a/src/components/grid-list/grid-list.spec.ts b/src/components/grid-list/grid-list.spec.ts new file mode 100644 index 000000000000..55fe5936478c --- /dev/null +++ b/src/components/grid-list/grid-list.spec.ts @@ -0,0 +1,393 @@ +import { + it, + describe, + expect, + beforeEach, + inject, + fakeAsync, + tick +} from '@angular/core/testing'; +import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing'; +import {Component} from '@angular/core'; +import {By} from '@angular/platform-browser'; + +import {MD_GRID_LIST_DIRECTIVES, MdGridList} from './grid-list'; +import {MdGridTile} from './grid-tile'; + +describe('MdGridList', () => { + let builder: TestComponentBuilder; + + beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + builder = tcb; + })); + + it('should throw error if cols is not defined', () => { + var template = ``; + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + expect(() => { + fixture.detectChanges(); + }).toThrowError(/must pass in number of columns/); + }); + }); + + it('should throw error if rowHeight ratio is invalid', () => { + var template = ` + + `; + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + expect(() => { + fixture.detectChanges(); + }).toThrowError(/invalid ratio given for row-height/); + }); + }); + + it('should throw error if tile colspan is wider than total cols', () => { + var template = ` + + + + `; + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + expect(() => { + fixture.detectChanges(); + }).toThrowError(/tile with colspan 5 is wider than grid/); + }); + }); + + it('should default to 1:1 row height if undefined ', () => { + var template = ` +
+ + + +
+ `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.detectChanges(); + let tile = fixture.debugElement.query(By.directive(MdGridTile)); + + // in ratio mode, heights are set using the padding-top property + expect(getProp(tile, 'padding-top')).toBe('200px'); + }); + }); + + it('should use a ratio row height if passed in', () => { + var template = ` +
+ + + +
+ `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.componentInstance.height = '4:1'; + fixture.detectChanges(); + + let tile = fixture.debugElement.query(By.directive(MdGridTile)); + expect(getProp(tile, 'padding-top')).toBe('100px'); + + fixture.componentInstance.height = '2:1'; + fixture.detectChanges(); + + expect(getProp(tile, 'padding-top')).toBe('200px'); + }); + }); + + it('should divide row height evenly in "fit" mode', () => { + var template = ` + + + + + `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.componentInstance.height = 300; + fixture.detectChanges(); + let tile = fixture.debugElement.query(By.directive(MdGridTile)); + + // 149.5 * 2 = 299px + 1px gutter = 300px + expect(getProp(tile, 'height')).toBe('149.5px'); + + fixture.componentInstance.height = 200; + fixture.detectChanges(); + + // 99.5 * 2 = 199px + 1px gutter = 200px + expect(getProp(tile, 'height')).toBe('99.5px'); + }); + }); + + it('should use the fixed row height if passed in', () => { + var template = ` + + + + `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.componentInstance.height = '100px'; + fixture.detectChanges(); + + let tile = fixture.debugElement.query(By.directive(MdGridTile)); + expect(getProp(tile, 'height')).toBe('100px'); + + fixture.componentInstance.height = '200px'; + fixture.detectChanges(); + + expect(getProp(tile, 'height')).toBe('200px'); + }); + }); + + it('should default to pixels if row height units are missing', () => { + var template = ` + + + + `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.detectChanges(); + let tile = fixture.debugElement.query(By.directive(MdGridTile)); + expect(getProp(tile, 'height')).toBe('100px'); + }); + }); + + it('should default gutter size to 1px', () => { + var template = ` +
+ + + + + +
+ `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.detectChanges(); + fakeAsync(() => { + tick(); + let tiles = fixture.debugElement.queryAll(By.css('md-grid-tile')); + + // check horizontal gutter + expect(getProp(tiles[0], 'width')).toBe('99.5px'); + expect(getProp(tiles[1], 'left')).toBe('100.5px'); + + // check vertical gutter + expect(getProp(tiles[0], 'height')).toBe('100px'); + expect(getProp(tiles[2], 'top')).toBe('101px'); + }); + }); + }); + + it('should set the gutter size if passed', () => { + var template = ` +
+ + + + + +
+ `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.detectChanges(); + fakeAsync(() => { + tick(); + let tiles = fixture.debugElement.queryAll(By.css('md-grid-tile')); + + // check horizontal gutter + expect(getProp(tiles[0], 'width')).toBe('99px'); + expect(getProp(tiles[1], 'left')).toBe('101px'); + + // check vertical gutter + expect(getProp(tiles[0], 'height')).toBe('100px'); + expect(getProp(tiles[2], 'top')).toBe('102px'); + }); + }); + }); + + it('should use pixels if gutter units are missing', () => { + var template = ` +
+ + + + + +
+ `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.detectChanges(); + fakeAsync(() => { + tick(); + let tiles = fixture.debugElement.queryAll(By.css('md-grid-tile')); + + // check horizontal gutter + expect(getProp(tiles[0], 'width')).toBe('99px'); + expect(getProp(tiles[1], 'left')).toBe('101px'); + + // check vertical gutter + expect(getProp(tiles[0], 'height')).toBe('100px'); + expect(getProp(tiles[2], 'top')).toBe('102px'); + }); + }); + }); + + it('should set the correct list height in ratio mode', () => { + var template = ` +
+ + + + +
+ `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.detectChanges(); + let list = fixture.debugElement.query(By.directive(MdGridList)); + expect(getProp(list, 'padding-bottom')).toBe('201px'); + }); + }); + + it('should set the correct list height in fixed mode', () => { + var template = ` + + + + + `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.detectChanges(); + let list = fixture.debugElement.query(By.directive(MdGridList)); + expect(getProp(list, 'height')).toBe('201px'); + }); + }); + + it('should allow adjustment of tile colspan', () => { + var template = ` +
+ + + +
+ `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.componentInstance.colspan = 2; + fixture.detectChanges(); + + let tile = fixture.debugElement.query(By.directive(MdGridTile)); + expect(getProp(tile, 'width')).toBe('199.5px'); + + fixture.componentInstance.colspan = 3; + fixture.detectChanges(); + expect(getProp(tile, 'width')).toBe('299.75px'); + }); + }); + + it('should allow adjustment of tile rowspan', () => { + var template = ` + + + + `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.componentInstance.rowspan = 2; + fixture.detectChanges(); + + let tile = fixture.debugElement.query(By.directive(MdGridTile)); + expect(getProp(tile, 'height')).toBe('201px'); + + fixture.componentInstance.rowspan = 3; + fixture.detectChanges(); + expect(getProp(tile, 'height')).toBe('302px'); + }); + }); + + it('should lay out tiles correctly for a complex layout', () => { + var template = ` +
+ + + {{tile.text}} + + +
+ `; + + return builder.overrideTemplate(TestGridList, template) + .createAsync(TestGridList).then((fixture: ComponentFixture) => { + fixture.componentInstance.tiles = [ + {cols: 3, rows: 1}, + {cols: 1, rows: 2}, + {cols: 1, rows: 1}, + {cols: 2, rows: 1} + ]; + fixture.detectChanges(); + fakeAsync(() => { + tick(); + let tiles = fixture.debugElement.queryAll(By.css('md-grid-tile')); + + expect(getProp(tiles[0], 'width')).toBe('299.75px'); + expect(getProp(tiles[0], 'height')).toBe('100px'); + expect(getProp(tiles[0], 'left')).toBe('0px'); + expect(getProp(tiles[0], 'top')).toBe('0px'); + + expect(getProp(tiles[1], 'width')).toBe('99.25px'); + expect(getProp(tiles[1], 'height')).toBe('201px'); + expect(getProp(tiles[1], 'left')).toBe('300.75px'); + expect(getProp(tiles[1], 'top')).toBe('0px'); + + expect(getProp(tiles[2], 'width')).toBe('99.25px'); + expect(getProp(tiles[2], 'height')).toBe('100px'); + expect(getProp(tiles[2], 'left')).toBe('0px'); + expect(getProp(tiles[2], 'top')).toBe('101px'); + + expect(getProp(tiles[3], 'width')).toBe('199.5px'); + expect(getProp(tiles[3], 'height')).toBe('100px'); + expect(getProp(tiles[3], 'left')).toBe('100.25px'); + expect(getProp(tiles[3], 'top')).toBe('101px'); + }); + }); + }); +}); + +@Component({ + selector: 'test-grid-list', + template: ``, + directives: [MD_GRID_LIST_DIRECTIVES] +}) +class TestGridList { + tiles: any[]; + height: string; + colspan: number; + rowspan: number; +} + +function getProp(el: any, prop: string): string { + return getComputedStyle(el.nativeElement).getPropertyValue(prop); +}