diff --git a/src/material/stepper/stepper.spec.ts b/src/material/stepper/stepper.spec.ts index b4269ff71952..e67e627732ff 100644 --- a/src/material/stepper/stepper.spec.ts +++ b/src/material/stepper/stepper.spec.ts @@ -31,10 +31,10 @@ import { ViewChild, ViewChildren, ViewEncapsulation, - provideZoneChangeDetection, + inject, signal, } from '@angular/core'; -import {ComponentFixture, TestBed, fakeAsync, flush, inject} from '@angular/core/testing'; +import {ComponentFixture, TestBed, fakeAsync, flush} from '@angular/core/testing'; import { AbstractControl, AsyncValidatorFn, @@ -480,23 +480,20 @@ describe('MatStepper', () => { i18nFixture.detectChanges(); }); - it('should re-render when the i18n labels change', inject( - [MatStepperIntl], - (intl: MatStepperIntl) => { - const header = i18nFixture.debugElement.queryAll(By.css('mat-step-header'))[2] - .nativeElement; - const optionalLabel = header.querySelector('.mat-step-optional'); + it('should re-render when the i18n labels change', () => { + const intl = TestBed.inject(MatStepperIntl); + const header = i18nFixture.debugElement.queryAll(By.css('mat-step-header'))[2].nativeElement; + const optionalLabel = header.querySelector('.mat-step-optional'); - expect(optionalLabel).toBeTruthy(); - expect(optionalLabel.textContent).toBe('Optional'); + expect(optionalLabel).toBeTruthy(); + expect(optionalLabel.textContent).toBe('Optional'); - intl.optionalLabel = 'Valgfri'; - intl.changes.next(); - i18nFixture.detectChanges(); + intl.optionalLabel = 'Valgfri'; + intl.changes.next(); + i18nFixture.detectChanges(); - expect(optionalLabel.textContent).toBe('Valgfri'); - }, - )); + expect(optionalLabel.textContent).toBe('Valgfri'); + }); }); describe('basic stepper with completed label change', () => { @@ -507,29 +504,27 @@ describe('MatStepper', () => { fixture.detectChanges(); }); - it('should re-render when the completed labels change', inject( - [MatStepperIntl], - (intl: MatStepperIntl) => { - const stepperDebugElement = fixture.debugElement.query(By.directive(MatStepper))!; - const stepperComponent: MatStepper = stepperDebugElement.componentInstance; + it('should re-render when the completed labels change', () => { + const intl = TestBed.inject(MatStepperIntl); + const stepperDebugElement = fixture.debugElement.query(By.directive(MatStepper))!; + const stepperComponent: MatStepper = stepperDebugElement.componentInstance; - stepperComponent.steps.toArray()[0].editable = false; - stepperComponent.next(); - fixture.detectChanges(); + stepperComponent.steps.toArray()[0].editable = false; + stepperComponent.next(); + fixture.detectChanges(); - const header = stepperDebugElement.nativeElement.querySelector('mat-step-header'); - const completedLabel = header.querySelector('.cdk-visually-hidden'); + const header = stepperDebugElement.nativeElement.querySelector('mat-step-header'); + const completedLabel = header.querySelector('.cdk-visually-hidden'); - expect(completedLabel).toBeTruthy(); - expect(completedLabel.textContent).toBe('Completed'); + expect(completedLabel).toBeTruthy(); + expect(completedLabel.textContent).toBe('Completed'); - intl.completedLabel = 'Completada'; - intl.changes.next(); - fixture.detectChanges(); + intl.completedLabel = 'Completada'; + intl.changes.next(); + fixture.detectChanges(); - expect(completedLabel.textContent).toBe('Completada'); - }, - )); + expect(completedLabel.textContent).toBe('Completada'); + }); }); describe('basic stepper with editable label change', () => { @@ -540,29 +535,27 @@ describe('MatStepper', () => { fixture.detectChanges(); }); - it('should re-render when the editable label changes', inject( - [MatStepperIntl], - (intl: MatStepperIntl) => { - const stepperDebugElement = fixture.debugElement.query(By.directive(MatStepper))!; - const stepperComponent: MatStepper = stepperDebugElement.componentInstance; + it('should re-render when the editable label changes', () => { + const intl = TestBed.inject(MatStepperIntl); + const stepperDebugElement = fixture.debugElement.query(By.directive(MatStepper))!; + const stepperComponent: MatStepper = stepperDebugElement.componentInstance; - stepperComponent.steps.toArray()[0].editable = true; - stepperComponent.next(); - fixture.detectChanges(); + stepperComponent.steps.toArray()[0].editable = true; + stepperComponent.next(); + fixture.detectChanges(); - const header = stepperDebugElement.nativeElement.querySelector('mat-step-header'); - const editableLabel = header.querySelector('.cdk-visually-hidden'); + const header = stepperDebugElement.nativeElement.querySelector('mat-step-header'); + const editableLabel = header.querySelector('.cdk-visually-hidden'); - expect(editableLabel).toBeTruthy(); - expect(editableLabel.textContent).toBe('Editable'); + expect(editableLabel).toBeTruthy(); + expect(editableLabel.textContent).toBe('Editable'); - intl.editableLabel = 'Modificabile'; - intl.changes.next(); - fixture.detectChanges(); + intl.editableLabel = 'Modificabile'; + intl.changes.next(); + fixture.detectChanges(); - expect(editableLabel.textContent).toBe('Modificabile'); - }, - )); + expect(editableLabel.textContent).toBe('Modificabile'); + }); }); describe('icon overrides', () => { @@ -647,7 +640,7 @@ describe('MatStepper', () => { let stepperComponent: MatStepper; beforeEach(() => { - fixture = createComponent(LinearMatVerticalStepperApp); + fixture = createComponent(LinearMatVerticalStepperApp, [], [], undefined, []); fixture.detectChanges(); testComponent = fixture.componentInstance; @@ -1792,15 +1785,12 @@ function createComponent( providers: Provider[] = [], imports: any[] = [], encapsulation?: ViewEncapsulation, + declarations = [component], ): ComponentFixture { TestBed.configureTestingModule({ imports: [MatStepperModule, NoopAnimationsModule, ReactiveFormsModule, ...imports], - providers: [ - provideZoneChangeDetection(), - {provide: Directionality, useFactory: () => dir}, - ...providers, - ], - declarations: [component], + providers: [{provide: Directionality, useFactory: () => dir}, ...providers], + declarations, }); if (encapsulation != null) { @@ -1843,12 +1833,12 @@ function createComponent( `, }) class MatHorizontalStepperWithErrorsApp { + private readonly _formBuilder = inject(FormBuilder); + formGroup = this._formBuilder.group({ firstNameCtrl: ['', Validators.required], lastNameCtrl: ['', Validators.required], }); - - constructor(private _formBuilder: FormBuilder) {} } @Component({ @@ -1931,6 +1921,7 @@ class SimpleMatVerticalStepperApp { } @Component({ + standalone: true, template: ` @@ -1938,8 +1929,8 @@ class SimpleMatVerticalStepperApp { Step one
- - + +
@@ -1948,8 +1939,8 @@ class SimpleMatVerticalStepperApp { Step two
- - + +
@@ -1958,8 +1949,8 @@ class SimpleMatVerticalStepperApp { Step two
- - + +
@@ -1968,6 +1959,7 @@ class SimpleMatVerticalStepperApp {
`, + imports: [ReactiveFormsModule, MatStepperModule], }) class LinearMatVerticalStepperApp { validationTrigger = new Subject(); diff --git a/src/material/tabs/tab-body.spec.ts b/src/material/tabs/tab-body.spec.ts index a8039a4bfddc..52b44b0bb8cf 100644 --- a/src/material/tabs/tab-body.spec.ts +++ b/src/material/tabs/tab-body.spec.ts @@ -1,30 +1,26 @@ import {Direction, Directionality} from '@angular/cdk/bidi'; import {PortalModule, TemplatePortal} from '@angular/cdk/portal'; +import {CdkScrollable, ScrollingModule} from '@angular/cdk/scrolling'; import {CommonModule} from '@angular/common'; import { - AfterContentInit, + AfterViewInit, Component, TemplateRef, ViewChild, ViewContainerRef, - provideZoneChangeDetection, + inject, + signal, } from '@angular/core'; -import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing'; +import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import {MatRippleModule} from '@angular/material/core'; -import {NoopAnimationsModule} from '@angular/platform-browser/animations'; -import {CdkScrollable, ScrollingModule} from '@angular/cdk/scrolling'; -import {MatTabBody, MatTabBodyPortal} from './tab-body'; import {By} from '@angular/platform-browser'; +import {NoopAnimationsModule} from '@angular/platform-browser/animations'; import {Subject} from 'rxjs'; +import {MatTabBody, MatTabBodyPortal} from './tab-body'; describe('MDC-based MatTabBody', () => { let dir: Direction = 'ltr'; let dirChange: Subject = new Subject(); - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideZoneChangeDetection()], - }); - }); beforeEach(waitForAsync(() => { dir = 'ltr'; @@ -125,6 +121,7 @@ describe('MDC-based MatTabBody', () => { it('to be left position with negative position', () => { fixture.componentInstance.position = -1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(fixture.componentInstance.tabBody._position).toBe('left'); @@ -132,6 +129,7 @@ describe('MDC-based MatTabBody', () => { it('to be center position with zero position', () => { fixture.componentInstance.position = 0; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(fixture.componentInstance.tabBody._position).toBe('center'); @@ -139,6 +137,7 @@ describe('MDC-based MatTabBody', () => { it('to be left position with positive position', () => { fixture.componentInstance.position = 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(fixture.componentInstance.tabBody._position).toBe('right'); @@ -156,6 +155,7 @@ describe('MDC-based MatTabBody', () => { it('to be right position with negative position', () => { fixture.componentInstance.position = -1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(fixture.componentInstance.tabBody._position).toBe('right'); @@ -163,6 +163,7 @@ describe('MDC-based MatTabBody', () => { it('to be center position with zero position', () => { fixture.componentInstance.position = 0; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(fixture.componentInstance.tabBody._position).toBe('center'); @@ -170,6 +171,7 @@ describe('MDC-based MatTabBody', () => { it('to be left position with positive position', () => { fixture.componentInstance.position = 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(fixture.componentInstance.tabBody._position).toBe('left'); @@ -218,22 +220,22 @@ describe('MDC-based MatTabBody', () => { @Component({ template: ` Tab Body Content - + `, standalone: true, imports: [CommonModule, PortalModule, MatRippleModule, MatTabBody], }) -class SimpleTabBodyApp implements AfterContentInit { - content: TemplatePortal; +class SimpleTabBodyApp implements AfterViewInit { + content = signal(undefined); position: number; origin: number | null; @ViewChild(MatTabBody) tabBody: MatTabBody; @ViewChild(TemplateRef) template: TemplateRef; - constructor(private _viewContainerRef: ViewContainerRef) {} + private readonly _viewContainerRef = inject(ViewContainerRef); - ngAfterContentInit() { - this.content = new TemplatePortal(this.template, this._viewContainerRef); + ngAfterViewInit() { + this.content.set(new TemplatePortal(this.template, this._viewContainerRef)); } } diff --git a/src/material/tabs/tab-body.ts b/src/material/tabs/tab-body.ts index f1008b136f1c..2e285078106f 100644 --- a/src/material/tabs/tab-body.ts +++ b/src/material/tabs/tab-body.ts @@ -6,6 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ +import {AnimationEvent} from '@angular/animations'; +import {Direction, Directionality} from '@angular/cdk/bidi'; +import {CdkPortalOutlet, TemplatePortal} from '@angular/cdk/portal'; +import {CdkScrollable} from '@angular/cdk/scrolling'; +import {DOCUMENT} from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, @@ -25,14 +30,9 @@ import { ViewContainerRef, ViewEncapsulation, } from '@angular/core'; -import {CdkPortalOutlet, TemplatePortal} from '@angular/cdk/portal'; -import {Direction, Directionality} from '@angular/cdk/bidi'; -import {DOCUMENT} from '@angular/common'; import {Subject, Subscription} from 'rxjs'; import {distinctUntilChanged, startWith} from 'rxjs/operators'; -import {AnimationEvent} from '@angular/animations'; import {matTabsAnimations} from './tabs-animations'; -import {CdkScrollable} from '@angular/cdk/scrolling'; /** * The portal host directive for the contents of the tab. @@ -64,7 +64,7 @@ export class MatTabBodyPortal extends CdkPortalOutlet implements OnInit, OnDestr this._centeringSub = this._host._beforeCentering .pipe(startWith(this._host._isCenterPosition(this._host._position))) .subscribe((isCentering: boolean) => { - if (isCentering && !this.hasAttached()) { + if (this._host._content && isCentering && !this.hasAttached()) { this.attach(this._host._content); } }); diff --git a/src/material/tabs/tab-group.spec.ts b/src/material/tabs/tab-group.spec.ts index c0c32fd0db50..c93b7ca3cd89 100644 --- a/src/material/tabs/tab-group.spec.ts +++ b/src/material/tabs/tab-group.spec.ts @@ -1,25 +1,17 @@ import {LEFT_ARROW, RIGHT_ARROW} from '@angular/cdk/keycodes'; import {dispatchFakeEvent, dispatchKeyboardEvent} from '@angular/cdk/testing/private'; -import { - Component, - DebugElement, - OnInit, - QueryList, - ViewChild, - ViewChildren, - provideZoneChangeDetection, -} from '@angular/core'; +import {CommonModule} from '@angular/common'; +import {Component, DebugElement, OnInit, QueryList, ViewChild, ViewChildren} from '@angular/core'; import { ComponentFixture, + TestBed, fakeAsync, flush, - TestBed, tick, waitForAsync, } from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; -import {CommonModule} from '@angular/common'; import {Observable} from 'rxjs'; import { MAT_TABS_CONFIG, @@ -31,11 +23,6 @@ import { } from './index'; describe('MDC-based MatTabGroup', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideZoneChangeDetection()], - }); - }); beforeEach(fakeAsync(() => { TestBed.configureTestingModule({ imports: [ @@ -115,14 +102,17 @@ describe('MDC-based MatTabGroup', () => { it('should set to correct tab on fast change', waitForAsync(() => { let component = fixture.componentInstance; component.selectedIndex = 0; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); setTimeout(() => { component.selectedIndex = 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); setTimeout(() => { component.selectedIndex = 0; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); fixture.whenStable().then(() => { expect(component.selectedIndex).toBe(0); @@ -140,6 +130,7 @@ describe('MDC-based MatTabGroup', () => { checkSelectedIndex(1, fixture); tabComponent.selectedIndex = 2; + fixture.changeDetectorRef.markForCheck(); checkSelectedIndex(2, fixture); tick(); @@ -161,6 +152,7 @@ describe('MDC-based MatTabGroup', () => { // Move to third tab component.selectedIndex = 2; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(tabs[0].position).toBeLessThan(0); expect(tabs[1].position).toBeLessThan(0); @@ -168,6 +160,7 @@ describe('MDC-based MatTabGroup', () => { // Move to the first tab component.selectedIndex = 0; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(tabs[0].position).toBe(0); expect(tabs[1].position).toBeGreaterThan(0); @@ -182,11 +175,13 @@ describe('MDC-based MatTabGroup', () => { // Set the index to be negative, expect first tab selected fixture.componentInstance.selectedIndex = -1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(component.selectedIndex).toBe(0); // Set the index beyond the size of the tabs, expect last tab selected fixture.componentInstance.selectedIndex = 3; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(component.selectedIndex).toBe(2); }); @@ -219,6 +214,7 @@ describe('MDC-based MatTabGroup', () => { it('should allow disabling ripples for tab-group labels', () => { fixture.componentInstance.disableRipple = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); const testElement = fixture.nativeElement; @@ -247,6 +243,7 @@ describe('MDC-based MatTabGroup', () => { expect(tabs[2].isActive).toBe(false); fixture.componentInstance.selectedIndex = 2; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); @@ -381,6 +378,7 @@ describe('MDC-based MatTabGroup', () => { it('should be able to set a tabindex on the inner content element', () => { fixture.componentInstance.contentTabIndex = 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); const contentElements = Array.from( fixture.nativeElement.querySelectorAll('mat-tab-body'), @@ -389,6 +387,7 @@ describe('MDC-based MatTabGroup', () => { expect(contentElements.map(e => e.getAttribute('tabindex'))).toEqual([null, '1', null]); fixture.componentInstance.selectedIndex = 0; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(contentElements.map(e => e.getAttribute('tabindex'))).toEqual(['1', null, null]); @@ -430,6 +429,7 @@ describe('MDC-based MatTabGroup', () => { it('should set the aria-label attribute', () => { fixture.componentInstance.ariaLabel = 'Fruit'; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(tab.getAttribute('aria-label')).toBe('Fruit'); @@ -437,6 +437,7 @@ describe('MDC-based MatTabGroup', () => { it('should set the aria-labelledby attribute', () => { fixture.componentInstance.ariaLabelledby = 'fruit-label'; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(tab.getAttribute('aria-labelledby')).toBe('fruit-label'); @@ -445,12 +446,14 @@ describe('MDC-based MatTabGroup', () => { it('should not be able to set both an aria-label and aria-labelledby', () => { fixture.componentInstance.ariaLabel = 'Fruit'; fixture.componentInstance.ariaLabelledby = 'fruit-label'; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(tab.getAttribute('aria-label')).toBe('Fruit'); expect(tab.hasAttribute('aria-labelledby')).toBe(false); fixture.componentInstance.ariaLabel = 'Veggie'; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(tab.getAttribute('aria-label')).toBe('Veggie'); }); @@ -499,6 +502,7 @@ describe('MDC-based MatTabGroup', () => { expect(labels[0].nativeElement.getAttribute('aria-disabled')).toBe('true'); fixture.componentInstance.isDisabled = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(tabs[2].disabled).toBe(true); @@ -533,6 +537,7 @@ describe('MDC-based MatTabGroup', () => { // Add a new tab on the right and select it, expect an origin >= than 0 (animate right) fixture.componentInstance.tabs.push({label: 'New tab', content: 'to right of index'}); fixture.componentInstance.selectedIndex = 4; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); @@ -541,6 +546,7 @@ describe('MDC-based MatTabGroup', () => { // Add a new tab in the beginning and select it, expect an origin < than 0 (animate left) fixture.componentInstance.selectedIndex = 0; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); @@ -559,6 +565,7 @@ describe('MDC-based MatTabGroup', () => { const numberOfTabs = component._tabs.length; fixture.componentInstance.selectedIndex = numberOfTabs - 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); @@ -577,10 +584,12 @@ describe('MDC-based MatTabGroup', () => { ).componentInstance; fixture.componentInstance.selectedIndex = 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); // Add a new tab at the beginning. fixture.componentInstance.tabs.unshift({label: 'New tab', content: 'at the start'}); + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(component.selectedIndex).toBe(2); @@ -590,6 +599,7 @@ describe('MDC-based MatTabGroup', () => { it('should maintain the selected tab if a tab is removed', () => { // Select the second tab. fixture.componentInstance.selectedIndex = 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); const component: MatTabGroup = fixture.debugElement.query( @@ -598,6 +608,7 @@ describe('MDC-based MatTabGroup', () => { // Remove the first tab that is right before the selected one. fixture.componentInstance.tabs.splice(0, 1); + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); // Since the first tab has been removed and the second one was selected before, the selected @@ -614,6 +625,7 @@ describe('MDC-based MatTabGroup', () => { fixture.componentInstance.tabs.push({label: 'Last tab', content: 'at the end'}); fixture.componentInstance.selectedIndex = 3; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); @@ -625,11 +637,13 @@ describe('MDC-based MatTabGroup', () => { it('should not fire `selectedTabChange` when the amount of tabs changes', fakeAsync(() => { fixture.detectChanges(); fixture.componentInstance.selectedIndex = 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); // Add a new tab at the beginning. spyOn(fixture.componentInstance, 'handleSelection'); fixture.componentInstance.tabs.unshift({label: 'New tab', content: 'at the start'}); + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); fixture.detectChanges(); @@ -648,6 +662,7 @@ describe('MDC-based MatTabGroup', () => { label: 'New', content: 'New', }; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); @@ -659,12 +674,14 @@ describe('MDC-based MatTabGroup', () => { it('should be able to disable the pagination', fakeAsync(() => { fixture.componentInstance.disablePagination = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); for (let i = 0; i < 50; i++) { fixture.componentInstance.tabs.push({label: `Extra ${i}`, content: ''}); } + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); @@ -718,6 +735,7 @@ describe('MDC-based MatTabGroup', () => { fixture.componentInstance.otherLabel = 'Chips'; fixture.componentInstance.otherContent = 'Salt, vinegar'; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(getSelectedLabel(fixture).textContent).toMatch('Chips'); @@ -753,12 +771,14 @@ describe('MDC-based MatTabGroup', () => { it('should be able to opt into keeping the inactive tab content in the DOM', fakeAsync(() => { fixture.componentInstance.preserveContent = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(fixture.nativeElement.textContent).toContain('Pizza, fries'); expect(fixture.nativeElement.textContent).not.toContain('Peanuts'); tabGroup.selectedIndex = 3; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); @@ -913,6 +933,7 @@ describe('MDC-based MatTabGroup', () => { expect(window.scrollY).toBe(250); fixture.componentInstance.tabGroup.selectedIndex = 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(window.scrollY).toBe(250); @@ -943,6 +964,7 @@ describe('MDC-based MatTabGroup', () => { fixture.componentInstance.labelClassList = 'custom-label-class'; fixture.componentInstance.bodyClassList = 'custom-body-class'; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(labelElements[0].nativeElement.classList).toContain('custom-label-class'); @@ -950,6 +972,7 @@ describe('MDC-based MatTabGroup', () => { delete fixture.componentInstance.labelClassList; delete fixture.componentInstance.bodyClassList; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(labelElements[0].nativeElement.classList).not.toContain('custom-label-class'); @@ -962,6 +985,7 @@ describe('MDC-based MatTabGroup', () => { fixture.componentInstance.labelClassList = ['custom-label-class']; fixture.componentInstance.bodyClassList = ['custom-body-class']; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(labelElements[0].nativeElement.classList).toContain('custom-label-class'); @@ -969,6 +993,7 @@ describe('MDC-based MatTabGroup', () => { delete fixture.componentInstance.labelClassList; delete fixture.componentInstance.bodyClassList; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(labelElements[0].nativeElement.classList).not.toContain('custom-label-class'); @@ -1049,11 +1074,6 @@ describe('nested MatTabGroup with enabled animations', () => { }); describe('MatTabGroup with ink bar fit to content', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideZoneChangeDetection()], - }); - }); let fixture: ComponentFixture; beforeEach(fakeAsync(() => { @@ -1079,6 +1099,7 @@ describe('MatTabGroup with ink bar fit to content', () => { it('should be able to move the ink bar between content and full', () => { fixture.componentInstance.fitInkBarToContent = false; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); const tabElement = fixture.nativeElement.querySelector('.mdc-tab'); @@ -1087,6 +1108,7 @@ describe('MatTabGroup with ink bar fit to content', () => { expect(indicatorElement.parentElement).toBe(tabElement); fixture.componentInstance.fitInkBarToContent = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); const contentElement = tabElement.querySelector('.mdc-tab__content'); diff --git a/src/material/tabs/tab-header.spec.ts b/src/material/tabs/tab-header.spec.ts index e115be70983d..a0171dfdd508 100644 --- a/src/material/tabs/tab-header.spec.ts +++ b/src/material/tabs/tab-header.spec.ts @@ -12,7 +12,7 @@ import { dispatchKeyboardEvent, } from '@angular/cdk/testing/private'; import {CommonModule} from '@angular/common'; -import {Component, ViewChild, provideZoneChangeDetection} from '@angular/core'; +import {ChangeDetectorRef, Component, ViewChild, inject} from '@angular/core'; import { ComponentFixture, TestBed, @@ -32,11 +32,6 @@ describe('MDC-based MatTabHeader', () => { let fixture: ComponentFixture; let appComponent: SimpleTabHeaderApp; let resizeEvents: Subject; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideZoneChangeDetection()], - }); - }); beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ @@ -228,6 +223,7 @@ describe('MDC-based MatTabHeader', () => { it('should focus disabled items when moving focus using END', () => { appComponent.tabHeader.focusIndex = 0; appComponent.tabs[3].disabled = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(appComponent.tabHeader.focusIndex).toBe(0); @@ -345,11 +341,13 @@ describe('MDC-based MatTabHeader', () => { it('should update the scroll distance if a tab is removed and no tabs are selected', fakeAsync(() => { appComponent.selectedIndex = 0; + fixture.changeDetectorRef.markForCheck(); appComponent.addTabsForScrolling(); fixture.detectChanges(); // Focus the last tab so the header scrolls to the end. appComponent.tabHeader.focusIndex = appComponent.tabs.length - 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); const {offsetLeft, offsetWidth} = appComponent.getSelectedLabel( appComponent.tabHeader.focusIndex, @@ -359,6 +357,7 @@ describe('MDC-based MatTabHeader', () => { // Remove the first two tabs which includes the selected tab. appComponent.tabs = appComponent.tabs.slice(2); + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); @@ -383,12 +382,14 @@ describe('MDC-based MatTabHeader', () => { // Focus on the last tab, expect this to be the maximum scroll distance. appComponent.tabHeader.focusIndex = appComponent.tabs.length - 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); const {offsetLeft} = appComponent.getSelectedLabel(appComponent.tabHeader.focusIndex); expect(offsetLeft).toBe(0); // Focus on the first tab, expect this to be the maximum scroll distance. appComponent.tabHeader.focusIndex = 0; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(appComponent.tabHeader.scrollDistance).toBe(0); }); @@ -656,6 +657,7 @@ describe('MDC-based MatTabHeader', () => { fixture.detectChanges(); fixture.componentInstance.dir = 'rtl'; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); @@ -767,6 +769,8 @@ class SimpleTabHeaderApp { @ViewChild(MatTabHeader, {static: true}) tabHeader: MatTabHeader; + private readonly _changeDetectorRef = inject(ChangeDetectorRef); + constructor() { this.tabs[this.disabledTabIndex].disabled = true; } @@ -775,6 +779,7 @@ class SimpleTabHeaderApp { for (let i = 0; i < amount; i++) { this.tabs.push({label: 'new'}); } + this._changeDetectorRef.markForCheck(); } getViewLength() { diff --git a/src/material/tabs/tab-nav-bar/tab-nav-bar.spec.ts b/src/material/tabs/tab-nav-bar/tab-nav-bar.spec.ts index 3f1fcdd30c49..da5fd0b060b1 100644 --- a/src/material/tabs/tab-nav-bar/tab-nav-bar.spec.ts +++ b/src/material/tabs/tab-nav-bar/tab-nav-bar.spec.ts @@ -6,13 +6,7 @@ import { dispatchKeyboardEvent, dispatchMouseEvent, } from '@angular/cdk/testing/private'; -import { - Component, - QueryList, - ViewChild, - ViewChildren, - provideZoneChangeDetection, -} from '@angular/core'; +import {Component, QueryList, ViewChild, ViewChildren} from '@angular/core'; import {ComponentFixture, TestBed, fakeAsync, tick, waitForAsync} from '@angular/core/testing'; import {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions} from '@angular/material/core'; import {By} from '@angular/platform-browser'; @@ -23,11 +17,6 @@ import {MatTabsModule} from '../module'; import {MatTabLink, MatTabNav} from './tab-nav-bar'; describe('MDC-based MatTabNavBar', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideZoneChangeDetection()], - }); - }); let dir: Direction = 'ltr'; let dirChange = new Subject(); let globalRippleOptions: RippleGlobalOptions; @@ -103,6 +92,7 @@ describe('MDC-based MatTabNavBar', () => { .toBe(true); fixture.componentInstance.disabled = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(tabLinkElements.every(tabLink => tabLink.getAttribute('aria-disabled') === 'true')) @@ -120,6 +110,7 @@ describe('MDC-based MatTabNavBar', () => { .toEqual([0, -1, -1]); fixture.componentInstance.disabled = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(tabLinkElements.every(tabLink => tabLink.tabIndex === -1)) @@ -133,6 +124,7 @@ describe('MDC-based MatTabNavBar', () => { expect(tabLinkElement.classList).not.toContain('mat-mdc-tab-disabled'); fixture.componentInstance.disabled = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(tabLinkElement.classList).toContain('mat-mdc-tab-disabled'); @@ -141,6 +133,7 @@ describe('MDC-based MatTabNavBar', () => { it('should prevent default keyboard actions on disabled links', () => { const link = fixture.debugElement.query(By.css('a')).nativeElement; fixture.componentInstance.disabled = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); const spaceEvent = dispatchKeyboardEvent(link, 'keydown', SPACE); @@ -170,6 +163,7 @@ describe('MDC-based MatTabNavBar', () => { spyOn(inkBar, 'alignToElement'); fixture.componentInstance.tabs = [1, 2, 3, 4]; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); tick(); @@ -185,6 +179,7 @@ describe('MDC-based MatTabNavBar', () => { }); fixture.componentInstance.label = 'label change'; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(spy.calls.any()).toBe(false); @@ -208,6 +203,7 @@ describe('MDC-based MatTabNavBar', () => { spyOn(inkBar, 'hide'); fixture.componentInstance.tabLinks.forEach(link => (link.active = false)); + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(inkBar.hide).toHaveBeenCalled(); @@ -238,6 +234,7 @@ describe('MDC-based MatTabNavBar', () => { let link = fixture.debugElement.nativeElement.querySelector('.mat-mdc-tab-link'); fixture.componentInstance.isDestroyed = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); dispatchMouseEvent(link, 'mousedown'); @@ -253,11 +250,13 @@ describe('MDC-based MatTabNavBar', () => { instance.tabs = []; instance.activeIndex = 1; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(instance.tabNavBar.selectedIndex).toBe(-1); instance.tabs = [0, 1, 2]; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(instance.tabNavBar.selectedIndex).toBe(1); @@ -374,6 +373,7 @@ describe('MDC-based MatTabNavBar', () => { .toBe(true); fixture.componentInstance.disableRippleOnBar = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(fixture.componentInstance.tabLinks.toArray().every(tabLink => tabLink.rippleDisabled)) @@ -390,6 +390,7 @@ describe('MDC-based MatTabNavBar', () => { firstTab.disableRipple = true; fixture.componentInstance.disableRippleOnBar = false; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); expect(firstTab.rippleDisabled) @@ -413,6 +414,7 @@ describe('MDC-based MatTabNavBar', () => { const tabLinkElement = tabLinkDebug.nativeElement; fixture.componentInstance.disableRippleOnLink = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); dispatchMouseEvent(tabLinkElement, 'mousedown'); @@ -454,6 +456,7 @@ describe('MDC-based MatTabNavBar', () => { beforeEach(() => { fixture = TestBed.createComponent(SimpleTabNavBarTestApp); fixture.componentInstance.fitInkBarToContent = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); }); @@ -467,6 +470,7 @@ describe('MDC-based MatTabNavBar', () => { it('should be able to move the ink bar between content and full', () => { fixture.componentInstance.fitInkBarToContent = false; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); const tabElement = fixture.nativeElement.querySelector('.mdc-tab'); @@ -475,6 +479,7 @@ describe('MDC-based MatTabNavBar', () => { expect(indicatorElement.parentElement).toBe(tabElement); fixture.componentInstance.fitInkBarToContent = true; + fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); const contentElement = tabElement.querySelector('.mdc-tab__content'); diff --git a/tslint.json b/tslint.json index c5eef598c560..44b6eb818a7a 100644 --- a/tslint.json +++ b/tslint.json @@ -190,8 +190,6 @@ // TODO(mmalerba): following files to be cleaned up and removed from this list: "**/src/cdk/testing/tests/testbed.spec.ts", "**/src/material/select/**/*.spec.ts", - "**/src/material/stepper/**/*.spec.ts", - "**/src/material/tabs/**/*.spec.ts", "**/src/material/tooltip/testing/tooltip-harness.spec.ts" ] ]