Skip to content
This repository has been archived by the owner on Feb 2, 2019. It is now read-only.

Commit

Permalink
feat(tabs): basic behavioral tests for tab selection binding and input
Browse files Browse the repository at this point in the history
  • Loading branch information
justindujardin committed Dec 23, 2015
1 parent 5b04345 commit 3cf848d
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 27 deletions.
60 changes: 33 additions & 27 deletions ng2-material/components/tabs/tabs.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import {
Component, Directive, Input, QueryList, Attribute, AfterContentInit,
ViewContainerRef, TemplateRef, ContentChildren
Component, Directive, Input, QueryList, Attribute, AfterViewInit,
ViewContainerRef, TemplateRef, ContentChildren, forwardRef
} from 'angular2/core';
import {isPresent} from "angular2/src/facade/lang";
import {Ink} from "../../core/util/ink";
import {ViewEncapsulation} from "angular2/core";
import {NgFor} from "angular2/common";
import {Host} from "angular2/core";
import {SkipSelf} from "angular2/core";
import {Query} from "angular2/core";


// TODO: behaviors to test
Expand Down Expand Up @@ -34,7 +37,9 @@ export class MdTab {
}

@Input() set active(active: boolean) {
if (active == this._active) return;
if (active == this._active) {
return;
}
this._active = active;
if (active) {
this.viewContainer.createEmbeddedView(this.templateRef);
Expand All @@ -58,7 +63,7 @@ export class MdTab {
<md-tab-item tabindex="-1"
class="md-tab"
(click)="onTabClick(pane,$event)"
[class.md-active]="selected == pane"
[class.md-active]="selectedTab == pane"
[disabled]="pane.disabled"
[style.max-width]="maxTabWidth + 'px'"
*ngFor="#pane of panes"
Expand All @@ -76,31 +81,40 @@ export class MdTab {
</md-tab-content>
</md-tabs-content-wrapper>`,
directives: [NgFor],
properties: ['selected'],
encapsulation: ViewEncapsulation.None
})
export class MdTabs implements AfterContentInit {
@ContentChildren(MdTab) panes: QueryList<MdTab>;
export class MdTabs {

@Input() mdNoScroll: boolean = false;

constructor(@Attribute('mdNoScroll') noScroll: string) {
constructor(@Query(MdTab) public panes: QueryList<MdTab>,
@Attribute('mdNoScroll') noScroll: string) {
this.mdNoScroll = isPresent(noScroll);
this.panes.changes.subscribe((_) => {
this.panes.toArray().forEach((p: MdTab, index: number) => {
p.active = index === this._selected;
});
});
}

private _selectedIndex: number = -1;
get selectedIndex(): number {
return this._selectedIndex;
private _selected: number = 0;
get selected(): number {
return this._selected;
}

set selectedIndex(value: number) {
@Input()
set selected(index: number) {
let panes = this.panes.toArray();
if (value > 0 && value < panes.length) {
this.select(panes[value]);
this._selectedIndex = value;
let pane = null;
if (index >= 0 && index < panes.length) {
pane = panes[index];
}
this.selectedTab = pane;
this._selected = index;
}

get selected(): MdTab {
get selectedTab(): MdTab {
let result = null;
this.panes.toArray().forEach((p: MdTab) => {
if (p.active) {
Expand All @@ -110,11 +124,11 @@ export class MdTabs implements AfterContentInit {
return result;
}

select(pane: MdTab) {
set selectedTab(value: MdTab) {
this.panes.toArray().forEach((p: MdTab, index: number) => {
p.active = p == pane;
p.active = p == value;
if (p.active) {
this._selectedIndex = index;
this._selected = index;
}
});
}
Expand All @@ -123,14 +137,6 @@ export class MdTabs implements AfterContentInit {
if (event && Ink.canApply(event.target)) {
Ink.rippleEvent(event.target, event);
}
this.select(pane);
}

ngAfterContentInit(): any {
setTimeout(()=> {
if (this._selectedIndex === -1) {
this.select(this.panes.toArray()[0]);
}
}, 0);
this.selectedTab = pane;
}
}
125 changes: 125 additions & 0 deletions test/components/tabs/tabs_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import {
AsyncTestCompleter,
TestComponentBuilder,
beforeEach,
beforeEachProviders,
describe,
expect,
inject,
it,
} from 'angular2/testing_internal';
import {DebugElement} from 'angular2/src/core/debug/debug_element';
import {Component, View, provide} from 'angular2/core';
import {UrlResolver} from 'angular2/compiler';
import {TestUrlResolver} from '../../test_url_resolver';
import {MdTab, MdTabs} from '../../../ng2-material/components/tabs/tabs';
import {MATERIAL_PROVIDERS} from '../../../ng2-material/all';
import {ComponentFixture} from "angular2/testing";
import {CORE_DIRECTIVES} from "angular2/common";
import {findChildrenByAttribute,findChildrenByTag,findChildByTag} from "../../util";
import {TimerWrapper} from "angular2/src/facade/async";


export function main() {

interface ITabsFixture {
fixture:ComponentFixture;
tabs:MdTabs;
tabButtons:HTMLElement[];
}
@Component({selector: 'test-app'})
@View({
directives: [CORE_DIRECTIVES, MdTabs, MdTab],
template: `
<md-tabs>
<template md-tab label="Tab1"><span>Tab1</span></template>
<template md-tab label="Tab2"><span>Tab2</span></template>
<template md-tab label="Tab3"><span>Tab3</span></template>
</md-tabs>`
})
class TestComponent {
selectedIndex: number = 2;
}

describe('Tabs', () => {
let builder: TestComponentBuilder;

function setup(template: string = null): Promise<ITabsFixture> {
let prep = template === null ?
builder.createAsync(TestComponent) :
builder.overrideTemplate(TestComponent, template).createAsync(TestComponent);
return prep.then((fixture: ComponentFixture) => {
fixture.detectChanges();
let tabs = <MdTabs>findChildByTag(fixture.debugElement, 'md-tabs').componentInstance;
let tabButtons = findChildrenByTag(fixture.debugElement, 'md-tab-item').map(b => b.nativeElement);
return {
fixture: fixture,
tabs: tabs,
tabButtons: tabButtons
};
}).catch(console.error.bind(console));
}

beforeEachProviders(() => [
MATERIAL_PROVIDERS,
provide(UrlResolver, {useValue: new TestUrlResolver()}),
]);
beforeEach(inject([TestComponentBuilder], (tcb) => {
builder = tcb;
}));

describe('md-tabs', () => {
it('should initialize with first tab selected', inject([AsyncTestCompleter], (async) => {
setup().then((api: ITabsFixture) => {
expect(api.tabs.selected).toBe(0);
expect(api.tabs.selectedTab).toBe(null);
async.done();
});
}));
it('should update selected and selectedTab when changed by clicking on tab buttons', inject([AsyncTestCompleter], (async) => {
setup().then((api: ITabsFixture) => {
api.tabButtons[1].click();
expect(api.tabs.selected).toBe(1);
expect(api.tabs.selectedTab).not.toBeNull();

api.tabButtons[0].click();
expect(api.tabs.selected).toBe(0);
expect(api.tabs.selectedTab).not.toBeNull();
async.done();
});
}));
it('should update selectedTab when selected is set', inject([AsyncTestCompleter], (async) => {
setup().then((api: ITabsFixture) => {
expect(api.tabs.selectedTab).toBeNull();
api.tabs.selected = 1;
expect(api.tabs.selectedTab).not.toBeNull();

api.tabs.selected = 0;
expect(api.tabs.selectedTab).not.toBeNull();

api.tabs.selected = -1;
expect(api.tabs.selectedTab).toBeNull();

async.done();
});
}));

it('should bind [selected] to an index', inject([AsyncTestCompleter], (async) => {
let template = `
<md-tabs [selected]="selectedIndex">
<template md-tab label="Tab1"><span>Tab1</span></template>
<template md-tab label="Tab2"><span>Tab2</span></template>
<template md-tab label="Tab3"><span>Tab3</span></template>
</md-tabs>`;

setup(template).then((api: ITabsFixture) => {
expect(api.tabs.selected).toBe(2);
async.done();
});
}));
});
});


}

0 comments on commit 3cf848d

Please sign in to comment.