From 303c3ff1216cdb32dbc104dd6c13725c601849b8 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 30 Oct 2025 15:30:37 +0100 Subject: [PATCH] test: move aria tests away from fakeAsync `fakeAsync` can be problematic on the framework side. These changes switch tha `aria` tests away from it since it's new code. --- src/aria/combobox/combobox.spec.ts | 23 +++++------- src/aria/listbox/listbox.spec.ts | 9 +++-- src/aria/menu/menu.spec.ts | 37 ++++++++----------- .../list-typeahead/list-typeahead.spec.ts | 7 ++-- src/aria/private/behaviors/list/list.spec.ts | 20 +++++----- src/aria/private/menu/menu.spec.ts | 33 +++++++++-------- 6 files changed, 61 insertions(+), 68 deletions(-) diff --git a/src/aria/combobox/combobox.spec.ts b/src/aria/combobox/combobox.spec.ts index bd5a1cba4457..0d1d50f24157 100644 --- a/src/aria/combobox/combobox.spec.ts +++ b/src/aria/combobox/combobox.spec.ts @@ -1,5 +1,5 @@ import {Component, computed, DebugElement, signal} from '@angular/core'; -import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {Combobox, ComboboxInput, ComboboxPopup, ComboboxPopupContainer} from '../combobox'; import {Listbox, Option} from '../listbox'; @@ -421,37 +421,33 @@ describe('Combobox', () => { expect(fixture.componentInstance.value()).toEqual(['California']); }); - it('should insert a highlighted completion string on input', fakeAsync(() => { + it('should insert a highlighted completion string on input', () => { focus(); input('A'); - tick(); expect(inputElement.value).toBe('Alabama'); expect(inputElement.selectionStart).toBe(1); expect(inputElement.selectionEnd).toBe(7); - })); + }); - it('should not insert a completion string on backspace', fakeAsync(() => { + it('should not insert a completion string on backspace', () => { focus(); input('New'); - tick(); expect(inputElement.value).toBe('New Hampshire'); expect(inputElement.selectionStart).toBe(3); expect(inputElement.selectionEnd).toBe(13); - })); + }); - it('should insert a completion string even if the items are not changed', fakeAsync(() => { + it('should insert a completion string even if the items are not changed', () => { focus(); input('New'); - tick(); input('New '); - tick(); expect(inputElement.value).toBe('New Hampshire'); expect(inputElement.selectionStart).toBe(4); expect(inputElement.selectionEnd).toBe(13); - })); + }); it('should commit the selected option on focusout', () => { focus(); @@ -937,15 +933,14 @@ describe('Combobox', () => { expect(fixture.componentInstance.value()).toEqual(['September']); }); - it('should insert a highlighted completion string on input', fakeAsync(() => { + it('should insert a highlighted completion string on input', () => { focus(); input('Feb'); - tick(); expect(inputElement.value).toBe('February'); expect(inputElement.selectionStart).toBe(3); expect(inputElement.selectionEnd).toBe(8); - })); + }); it('should commit the selected option on focusout', () => { focus(); diff --git a/src/aria/listbox/listbox.spec.ts b/src/aria/listbox/listbox.spec.ts index f956c66e405d..60de0e9c816f 100644 --- a/src/aria/listbox/listbox.spec.ts +++ b/src/aria/listbox/listbox.spec.ts @@ -1,6 +1,6 @@ import {Component, DebugElement, signal} from '@angular/core'; import {Listbox, Option} from './listbox'; -import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {Direction} from '@angular/cdk/bidi'; import {provideFakeDirectionality, runAccessibilityChecks} from '@angular/cdk/testing/private'; @@ -686,15 +686,16 @@ describe('Listbox', () => { expect(optionElements[4].getAttribute('aria-selected')).toBe('false'); }); - it('should reset search term after typeaheadDelay', fakeAsync(() => { + it('should reset search term after typeaheadDelay', async () => { setupListbox({options: getOptions(), focusMode, typeaheadDelay: 0.1}); type('A'); expect(isFocused(1)).toBe(true); - tick(100); + await new Promise(resolve => setTimeout(resolve, 100)); + type('A'); expect(isFocused(0)).toBe(true); - })); + }); it('should skip disabled options with typeahead (softDisabled=false)', () => { setupListbox({options: getOptions(), focusMode, disabledOptions: [2], softDisabled: false}); diff --git a/src/aria/menu/menu.spec.ts b/src/aria/menu/menu.spec.ts index 8e799347c103..b64fdc479e15 100644 --- a/src/aria/menu/menu.spec.ts +++ b/src/aria/menu/menu.spec.ts @@ -1,5 +1,5 @@ import {Component, DebugElement} from '@angular/core'; -import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {Menu, MenuBar, MenuItem, MenuTrigger} from './menu'; @@ -102,15 +102,15 @@ describe('Standalone Menu Pattern', () => { }); describe('Typeahead', () => { - it('should move the active item to the next item that starts with the typed character', fakeAsync(() => { + it('should move the active item to the next item that starts with the typed character', () => { const apple = getItem('Apple'); const banana = getItem('Banana'); keydown(apple!, 'b'); expect(document.activeElement).toBe(banana); - })); + }); - it('should support multi-character typeahead', fakeAsync(() => { + it('should support multi-character typeahead', () => { const apple = getItem('Apple'); const banana = getItem('Banana'); const berries = getItem('Berries'); @@ -118,13 +118,11 @@ describe('Standalone Menu Pattern', () => { keydown(apple!, 'b'); expect(document.activeElement).toBe(banana); - tick(100); keydown(document.activeElement!, 'e'); - expect(document.activeElement).toBe(berries); - })); + }); - it('should wrap when reaching the end of the list during typeahead', fakeAsync(() => { + it('should wrap when reaching the end of the list during typeahead', () => { const apple = getItem('Apple'); const cherry = getItem('Cherry'); @@ -135,14 +133,14 @@ describe('Standalone Menu Pattern', () => { // Type 'a', which should wrap to 'Apple' keydown(document.activeElement!, 'a'); expect(document.activeElement).toBe(apple); - })); + }); - it('should not move the active item if no item matches the typed character', fakeAsync(() => { + it('should not move the active item if no item matches the typed character', () => { const apple = getItem('Apple'); keydown(apple!, 'z'); expect(document.activeElement).toBe(apple); - })); + }); }); }); @@ -308,12 +306,11 @@ describe('Standalone Menu Pattern', () => { expect(document.activeElement).toBe(berries); }); - it('should open submenu on mouseover', fakeAsync(() => { + it('should open submenu on mouseover', () => { const berries = getItem('Berries'); mouseover(berries!); - tick(); expect(isSubmenuExpanded()).toBe(true); - })); + }); it('should close on selecting an item on click', () => { spyOn(fixture.componentInstance, 'onSelect'); @@ -385,34 +382,30 @@ describe('Standalone Menu Pattern', () => { externalElement.remove(); }); - it('should close an unfocused submenu on mouse out', fakeAsync(() => { + it('should close an unfocused submenu on mouse out', () => { const berries = getItem('Berries'); const submenu = getSubmenu(); mouseover(berries!); - tick(); expect(isSubmenuExpanded()).toBe(true); mouseout(berries!); mouseout(submenu!); - tick(500); expect(isSubmenuExpanded()).toBe(false); - })); + }); - it('should not close an unfocused submenu on mouse out if the parent menu is hovered', fakeAsync(() => { + it('should not close an unfocused submenu on mouse out if the parent menu is hovered', () => { const berries = getItem('Berries'); const submenu = getSubmenu(); mouseover(berries!); - tick(); expect(isSubmenuExpanded()).toBe(true); mouseout(berries!); mouseover(submenu!); - tick(500); expect(isSubmenuExpanded()).toBe(true); - })); + }); }); }); diff --git a/src/aria/private/behaviors/list-typeahead/list-typeahead.spec.ts b/src/aria/private/behaviors/list-typeahead/list-typeahead.spec.ts index 3d5296035a04..8490433a7209 100644 --- a/src/aria/private/behaviors/list-typeahead/list-typeahead.spec.ts +++ b/src/aria/private/behaviors/list-typeahead/list-typeahead.spec.ts @@ -8,7 +8,6 @@ import {Signal, signal, WritableSignal} from '@angular/core'; import {ListTypeaheadItem, ListTypeahead, ListTypeaheadInputs} from './list-typeahead'; -import {fakeAsync, tick} from '@angular/core/testing'; import {getListFocus} from '../list-focus/list-focus.spec'; import {ListFocus} from '../list-focus/list-focus'; @@ -68,15 +67,15 @@ describe('List Typeahead', () => { expect(typeahead.inputs.focusManager.activeIndex()).toBe(3); }); - it('should reset after a delay', fakeAsync(() => { + it('should reset after a delay', async () => { typeahead.search('i'); expect(typeahead.inputs.focusManager.activeIndex()).toBe(1); - tick(500); + await new Promise(resolve => setTimeout(resolve, 500)); typeahead.search('i'); expect(typeahead.inputs.focusManager.activeIndex()).toBe(2); - })); + }); it('should skip disabled items', () => { items[1].disabled.set(true); diff --git a/src/aria/private/behaviors/list/list.spec.ts b/src/aria/private/behaviors/list/list.spec.ts index 34c7b7e578a8..23f993a39491 100644 --- a/src/aria/private/behaviors/list/list.spec.ts +++ b/src/aria/private/behaviors/list/list.spec.ts @@ -8,7 +8,6 @@ import {signal, WritableSignal} from '@angular/core'; import {List, ListItem, ListInputs} from './list'; -import {fakeAsync, tick} from '@angular/core/testing'; type TestItem = ListItem & { disabled: WritableSignal; @@ -341,7 +340,11 @@ describe('List Behavior', () => { }); describe('Typeahead', () => { - it('should navigate to an item via typeahead', fakeAsync(() => { + function delay(amount: number) { + return new Promise(resolve => setTimeout(resolve, amount)); + } + + it('should navigate to an item via typeahead', async () => { const {list} = getDefaultPatterns(); expect(list.inputs.activeItem()).toBe(list.inputs.items()[0]); list.search('b'); @@ -350,24 +353,23 @@ describe('List Behavior', () => { expect(list.inputs.activeItem()).toBe(list.inputs.items()[3]); // Blackberry list.search('u'); expect(list.inputs.activeItem()).toBe(list.inputs.items()[4]); // Blueberry - - tick(500); // Default delay + await delay(500); list.search('c'); expect(list.inputs.activeItem()).toBe(list.inputs.items()[5]); // Cantaloupe - })); + }); - it('should respect typeaheadDelay', fakeAsync(() => { + it('should respect typeaheadDelay', async () => { const {list} = getDefaultPatterns({typeaheadDelay: signal(0.1)}); list.search('b'); expect(list.inputs.activeItem()).toBe(list.inputs.items()[2]); // Banana - tick(50); // Less than delay + await delay(50); // Less than delay list.search('l'); expect(list.inputs.activeItem()).toBe(list.inputs.items()[3]); // Blackberry - tick(101); // More than delay + await delay(101); // More than delay list.search('c'); expect(list.inputs.activeItem()).toBe(list.inputs.items()[5]); // Cantaloupe - })); + }); it('should select an item via typeahead', () => { const {list} = getDefaultPatterns({multi: signal(false)}); diff --git a/src/aria/private/menu/menu.spec.ts b/src/aria/private/menu/menu.spec.ts index 56c8a2208427..a31697d00b32 100644 --- a/src/aria/private/menu/menu.spec.ts +++ b/src/aria/private/menu/menu.spec.ts @@ -10,7 +10,6 @@ import {signal, WritableSignal} from '@angular/core'; import {MenuPattern, MenuBarPattern, MenuItemPattern, MenuTriggerPattern} from './menu'; import {createKeyboardEvent} from '@angular/cdk/testing/private'; import {ModifierKeys} from '@angular/cdk/testing'; -import {fakeAsync, tick} from '@angular/core/testing'; // Test types type TestMenuItem = MenuItemPattern & { @@ -177,22 +176,26 @@ describe('Standalone Menu Pattern', () => { }); describe('Typeahead', () => { - it('should move the active item to the next item that starts with the typed character', fakeAsync(() => { + function delay(amount: number) { + return new Promise(resolve => setTimeout(resolve, amount)); + } + + it('should move the active item to the next item that starts with the typed character', async () => { const menu = getMenuPattern(undefined, ['Apple', 'Banana', 'Cherry']); const items = menu.inputs.items(); const b = createKeyboardEvent('keydown', 66, 'b'); menu.onKeydown(b); - tick(500); + await delay(500); expect(menu.inputs.activeItem()).toBe(items[1]); const c = createKeyboardEvent('keydown', 67, 'c'); menu.onKeydown(c); - tick(500); + await delay(500); expect(menu.inputs.activeItem()).toBe(items[2]); - })); + }); - it('should support multi-character typeahead', fakeAsync(() => { + it('should support multi-character typeahead', async () => { const menu = getMenuPattern(undefined, ['Cabbage', 'Chard', 'Cherry', 'Cilantro']); const c = createKeyboardEvent('keydown', 67, 'c'); @@ -208,36 +211,36 @@ describe('Standalone Menu Pattern', () => { menu.onKeydown(e); expect(menu.inputs.activeItem()?.value()).toBe('Cherry'); - tick(500); + await delay(500); menu.onKeydown(c); expect(menu.inputs.activeItem()?.value()).toBe('Cilantro'); - })); + }); - it('should wrap when reaching the end of the list during typeahead', fakeAsync(() => { + it('should wrap when reaching the end of the list during typeahead', async () => { const menu = getMenuPattern(undefined, ['Apple', 'Banana', 'Avocado']); const items = menu.inputs.items(); menu.inputs.activeItem.set(items[1]); const a = createKeyboardEvent('keydown', 65, 'a'); menu.onKeydown(a); - tick(500); + await delay(500); expect(menu.inputs.activeItem()).toBe(items[2]); menu.onKeydown(a); - tick(500); + await delay(500); expect(menu.inputs.activeItem()).toBe(items[0]); - })); + }); - it('should not move the active item if no item matches the typed character', fakeAsync(() => { + it('should not move the active item if no item matches the typed character', async () => { const menu = getMenuPattern(undefined, ['Apple', 'Banana', 'Cherry']); const items = menu.inputs.items(); menu.inputs.activeItem.set(items[0]); const z = createKeyboardEvent('keydown', 90, 'z'); menu.onKeydown(z); - tick(500); + await delay(500); expect(menu.inputs.activeItem()).toBe(items[0]); - })); + }); }); });