diff --git a/src/cdk-experimental/popover-edit/popover-edit.spec.ts b/src/cdk-experimental/popover-edit/popover-edit.spec.ts index c08a22b7c6fa..5fabe4bd1ee3 100644 --- a/src/cdk-experimental/popover-edit/popover-edit.spec.ts +++ b/src/cdk-experimental/popover-edit/popover-edit.spec.ts @@ -23,385 +23,26 @@ import { PopoverEditClickOutBehavior, } from './index'; -const NAME_EDIT_TEMPLATE = ` -
-
- - -
- - - -
-
- `; - -const WEIGHT_EDIT_TEMPLATE = ` -
-
- -
-
- `; - -const CELL_TEMPLATE = ` - {{element.name}} - - - - - `; - -const POPOVER_EDIT_DIRECTIVE_NAME = ` - [cdkPopoverEdit]="nameEdit" - [cdkPopoverEditColspan]="colspan" - [cdkPopoverEditDisabled]="nameEditDisabled" - [cdkPopoverEditAriaLabel]="nameEditAriaLabel" - `; - -const POPOVER_EDIT_DIRECTIVE_WEIGHT = `[cdkPopoverEdit]="weightEdit" cdkPopoverEditTabOut`; - interface PeriodicElement { name: string; weight: number; } -@Directive() -abstract class BaseTestComponent { - @ViewChild('table') table: ElementRef; - - preservedValues = new FormValueContainer(); - nameEditDisabled = false; - nameEditAriaLabel: string | undefined = undefined; - ignoreSubmitUnlessValid = true; - clickOutBehavior: PopoverEditClickOutBehavior = 'close'; - colspan: CdkPopoverEditColspan = {}; - direction: Direction = 'ltr'; - cdr = inject(ChangeDetectorRef); - - constructor() { - this.renderData(); - } - - abstract renderData(): void; - - onSubmit(element: PeriodicElement, form: NgForm) { - if (!form.valid) { - return; - } - - element.name = form.value['name']; - } - - triggerHoverState(rowIndex = 0) { - const row = getRows(this.table.nativeElement)[rowIndex]; - row.dispatchEvent(new Event('mouseover', {bubbles: true})); - row.dispatchEvent(new Event('mousemove', {bubbles: true})); - - // Wait for the mouse hover debounce in edit-event-dispatcher. - tick(41); - } - - getRows() { - return getRows(this.table.nativeElement); - } - - getEditCell(rowIndex = 0, cellIndex = 1) { - const row = this.getRows()[rowIndex]; - return getCells(row)[cellIndex]; - } - - focusEditCell(rowIndex = 0, cellIndex = 1) { - this.getEditCell(rowIndex, cellIndex).focus(); - } - - hoverContentStateForRow(rowIndex = 0) { - const openButton = this.getOpenButton(rowIndex); - - if (!openButton) { - return HoverContentState.OFF; - } - return parseInt(getComputedStyle(openButton.parentNode as Element).opacity || '', 10) === 0 - ? HoverContentState.FOCUSABLE - : HoverContentState.ON; - } - - getOpenButton(rowIndex = 0) { - return this.getEditCell(rowIndex).querySelector('.open') as HTMLElement | null; - } - - clickOpenButton(rowIndex = 0) { - this.getOpenButton(rowIndex)!.click(); - } - - openLens(rowIndex = 0, cellIndex = 1) { - this.focusEditCell(rowIndex, cellIndex); - this.getEditCell(rowIndex, cellIndex).dispatchEvent( - new KeyboardEvent('keydown', {bubbles: true, key: 'Enter'}), - ); - flush(); - } - - getEditPane() { - return document.querySelector('.cdk-edit-pane'); - } - - getEditBoundingBox() { - return document.querySelector('.cdk-overlay-connected-position-bounding-box'); - } - - getNameInput() { - return document.querySelector('input[name="name"]') as HTMLInputElement | null; - } - - getWeightInput() { - return document.querySelector('input[name="weight"]') as HTMLInputElement | null; - } - - lensIsOpen() { - return !!this.getNameInput(); - } - - getSubmitButton() { - return document.querySelector('.submit') as HTMLElement | null; - } - - clickSubmitButton() { - this.getSubmitButton()!.click(); - } - - getRevertButton() { - return document.querySelector('.revert') as HTMLElement | null; - } - - clickRevertButton() { - this.getRevertButton()!.click(); - } - - getCloseButton() { - return document.querySelector('.close') as HTMLElement | null; - } - - clickCloseButton() { - this.getCloseButton()!.click(); - } -} - -@Component({ - template: ` - - - ${NAME_EDIT_TEMPLATE} - - - - ${WEIGHT_EDIT_TEMPLATE} - - - @for (element of elements; track element) { - - - - - - - - } -
just a cell - ${CELL_TEMPLATE} - - {{element.weight}} -
- `, - standalone: false, -}) -class VanillaTableOutOfCell extends BaseTestComponent { - elements: ChemicalElement[]; - - renderData() { - this.elements = createElementData(); - this.cdr.markForCheck(); - } -} - -@Component({ - template: ` - - @for (element of elements; track element) { - - - - - - - - } -
just a cell - ${CELL_TEMPLATE} - - - ${NAME_EDIT_TEMPLATE} - - - {{element.weight}} - - - ${WEIGHT_EDIT_TEMPLATE} - -
- `, - standalone: false, -}) -class VanillaTableInCell extends BaseTestComponent { - elements: ChemicalElement[]; - - renderData() { - this.elements = createElementData(); - this.cdr.markForCheck(); - } -} - -class ElementDataSource extends DataSource { - /** Stream of data that is provided to the table. */ - data = new BehaviorSubject(createElementData()); - - /** Connect function called by the table to retrieve one stream containing the data to render. */ - connect() { - return this.data; - } - - disconnect() {} -} - -@Component({ - template: ` -
- - - - just a cell - - - - - - ${CELL_TEMPLATE} - - - ${NAME_EDIT_TEMPLATE} - - - - - - - - - - - {{element.weight}} - - - ${WEIGHT_EDIT_TEMPLATE} - - - - - - -
- `, - standalone: false, -}) -class CdkFlexTableInCell extends BaseTestComponent { - displayedColumns = ['before', 'name', 'weight']; - dataSource: ElementDataSource; - - renderData() { - this.dataSource = new ElementDataSource(); - this.cdr.markForCheck(); - } -} - -@Component({ - template: ` -
- - - - - - - - - - - - - - -
- just a cell - - ${CELL_TEMPLATE} - - - ${NAME_EDIT_TEMPLATE} - - - - - - - {{element.weight}} - - - ${WEIGHT_EDIT_TEMPLATE} - -
-
- `, - standalone: false, -}) -class CdkTableInCell extends BaseTestComponent { - displayedColumns = ['before', 'name', 'weight']; - dataSource: ElementDataSource; - - renderData() { - this.dataSource = new ElementDataSource(); - this.cdr.markForCheck(); - } -} - const testCases = [ - [VanillaTableOutOfCell, 'Vanilla HTML table; edit defined outside of cell'], - [VanillaTableInCell, 'Vanilla HTML table; edit defined within cell'], - [CdkFlexTableInCell, 'Flex cdk-table; edit defined within cell'], - [CdkTableInCell, 'Table cdk-table; edit defined within cell'], + [() => VanillaTableOutOfCell, 'Vanilla HTML table; edit defined outside of cell'], + [() => VanillaTableInCell, 'Vanilla HTML table; edit defined within cell'], + [() => CdkFlexTableInCell, 'Flex cdk-table; edit defined within cell'], + [() => CdkTableInCell, 'Table cdk-table; edit defined within cell'], ] as const; describe('CDK Popover Edit', () => { - for (const [componentClass, label] of testCases) { + for (const [getComponentClass, label] of testCases) { describe(label, () => { let component: BaseTestComponent; let fixture: ComponentFixture; beforeEach(fakeAsync(() => { - TestBed.configureTestingModule({ - imports: [CdkTableModule, CdkPopoverEditModule, FormsModule, BidiModule], - declarations: [componentClass], - }); - fixture = TestBed.createComponent(componentClass); + fixture = TestBed.createComponent(getComponentClass()); component = fixture.componentInstance; component.renderData(); fixture.detectChanges(); @@ -759,290 +400,694 @@ cdkPopoverEditTabOut`, fakeAsync(() => { component.openLens(); fixture.detectChanges(); - let paneRect = component.getEditPane()!.getBoundingClientRect(); - expectPixelsToEqual(paneRect.top, cellRects[0].top); - expectPixelsToEqual(paneRect.left, cellRects[0].left); - expectPixelsToEqual(paneRect.right, cellRects[1].right); + let paneRect = component.getEditPane()!.getBoundingClientRect(); + expectPixelsToEqual(paneRect.top, cellRects[0].top); + expectPixelsToEqual(paneRect.left, cellRects[0].left); + expectPixelsToEqual(paneRect.right, cellRects[1].right); + + component.colspan = {after: 1}; + fixture.changeDetectorRef.markForCheck(); + fixture.detectChanges(); + + paneRect = component.getEditPane()!.getBoundingClientRect(); + expectPixelsToEqual(paneRect.top, cellRects[1].top); + expectPixelsToEqual(paneRect.left, cellRects[1].left); + expectPixelsToEqual(paneRect.right, cellRects[2].right); + + component.colspan = {before: 1, after: 1}; + fixture.changeDetectorRef.markForCheck(); + fixture.detectChanges(); + + paneRect = component.getEditPane()!.getBoundingClientRect(); + expectPixelsToEqual(paneRect.top, cellRects[0].top); + expectPixelsToEqual(paneRect.left, cellRects[0].left); + expectPixelsToEqual(paneRect.right, cellRects[2].right); + clearLeftoverTimers(); + })); + + it('updates the form and submits, closing the lens', fakeAsync(() => { + component.openLens(); + fixture.detectChanges(); + + component.getNameInput()!.value = 'Hydragon'; + component.getNameInput()!.dispatchEvent(new Event('input')); + + component.clickSubmitButton(); + fixture.detectChanges(); + expect(component.getEditCell().firstChild!.textContent!.trim()).toBe('Hydragon'); + expect(component.lensIsOpen()).toBe(false); + clearLeftoverTimers(); + })); + + it('does not close the lens on submit when form is invalid', fakeAsync(() => { + component.openLens(); + fixture.detectChanges(); + + component.getNameInput()!.value = ''; + component.getNameInput()!.dispatchEvent(new Event('input')); + + component.clickSubmitButton(); + + expect(component.lensIsOpen()).toBe(true); + clearLeftoverTimers(); + })); + + it( + 'closes lens on submit when form is invalid with ' + + 'cdkEditControlIgnoreSubmitUnlessValid = false', + fakeAsync(() => { + component.ignoreSubmitUnlessValid = false; + component.openLens(); + fixture.detectChanges(); + + component.getNameInput()!.value = ''; + component.getNameInput()!.dispatchEvent(new Event('input')); + + component.clickSubmitButton(); + + expect(component.lensIsOpen()).toBe(false); + clearLeftoverTimers(); + }), + ); + + it('closes the lens on close', fakeAsync(() => { + component.openLens(); + fixture.detectChanges(); + + component.clickCloseButton(); + + expect(component.lensIsOpen()).toBe(false); + clearLeftoverTimers(); + })); + + it('closes and reopens a lens with modified value persisted', fakeAsync(() => { + component.openLens(); + fixture.detectChanges(); + + component.getNameInput()!.value = 'Hydragon'; + component.getNameInput()!.dispatchEvent(new Event('input')); + + component.clickCloseButton(); + fixture.detectChanges(); + + expect(component.getEditCell().firstChild!.textContent!.trim()).toBe('Hydrogen'); + expect(component.lensIsOpen()).toBe(false); + + component.openLens(); + fixture.detectChanges(); + + expect(component.getNameInput()!.value).toBe('Hydragon'); + clearLeftoverTimers(); + })); + + it('resets the lens to original value', fakeAsync(() => { + component.openLens(); + fixture.detectChanges(); + + component.getNameInput()!.value = 'Hydragon'; + component.getNameInput()!.dispatchEvent(new Event('input')); + + component.clickRevertButton(); + + expect(component.getNameInput()!.value).toBe('Hydrogen'); + clearLeftoverTimers(); + })); + + it('should not reset the values when clicking revert without making changes', fakeAsync(() => { + component.openLens(); + fixture.detectChanges(); + + expect(component.getNameInput()!.value).toBe('Hydrogen'); + expect(component.getWeightInput()!.value).toBe('1.007'); + + component.clickRevertButton(); + + expect(component.getNameInput()!.value).toBe('Hydrogen'); + expect(component.getWeightInput()!.value).toBe('1.007'); + clearLeftoverTimers(); + })); + + it('resets the lens to previously submitted value', fakeAsync(() => { + component.openLens(); + fixture.detectChanges(); + + component.getNameInput()!.value = 'Hydragon'; + component.getNameInput()!.dispatchEvent(new Event('input')); + + component.clickSubmitButton(); + fixture.detectChanges(); + + component.openLens(); + fixture.detectChanges(); + + component.getNameInput()!.value = 'Hydragon X'; + component.getNameInput()!.dispatchEvent(new Event('input')); + + component.clickRevertButton(); + + expect(component.getNameInput()!.value).toBe('Hydragon'); + clearLeftoverTimers(); + })); + + it('closes the lens on escape', fakeAsync(() => { + component.openLens(); + fixture.detectChanges(); + + const event = new KeyboardEvent('keydown', {bubbles: true, key: 'Escape'}); + spyOn(event, 'preventDefault').and.callThrough(); + component.getNameInput()!.dispatchEvent(event); - component.colspan = {after: 1}; - fixture.changeDetectorRef.markForCheck(); + expect(component.lensIsOpen()).toBe(false); + expect(event.preventDefault).toHaveBeenCalled(); + clearLeftoverTimers(); + })); + + it('does not close the lens on escape with a modifier key', fakeAsync(() => { + component.openLens(); fixture.detectChanges(); - paneRect = component.getEditPane()!.getBoundingClientRect(); - expectPixelsToEqual(paneRect.top, cellRects[1].top); - expectPixelsToEqual(paneRect.left, cellRects[1].left); - expectPixelsToEqual(paneRect.right, cellRects[2].right); + const event = new KeyboardEvent('keydown', {bubbles: true, key: 'Escape'}); + Object.defineProperty(event, 'altKey', {get: () => true}); - component.colspan = {before: 1, after: 1}; - fixture.changeDetectorRef.markForCheck(); - fixture.detectChanges(); + spyOn(event, 'preventDefault').and.callThrough(); + component.getNameInput()!.dispatchEvent(event); - paneRect = component.getEditPane()!.getBoundingClientRect(); - expectPixelsToEqual(paneRect.top, cellRects[0].top); - expectPixelsToEqual(paneRect.left, cellRects[0].left); - expectPixelsToEqual(paneRect.right, cellRects[2].right); + expect(component.lensIsOpen()).toBe(true); + expect(event.preventDefault).not.toHaveBeenCalled(); clearLeftoverTimers(); })); - it('updates the form and submits, closing the lens', fakeAsync(() => { + it('does not close the lens on click within lens', fakeAsync(() => { component.openLens(); fixture.detectChanges(); - component.getNameInput()!.value = 'Hydragon'; - component.getNameInput()!.dispatchEvent(new Event('input')); + component.getNameInput()!.dispatchEvent(new Event('click', {bubbles: true})); - component.clickSubmitButton(); - fixture.detectChanges(); - expect(component.getEditCell().firstChild!.textContent!.trim()).toBe('Hydragon'); - expect(component.lensIsOpen()).toBe(false); + expect(component.lensIsOpen()).toBe(true); clearLeftoverTimers(); })); - it('does not close the lens on submit when form is invalid', fakeAsync(() => { + it('closes the lens on outside click', fakeAsync(() => { component.openLens(); fixture.detectChanges(); - component.getNameInput()!.value = ''; + component.getNameInput()!.value = 'Hydragon'; component.getNameInput()!.dispatchEvent(new Event('input')); + document.body.dispatchEvent(new Event('click', {bubbles: true})); + fixture.detectChanges(); - component.clickSubmitButton(); - - expect(component.lensIsOpen()).toBe(true); + expect(component.lensIsOpen()).toBe(false); + expect(component.getEditCell().firstChild!.textContent!.trim()).toBe('Hydrogen'); clearLeftoverTimers(); })); it( - 'closes lens on submit when form is invalid with ' + - 'cdkEditControlIgnoreSubmitUnlessValid = false', + 'submits the lens on outside click with ' + 'cdkEditControlClickOutBehavior = "submit"', fakeAsync(() => { - component.ignoreSubmitUnlessValid = false; + component.clickOutBehavior = 'submit'; component.openLens(); fixture.detectChanges(); - component.getNameInput()!.value = ''; + component.getNameInput()!.value = 'Hydragon'; component.getNameInput()!.dispatchEvent(new Event('input')); - - component.clickSubmitButton(); + document.body.dispatchEvent(new Event('click', {bubbles: true})); + fixture.detectChanges(); expect(component.lensIsOpen()).toBe(false); + expect(component.getEditCell().firstChild!.textContent!.trim()).toBe('Hydragon'); clearLeftoverTimers(); }), ); - it('closes the lens on close', fakeAsync(() => { + it( + 'does nothing on outside click with ' + 'cdkEditControlClickOutBehavior = "noop"', + fakeAsync(() => { + component.clickOutBehavior = 'noop'; + component.openLens(); + fixture.detectChanges(); + + component.getNameInput()!.value = 'Hydragon'; + component.getNameInput()!.dispatchEvent(new Event('input')); + document.body.dispatchEvent(new Event('click', {bubbles: true})); + fixture.detectChanges(); + + expect(component.lensIsOpen()).toBe(true); + expect(component.getEditCell().firstChild!.textContent!.trim()).toBe('Hydrogen'); + clearLeftoverTimers(); + }), + ); + + it('sets focus on the first input in the lens', fakeAsync(() => { component.openLens(); fixture.detectChanges(); - component.clickCloseButton(); - - expect(component.lensIsOpen()).toBe(false); + expect(document.activeElement).toBe(component.getNameInput()); clearLeftoverTimers(); })); - it('closes and reopens a lens with modified value persisted', fakeAsync(() => { + it('returns focus to the edited cell after closing', fakeAsync(() => { component.openLens(); fixture.detectChanges(); - component.getNameInput()!.value = 'Hydragon'; - component.getNameInput()!.dispatchEvent(new Event('input')); - component.clickCloseButton(); - fixture.detectChanges(); - expect(component.getEditCell().firstChild!.textContent!.trim()).toBe('Hydrogen'); - expect(component.lensIsOpen()).toBe(false); + expect(document.activeElement).toBe(component.getEditCell()); + clearLeftoverTimers(); + })); + + it( + 'does not focus to the edited cell after closing if another element ' + + 'outside the lens is already focused', + fakeAsync(() => { + component.openLens(0); + + component.getEditCell(1).focus(); + component.getEditCell(1).dispatchEvent(new Event('click', {bubbles: true})); + + expect(document.activeElement).toBe(component.getEditCell(1)); + clearLeftoverTimers(); + }), + ); + + it('should pass the directionality to the overlay', fakeAsync(() => { + component.direction = 'rtl'; + fixture.changeDetectorRef.markForCheck(); + fixture.detectChanges(); component.openLens(); fixture.detectChanges(); - expect(component.getNameInput()!.value).toBe('Hydragon'); + expect(component.getEditBoundingBox()!.getAttribute('dir')).toBe('rtl'); clearLeftoverTimers(); })); + }); + }); + } +}); - it('resets the lens to original value', fakeAsync(() => { - component.openLens(); - fixture.detectChanges(); +@Directive() +abstract class BaseTestComponent { + @ViewChild('table') table: ElementRef; - component.getNameInput()!.value = 'Hydragon'; - component.getNameInput()!.dispatchEvent(new Event('input')); + preservedValues = new FormValueContainer(); + nameEditDisabled = false; + nameEditAriaLabel: string | undefined = undefined; + ignoreSubmitUnlessValid = true; + clickOutBehavior: PopoverEditClickOutBehavior = 'close'; + colspan: CdkPopoverEditColspan = {}; + direction: Direction = 'ltr'; + cdr = inject(ChangeDetectorRef); - component.clickRevertButton(); + constructor() { + this.renderData(); + } - expect(component.getNameInput()!.value).toBe('Hydrogen'); - clearLeftoverTimers(); - })); + abstract renderData(): void; - it('should not reset the values when clicking revert without making changes', fakeAsync(() => { - component.openLens(); - fixture.detectChanges(); + onSubmit(element: PeriodicElement, form: NgForm) { + if (!form.valid) { + return; + } - expect(component.getNameInput()!.value).toBe('Hydrogen'); - expect(component.getWeightInput()!.value).toBe('1.007'); + element.name = form.value['name']; + } - component.clickRevertButton(); + triggerHoverState(rowIndex = 0) { + const row = getRows(this.table.nativeElement)[rowIndex]; + row.dispatchEvent(new Event('mouseover', {bubbles: true})); + row.dispatchEvent(new Event('mousemove', {bubbles: true})); - expect(component.getNameInput()!.value).toBe('Hydrogen'); - expect(component.getWeightInput()!.value).toBe('1.007'); - clearLeftoverTimers(); - })); + // Wait for the mouse hover debounce in edit-event-dispatcher. + tick(41); + } - it('resets the lens to previously submitted value', fakeAsync(() => { - component.openLens(); - fixture.detectChanges(); + getRows() { + return getRows(this.table.nativeElement); + } - component.getNameInput()!.value = 'Hydragon'; - component.getNameInput()!.dispatchEvent(new Event('input')); + getEditCell(rowIndex = 0, cellIndex = 1) { + const row = this.getRows()[rowIndex]; + return getCells(row)[cellIndex]; + } - component.clickSubmitButton(); - fixture.detectChanges(); + focusEditCell(rowIndex = 0, cellIndex = 1) { + this.getEditCell(rowIndex, cellIndex).focus(); + } - component.openLens(); - fixture.detectChanges(); + hoverContentStateForRow(rowIndex = 0) { + const openButton = this.getOpenButton(rowIndex); + + if (!openButton) { + return HoverContentState.OFF; + } + return parseInt(getComputedStyle(openButton.parentNode as Element).opacity || '', 10) === 0 + ? HoverContentState.FOCUSABLE + : HoverContentState.ON; + } + + getOpenButton(rowIndex = 0) { + return this.getEditCell(rowIndex).querySelector('.open') as HTMLElement | null; + } + + clickOpenButton(rowIndex = 0) { + this.getOpenButton(rowIndex)!.click(); + } + + openLens(rowIndex = 0, cellIndex = 1) { + this.focusEditCell(rowIndex, cellIndex); + this.getEditCell(rowIndex, cellIndex).dispatchEvent( + new KeyboardEvent('keydown', {bubbles: true, key: 'Enter'}), + ); + flush(); + } + + getEditPane() { + return document.querySelector('.cdk-edit-pane'); + } + + getEditBoundingBox() { + return document.querySelector('.cdk-overlay-connected-position-bounding-box'); + } + + getNameInput() { + return document.querySelector('input[name="name"]') as HTMLInputElement | null; + } + + getWeightInput() { + return document.querySelector('input[name="weight"]') as HTMLInputElement | null; + } + + lensIsOpen() { + return !!this.getNameInput(); + } + + getSubmitButton() { + return document.querySelector('.submit') as HTMLElement | null; + } + + clickSubmitButton() { + this.getSubmitButton()!.click(); + } + + getRevertButton() { + return document.querySelector('.revert') as HTMLElement | null; + } + + clickRevertButton() { + this.getRevertButton()!.click(); + } - component.getNameInput()!.value = 'Hydragon X'; - component.getNameInput()!.dispatchEvent(new Event('input')); + getCloseButton() { + return document.querySelector('.close') as HTMLElement | null; + } - component.clickRevertButton(); + clickCloseButton() { + this.getCloseButton()!.click(); + } +} - expect(component.getNameInput()!.value).toBe('Hydragon'); - clearLeftoverTimers(); - })); +@Component({ + template: ` + + +
+
+ + +
+ + + + +
+
- it('closes the lens on escape', fakeAsync(() => { - component.openLens(); - fixture.detectChanges(); + +
+
+ + +
+
- const event = new KeyboardEvent('keydown', {bubbles: true, key: 'Escape'}); - spyOn(event, 'preventDefault').and.callThrough(); - component.getNameInput()!.dispatchEvent(event); + @for (element of elements; track element) { + + - expect(component.lensIsOpen()).toBe(false); - expect(event.preventDefault).toHaveBeenCalled(); - clearLeftoverTimers(); - })); + - it('does not close the lens on escape with a modifier key', fakeAsync(() => { - component.openLens(); - fixture.detectChanges(); + + + } +
just a cell + {{element.name}} + + + + + {{element.weight}} +
+ `, + imports: [CdkPopoverEditModule, FormsModule, CdkTableModule, BidiModule], +}) +class VanillaTableOutOfCell extends BaseTestComponent { + elements: ChemicalElement[]; - const event = new KeyboardEvent('keydown', {bubbles: true, key: 'Escape'}); - Object.defineProperty(event, 'altKey', {get: () => true}); + renderData() { + this.elements = createElementData(); + this.cdr.markForCheck(); + } +} - spyOn(event, 'preventDefault').and.callThrough(); - component.getNameInput()!.dispatchEvent(event); +@Component({ + template: ` + + @for (element of elements; track element) { + + - expect(component.lensIsOpen()).toBe(true); - expect(event.preventDefault).not.toHaveBeenCalled(); - clearLeftoverTimers(); - })); + - component.getNameInput()!.dispatchEvent(new Event('click', {bubbles: true})); + + + } +
just a cell + {{element.name}} + + + - it('does not close the lens on click within lens', fakeAsync(() => { - component.openLens(); - fixture.detectChanges(); + +
+
+ + +
+ + + +
+
+
+
+ {{element.weight}} - expect(component.lensIsOpen()).toBe(true); - clearLeftoverTimers(); - })); + +
+
+ +
+
+
+
+ `, + imports: [CdkPopoverEditModule, FormsModule, CdkTableModule, BidiModule], +}) +class VanillaTableInCell extends BaseTestComponent { + elements: ChemicalElement[]; - it('closes the lens on outside click', fakeAsync(() => { - component.openLens(); - fixture.detectChanges(); + renderData() { + this.elements = createElementData(); + this.cdr.markForCheck(); + } +} - component.getNameInput()!.value = 'Hydragon'; - component.getNameInput()!.dispatchEvent(new Event('input')); - document.body.dispatchEvent(new Event('click', {bubbles: true})); - fixture.detectChanges(); +class ElementDataSource extends DataSource { + /** Stream of data that is provided to the table. */ + data = new BehaviorSubject(createElementData()); - expect(component.lensIsOpen()).toBe(false); - expect(component.getEditCell().firstChild!.textContent!.trim()).toBe('Hydrogen'); - clearLeftoverTimers(); - })); + /** Connect function called by the table to retrieve one stream containing the data to render. */ + connect() { + return this.data; + } - it( - 'submits the lens on outside click with ' + 'cdkEditControlClickOutBehavior = "submit"', - fakeAsync(() => { - component.clickOutBehavior = 'submit'; - component.openLens(); - fixture.detectChanges(); + disconnect() {} +} - component.getNameInput()!.value = 'Hydragon'; - component.getNameInput()!.dispatchEvent(new Event('input')); - document.body.dispatchEvent(new Event('click', {bubbles: true})); - fixture.detectChanges(); +@Component({ + template: ` +
+ + + + just a cell + + - expect(component.lensIsOpen()).toBe(false); - expect(component.getEditCell().firstChild!.textContent!.trim()).toBe('Hydragon'); - clearLeftoverTimers(); - }), - ); + + + {{element.name}} + + + - it( - 'does nothing on outside click with ' + 'cdkEditControlClickOutBehavior = "noop"', - fakeAsync(() => { - component.clickOutBehavior = 'noop'; - component.openLens(); - fixture.detectChanges(); + +
+
+ + +
+ + + +
+
+
- component.getNameInput()!.value = 'Hydragon'; - component.getNameInput()!.dispatchEvent(new Event('input')); - document.body.dispatchEvent(new Event('click', {bubbles: true})); - fixture.detectChanges(); + + + +
+
- expect(component.lensIsOpen()).toBe(true); - expect(component.getEditCell().firstChild!.textContent!.trim()).toBe('Hydrogen'); - clearLeftoverTimers(); - }), - ); + + + {{element.weight}} - it('sets focus on the first input in the lens', fakeAsync(() => { - component.openLens(); - fixture.detectChanges(); + +
+
+ +
+
+
+
+
- expect(document.activeElement).toBe(component.getNameInput()); - clearLeftoverTimers(); - })); + +
+
+ `, + imports: [CdkPopoverEditModule, FormsModule, CdkTableModule, BidiModule], +}) +class CdkFlexTableInCell extends BaseTestComponent { + displayedColumns = ['before', 'name', 'weight']; + dataSource: ElementDataSource; - it('returns focus to the edited cell after closing', fakeAsync(() => { - component.openLens(); - fixture.detectChanges(); + renderData() { + this.dataSource = new ElementDataSource(); + this.cdr.markForCheck(); + } +} - component.clickCloseButton(); +@Component({ + template: ` +
+ + + + - expect(document.activeElement).toBe(component.getEditCell()); - clearLeftoverTimers(); - })); + + + - expect(document.activeElement).toBe(component.getEditCell(1)); - clearLeftoverTimers(); - }), - ); + + + - component.openLens(); - fixture.detectChanges(); + +
+ just a cell + + {{element.name}} + + + - it( - 'does not focus to the edited cell after closing if another element ' + - 'outside the lens is already focused', - fakeAsync(() => { - component.openLens(0); + +
+
+ + +
+ + + +
+
+
- component.getEditCell(1).focus(); - component.getEditCell(1).dispatchEvent(new Event('click', {bubbles: true})); + + + +
+ {{element.weight}} - it('should pass the directionality to the overlay', fakeAsync(() => { - component.direction = 'rtl'; - fixture.changeDetectorRef.markForCheck(); - fixture.detectChanges(); + +
+
+ +
+
+
+
+
+ `, + imports: [CdkPopoverEditModule, FormsModule, CdkTableModule, BidiModule], +}) +class CdkTableInCell extends BaseTestComponent { + displayedColumns = ['before', 'name', 'weight']; + dataSource: ElementDataSource; - expect(component.getEditBoundingBox()!.getAttribute('dir')).toBe('rtl'); - clearLeftoverTimers(); - })); - }); - }); + renderData() { + this.dataSource = new ElementDataSource(); + this.cdr.markForCheck(); } -}); +} @Component({ template: ` @@ -1056,11 +1101,31 @@ cdkPopoverEditTabOut`, fakeAsync(() => { - ${CELL_TEMPLATE} + [cdkPopoverEdit]="nameEdit" + [cdkPopoverEditColspan]="colspan" + [cdkPopoverEditDisabled]="nameEditDisabled" + [cdkPopoverEditAriaLabel]="nameEditAriaLabel"> + {{element.name}} + + + - ${NAME_EDIT_TEMPLATE} +
+
+ + +
+ + + +
+
@@ -1070,12 +1135,15 @@ cdkPopoverEditTabOut`, fakeAsync(() => {
- + {{element.weight}} - ${WEIGHT_EDIT_TEMPLATE} +
+
+ +
+
@@ -1090,7 +1158,7 @@ cdkPopoverEditTabOut`, fakeAsync(() => {
`, - standalone: false, + imports: [CdkPopoverEditModule, FormsModule, CdkTableModule, BidiModule], }) class CdkTableWithSkipRows extends BaseTestComponent { displayedColumns = ['before', 'name', 'weight']; @@ -1110,10 +1178,6 @@ describe('CDK Popover Edit - with focus ignore rows', () => { dispatchKeyboardEvent(cell, 'keydown', keyCode); beforeEach(fakeAsync(() => { - TestBed.configureTestingModule({ - imports: [CdkTableModule, CdkPopoverEditModule, FormsModule, BidiModule], - declarations: [CdkTableWithSkipRows], - }); fixture = TestBed.createComponent(CdkTableWithSkipRows); component = fixture.componentInstance; component.renderData(); diff --git a/src/cdk/dialog/dialog.spec.ts b/src/cdk/dialog/dialog.spec.ts index 71383634c35b..c36e70516fb4 100644 --- a/src/cdk/dialog/dialog.spec.ts +++ b/src/cdk/dialog/dialog.spec.ts @@ -46,18 +46,6 @@ describe('Dialog', () => { beforeEach(fakeAsync(() => { TestBed.configureTestingModule({ - imports: [ - DialogModule, - ComponentWithChildViewContainer, - ComponentWithTemplateRef, - PizzaMsg, - ContentElementDialog, - DialogWithInjectedData, - DialogWithoutFocusableElements, - DirectiveWithViewContainer, - TemplateInjectorParentComponent, - TemplateInjectorInnerDirective, - ], providers: [ {provide: Location, useClass: SpyLocation}, {provide: TEMPLATE_INJECTOR_TEST_TOKEN, useValue: 'hello from test module'}, @@ -1416,7 +1404,6 @@ class DirectiveWithViewContainer { @Component({ changeDetection: ChangeDetectionStrategy.OnPush, template: 'hello', - standalone: false, }) class ComponentWithOnPushViewContainer { viewContainerRef = inject(ViewContainerRef); @@ -1509,7 +1496,6 @@ class DialogWithoutFocusableElements {} @Component({ template: ``, encapsulation: ViewEncapsulation.ShadowDom, - standalone: false, }) class ShadowDomComponent {} diff --git a/src/cdk/listbox/listbox.spec.ts b/src/cdk/listbox/listbox.spec.ts index a986f13eaf18..56a2817283d1 100644 --- a/src/cdk/listbox/listbox.spec.ts +++ b/src/cdk/listbox/listbox.spec.ts @@ -4,13 +4,9 @@ import {TestBed, fakeAsync, tick} from '@angular/core/testing'; import {FormControl, ReactiveFormsModule} from '@angular/forms'; import {By} from '@angular/platform-browser'; import {dispatchFakeEvent, dispatchKeyboardEvent, dispatchMouseEvent} from '../testing/private'; -import {CdkListbox, CdkListboxModule, CdkOption, ListboxValueChangeEvent} from './index'; +import {CdkListbox, CdkOption, ListboxValueChangeEvent} from './index'; -function setupComponent(component: Type, imports: any[] = []) { - TestBed.configureTestingModule({ - imports: [CdkListboxModule, ...imports], - declarations: [component], - }); +function setupComponent(component: Type) { const fixture = TestBed.createComponent(component); fixture.detectChanges(); @@ -861,9 +857,7 @@ describe('CdkOption and CdkListbox', () => { describe('with FormControl', () => { it('should reflect disabled state of the FormControl', () => { - const {testComponent, fixture, listbox} = setupComponent(ListboxWithFormControl, [ - ReactiveFormsModule, - ]); + const {testComponent, fixture, listbox} = setupComponent(ListboxWithFormControl); testComponent.formControl.disable(); fixture.detectChanges(); @@ -871,9 +865,7 @@ describe('CdkOption and CdkListbox', () => { }); it('should update when FormControl value changes', () => { - const {testComponent, fixture, options} = setupComponent(ListboxWithFormControl, [ - ReactiveFormsModule, - ]); + const {testComponent, fixture, options} = setupComponent(ListboxWithFormControl); testComponent.formControl.setValue(['banana']); fixture.detectChanges(); @@ -881,9 +873,7 @@ describe('CdkOption and CdkListbox', () => { }); it('should update FormControl when selection changes', () => { - const {testComponent, fixture, optionEls} = setupComponent(ListboxWithFormControl, [ - ReactiveFormsModule, - ]); + const {testComponent, fixture, optionEls} = setupComponent(ListboxWithFormControl); const spy = jasmine.createSpy(); const subscription = testComponent.formControl.valueChanges.subscribe(spy); fixture.detectChanges(); @@ -898,9 +888,7 @@ describe('CdkOption and CdkListbox', () => { }); it('should update multi-select listbox when FormControl value changes', () => { - const {testComponent, fixture, options} = setupComponent(ListboxWithFormControl, [ - ReactiveFormsModule, - ]); + const {testComponent, fixture, options} = setupComponent(ListboxWithFormControl); testComponent.isMultiselectable = true; fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); @@ -912,9 +900,7 @@ describe('CdkOption and CdkListbox', () => { }); it('should update FormControl when multi-selection listbox changes', () => { - const {testComponent, fixture, optionEls} = setupComponent(ListboxWithFormControl, [ - ReactiveFormsModule, - ]); + const {testComponent, fixture, optionEls} = setupComponent(ListboxWithFormControl); testComponent.isMultiselectable = true; fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); @@ -935,9 +921,7 @@ describe('CdkOption and CdkListbox', () => { }); it('should throw when multiple values selected in single-select listbox', () => { - const {testComponent, fixture} = setupComponent(ListboxWithFormControl, [ - ReactiveFormsModule, - ]); + const {testComponent, fixture} = setupComponent(ListboxWithFormControl); expect(() => { testComponent.formControl.setValue(['orange', 'banana']); @@ -946,9 +930,7 @@ describe('CdkOption and CdkListbox', () => { }); it('should throw when an invalid value is selected', () => { - const {testComponent, fixture} = setupComponent(ListboxWithFormControl, [ - ReactiveFormsModule, - ]); + const {testComponent, fixture} = setupComponent(ListboxWithFormControl); testComponent.isMultiselectable = true; fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); @@ -961,13 +943,13 @@ describe('CdkOption and CdkListbox', () => { it('should not throw on init with a preselected form control and a dynamic set of options', () => { expect(() => { - setupComponent(ListboxWithPreselectedFormControl, [ReactiveFormsModule]); + setupComponent(ListboxWithPreselectedFormControl); }).not.toThrow(); }); it('should throw on init if the preselected value is invalid', () => { expect(() => { - setupComponent(ListboxWithInvalidPreselectedFormControl, [ReactiveFormsModule]); + setupComponent(ListboxWithInvalidPreselectedFormControl); }).toThrowError('Listbox has selected values that do not match any of its options.'); }); }); @@ -1000,7 +982,7 @@ describe('CdkOption and CdkListbox', () => {
Peach
`, - standalone: false, + imports: [CdkListbox, CdkOption], }) class ListboxWithOptions { changedOption: CdkOption | null; @@ -1026,7 +1008,7 @@ class ListboxWithOptions { @Component({ template: `
`, - standalone: false, + imports: [CdkListbox], }) class ListboxWithNoOptions {} @@ -1042,7 +1024,7 @@ class ListboxWithNoOptions {}
Peach
`, - standalone: false, + imports: [CdkListbox, CdkOption, ReactiveFormsModule], }) class ListboxWithFormControl { formControl = new FormControl(); @@ -1058,7 +1040,7 @@ class ListboxWithFormControl { }
`, - standalone: false, + imports: [CdkListbox, CdkOption, ReactiveFormsModule], }) class ListboxWithPreselectedFormControl { options = ['a', 'b', 'c']; @@ -1073,7 +1055,7 @@ class ListboxWithPreselectedFormControl { }
`, - standalone: false, + imports: [CdkListbox, CdkOption, ReactiveFormsModule], }) class ListboxWithInvalidPreselectedFormControl { options = ['a', 'b', 'c']; @@ -1089,7 +1071,7 @@ class ListboxWithInvalidPreselectedFormControl {
  • 🍑
  • `, - standalone: false, + imports: [CdkListbox, CdkOption], }) class ListboxWithCustomTypeahead {} @@ -1103,7 +1085,7 @@ class ListboxWithCustomTypeahead {}
    Peach
    `, - standalone: false, + imports: [CdkListbox, CdkOption], }) class ListboxWithBoundValue { value = ['banana']; @@ -1120,7 +1102,7 @@ class ListboxWithBoundValue {
    Peach
    `, - standalone: false, + imports: [CdkListbox, CdkOption], }) class ListboxWithMultipleBoundValues { value = ['apple', 'banana']; @@ -1134,7 +1116,7 @@ class ListboxWithMultipleBoundValues { } `, - standalone: false, + imports: [CdkListbox, CdkOption], }) class ListboxWithObjectValues { fruits = [{name: 'Apple'}, {name: 'Orange'}, {name: 'Banana'}, {name: 'Peach'}]; diff --git a/src/cdk/menu/context-menu-trigger.spec.ts b/src/cdk/menu/context-menu-trigger.spec.ts index 3f262ccedd63..84a8043777af 100644 --- a/src/cdk/menu/context-menu-trigger.spec.ts +++ b/src/cdk/menu/context-menu-trigger.spec.ts @@ -1,6 +1,5 @@ -import {Component, ViewChild, ElementRef, Type, ViewChildren, QueryList} from '@angular/core'; -import {CdkMenuModule} from './menu-module'; -import {TestBed, waitForAsync, ComponentFixture} from '@angular/core/testing'; +import {Component, ViewChild, ElementRef, ViewChildren, QueryList} from '@angular/core'; +import {TestBed, ComponentFixture} from '@angular/core/testing'; import {CdkMenu} from './menu'; import {CdkContextMenuTrigger} from './context-menu-trigger'; import {dispatchKeyboardEvent, dispatchMouseEvent} from '../testing/private'; @@ -14,13 +13,6 @@ describe('CdkContextMenuTrigger', () => { describe('with simple context menu trigger', () => { let fixture: ComponentFixture; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [SimpleContextMenu], - }); - })); - beforeEach(() => { fixture = TestBed.createComponent(SimpleContextMenu); fixture.detectChanges(); @@ -164,13 +156,6 @@ describe('CdkContextMenuTrigger', () => { describe('nested context menu triggers', () => { let fixture: ComponentFixture; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [NestedContextMenu], - }); - })); - beforeEach(() => { fixture = TestBed.createComponent(NestedContextMenu); fixture.detectChanges(); @@ -279,13 +264,6 @@ describe('CdkContextMenuTrigger', () => { let fixture: ComponentFixture; let instance: ContextMenuWithSubmenu; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [ContextMenuWithSubmenu], - }); - })); - beforeEach(() => { fixture = TestBed.createComponent(ContextMenuWithSubmenu); fixture.detectChanges(); @@ -310,13 +288,6 @@ describe('CdkContextMenuTrigger', () => { let nativeMenuBar: HTMLElement; let nativeMenuBarTrigger: HTMLElement; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [ContextMenuWithMenuBarAndInlineMenu], - }); - })); - beforeEach(() => { fixture = TestBed.createComponent(ContextMenuWithMenuBarAndInlineMenu); fixture.detectChanges(); @@ -410,23 +381,10 @@ describe('CdkContextMenuTrigger', () => { }); describe('with shared triggered menu', () => { - /** - * Return a function which builds the given component and renders it. - * @param componentClass the component to create - */ - function createComponent(componentClass: Type) { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [componentClass], - }); - - const fixture = TestBed.createComponent(componentClass); + it('should allow a context menu and menubar trigger share a menu', () => { + const fixture = TestBed.createComponent(MenuBarAndContextTriggerShareMenu); fixture.detectChanges(); - return fixture; - } - it('should allow a context menu and menubar trigger share a menu', () => { - const fixture = createComponent(MenuBarAndContextTriggerShareMenu); expect(fixture.componentInstance.menus.length).toBe(0); fixture.componentInstance.menuBarTrigger.toggle(); fixture.detectChanges(); @@ -441,11 +399,6 @@ describe('CdkContextMenuTrigger', () => { }); it('should be able to pass data to the menu via the template context', () => { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [ContextTriggerWithData], - }); - const fixture = TestBed.createComponent(ContextTriggerWithData); fixture.componentInstance.menuData = {message: 'Hello!'}; fixture.detectChanges(); @@ -467,7 +420,7 @@ describe('CdkContextMenuTrigger', () => { `, - standalone: false, + imports: [CdkContextMenuTrigger, CdkMenu, CdkMenuItem], }) class SimpleContextMenu { @ViewChild(CdkContextMenuTrigger) trigger: CdkContextMenuTrigger; @@ -496,7 +449,7 @@ class SimpleContextMenu {
    `, - standalone: false, + imports: [CdkContextMenuTrigger, CdkMenu], }) class NestedContextMenu { @ViewChild('cut_trigger', {read: ElementRef}) cutContext: ElementRef; @@ -522,7 +475,7 @@ class NestedContextMenu {
    `, - standalone: false, + imports: [CdkContextMenuTrigger, CdkMenuTrigger, CdkMenu, CdkMenuItem], }) class ContextMenuWithSubmenu { @ViewChild(CdkContextMenuTrigger, {read: ElementRef}) context: ElementRef; @@ -553,7 +506,7 @@ class ContextMenuWithSubmenu { `, - standalone: false, + imports: [CdkContextMenuTrigger, CdkMenuTrigger, CdkMenu, CdkMenuItem, CdkMenuBar], }) class ContextMenuWithMenuBarAndInlineMenu { @ViewChild(CdkMenuBar, {read: ElementRef}) nativeMenuBar: ElementRef; @@ -582,7 +535,7 @@ class ContextMenuWithMenuBarAndInlineMenu { `, - standalone: false, + imports: [CdkMenuBar, CdkContextMenuTrigger, CdkMenu, CdkMenuItem, CdkMenuTrigger], }) class MenuBarAndContextTriggerShareMenu { @ViewChild(CdkMenuTrigger) menuBarTrigger: CdkMenuTrigger; @@ -598,7 +551,7 @@ class MenuBarAndContextTriggerShareMenu {
    {{message}}
    `, - standalone: false, + imports: [CdkContextMenuTrigger, CdkMenu], }) class ContextTriggerWithData { @ViewChild(CdkContextMenuTrigger, {read: ElementRef}) triggerElement: ElementRef; diff --git a/src/cdk/menu/menu-trigger.spec.ts b/src/cdk/menu/menu-trigger.spec.ts index fe821303eced..7571010df95d 100644 --- a/src/cdk/menu/menu-trigger.spec.ts +++ b/src/cdk/menu/menu-trigger.spec.ts @@ -1,13 +1,13 @@ import {ENTER, SPACE, TAB} from '../keycodes'; -import {Component, ElementRef, QueryList, Type, ViewChild, ViewChildren} from '@angular/core'; -import {ComponentFixture, TestBed, fakeAsync, tick, waitForAsync} from '@angular/core/testing'; +import {Component, ElementRef, QueryList, ViewChild, ViewChildren} from '@angular/core'; +import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {dispatchKeyboardEvent} from '../../cdk/testing/private'; import {CdkMenu} from './menu'; import {Menu} from './menu-interface'; import {CdkMenuItem} from './menu-item'; -import {CdkMenuModule} from './menu-module'; import {CdkMenuTrigger} from './menu-trigger'; +import {CdkMenuBar} from './menu-bar'; describe('MenuTrigger', () => { describe('on CdkMenuItem', () => { @@ -15,13 +15,6 @@ describe('MenuTrigger', () => { let menuItem: CdkMenuItem; let menuItemElement: HTMLButtonElement; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [TriggerForEmptyMenu], - }); - })); - beforeEach(() => { fixture = TestBed.createComponent(TriggerForEmptyMenu); fixture.detectChanges(); @@ -110,13 +103,6 @@ describe('MenuTrigger', () => { const setDocumentDirection = (dir: 'ltr' | 'rtl') => (document.dir = dir); - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [MenuBarWithNestedSubMenus], - }); - })); - beforeEach(() => { fixture = TestBed.createComponent(MenuBarWithNestedSubMenus); detectChanges(); @@ -326,23 +312,9 @@ describe('MenuTrigger', () => { }); describe('with shared triggered menu', () => { - /** - * Return a function which builds the given component and renders it. - * @param componentClass the component to create - */ - function createComponent(componentClass: Type) { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [componentClass], - }); - - const fixture = TestBed.createComponent(componentClass); - fixture.detectChanges(); - return fixture; - } - it('should allow two triggers in different menubars to open the same menu', () => { - const fixture = createComponent(TriggersWithSameMenuDifferentMenuBars); + const fixture = TestBed.createComponent(TriggersWithSameMenuDifferentMenuBars); + fixture.detectChanges(); expect(fixture.componentInstance.menus.length).toBe(0); fixture.componentInstance.triggers.get(0)!.toggle(); fixture.detectChanges(); @@ -356,7 +328,8 @@ describe('MenuTrigger', () => { }); it('should allow two triggers in the same menubar open the same menu', () => { - const fixture = createComponent(TriggersWithSameMenuSameMenuBar); + const fixture = TestBed.createComponent(TriggersWithSameMenuSameMenuBar); + fixture.detectChanges(); expect(fixture.componentInstance.menus.length).toBe(0); fixture.componentInstance.triggers.get(0)!.toggle(); fixture.detectChanges(); @@ -370,7 +343,8 @@ describe('MenuTrigger', () => { }); it('should allow a trigger in a submenu references its parent menu', () => { - const fixture = createComponent(TriggerOpensItsMenu); + const fixture = TestBed.createComponent(TriggerOpensItsMenu); + fixture.detectChanges(); expect(fixture.componentInstance.menus.length).toBe(0); expect(fixture.componentInstance.triggers.length).toBe(1); fixture.componentInstance.triggers.get(0)!.toggle(); @@ -403,13 +377,6 @@ describe('MenuTrigger', () => { grabElementsForTesting(); }; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [StandaloneTriggerWithInlineMenu], - }); - })); - beforeEach(() => { fixture = TestBed.createComponent(StandaloneTriggerWithInlineMenu); detectChanges(); @@ -503,11 +470,6 @@ describe('MenuTrigger', () => { }); it('should be able to pass data to the menu via the template context', () => { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [TriggerWithData], - }); - const fixture = TestBed.createComponent(TriggerWithData); fixture.componentInstance.menuData = {message: 'Hello!'}; fixture.detectChanges(); @@ -519,16 +481,8 @@ describe('MenuTrigger', () => { describe('null triggerFor', () => { let fixture: ComponentFixture; - let nativeTrigger: HTMLElement; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [TriggerWithNullValue], - }); - })); - beforeEach(() => { fixture = TestBed.createComponent(TriggerWithNullValue); nativeTrigger = fixture.componentInstance.nativeTrigger.nativeElement; @@ -562,11 +516,6 @@ describe('MenuTrigger', () => { }); it('should focus the first item when opening on click', fakeAsync(() => { - TestBed.configureTestingModule({ - imports: [CdkMenuModule], - declarations: [TriggersWithSameMenuDifferentMenuBars], - }); - const fixture = TestBed.createComponent(TriggersWithSameMenuDifferentMenuBars); fixture.detectChanges(); @@ -587,7 +536,7 @@ describe('MenuTrigger', () => {
    `, - standalone: false, + imports: [CdkMenuBar, CdkMenu, CdkMenuItem, CdkMenuTrigger], }) class TriggerForEmptyMenu { @ViewChild(CdkMenuTrigger) trigger: CdkMenuTrigger; @@ -612,7 +561,7 @@ class TriggerForEmptyMenu { `, - standalone: false, + imports: [CdkMenu, CdkMenuItem, CdkMenuTrigger, CdkMenuBar], }) class MenuBarWithNestedSubMenus { @ViewChildren(CdkMenu) menus: QueryList; @@ -639,7 +588,7 @@ class MenuBarWithNestedSubMenus { `, - standalone: false, + imports: [CdkMenu, CdkMenuItem, CdkMenuTrigger, CdkMenuBar], }) class TriggersWithSameMenuDifferentMenuBars { @ViewChildren(CdkMenuTrigger) triggers: QueryList; @@ -662,7 +611,7 @@ class TriggersWithSameMenuDifferentMenuBars { `, - standalone: false, + imports: [CdkMenu, CdkMenuItem, CdkMenuTrigger, CdkMenuBar], }) class TriggersWithSameMenuSameMenuBar { @ViewChildren(CdkMenuTrigger) triggers: QueryList; @@ -681,7 +630,7 @@ class TriggersWithSameMenuSameMenuBar { `, - standalone: false, + imports: [CdkMenu, CdkMenuItem, CdkMenuTrigger, CdkMenuBar], }) class TriggerOpensItsMenu { @ViewChildren(CdkMenuTrigger) triggers: QueryList; @@ -706,7 +655,7 @@ class TriggerOpensItsMenu { `, - standalone: false, + imports: [CdkMenu, CdkMenuItem, CdkMenuTrigger], }) class StandaloneTriggerWithInlineMenu { @ViewChild(CdkMenuItem, {read: ElementRef}) nativeTrigger: ElementRef; @@ -726,7 +675,7 @@ class StandaloneTriggerWithInlineMenu {
    {{message}}
    `, - standalone: false, + imports: [CdkMenu, CdkMenuTrigger], }) class TriggerWithData { menuData: unknown; @@ -736,7 +685,7 @@ class TriggerWithData { template: ` `, - standalone: false, + imports: [CdkMenuTrigger], }) class TriggerWithNullValue { @ViewChild(CdkMenuTrigger, {static: true}) diff --git a/src/cdk/table/table.spec.ts b/src/cdk/table/table.spec.ts index 534e4e146b11..e7604ccd9c0b 100644 --- a/src/cdk/table/table.spec.ts +++ b/src/cdk/table/table.spec.ts @@ -35,26 +35,15 @@ import { getTableUnknownColumnError, getTableUnknownDataSourceError, } from './table-errors'; +import {NgClass} from '@angular/common'; describe('CdkTable', () => { let fixture: ComponentFixture; let component: any; let tableElement: HTMLElement; - function createComponent( - componentType: Type, - declarations: any[] = [], - ): ComponentFixture { - TestBed.configureTestingModule({ - imports: [CdkTableModule, BidiModule], - declarations: [componentType, ...declarations], - }); - - return TestBed.createComponent(componentType); - } - - function setupTableTestApp(componentType: Type, declarations: any[] = []) { - fixture = createComponent(componentType, declarations); + function setupTableTestApp(componentType: Type) { + fixture = TestBed.createComponent(componentType); component = fixture.componentInstance; fixture.detectChanges(); @@ -380,7 +369,7 @@ describe('CdkTable', () => { it('should not throw if `renderRows` is called too early', () => { // Note that we don't call `detectChanges` here, because we're testing specifically // what happens when `renderRows` is called before the first change detection run. - const fixture = createComponent(SimpleCdkTableApp); + const fixture = TestBed.createComponent(SimpleCdkTableApp); const table = fixture.debugElement.query(By.directive(CdkTable)) .componentInstance as CdkTable; expect(() => table.renderRows()).not.toThrow(); @@ -546,7 +535,7 @@ describe('CdkTable', () => { }); it('should render correctly when using native HTML tags', () => { - const thisFixture = createComponent(NativeHtmlTableApp); + const thisFixture = TestBed.createComponent(NativeHtmlTableApp); const thisTableElement = thisFixture.nativeElement.querySelector('table'); thisFixture.detectChanges(); @@ -559,7 +548,7 @@ describe('CdkTable', () => { }); it('defaults to table role in native HTML table', () => { - const fixture = createComponent(NativeHtmlTableApp); + const fixture = TestBed.createComponent(NativeHtmlTableApp); const tableElement = fixture.nativeElement.querySelector('table'); fixture.detectChanges(); expect(tableElement.getAttribute('role')).toBe('table'); @@ -579,7 +568,7 @@ describe('CdkTable', () => { }); it('should be able to nest tables', () => { - const thisFixture = createComponent(NestedHtmlTableApp); + const thisFixture = TestBed.createComponent(NestedHtmlTableApp); thisFixture.detectChanges(); const outerTable = thisFixture.nativeElement.querySelector('table'); const innerTable = outerTable.querySelector('table'); @@ -594,7 +583,7 @@ describe('CdkTable', () => { }); it('should be able to show a message when no data is being displayed in a native table', () => { - const thisFixture = createComponent(NativeHtmlTableApp); + const thisFixture = TestBed.createComponent(NativeHtmlTableApp); thisFixture.detectChanges(); // Assert that the data is inside the tbody specifically. @@ -618,7 +607,7 @@ describe('CdkTable', () => { }); it('should apply correct roles for native table elements', () => { - const thisFixture = createComponent(NativeHtmlTableApp); + const thisFixture = TestBed.createComponent(NativeHtmlTableApp); const thisTableElement: HTMLTableElement = thisFixture.nativeElement.querySelector('table'); thisFixture.detectChanges(); @@ -634,7 +623,7 @@ describe('CdkTable', () => { }); it('should hide thead/tfoot when there are no header/footer rows', () => { - const thisFixture = createComponent(NativeTableWithNoHeaderOrFooterRows); + const thisFixture = TestBed.createComponent(NativeTableWithNoHeaderOrFooterRows); const thisTableElement: HTMLTableElement = thisFixture.nativeElement.querySelector('table'); thisFixture.detectChanges(); @@ -686,23 +675,25 @@ describe('CdkTable', () => { }); it('should throw an error if two column definitions have the same name', () => { - expect(() => createComponent(DuplicateColumnDefNameCdkTableApp).detectChanges()).toThrowError( - getTableDuplicateColumnNameError('column_a').message, - ); + expect(() => + TestBed.createComponent(DuplicateColumnDefNameCdkTableApp).detectChanges(), + ).toThrowError(getTableDuplicateColumnNameError('column_a').message); }); it('should throw an error if a column definition is requested but not defined', () => { - expect(() => createComponent(MissingColumnDefCdkTableApp).detectChanges()).toThrowError( + expect(() => TestBed.createComponent(MissingColumnDefCdkTableApp).detectChanges()).toThrowError( getTableUnknownColumnError('column_a').message, ); }); it('should pick up columns that are indirect descendants', () => { - expect(() => createComponent(TableWithIndirectDescendantDefs).detectChanges()).not.toThrow(); + expect(() => + TestBed.createComponent(TableWithIndirectDescendantDefs).detectChanges(), + ).not.toThrow(); }); it('should throw an error if a column definition is requested but not defined after render', fakeAsync(() => { - const columnDefinitionMissingAfterRenderFixture = createComponent( + const columnDefinitionMissingAfterRenderFixture = TestBed.createComponent( MissingColumnDefAfterRenderCdkTableApp, ); expect(() => { @@ -713,9 +704,9 @@ describe('CdkTable', () => { })); it('should throw an error if the row definitions are missing', () => { - expect(() => createComponent(MissingAllRowDefsCdkTableApp).detectChanges()).toThrowError( - getTableMissingRowDefsError().message, - ); + expect(() => + TestBed.createComponent(MissingAllRowDefsCdkTableApp).detectChanges(), + ).toThrowError(getTableMissingRowDefsError().message); }); it('should not throw an error if columns are undefined on initialization', () => { @@ -772,7 +763,7 @@ describe('CdkTable', () => { }); it('should be able to register column, row, and header row definitions outside content', () => { - setupTableTestApp(OuterTableApp, [WrapperCdkTableApp]); + setupTableTestApp(OuterTableApp); // The first two columns were defined in the wrapped table component as content children, // while the injected columns were provided to the wrapped table from the outer component. @@ -787,7 +778,7 @@ describe('CdkTable', () => { }); it('should be able to register a no data row defined outside the table', () => { - setupTableTestApp(OuterTableApp, [WrapperCdkTableApp]); + setupTableTestApp(OuterTableApp); fixture.componentInstance.dataSource.data = []; fixture.detectChanges(); @@ -809,7 +800,9 @@ describe('CdkTable', () => { }); it('should error if there is row data that does not have a matching row template', fakeAsync(() => { - const whenRowWithoutDefaultFixture = createComponent(WhenRowWithoutDefaultCdkTableApp); + const whenRowWithoutDefaultFixture = TestBed.createComponent( + WhenRowWithoutDefaultCdkTableApp, + ); const data = whenRowWithoutDefaultFixture.componentInstance.dataSource.data; expect(() => { whenRowWithoutDefaultFixture.detectChanges(); @@ -819,7 +812,7 @@ describe('CdkTable', () => { })); it('should fail when multiple rows match data without multiTemplateDataRows', fakeAsync(() => { - let whenFixture = createComponent(WhenRowMultipleDefaultsCdkTableApp); + let whenFixture = TestBed.createComponent(WhenRowMultipleDefaultsCdkTableApp); expect(() => { whenFixture.detectChanges(); flush(); @@ -1742,7 +1735,7 @@ describe('CdkTable', () => { describe('with trackBy', () => { function createTestComponentWithTrackyByTable(trackByStrategy: string) { - fixture = createComponent(TrackByCdkTableApp); + fixture = TestBed.createComponent(TrackByCdkTableApp); component = fixture.componentInstance; component.trackByStrategy = trackByStrategy; @@ -1990,7 +1983,7 @@ describe('CdkTable', () => { }); it('should be able to show a message when no data is being displayed in the strategy ChangeDetectionOnPush', () => { - setupTableTestApp(WrapNativeHtmlTableAppOnPush, [NativeHtmlTableAppOnPush]); + setupTableTestApp(WrapNativeHtmlTableAppOnPush); expect(tableElement.querySelector('.cdk-no-data-row')).toBeFalsy(); @@ -2095,7 +2088,7 @@ class BooleanDataSource extends DataSource {
    No data
    `, - standalone: false, + imports: [CdkTableModule], }) class SimpleCdkTableApp { dataSource: FakeDataSource | undefined = new FakeDataSource(); @@ -2127,7 +2120,7 @@ class SimpleCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class CdkTableWithDifferentDataInputsApp { dataSource: DataSource | Observable | TestData[] | any = null; @@ -2148,7 +2141,7 @@ class CdkTableWithDifferentDataInputsApp { `, - standalone: false, + imports: [CdkTableModule], }) class BooleanRowCdkTableApp { dataSource = new BooleanDataSource(); @@ -2167,7 +2160,7 @@ class BooleanRowCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class NullDataCdkTableApp { dataSource = observableOf(null); @@ -2199,7 +2192,7 @@ class NullDataCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class MultipleHeaderFooterRowsCdkTableApp {} @@ -2252,7 +2245,7 @@ class MultipleHeaderFooterRowsCdkTableApp {} `, - standalone: false, + imports: [CdkTableModule], }) class WhenRowCdkTableApp { multiTemplateDataRows = false; @@ -2328,7 +2321,7 @@ class WhenRowCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class CoercedMultiTemplateDataRows extends WhenRowCdkTableApp {} @@ -2365,7 +2358,7 @@ class CoercedMultiTemplateDataRows extends WhenRowCdkTableApp {} `, - standalone: false, + imports: [CdkTableModule], }) class WhenRowWithoutDefaultCdkTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2410,7 +2403,7 @@ class WhenRowWithoutDefaultCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class WhenRowMultipleDefaultsCdkTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2432,7 +2425,7 @@ class WhenRowMultipleDefaultsCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class DynamicDataSourceCdkTableApp { dataSource: FakeDataSource | undefined; @@ -2458,7 +2451,7 @@ class DynamicDataSourceCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class TrackByCdkTableApp { trackByStrategy: 'reference' | 'propertyA' | 'index' = 'reference'; @@ -2543,7 +2536,7 @@ class StickyPositioningListenerTest implements StickyPositioningListener { } `, providers: [{provide: STICKY_POSITIONING_LISTENER, useExisting: StickyFlexLayoutCdkTableApp}], - standalone: false, + imports: [CdkTableModule, BidiModule], }) class StickyFlexLayoutCdkTableApp extends StickyPositioningListenerTest { dataSource: FakeDataSource = new FakeDataSource(); @@ -2600,7 +2593,7 @@ class StickyFlexLayoutCdkTableApp extends StickyPositioningListenerTest { } `, providers: [{provide: STICKY_POSITIONING_LISTENER, useExisting: StickyNativeLayoutCdkTableApp}], - standalone: false, + imports: [CdkTableModule], }) class StickyNativeLayoutCdkTableApp extends StickyPositioningListenerTest { dataSource: FakeDataSource = new FakeDataSource(); @@ -2632,7 +2625,7 @@ class StickyNativeLayoutCdkTableApp extends StickyPositioningListenerTest { `, - standalone: false, + imports: [CdkTableModule], }) class DynamicColumnDefinitionsCdkTableApp { dynamicColumns: any[] = []; @@ -2653,7 +2646,7 @@ class DynamicColumnDefinitionsCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class CustomRoleCdkTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2674,7 +2667,7 @@ class CustomRoleCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class CrazyColumnNameCdkTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2700,7 +2693,7 @@ class CrazyColumnNameCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class DuplicateColumnDefNameCdkTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2718,7 +2711,7 @@ class DuplicateColumnDefNameCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class MissingColumnDefCdkTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2736,7 +2729,7 @@ class MissingColumnDefCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class MissingColumnDefAfterRenderCdkTableApp implements AfterViewInit { dataSource: FakeDataSource | null = null; @@ -2760,7 +2753,7 @@ class MissingColumnDefAfterRenderCdkTableApp implements AfterViewInit { `, - standalone: false, + imports: [CdkTableModule], }) class MissingAllRowDefsCdkTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2779,7 +2772,7 @@ class MissingAllRowDefsCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class MissingHeaderRowDefCdkTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2798,7 +2791,7 @@ class MissingHeaderRowDefCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class MissingRowDefCdkTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2817,7 +2810,7 @@ class MissingRowDefCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class MissingFooterRowDefCdkTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2835,7 +2828,7 @@ class MissingFooterRowDefCdkTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class UndefinedColumnsCdkTableApp { undefinedColumns: string[]; @@ -2870,7 +2863,7 @@ class UndefinedColumnsCdkTableApp { `, - standalone: false, + imports: [CdkTableModule, NgClass], }) class RowContextCdkTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2896,7 +2889,7 @@ class RowContextCdkTableApp {
    No data
    `, - standalone: false, + imports: [CdkTableModule], }) class WrapperCdkTableApp implements AfterContentInit { @ContentChildren(CdkColumnDef) columnDefs: QueryList; @@ -2940,7 +2933,7 @@ class WrapperCdkTableApp implements AfterContentInit { `, - standalone: false, + imports: [CdkTableModule, WrapperCdkTableApp], }) class OuterTableApp { dataSource: FakeDataSource = new FakeDataSource(); @@ -2979,7 +2972,7 @@ class OuterTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class NativeHtmlTableApp { dataSource: FakeDataSource | undefined = new FakeDataSource(); @@ -3030,7 +3023,7 @@ class NativeHtmlTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class NestedHtmlTableApp { dataSource: FakeDataSource | undefined = new FakeDataSource(); @@ -3058,7 +3051,7 @@ class NestedHtmlTableApp { `, - standalone: false, + imports: [CdkTableModule], }) class NativeTableWithNoHeaderOrFooterRows { dataSource: FakeDataSource | undefined = new FakeDataSource(); @@ -3080,7 +3073,7 @@ class NativeTableWithNoHeaderOrFooterRows { `, - standalone: false, + imports: [CdkTableModule], }) class NativeHtmlTableWithCaptionApp { dataSource: FakeDataSource | undefined = new FakeDataSource(); @@ -3109,7 +3102,7 @@ class NativeHtmlTableWithCaptionApp { `, - standalone: false, + imports: [CdkTableModule], }) class NativeHtmlTableWithColgroupAndCol { dataSource: FakeDataSource | undefined = new FakeDataSource(); @@ -3133,7 +3126,7 @@ class NativeHtmlTableWithColgroupAndCol { `, - standalone: false, + imports: [CdkTableModule], }) class TableWithIndirectDescendantDefs { dataSource = new FakeDataSource(); @@ -3166,7 +3159,7 @@ class TableWithIndirectDescendantDefs { `, changeDetection: ChangeDetectionStrategy.OnPush, - standalone: false, + imports: [CdkTableModule], }) class NativeHtmlTableAppOnPush { @Input() dataSource: Observable | null = null; @@ -3177,7 +3170,7 @@ class NativeHtmlTableAppOnPush { template: ` `, - standalone: false, + imports: [NativeHtmlTableAppOnPush], }) class WrapNativeHtmlTableAppOnPush { dataSource: FakeDataSource = new FakeDataSource(); diff --git a/src/cdk/tree/tree-using-legacy-key-manager.spec.ts b/src/cdk/tree/tree-using-legacy-key-manager.spec.ts index 54f34e0ea048..fecb0b756ce6 100644 --- a/src/cdk/tree/tree-using-legacy-key-manager.spec.ts +++ b/src/cdk/tree/tree-using-legacy-key-manager.spec.ts @@ -8,12 +8,7 @@ describe('CdkTree when provided LegacyTreeKeyManager', () => { let fixture: ComponentFixture; beforeEach(() => { - TestBed.configureTestingModule({ - imports: [CdkTreeModule], - declarations: [SimpleCdkTreeApp], - providers: [NOOP_TREE_KEY_MANAGER_FACTORY_PROVIDER], - }); - + TestBed.configureTestingModule({providers: [NOOP_TREE_KEY_MANAGER_FACTORY_PROVIDER]}); fixture = TestBed.createComponent(SimpleCdkTreeApp); fixture.detectChanges(); }); @@ -80,7 +75,7 @@ class MinimalTestData { `, - standalone: false, + imports: [CdkTreeModule], }) class SimpleCdkTreeApp { isExpandable = (node: MinimalTestData) => node.children.length > 0; diff --git a/src/cdk/tree/tree-with-tree-control.spec.ts b/src/cdk/tree/tree-with-tree-control.spec.ts index 472776a7c991..49b58636efa0 100644 --- a/src/cdk/tree/tree-with-tree-control.spec.ts +++ b/src/cdk/tree/tree-with-tree-control.spec.ts @@ -11,10 +11,9 @@ import { QueryList, signal, TrackByFunction, - Type, - ViewChild, ViewChildren, WritableSignal, + ViewChild, } from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; @@ -39,10 +38,10 @@ describe('CdkTree with TreeControl', () => { let tree: CdkTree; let dir: WritableSignal; - function configureCdkTreeTestingModule(declarations: Type[]) { + beforeEach(() => { dir = signal('ltr'); + TestBed.configureTestingModule({ - imports: [CdkTreeModule], providers: [ provideFakeDirectionality(dir), // Custom error handler that re-throws the error. Errors happening within @@ -58,12 +57,10 @@ describe('CdkTree with TreeControl', () => { }, }, ], - declarations: declarations, }); - } + }); it('should clear out the `mostRecentTreeNode` on destroy', () => { - configureCdkTreeTestingModule([SimpleCdkTreeApp]); const fixture = TestBed.createComponent(SimpleCdkTreeApp); fixture.detectChanges(); @@ -77,7 +74,6 @@ describe('CdkTree with TreeControl', () => { }); it('should complete the viewChange stream on destroy', () => { - configureCdkTreeTestingModule([SimpleCdkTreeApp]); const fixture = TestBed.createComponent(SimpleCdkTreeApp); fixture.detectChanges(); const spy = jasmine.createSpy('completeSpy'); @@ -94,7 +90,6 @@ describe('CdkTree with TreeControl', () => { let component: SimpleCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([SimpleCdkTreeApp]); fixture = TestBed.createComponent(SimpleCdkTreeApp); fixture.detectChanges(); @@ -255,7 +250,6 @@ describe('CdkTree with TreeControl', () => { let component: CdkTreeAppWithToggle; beforeEach(() => { - configureCdkTreeTestingModule([CdkTreeAppWithToggle]); fixture = TestBed.createComponent(CdkTreeAppWithToggle); fixture.detectChanges(); @@ -356,7 +350,6 @@ describe('CdkTree with TreeControl', () => { let component: WhenNodeCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([WhenNodeCdkTreeApp]); fixture = TestBed.createComponent(WhenNodeCdkTreeApp); fixture.detectChanges(); @@ -403,7 +396,6 @@ describe('CdkTree with TreeControl', () => { let component: ArrayDataSourceCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([ArrayDataSourceCdkTreeApp]); fixture = TestBed.createComponent(ArrayDataSourceCdkTreeApp); fixture.detectChanges(); @@ -450,7 +442,6 @@ describe('CdkTree with TreeControl', () => { let component: ObservableDataSourceCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([ObservableDataSourceCdkTreeApp]); fixture = TestBed.createComponent(ObservableDataSourceCdkTreeApp); fixture.detectChanges(); @@ -497,7 +488,6 @@ describe('CdkTree with TreeControl', () => { let component: CdkTreeAppWithTrackBy; function createTrackByTestComponent(trackByStrategy: 'reference' | 'property' | 'index') { - configureCdkTreeTestingModule([CdkTreeAppWithTrackBy]); fixture = TestBed.createComponent(CdkTreeAppWithTrackBy); component = fixture.componentInstance; component.trackByStrategy = trackByStrategy; @@ -586,7 +576,6 @@ describe('CdkTree with TreeControl', () => { }); it('should pick up indirect descendant node definitions', () => { - configureCdkTreeTestingModule([SimpleCdkTreeAppWithIndirectNodes]); const fixture = TestBed.createComponent(SimpleCdkTreeAppWithIndirectNodes); fixture.detectChanges(); treeElement = fixture.nativeElement.querySelector('cdk-tree'); @@ -601,7 +590,6 @@ describe('CdkTree with TreeControl', () => { let component: NestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([NestedCdkTreeApp]); fixture = TestBed.createComponent(NestedCdkTreeApp); fixture.detectChanges(); @@ -715,7 +703,6 @@ describe('CdkTree with TreeControl', () => { let component: StaticNestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([StaticNestedCdkTreeApp]); fixture = TestBed.createComponent(StaticNestedCdkTreeApp); fixture.detectChanges(); @@ -743,7 +730,6 @@ describe('CdkTree with TreeControl', () => { let component: WhenNodeNestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([WhenNodeNestedCdkTreeApp]); fixture = TestBed.createComponent(WhenNodeNestedCdkTreeApp); fixture.detectChanges(); @@ -785,7 +771,6 @@ describe('CdkTree with TreeControl', () => { let component: NestedCdkTreeAppWithToggle; beforeEach(() => { - configureCdkTreeTestingModule([NestedCdkTreeAppWithToggle]); fixture = TestBed.createComponent(NestedCdkTreeAppWithToggle); fixture.detectChanges(); @@ -931,7 +916,6 @@ describe('CdkTree with TreeControl', () => { let component: ArrayDataSourceNestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([ArrayDataSourceNestedCdkTreeApp]); fixture = TestBed.createComponent(ArrayDataSourceNestedCdkTreeApp); fixture.detectChanges(); @@ -971,7 +955,6 @@ describe('CdkTree with TreeControl', () => { let component: ObservableDataSourceNestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([ObservableDataSourceNestedCdkTreeApp]); fixture = TestBed.createComponent(ObservableDataSourceNestedCdkTreeApp); fixture.detectChanges(); @@ -1011,7 +994,6 @@ describe('CdkTree with TreeControl', () => { let component: NestedCdkTreeAppWithTrackBy; function createTrackByTestComponent(trackByStrategy: 'reference' | 'property' | 'index') { - configureCdkTreeTestingModule([NestedCdkTreeAppWithTrackBy]); fixture = TestBed.createComponent(NestedCdkTreeAppWithTrackBy); component = fixture.componentInstance; component.trackByStrategy = trackByStrategy; @@ -1141,7 +1123,6 @@ describe('CdkTree with TreeControl', () => { let component: DepthNestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([DepthNestedCdkTreeApp]); fixture = TestBed.createComponent(DepthNestedCdkTreeApp); fixture.detectChanges(); @@ -1172,7 +1153,6 @@ describe('CdkTree with TreeControl', () => { let nodes: HTMLElement[]; beforeEach(() => { - configureCdkTreeTestingModule([StaticNestedCdkTreeApp]); fixture = TestBed.createComponent(StaticNestedCdkTreeApp); fixture.detectChanges(); @@ -1461,7 +1441,7 @@ function expectNestedTreeToMatch(treeElement: Element, ...expectedTree: any[]) { `, - standalone: false, + imports: [CdkTreeModule], }) class SimpleCdkTreeApp { getLevel = (node: TestData) => node.level; @@ -1478,16 +1458,16 @@ class SimpleCdkTreeApp { @Component({ template: ` - + @if (true) { {{node.pizzaTopping}} - {{node.pizzaCheese}} + {{node.pizzaBase}} - + } `, - standalone: false, + imports: [CdkTreeModule], }) class SimpleCdkTreeAppWithIndirectNodes extends SimpleCdkTreeApp {} @@ -1500,7 +1480,7 @@ class SimpleCdkTreeAppWithIndirectNodes extends SimpleCdkTreeApp {} `, - standalone: false, + imports: [CdkTreeModule], }) class NestedCdkTreeApp { getChildren = (node: TestData) => node.observableChildren; @@ -1524,7 +1504,7 @@ class NestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class StaticNestedCdkTreeApp { getChildren = (node: TestData) => node.children; @@ -1561,7 +1541,7 @@ class StaticNestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class WhenNodeNestedCdkTreeApp { isSecondNode = (_: number, node: TestData) => node.pizzaBase.indexOf('2') > 0; @@ -1585,7 +1565,7 @@ class WhenNodeNestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class CdkTreeAppWithToggle { toggleRecursively: boolean = true; @@ -1606,13 +1586,13 @@ class CdkTreeAppWithToggle { cdkTreeNodeToggle [cdkTreeNodeToggleRecursive]="toggleRecursively"> {{node.pizzaTopping}} - {{node.pizzaCheese}} + {{node.pizzaBase}} -
    + @if (treeControl.isExpanded(node)) { -
    + } `, - standalone: false, + imports: [CdkTreeModule], }) class NestedCdkTreeAppWithToggle { toggleRecursively: boolean = true; @@ -1642,7 +1622,7 @@ class NestedCdkTreeAppWithToggle { `, - standalone: false, + imports: [CdkTreeModule], }) class WhenNodeCdkTreeApp { isOddNode = (_: number, node: TestData) => node.level % 2 === 1; @@ -1666,7 +1646,7 @@ class WhenNodeCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class ArrayDataSourceCdkTreeApp { getLevel = (node: TestData) => node.level; @@ -1693,7 +1673,7 @@ class ArrayDataSourceCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class ObservableDataSourceCdkTreeApp { getLevel = (node: TestData) => node.level; @@ -1719,7 +1699,7 @@ class ObservableDataSourceCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class ArrayDataSourceNestedCdkTreeApp { getChildren = (node: TestData) => node.observableChildren; @@ -1744,7 +1724,7 @@ class ArrayDataSourceNestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class ObservableDataSourceNestedCdkTreeApp { getChildren = (node: TestData) => node.observableChildren; @@ -1770,7 +1750,7 @@ class ObservableDataSourceNestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class DepthNestedCdkTreeApp { getChildren = (node: TestData) => node.observableChildren; @@ -1794,7 +1774,7 @@ class DepthNestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class CdkTreeAppWithTrackBy { trackByStrategy: 'reference' | 'property' | 'index' = 'reference'; @@ -1828,7 +1808,7 @@ class CdkTreeAppWithTrackBy { `, - standalone: false, + imports: [CdkTreeModule], }) class NestedCdkTreeAppWithTrackBy { trackByStrategy: 'reference' | 'property' | 'index' = 'reference'; diff --git a/src/cdk/tree/tree.spec.ts b/src/cdk/tree/tree.spec.ts index 8345af468459..c678042f77e4 100644 --- a/src/cdk/tree/tree.spec.ts +++ b/src/cdk/tree/tree.spec.ts @@ -12,7 +12,6 @@ import { ErrorHandler, QueryList, TrackByFunction, - Type, ViewChild, ViewChildren, WritableSignal, @@ -20,6 +19,7 @@ import { signal, } from '@angular/core'; import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {AsyncPipe} from '@angular/common'; import {BehaviorSubject, Observable, combineLatest, of} from 'rxjs'; import {map} from 'rxjs/operators'; @@ -43,10 +43,10 @@ describe('CdkTree', () => { let tree: CdkTree; let dir: WritableSignal; - function configureCdkTreeTestingModule(declarations: Type[]) { + beforeEach(() => { dir = signal('ltr'); + TestBed.configureTestingModule({ - imports: [CdkTreeModule], providers: [ provideFakeDirectionality(dir), // Custom error handler that re-throws the error. Errors happening within @@ -62,13 +62,11 @@ describe('CdkTree', () => { }, }, ], - declarations: declarations, }); - } + }); describe('onDestroy', () => { it('should clear out the `mostRecentTreeNode` on destroy', () => { - configureCdkTreeTestingModule([SimpleCdkTreeApp]); const fixture = TestBed.createComponent(SimpleCdkTreeApp); fixture.detectChanges(); @@ -82,7 +80,6 @@ describe('CdkTree', () => { }); it('should complete the viewChange stream on destroy', () => { - configureCdkTreeTestingModule([SimpleCdkTreeApp]); const fixture = TestBed.createComponent(SimpleCdkTreeApp); fixture.detectChanges(); const spy = jasmine.createSpy('completeSpy'); @@ -100,7 +97,6 @@ describe('CdkTree', () => { let component: SimpleCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([SimpleCdkTreeApp]); fixture = TestBed.createComponent(SimpleCdkTreeApp); fixture.detectChanges(); @@ -260,7 +256,6 @@ describe('CdkTree', () => { let component: CdkTreeAppWithToggle; beforeEach(() => { - configureCdkTreeTestingModule([CdkTreeAppWithToggle]); fixture = TestBed.createComponent(CdkTreeAppWithToggle); fixture.detectChanges(); @@ -408,7 +403,6 @@ describe('CdkTree', () => { let component: WhenNodeCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([WhenNodeCdkTreeApp]); fixture = TestBed.createComponent(WhenNodeCdkTreeApp); fixture.detectChanges(); @@ -455,7 +449,6 @@ describe('CdkTree', () => { let component: ArrayDataSourceCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([ArrayDataSourceCdkTreeApp]); fixture = TestBed.createComponent(ArrayDataSourceCdkTreeApp); fixture.detectChanges(); @@ -501,7 +494,6 @@ describe('CdkTree', () => { let component: ObservableDataSourceCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([ObservableDataSourceCdkTreeApp]); fixture = TestBed.createComponent(ObservableDataSourceCdkTreeApp); fixture.detectChanges(); @@ -548,7 +540,6 @@ describe('CdkTree', () => { let component: CdkTreeAppWithTrackBy; function createTrackByTestComponent(trackByStrategy: 'reference' | 'property' | 'index') { - configureCdkTreeTestingModule([CdkTreeAppWithTrackBy]); fixture = TestBed.createComponent(CdkTreeAppWithTrackBy); component = fixture.componentInstance; component.trackByStrategy = trackByStrategy; @@ -656,7 +647,6 @@ describe('CdkTree', () => { }); it('should pick up indirect descendant node definitions', () => { - configureCdkTreeTestingModule([SimpleCdkTreeAppWithIndirectNodes]); const fixture = TestBed.createComponent(SimpleCdkTreeAppWithIndirectNodes); fixture.detectChanges(); treeElement = fixture.nativeElement.querySelector('cdk-tree'); @@ -671,7 +661,6 @@ describe('CdkTree', () => { let component: NestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([NestedCdkTreeApp]); fixture = TestBed.createComponent(NestedCdkTreeApp); fixture.detectChanges(); @@ -775,7 +764,6 @@ describe('CdkTree', () => { let component: StaticNestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([StaticNestedCdkTreeApp]); fixture = TestBed.createComponent(StaticNestedCdkTreeApp); fixture.detectChanges(); @@ -803,7 +791,6 @@ describe('CdkTree', () => { let component: WhenNodeNestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([WhenNodeNestedCdkTreeApp]); fixture = TestBed.createComponent(WhenNodeNestedCdkTreeApp); fixture.detectChanges(); @@ -845,7 +832,6 @@ describe('CdkTree', () => { let component: NestedCdkTreeAppWithToggle; beforeEach(() => { - configureCdkTreeTestingModule([NestedCdkTreeAppWithToggle]); fixture = TestBed.createComponent(NestedCdkTreeAppWithToggle); fixture.detectChanges(); @@ -986,7 +972,6 @@ describe('CdkTree', () => { let component: ArrayDataSourceNestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([ArrayDataSourceNestedCdkTreeApp]); fixture = TestBed.createComponent(ArrayDataSourceNestedCdkTreeApp); fixture.detectChanges(); @@ -1026,7 +1011,6 @@ describe('CdkTree', () => { let component: ObservableDataSourceNestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([ObservableDataSourceNestedCdkTreeApp]); fixture = TestBed.createComponent(ObservableDataSourceNestedCdkTreeApp); fixture.detectChanges(); @@ -1066,7 +1050,6 @@ describe('CdkTree', () => { let component: NestedCdkTreeAppWithTrackBy; function createTrackByTestComponent(trackByStrategy: 'reference' | 'property' | 'index') { - configureCdkTreeTestingModule([NestedCdkTreeAppWithTrackBy]); fixture = TestBed.createComponent(NestedCdkTreeAppWithTrackBy); component = fixture.componentInstance; component.trackByStrategy = trackByStrategy; @@ -1196,7 +1179,6 @@ describe('CdkTree', () => { let component: DepthNestedCdkTreeApp; beforeEach(() => { - configureCdkTreeTestingModule([DepthNestedCdkTreeApp]); fixture = TestBed.createComponent(DepthNestedCdkTreeApp); fixture.detectChanges(); @@ -1227,7 +1209,6 @@ describe('CdkTree', () => { let nodes: HTMLElement[]; beforeEach(() => { - configureCdkTreeTestingModule([StaticNestedCdkTreeApp]); fixture = TestBed.createComponent(StaticNestedCdkTreeApp); fixture.detectChanges(); @@ -1381,7 +1362,6 @@ describe('CdkTree', () => { let component: FlatTreeWithThreeNodes; beforeEach(() => { - configureCdkTreeTestingModule([FlatTreeWithThreeNodes]); fixture = TestBed.createComponent(FlatTreeWithThreeNodes); fixture.detectChanges(); @@ -1409,7 +1389,6 @@ describe('CdkTree', () => { let component: TypeaheadLabelFlatTreeWithThreeNodes; beforeEach(() => { - configureCdkTreeTestingModule([TypeaheadLabelFlatTreeWithThreeNodes]); fixture = TestBed.createComponent(TypeaheadLabelFlatTreeWithThreeNodes); fixture.detectChanges(); @@ -1471,7 +1450,6 @@ describe('CdkTree', () => { }); it('sets a node as expanded if attribute is ordered before `isExpandable`', () => { - configureCdkTreeTestingModule([IsExpandableOrderingTest]); const fixture = TestBed.createComponent(IsExpandableOrderingTest); fixture.detectChanges(); @@ -1482,7 +1460,6 @@ describe('CdkTree', () => { }); it('should expand/collapse all nested nodes when calling expandAll/collapseAll', () => { - configureCdkTreeTestingModule([IsExpandableOrderingTest]); const fixture = TestBed.createComponent(IsExpandableOrderingTest); const component = fixture.componentInstance; const data = fixture.componentInstance.dataSource; @@ -1712,7 +1689,7 @@ function expectNestedTreeToMatch(treeElement: Element, ...expectedTree: any[]) { `, - standalone: false, + imports: [CdkTreeModule], }) class SimpleCdkTreeApp { getLevel = (node: TestData) => node.level; @@ -1740,7 +1717,7 @@ class SimpleCdkTreeApp { } `, - standalone: false, + imports: [CdkTreeModule], }) class SimpleCdkTreeAppWithIndirectNodes extends SimpleCdkTreeApp {} @@ -1754,7 +1731,7 @@ class SimpleCdkTreeAppWithIndirectNodes extends SimpleCdkTreeApp {} `, - standalone: false, + imports: [CdkTreeModule], }) class NestedCdkTreeApp { getChildren = (node: TestData) => node.observableChildren; @@ -1778,7 +1755,7 @@ class NestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class StaticNestedCdkTreeApp { getChildren = (node: TestData) => node.children; @@ -1812,7 +1789,7 @@ class StaticNestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class WhenNodeNestedCdkTreeApp { isSecondNode = (_: number, node: TestData) => node.pizzaBase.indexOf('2') > 0; @@ -1836,7 +1813,7 @@ class WhenNodeNestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class CdkTreeAppWithToggle { toggleRecursively: boolean = true; @@ -1866,7 +1843,7 @@ class CdkTreeAppWithToggle { `, - standalone: false, + imports: [CdkTreeModule, AsyncPipe], }) class NestedCdkTreeAppWithToggle { toggleRecursively: boolean = true; @@ -1898,7 +1875,7 @@ class NestedCdkTreeAppWithToggle { `, - standalone: false, + imports: [CdkTreeModule], }) class WhenNodeCdkTreeApp { isOddNode = (_: number, node: TestData) => node.level % 2 === 1; @@ -1922,7 +1899,7 @@ class WhenNodeCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class ArrayDataSourceCdkTreeApp { getLevel = (node: TestData) => node.level; @@ -1957,7 +1934,7 @@ class ArrayDataSourceCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class ObservableDataSourceCdkTreeApp { getLevel = (node: TestData) => node.level; @@ -1982,7 +1959,7 @@ class ObservableDataSourceCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class ArrayDataSourceNestedCdkTreeApp { getChildren = (node: TestData) => node.observableChildren; @@ -2006,7 +1983,7 @@ class ArrayDataSourceNestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class ObservableDataSourceNestedCdkTreeApp { getChildren = (node: TestData) => node.observableChildren; @@ -2031,7 +2008,7 @@ class ObservableDataSourceNestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class DepthNestedCdkTreeApp { getChildren = (node: TestData) => node.observableChildren; @@ -2054,7 +2031,7 @@ class DepthNestedCdkTreeApp { `, - standalone: false, + imports: [CdkTreeModule], }) class CdkTreeAppWithTrackBy { trackByStrategy: 'reference' | 'property' | 'index' = 'reference'; @@ -2088,7 +2065,7 @@ class CdkTreeAppWithTrackBy { `, - standalone: false, + imports: [CdkTreeModule], }) class NestedCdkTreeAppWithTrackBy { trackByStrategy: 'reference' | 'property' | 'index' = 'reference'; @@ -2132,7 +2109,7 @@ class MinimalTestData { `, - standalone: false, + imports: [CdkTreeModule], }) class TypeaheadLabelFlatTreeWithThreeNodes { isExpandable = (node: MinimalTestData) => node.children.length > 0; @@ -2156,7 +2133,7 @@ class TypeaheadLabelFlatTreeWithThreeNodes { `, - standalone: false, + imports: [CdkTreeModule], }) class FlatTreeWithThreeNodes { isExpandable = (node: MinimalTestData) => node.children.length > 0; @@ -2183,7 +2160,7 @@ class FlatTreeWithThreeNodes { `, - standalone: false, + imports: [CdkTreeModule], }) class IsExpandableOrderingTest { getChildren = (node: MinimalTestData) => node.children;