Skip to content

Commit 4a01df8

Browse files
authored
feat(material-experimental/mdc-button): copy tests from button (#16926)
1 parent fb5750b commit 4a01df8

File tree

3 files changed

+295
-1
lines changed

3 files changed

+295
-1
lines changed

src/material-experimental/mdc-button/button-base.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
*/
88

99
import {Platform} from '@angular/cdk/platform';
10-
import {ElementRef, NgZone} from '@angular/core';
10+
import {ElementRef, NgZone, ViewChild} from '@angular/core';
1111
import {
1212
CanColor,
1313
CanColorCtor,
1414
CanDisable,
1515
CanDisableCtor,
1616
CanDisableRipple,
1717
CanDisableRippleCtor,
18+
MatRipple,
1819
mixinColor,
1920
mixinDisabled,
2021
mixinDisableRipple,
@@ -84,6 +85,9 @@ export class MatButtonBase extends _MatButtonBaseMixin implements CanDisable, Ca
8485
/** Whether the ripple is centered on the button. */
8586
_isRippleCentered = false;
8687

88+
/** Reference to the MatRipple instance of the button. */
89+
@ViewChild(MatRipple, {static: false}) ripple: MatRipple;
90+
8791
constructor(
8892
elementRef: ElementRef, public _platform: Platform, public _ngZone: NgZone,
8993
public _animationMode?: string) {
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
2+
import {Component, DebugElement} from '@angular/core';
3+
import {By} from '@angular/platform-browser';
4+
import {MatButtonModule, MatButton} from './index';
5+
import {MatRipple, ThemePalette} from '@angular/material/core';
6+
7+
8+
describe('MatButton', () => {
9+
10+
beforeEach(async(() => {
11+
TestBed.configureTestingModule({
12+
imports: [MatButtonModule],
13+
declarations: [TestApp],
14+
});
15+
16+
TestBed.compileComponents();
17+
}));
18+
19+
// General button tests
20+
it('should apply class based on color attribute', () => {
21+
let fixture = TestBed.createComponent(TestApp);
22+
23+
let testComponent = fixture.debugElement.componentInstance;
24+
let buttonDebugElement = fixture.debugElement.query(By.css('button'))!;
25+
let aDebugElement = fixture.debugElement.query(By.css('a'))!;
26+
27+
testComponent.buttonColor = 'primary';
28+
fixture.detectChanges();
29+
expect(buttonDebugElement.nativeElement.classList.contains('mat-primary')).toBe(true);
30+
expect(aDebugElement.nativeElement.classList.contains('mat-primary')).toBe(true);
31+
32+
testComponent.buttonColor = 'accent';
33+
fixture.detectChanges();
34+
expect(buttonDebugElement.nativeElement.classList.contains('mat-accent')).toBe(true);
35+
expect(aDebugElement.nativeElement.classList.contains('mat-accent')).toBe(true);
36+
37+
testComponent.buttonColor = null;
38+
fixture.detectChanges();
39+
40+
expect(buttonDebugElement.nativeElement.classList).not.toContain('mat-accent');
41+
expect(aDebugElement.nativeElement.classList).not.toContain('mat-accent');
42+
});
43+
44+
it('should expose the ripple instance', () => {
45+
const fixture = TestBed.createComponent(TestApp);
46+
fixture.detectChanges();
47+
48+
const button = fixture.debugElement.query(By.directive(MatButton))!.componentInstance;
49+
expect(button.ripple).toBeTruthy();
50+
});
51+
52+
it('should not clear previous defined classes', () => {
53+
let fixture = TestBed.createComponent(TestApp);
54+
let testComponent = fixture.debugElement.componentInstance;
55+
let buttonDebugElement = fixture.debugElement.query(By.css('button'))!;
56+
57+
buttonDebugElement.nativeElement.classList.add('custom-class');
58+
59+
testComponent.buttonColor = 'primary';
60+
fixture.detectChanges();
61+
62+
expect(buttonDebugElement.nativeElement.classList.contains('mat-primary')).toBe(true);
63+
expect(buttonDebugElement.nativeElement.classList.contains('custom-class')).toBe(true);
64+
65+
testComponent.buttonColor = 'accent';
66+
fixture.detectChanges();
67+
68+
expect(buttonDebugElement.nativeElement.classList.contains('mat-primary')).toBe(false);
69+
expect(buttonDebugElement.nativeElement.classList.contains('mat-accent')).toBe(true);
70+
expect(buttonDebugElement.nativeElement.classList.contains('custom-class')).toBe(true);
71+
});
72+
73+
describe('button[mat-fab]', () => {
74+
it('should have accent palette by default', () => {
75+
const fixture = TestBed.createComponent(TestApp);
76+
const fabButtonDebugEl = fixture.debugElement.query(By.css('button[mat-fab]'))!;
77+
78+
fixture.detectChanges();
79+
80+
expect(fabButtonDebugEl.nativeElement.classList)
81+
.toContain('mat-accent', 'Expected fab buttons to use accent palette by default');
82+
});
83+
});
84+
85+
describe('button[mat-mini-fab]', () => {
86+
it('should have accent palette by default', () => {
87+
const fixture = TestBed.createComponent(TestApp);
88+
const miniFabButtonDebugEl = fixture.debugElement.query(By.css('button[mat-mini-fab]'))!;
89+
90+
fixture.detectChanges();
91+
92+
expect(miniFabButtonDebugEl.nativeElement.classList)
93+
.toContain('mat-accent', 'Expected mini-fab buttons to use accent palette by default');
94+
});
95+
});
96+
97+
// Regular button tests
98+
describe('button[mat-button]', () => {
99+
it('should handle a click on the button', () => {
100+
let fixture = TestBed.createComponent(TestApp);
101+
let testComponent = fixture.debugElement.componentInstance;
102+
let buttonDebugElement = fixture.debugElement.query(By.css('button'))!;
103+
104+
buttonDebugElement.nativeElement.click();
105+
expect(testComponent.clickCount).toBe(1);
106+
});
107+
108+
it('should not increment if disabled', () => {
109+
let fixture = TestBed.createComponent(TestApp);
110+
let testComponent = fixture.debugElement.componentInstance;
111+
let buttonDebugElement = fixture.debugElement.query(By.css('button'))!;
112+
113+
testComponent.isDisabled = true;
114+
fixture.detectChanges();
115+
116+
buttonDebugElement.nativeElement.click();
117+
118+
expect(testComponent.clickCount).toBe(0);
119+
});
120+
121+
it('should disable the native button element', () => {
122+
let fixture = TestBed.createComponent(TestApp);
123+
let buttonNativeElement = fixture.nativeElement.querySelector('button');
124+
expect(buttonNativeElement.disabled).toBeFalsy('Expected button not to be disabled');
125+
126+
fixture.componentInstance.isDisabled = true;
127+
fixture.detectChanges();
128+
expect(buttonNativeElement.disabled).toBeTruthy('Expected button to be disabled');
129+
});
130+
131+
});
132+
133+
// Anchor button tests
134+
describe('a[mat-button]', () => {
135+
it('should not redirect if disabled', () => {
136+
let fixture = TestBed.createComponent(TestApp);
137+
let testComponent = fixture.debugElement.componentInstance;
138+
let buttonDebugElement = fixture.debugElement.query(By.css('a'))!;
139+
140+
testComponent.isDisabled = true;
141+
fixture.detectChanges();
142+
143+
buttonDebugElement.nativeElement.click();
144+
});
145+
146+
it('should remove tabindex if disabled', () => {
147+
let fixture = TestBed.createComponent(TestApp);
148+
let testComponent = fixture.debugElement.componentInstance;
149+
let buttonDebugElement = fixture.debugElement.query(By.css('a'))!;
150+
expect(buttonDebugElement.nativeElement.getAttribute('tabIndex')).toBe(null);
151+
152+
testComponent.isDisabled = true;
153+
fixture.detectChanges();
154+
expect(buttonDebugElement.nativeElement.getAttribute('tabIndex')).toBe('-1');
155+
});
156+
157+
it('should add aria-disabled attribute if disabled', () => {
158+
let fixture = TestBed.createComponent(TestApp);
159+
let testComponent = fixture.debugElement.componentInstance;
160+
let buttonDebugElement = fixture.debugElement.query(By.css('a'))!;
161+
fixture.detectChanges();
162+
expect(buttonDebugElement.nativeElement.getAttribute('aria-disabled')).toBe('false');
163+
164+
testComponent.isDisabled = true;
165+
fixture.detectChanges();
166+
expect(buttonDebugElement.nativeElement.getAttribute('aria-disabled')).toBe('true');
167+
});
168+
169+
it('should not add aria-disabled attribute if disabled is false', () => {
170+
let fixture = TestBed.createComponent(TestApp);
171+
let testComponent = fixture.debugElement.componentInstance;
172+
let buttonDebugElement = fixture.debugElement.query(By.css('a'))!;
173+
fixture.detectChanges();
174+
expect(buttonDebugElement.nativeElement.getAttribute('aria-disabled'))
175+
.toBe('false', 'Expect aria-disabled="false"');
176+
expect(buttonDebugElement.nativeElement.getAttribute('disabled'))
177+
.toBeNull('Expect disabled="false"');
178+
179+
testComponent.isDisabled = false;
180+
fixture.detectChanges();
181+
expect(buttonDebugElement.nativeElement.getAttribute('aria-disabled'))
182+
.toBe('false', 'Expect no aria-disabled');
183+
expect(buttonDebugElement.nativeElement.getAttribute('disabled'))
184+
.toBeNull('Expect no disabled');
185+
});
186+
187+
it('should be able to set a custom tabindex', () => {
188+
let fixture = TestBed.createComponent(TestApp);
189+
let testComponent = fixture.debugElement.componentInstance;
190+
let buttonElement = fixture.debugElement.query(By.css('a'))!.nativeElement;
191+
192+
fixture.componentInstance.tabIndex = 3;
193+
fixture.detectChanges();
194+
195+
expect(buttonElement.getAttribute('tabIndex'))
196+
.toBe('3', 'Expected custom tabindex to be set');
197+
198+
testComponent.isDisabled = true;
199+
fixture.detectChanges();
200+
201+
expect(buttonElement.getAttribute('tabIndex'))
202+
.toBe('-1', 'Expected custom tabindex to be overwritten when disabled.');
203+
});
204+
});
205+
206+
// Ripple tests.
207+
describe('button ripples', () => {
208+
let fixture: ComponentFixture<TestApp>;
209+
let testComponent: TestApp;
210+
let buttonDebugElement: DebugElement;
211+
let buttonRippleDebugElement: DebugElement;
212+
let buttonRippleInstance: MatRipple;
213+
let anchorDebugElement: DebugElement;
214+
let anchorRippleDebugElement: DebugElement;
215+
let anchorRippleInstance: MatRipple;
216+
217+
beforeEach(() => {
218+
fixture = TestBed.createComponent(TestApp);
219+
fixture.detectChanges();
220+
221+
testComponent = fixture.componentInstance;
222+
223+
buttonDebugElement = fixture.debugElement.query(By.css('button[mat-button]'))!;
224+
buttonRippleDebugElement = buttonDebugElement.query(By.directive(MatRipple))!;
225+
buttonRippleInstance = buttonRippleDebugElement.injector.get<MatRipple>(MatRipple);
226+
227+
anchorDebugElement = fixture.debugElement.query(By.css('a[mat-button]'))!;
228+
anchorRippleDebugElement = anchorDebugElement.query(By.directive(MatRipple))!;
229+
anchorRippleInstance = anchorRippleDebugElement.injector.get<MatRipple>(MatRipple);
230+
});
231+
232+
it('should disable the ripple if matRippleDisabled input is set', () => {
233+
expect(buttonRippleInstance.disabled).toBeFalsy();
234+
235+
testComponent.rippleDisabled = true;
236+
fixture.detectChanges();
237+
238+
expect(buttonRippleInstance.disabled).toBeTruthy();
239+
});
240+
241+
it('should disable the ripple when the button is disabled', () => {
242+
expect(buttonRippleInstance.disabled).toBeFalsy(
243+
'Expected an enabled button[mat-button] to have an enabled ripple'
244+
);
245+
expect(anchorRippleInstance.disabled).toBeFalsy(
246+
'Expected an enabled a[mat-button] to have an enabled ripple'
247+
);
248+
249+
testComponent.isDisabled = true;
250+
fixture.detectChanges();
251+
252+
expect(buttonRippleInstance.disabled).toBeTruthy(
253+
'Expected a disabled button[mat-button] not to have an enabled ripple'
254+
);
255+
expect(anchorRippleInstance.disabled).toBeTruthy(
256+
'Expected a disabled a[mat-button] not to have an enabled ripple'
257+
);
258+
});
259+
});
260+
});
261+
262+
/** Test component that contains an MatButton. */
263+
@Component({
264+
selector: 'test-app',
265+
template: `
266+
<button [tabIndex]="tabIndex" mat-button type="button" (click)="increment()"
267+
[disabled]="isDisabled" [color]="buttonColor" [disableRipple]="rippleDisabled">
268+
Go
269+
</button>
270+
<a [tabIndex]="tabIndex" href="http://www.google.com" mat-button [disabled]="isDisabled"
271+
[color]="buttonColor">
272+
Link
273+
</a>
274+
<button mat-fab>Fab Button</button>
275+
<button mat-mini-fab>Mini Fab Button</button>
276+
`
277+
})
278+
class TestApp {
279+
clickCount: number = 0;
280+
isDisabled: boolean = false;
281+
rippleDisabled: boolean = false;
282+
buttonColor: ThemePalette;
283+
tabIndex: number;
284+
285+
increment() {
286+
this.clickCount++;
287+
}
288+
}

src/material-experimental/mdc-button/fab.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export class MatFabButton extends MatButtonBase {
4444
elementRef: ElementRef, platform: Platform, ngZone: NgZone,
4545
@Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string) {
4646
super(elementRef, platform, ngZone, animationMode);
47+
this.color = 'accent';
4748
}
4849
}
4950

@@ -63,5 +64,6 @@ export class MatFabAnchor extends MatAnchor {
6364
elementRef: ElementRef, platform: Platform, ngZone: NgZone,
6465
@Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string) {
6566
super(elementRef, platform, ngZone, animationMode);
67+
this.color = 'accent';
6668
}
6769
}

0 commit comments

Comments
 (0)