Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 9 additions & 14 deletions src/aria/combobox/combobox.spec.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
9 changes: 5 additions & 4 deletions src/aria/listbox/listbox.spec.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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});
Expand Down
37 changes: 15 additions & 22 deletions src/aria/menu/menu.spec.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -102,29 +102,27 @@ 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');

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');

Expand All @@ -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);
}));
});
});
});

Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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);
}));
});
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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);
Expand Down
20 changes: 11 additions & 9 deletions src/aria/private/behaviors/list/list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<V> = ListItem<V> & {
disabled: WritableSignal<boolean>;
Expand Down Expand Up @@ -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');
Expand All @@ -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)});
Expand Down
33 changes: 18 additions & 15 deletions src/aria/private/menu/menu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> & {
Expand Down Expand Up @@ -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');
Expand All @@ -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]);
}));
});
});
});

Expand Down
Loading