Skip to content

Commit 0909bc9

Browse files
authored
test(material-experimental/mdc-list): add missing test coverage (#20771)
Implements tests that were missing from the `mdc-list` package, as well as the `mdc-checkbox`, `mdc-progress-spinner` and `mdc-snack-bar`. The idea is that once we have parity on the test coverage, we can start to enforce test consistency automatically on the CI.
1 parent bbcc5b2 commit 0909bc9

File tree

13 files changed

+140
-53
lines changed

13 files changed

+140
-53
lines changed

src/material-experimental/mdc-checkbox/checkbox.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ describe('MDC-based MatCheckbox', () => {
7171
expect(inputElement.checked).toBe(false);
7272
}));
7373

74+
it('should expose the ripple instance', () => {
75+
expect(checkboxInstance.ripple).toBeTruthy();
76+
});
7477

7578
it('should toggle checkbox ripple disabledness correctly', fakeAsync(() => {
7679
const rippleSelector = '.mat-ripple-element:not(.mat-checkbox-persistent-ripple)';
@@ -189,6 +192,15 @@ describe('MDC-based MatCheckbox', () => {
189192
expect(testComponent.isIndeterminate).toBe(true);
190193
}));
191194

195+
it('should change native element checked when check programmatically', () => {
196+
expect(inputElement.checked).toBe(false);
197+
198+
checkboxInstance.checked = true;
199+
fixture.detectChanges();
200+
201+
expect(inputElement.checked).toBe(true);
202+
});
203+
192204
it('should toggle checked state on click', fakeAsync(() => {
193205
expect(checkboxInstance.checked).toBe(false);
194206

src/material-experimental/mdc-checkbox/checkbox.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
mixinDisabled,
3939
CanColor,
4040
CanDisable,
41+
MatRipple,
4142
} from '@angular/material-experimental/mdc-core';
4243
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
4344
import {MDCCheckboxAdapter, MDCCheckboxFoundation} from '@material/checkbox';
@@ -190,6 +191,9 @@ export class MatCheckbox extends _MatCheckboxMixinBase implements AfterViewInit,
190191
/** The native label element. */
191192
@ViewChild('label') _label: ElementRef<HTMLElement>;
192193

194+
/** Reference to the ripple instance of the checkbox. */
195+
@ViewChild(MatRipple) ripple: MatRipple;
196+
193197
/** Returns the unique id for the visual hidden input. */
194198
get inputId(): string {
195199
return `${this.id || this._uniqueId}-input`;

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';
1010
import {Platform} from '@angular/cdk/platform';
1111
import {
1212
AfterContentInit,
13+
ContentChildren,
1314
Directive,
1415
ElementRef,
1516
HostBinding,
@@ -24,6 +25,7 @@ import {
2425
RippleTarget,
2526
setLines,
2627
} from '@angular/material-experimental/mdc-core';
28+
import {MatListAvatarCssMatStyler, MatListIconCssMatStyler} from './list-styling';
2729
import {Subscription} from 'rxjs';
2830
import {startWith} from 'rxjs/operators';
2931

@@ -47,6 +49,9 @@ export abstract class MatListItemBase implements AfterContentInit, OnDestroy, Ri
4749
/** Host element for the list item. */
4850
_hostElement: HTMLElement;
4951

52+
@ContentChildren(MatListAvatarCssMatStyler, {descendants: false}) _avatars: QueryList<never>;
53+
@ContentChildren(MatListIconCssMatStyler, {descendants: false}) _icons: QueryList<never>;
54+
5055
@Input()
5156
get disableRipple(): boolean {
5257
return this.disabled || this._disableRipple || this._listBase.disableRipple;
@@ -110,6 +115,11 @@ export abstract class MatListItemBase implements AfterContentInit, OnDestroy, Ri
110115
return this._itemText ? (this._itemText.nativeElement.textContent || '') : '';
111116
}
112117

118+
/** Whether the list item has icons or avatars. */
119+
_hasIconOrAvatar() {
120+
return this._avatars.length || this._icons.length;
121+
}
122+
113123
private _initInteractiveListItem() {
114124
this._hostElement.classList.add('mat-mdc-list-item-interactive');
115125
this._rippleRenderer =

src/material-experimental/mdc-list/list-option.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import {
2626
ViewEncapsulation
2727
} from '@angular/core';
2828
import {MatLine, ThemePalette} from '@angular/material-experimental/mdc-core';
29-
import {MatListAvatarCssMatStyler, MatListIconCssMatStyler} from './list';
3029
import {MatListBase, MatListItemBase} from './list-base';
3130

3231
/**
@@ -87,9 +86,6 @@ export class MatListOption extends MatListItemBase implements OnInit, OnDestroy
8786
@ContentChildren(MatLine, {read: ElementRef, descendants: true}) lines:
8887
QueryList<ElementRef<Element>>;
8988

90-
@ContentChildren(MatListAvatarCssMatStyler, {descendants: false}) _avatars: QueryList<never>;
91-
@ContentChildren(MatListIconCssMatStyler, {descendants: false}) _icons: QueryList<never>;
92-
9389
/** Unique id for the text. Used for describing the underlying checkbox input. */
9490
_optionTextId: string = `mat-mdc-list-option-text-${uniqueId++}`;
9591

@@ -194,11 +190,6 @@ export class MatListOption extends MatListItemBase implements OnInit, OnDestroy
194190
return this._selectionList.multiple;
195191
}
196192

197-
/** Whether the list-option has icons or avatars. */
198-
_hasIconOrAvatar() {
199-
return this._avatars.length || this._icons.length;
200-
}
201-
202193
_handleBlur() {
203194
this._selectionList._onTouched();
204195
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Directive} from '@angular/core';
10+
11+
/**
12+
* Directive whose purpose is to add the mat- CSS styling to this selector.
13+
* @docs-private
14+
*/
15+
@Directive({
16+
selector: '[mat-list-avatar], [matListAvatar]',
17+
host: {'class': 'mat-mdc-list-avatar mdc-list-item__graphic'}
18+
})
19+
export class MatListAvatarCssMatStyler {}
20+
21+
/**
22+
* Directive whose purpose is to add the mat- CSS styling to this selector.
23+
* @docs-private
24+
*/
25+
@Directive({
26+
selector: '[mat-list-icon], [matListIcon]',
27+
host: {'class': 'mat-mdc-list-icon mdc-list-item__graphic'}
28+
})
29+
export class MatListIconCssMatStyler {}
30+
31+
/**
32+
* Directive whose purpose is to add the mat- CSS styling to this selector.
33+
* @docs-private
34+
*/
35+
@Directive({
36+
selector: '[mat-subheader], [matSubheader]',
37+
// TODO(mmalerba): MDC's subheader font looks identical to the list item font, figure out why and
38+
// make a change in one of the repos to visually distinguish.
39+
host: {'class': 'mat-mdc-subheader mdc-list-group__subheader'}
40+
})
41+
export class MatListSubheaderCssMatStyler {}
42+

src/material-experimental/mdc-list/list.spec.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe('MDC-based MatList', () => {
3333
expect(listItem.nativeElement.classList).toContain('mat-mdc-list-item-single-line');
3434
});
3535

36-
it('should apply mat-mdc-2-line class to lists with two lines', () => {
36+
it('should apply a particular class to lists with two lines', () => {
3737
const fixture = TestBed.createComponent(ListWithTwoLineItem);
3838
fixture.detectChanges();
3939

@@ -42,7 +42,7 @@ describe('MDC-based MatList', () => {
4242
expect(listItems[1].nativeElement.className).toContain('mat-mdc-2-line');
4343
});
4444

45-
it('should apply mat-mdc-3-line class to lists with three lines', () => {
45+
it('should apply a particular class to lists with three lines', () => {
4646
const fixture = TestBed.createComponent(ListWithThreeLineItem);
4747
fixture.detectChanges();
4848

@@ -51,7 +51,7 @@ describe('MDC-based MatList', () => {
5151
expect(listItems[1].nativeElement.className).toContain('mat-mdc-3-line');
5252
});
5353

54-
it('should apply mat-mdc-multi-line class to lists with more than 3 lines', () => {
54+
it('should apply a particular class to lists with more than 3 lines', () => {
5555
const fixture = TestBed.createComponent(ListWithManyLines);
5656
fixture.detectChanges();
5757

@@ -60,6 +60,15 @@ describe('MDC-based MatList', () => {
6060
expect(listItems[1].nativeElement.className).toContain('mat-mdc-multi-line');
6161
});
6262

63+
it('should apply a class to list items with avatars', () => {
64+
const fixture = TestBed.createComponent(ListWithAvatar);
65+
fixture.detectChanges();
66+
67+
const listItems = fixture.debugElement.children[0].queryAll(By.css('mat-list-item'));
68+
expect(listItems[0].nativeElement.className).toContain('mat-mdc-list-item-with-avatar');
69+
expect(listItems[1].nativeElement.className).not.toContain('mat-mdc-list-item-with-avatar');
70+
});
71+
6372
it('should have a strong focus indicator configured for all list-items', () => {
6473
const fixture = TestBed.createComponent(ListWithManyLines);
6574
fixture.detectChanges();

src/material-experimental/mdc-list/list.ts

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
ChangeDetectionStrategy,
1212
Component,
1313
ContentChildren,
14-
Directive,
1514
ElementRef,
1615
NgZone,
1716
QueryList, ViewChild,
@@ -20,38 +19,6 @@ import {
2019
import {MatLine} from '@angular/material-experimental/mdc-core';
2120
import {MatListBase, MatListItemBase} from './list-base';
2221

23-
/**
24-
* Directive whose purpose is to add the mat- CSS styling to this selector.
25-
* @docs-private
26-
*/
27-
@Directive({
28-
selector: '[mat-list-avatar], [matListAvatar]',
29-
host: {'class': 'mat-mdc-list-avatar mdc-list-item__graphic'}
30-
})
31-
export class MatListAvatarCssMatStyler {}
32-
33-
/**
34-
* Directive whose purpose is to add the mat- CSS styling to this selector.
35-
* @docs-private
36-
*/
37-
@Directive({
38-
selector: '[mat-list-icon], [matListIcon]',
39-
host: {'class': 'mat-mdc-list-icon mdc-list-item__graphic'}
40-
})
41-
export class MatListIconCssMatStyler {}
42-
43-
/**
44-
* Directive whose purpose is to add the mat- CSS styling to this selector.
45-
* @docs-private
46-
*/
47-
@Directive({
48-
selector: '[mat-subheader], [matSubheader]',
49-
// TODO(mmalerba): MDC's subheader font looks identical to the list item font, figure out why and
50-
// make a change in one of the repos to visually distinguish.
51-
host: {'class': 'mat-mdc-subheader mdc-list-group__subheader'}
52-
})
53-
export class MatListSubheaderCssMatStyler {}
54-
5522
@Component({
5623
selector: 'mat-list',
5724
exportAs: 'matList',
@@ -73,6 +40,7 @@ export class MatList extends MatListBase {}
7340
exportAs: 'matListItem',
7441
host: {
7542
'class': 'mat-mdc-list-item mdc-list-item',
43+
'[class.mat-mdc-list-item-with-avatar]': '_hasIconOrAvatar()',
7644
},
7745
templateUrl: 'list-item.html',
7846
encapsulation: ViewEncapsulation.None,

src/material-experimental/mdc-list/module.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@ import {MatDividerModule} from '@angular/material/divider';
1717
import {MatActionList} from './action-list';
1818
import {
1919
MatList,
20-
MatListAvatarCssMatStyler,
21-
MatListIconCssMatStyler,
2220
MatListItem,
23-
MatListSubheaderCssMatStyler,
2421
} from './list';
2522
import {MatNavList} from './nav-list';
2623
import {MatSelectionList} from './selection-list';
2724
import {MatListOption} from './list-option';
25+
import {
26+
MatListAvatarCssMatStyler,
27+
MatListIconCssMatStyler,
28+
MatListSubheaderCssMatStyler,
29+
} from './list-styling';
2830

2931
@NgModule({
3032
imports: [

src/material-experimental/mdc-list/public-api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ export * from './nav-list';
1212
export * from './selection-list';
1313
export * from './module';
1414
export * from './list-option';
15+
export * from './list-styling';

src/material-experimental/mdc-progress-spinner/progress-spinner.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,42 @@ describe('MDC-based MatProgressSpinner', () => {
152152
.toBe('0 0 130 130', 'Expected the viewBox to be adjusted based on the stroke width.');
153153
});
154154

155+
it('should allow floating point values for custom diameter', () => {
156+
const fixture = TestBed.createComponent(ProgressSpinnerCustomDiameter);
157+
158+
fixture.componentInstance.diameter = 32.5;
159+
fixture.detectChanges();
160+
161+
const spinner = fixture.debugElement.query(By.css('mat-progress-spinner'))!.nativeElement;
162+
const svgElement: HTMLElement = fixture.nativeElement.querySelector('svg');
163+
164+
expect(parseFloat(spinner.style.width))
165+
.toBe(32.5, 'Expected the custom diameter to be applied to the host element width.');
166+
expect(parseFloat(spinner.style.height))
167+
.toBe(32.5, 'Expected the custom diameter to be applied to the host element height.');
168+
expect(Math.ceil(svgElement.clientWidth))
169+
.toBe(33, 'Expected the custom diameter to be applied to the svg element width.');
170+
expect(Math.ceil(svgElement.clientHeight))
171+
.toBe(33, 'Expected the custom diameter to be applied to the svg element height.');
172+
expect(svgElement.getAttribute('viewBox'))
173+
.toBe('0 0 25.75 25.75', 'Expected the custom diameter to be applied to the svg viewBox.');
174+
});
175+
176+
it('should allow floating point values for custom stroke width', () => {
177+
const fixture = TestBed.createComponent(ProgressSpinnerCustomStrokeWidth);
178+
179+
fixture.componentInstance.strokeWidth = 40.5;
180+
fixture.detectChanges();
181+
182+
const circleElement = fixture.nativeElement.querySelector('circle');
183+
const svgElement = fixture.nativeElement.querySelector('svg');
184+
185+
expect(parseFloat(circleElement.style.strokeWidth)).toBe(40.5, 'Expected the custom stroke ' +
186+
'width to be applied to the circle element as a percentage of the element size.');
187+
expect(svgElement.getAttribute('viewBox'))
188+
.toBe('0 0 130.5 130.5', 'Expected the viewBox to be adjusted based on the stroke width.');
189+
});
190+
155191
it('should expand the host element if the stroke width is greater than the default', () => {
156192
const fixture = TestBed.createComponent(ProgressSpinnerCustomStrokeWidth);
157193
const element = fixture.debugElement.nativeElement.querySelector('.mat-mdc-progress-spinner');

0 commit comments

Comments
 (0)