Skip to content

Commit bfbce54

Browse files
committed
chore(material): add unit tests for MdButton.
1 parent d245886 commit bfbce54

File tree

9 files changed

+191
-5
lines changed

9 files changed

+191
-5
lines changed

gulpfile.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,7 @@ gulp.task('test.unit.dart', function (done) {
638638
'!build/pubget.angular2.dart',
639639
'!build/change_detect.dart',
640640
'!build/remove-pub-symlinks',
641+
'build.dart.material.css',
641642
'!test.unit.dart/karma-server',
642643
'!test.unit.dart/karma-run',
643644
function(error) {
@@ -950,6 +951,7 @@ gulp.task('!broccoli.js.prod', function() {
950951
gulp.task('build.js.dev', ['build/clean.js'], function(done) {
951952
runSequence(
952953
'broccoli.js.dev',
954+
'build.css.material',
953955
sequenceComplete(done)
954956
);
955957
});

karma-js.conf.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ module.exports = function(config) {
4545
}
4646
},
4747

48-
browsers: ['ChromeCanary'],
48+
browsers: ['Chrome'],
4949

5050
port: 9876
5151
});

modules/angular2_material/pubspec.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ dependencies:
1414
dependency_overrides:
1515
angular2:
1616
path: ../angular2
17+
dev_dependencies:
18+
guinness: '^0.1.17'
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
<style>@import "package:angular2_material/src/components/button/button.css";</style>
21
<span class="md-button-wrapper"><ng-content></ng-content></span>

modules/angular2_material/src/components/button/button.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {Component, View, LifecycleEvent, ViewEncapsulation, OnChanges} from 'ang
33
import {TimerWrapper} from 'angular2/src/core/facade/async';
44
import {isPresent} from 'angular2/src/core/facade/lang';
55

6+
67
// TODO(jelbourn): Ink ripples.
78
// TODO(jelbourn): Make the `isMosueDown` stuff done with one global listener.
89

@@ -17,6 +18,7 @@ import {isPresent} from 'angular2/src/core/facade/lang';
1718
})
1819
@View({
1920
templateUrl: 'package:angular2_material/src/components/button/button.html',
21+
styleUrls: ['package:angular2_material/src/components/button/button.css'],
2022
encapsulation: ViewEncapsulation.None,
2123
})
2224
export class MdButton {
@@ -55,7 +57,7 @@ export class MdButton {
5557
'(blur)': 'onBlur()',
5658
'[tabIndex]': 'tabIndex',
5759
'[class.md-button-focus]': 'isKeyboardFocused',
58-
'[attr.aria-disabled]': 'disabled',
60+
'[attr.aria-disabled]': 'isAriaDisabled',
5961
},
6062
})
6163
@View({
@@ -64,8 +66,6 @@ export class MdButton {
6466
})
6567
export class MdAnchor extends MdButton implements OnChanges {
6668
tabIndex: number;
67-
68-
/** Whether the component is disabled. */
6969
disabled_: boolean;
7070

7171
get disabled(): boolean {
@@ -89,4 +89,9 @@ export class MdAnchor extends MdButton implements OnChanges {
8989
// A disabled anchor should not be in the tab flow.
9090
this.tabIndex = this.disabled ? -1 : 0;
9191
}
92+
93+
/** Gets the aria-disabled value for the component, which must be a string for Dart. */
94+
get isAriaDisabled(): string {
95+
return this.disabled ? 'true' : 'false';
96+
}
9297
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import {
2+
AsyncTestCompleter,
3+
TestComponentBuilder,
4+
beforeEach,
5+
beforeEachBindings,
6+
ddescribe,
7+
describe,
8+
el,
9+
expect,
10+
iit,
11+
inject,
12+
it,
13+
xit,
14+
} from 'angular2/test_lib';
15+
import {DebugElement} from 'angular2/src/core/debug/debug_element';
16+
17+
import {Component, View, ViewMetadata, UrlResolver, bind} from 'angular2/core';
18+
19+
import {MdButton, MdAnchor} from 'angular2_material/src/components/button/button';
20+
21+
import {TestUrlResolver} from './test_url_resolver';
22+
23+
import {XHR} from 'angular2/src/core/render/xhr';
24+
import {XHRImpl} from 'angular2/src/core/render/xhr_impl';
25+
26+
27+
export function main() {
28+
describe('MdButton', () => {
29+
let builder: TestComponentBuilder;
30+
31+
beforeEachBindings(() => [
32+
// Need a custom URL resolver for ng-material template files in order for them to work
33+
// with both JS and Dart output.
34+
bind(UrlResolver)
35+
.toValue(new TestUrlResolver()),
36+
37+
// Need to use the real XHR implementation (instead of the mock) so we can actually request
38+
// the template files, since Angular 2 doesn't have anything like $templateCache. This should
39+
// eventually be replaced with a preprocessor that inlines templates.
40+
bind(XHR).toClass(XHRImpl)
41+
]);
42+
43+
beforeEach(inject([TestComponentBuilder], (tcb) => { builder = tcb; }));
44+
45+
describe('button[md-button]', () => {
46+
it('should handle a click on the button', inject([AsyncTestCompleter], (async) => {
47+
builder.createAsync(TestApp).then(rootTestComponent => {
48+
let testComponent = rootTestComponent.debugElement.componentInstance;
49+
let buttonDebugElement =
50+
getChildDebugElement(rootTestComponent.debugElement, 'button');
51+
52+
buttonDebugElement.nativeElement.click();
53+
expect(testComponent.clickCount).toBe(1);
54+
55+
async.done();
56+
});
57+
}));
58+
59+
it('should disable the button', inject([AsyncTestCompleter], (async) => {
60+
builder.createAsync(TestApp).then(rootTestComponent => {
61+
let testAppComponent = rootTestComponent.debugElement.componentInstance;
62+
let buttonDebugElement =
63+
getChildDebugElement(rootTestComponent.debugElement, 'button');
64+
let buttonElement = buttonDebugElement.nativeElement;
65+
66+
// The button should initially be enabled.
67+
expect(buttonElement.disabled).toBe(false);
68+
69+
// After the disabled binding has been changed.
70+
testAppComponent.isDisabled = true;
71+
rootTestComponent.detectChanges();
72+
73+
// The button should should now be disabled.
74+
expect(buttonElement.disabled).toBe(true);
75+
76+
// Clicking the button should not invoke the handler.
77+
buttonElement.click();
78+
expect(testAppComponent.clickCount).toBe(0);
79+
async.done();
80+
});
81+
}));
82+
});
83+
84+
describe('a[md-button]', () => {
85+
const anchorTemplate = `<a md-button href="http://google.com" [disabled]="isDisabled">Go</a>`;
86+
87+
beforeEach(() => {
88+
builder = builder.overrideView(
89+
TestApp, new ViewMetadata({template: anchorTemplate, directives: [MdAnchor]}));
90+
});
91+
92+
it('should remove disabled anchors from tab order', inject([AsyncTestCompleter], (async) => {
93+
builder.createAsync(TestApp).then(rootTestComponent => {
94+
let testAppComponent = rootTestComponent.debugElement.componentInstance;
95+
let anchorDebugElement = getChildDebugElement(rootTestComponent.debugElement, 'a');
96+
let anchorElement = anchorDebugElement.nativeElement;
97+
98+
// The anchor should initially be in the tab order.
99+
expect(anchorElement.tabIndex).toBe(0);
100+
101+
// After the disabled binding has been changed.
102+
testAppComponent.isDisabled = true;
103+
rootTestComponent.detectChanges();
104+
105+
// The anchor should now be out of the tab order.
106+
expect(anchorElement.tabIndex).toBe(-1);
107+
108+
async.done();
109+
});
110+
111+
it('should preventDefault for disabled anchor clicks',
112+
inject([AsyncTestCompleter], (async) => {
113+
// No clear way to test this; see https://github.com/angular/angular/issues/3782
114+
async.done();
115+
}));
116+
}));
117+
});
118+
});
119+
}
120+
121+
/** Gets a child DebugElement by tag name. */
122+
function getChildDebugElement(parent: DebugElement, tagName: string): DebugElement {
123+
return parent.query(debugEl => debugEl.nativeElement.tagName.toLowerCase() == tagName);
124+
}
125+
126+
/** Test component that contains an MdButton. */
127+
@Component({selector: 'test-app'})
128+
@View({
129+
directives: [MdButton],
130+
template:
131+
`<button md-button type="button" (click)="increment()" [disabled]="isDisabled">Go</button>`
132+
})
133+
class TestApp {
134+
clickCount: number = 0;
135+
isDisabled: boolean = false;
136+
137+
increment() {
138+
this.clickCount++;
139+
}
140+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
library ng_material.test_url_resolver;
2+
3+
import 'package:angular2/src/core/dom/browser_adapter.dart';
4+
import 'package:angular2/src/core/services/url_resolver.dart';
5+
6+
void commonDemoSetup() {
7+
BrowserDomAdapter.makeCurrent();
8+
}
9+
10+
class TestUrlResolver extends UrlResolver {
11+
@override
12+
String resolve(String baseUrl, String url) {
13+
const MATERIAL_PKG = 'package:angular2_material/';
14+
15+
if (url.startsWith(MATERIAL_PKG)) {
16+
return '/packages/angular2_material/' +
17+
url.substring(MATERIAL_PKG.length);
18+
}
19+
return super.resolve(baseUrl, url);
20+
}
21+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
2+
3+
export class TestUrlResolver extends UrlResolver {
4+
constructor() {
5+
super();
6+
}
7+
8+
resolve(baseUrl: string, url: string): string {
9+
// The standard UrlResolver looks for "package:" templateUrls in
10+
// node_modules, however in our repo we host material widgets at the root.
11+
if (url.startsWith('package:angular2_material/')) {
12+
return '/base/dist/js/dev/es5/' + url.substring(8);
13+
}
14+
return super.resolve(baseUrl, url);
15+
}
16+
}

test-main.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ System.config({
1313
paths: {
1414
'benchpress/*': 'dist/js/dev/es5/benchpress/*.js',
1515
'angular2/*': 'dist/js/dev/es5/angular2/*.js',
16+
'angular2_material/*': 'dist/js/dev/es5/angular2_material/*.js',
1617
'rtts_assert/*': 'dist/js/dev/es5/rtts_assert/*.js',
1718
'rx': 'node_modules/rx/dist/rx.js'
1819
}

0 commit comments

Comments
 (0)