From e9cfe0e6fa8ac6e045d9b0b0c41d3aed5eec34b6 Mon Sep 17 00:00:00 2001 From: Cassandra Choi Date: Wed, 22 Nov 2023 20:06:44 +0000 Subject: [PATCH] fix(cdk/a11y): fix tests --- .../a11y/key-manager/list-key-manager.spec.ts | 16 +++++++++++++++ src/cdk/a11y/key-manager/list-key-manager.ts | 4 ++-- src/cdk/a11y/key-manager/typeahead.ts | 20 +++++++++---------- .../cdk-tree-custom-key-manager-example.ts | 4 ++++ 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/cdk/a11y/key-manager/list-key-manager.spec.ts b/src/cdk/a11y/key-manager/list-key-manager.spec.ts index 8dd47c94db2a..f4cff3efa4f3 100644 --- a/src/cdk/a11y/key-manager/list-key-manager.spec.ts +++ b/src/cdk/a11y/key-manager/list-key-manager.spec.ts @@ -150,6 +150,7 @@ describe('Key managers', () => { keyManager.setActiveItem(0); itemList.reset([new FakeFocusable('zero'), ...itemList.toArray()]); + itemList.notifyOnChanges(); keyManager.setActiveItem(0); expect(spy).toHaveBeenCalledTimes(1); @@ -342,6 +343,7 @@ describe('Key managers', () => { const items = itemList.toArray(); items[1].disabled = true; itemList.reset(items); + itemList.notifyOnChanges(); // Next event should skip past disabled item from 0 to 2 keyManager.onKeydown(this.nextKeyEvent); @@ -367,6 +369,7 @@ describe('Key managers', () => { items[1].disabled = undefined; items[2].disabled = undefined; itemList.reset(items); + itemList.notifyOnChanges(); keyManager.onKeydown(this.nextKeyEvent); expect(keyManager.activeItemIndex) @@ -416,6 +419,7 @@ describe('Key managers', () => { const items = itemList.toArray(); items[2].disabled = true; itemList.reset(items); + itemList.notifyOnChanges(); keyManager.onKeydown(this.nextKeyEvent); expect(keyManager.activeItemIndex) @@ -558,6 +562,7 @@ describe('Key managers', () => { const items = itemList.toArray(); items[0].disabled = true; itemList.reset(items); + itemList.notifyOnChanges(); keyManager.setFirstItemActive(); expect(keyManager.activeItemIndex) @@ -580,6 +585,7 @@ describe('Key managers', () => { const items = itemList.toArray(); items[2].disabled = true; itemList.reset(items); + itemList.notifyOnChanges(); keyManager.setLastItemActive(); expect(keyManager.activeItemIndex) @@ -602,6 +608,7 @@ describe('Key managers', () => { const items = itemList.toArray(); items[1].disabled = true; itemList.reset(items); + itemList.notifyOnChanges(); expect(keyManager.activeItemIndex) .withContext(`Expected first item of the list to be active.`) @@ -629,6 +636,7 @@ describe('Key managers', () => { const items = itemList.toArray(); items[1].disabled = true; itemList.reset(items); + itemList.notifyOnChanges(); keyManager.onKeydown(fakeKeyEvents.downArrow); keyManager.onKeydown(fakeKeyEvents.downArrow); @@ -706,6 +714,7 @@ describe('Key managers', () => { const items = itemList.toArray(); items.forEach(item => (item.disabled = true)); itemList.reset(items); + itemList.notifyOnChanges(); keyManager.onKeydown(fakeKeyEvents.downArrow); }); @@ -730,6 +739,7 @@ describe('Key managers', () => { const items = itemList.toArray(); items[1].disabled = true; itemList.reset(items); + itemList.notifyOnChanges(); expect(keyManager.activeItemIndex).toBe(0); @@ -744,6 +754,7 @@ describe('Key managers', () => { const items = itemList.toArray(); items[1].skipItem = true; itemList.reset(items); + itemList.notifyOnChanges(); expect(keyManager.activeItemIndex).toBe(0); @@ -839,6 +850,7 @@ describe('Key managers', () => { new FakeFocusable('две'), new FakeFocusable('три'), ]); + itemList.notifyOnChanges(); const keyboardEvent = createKeyboardEvent('keydown', 68, 'д'); @@ -854,6 +866,7 @@ describe('Key managers', () => { new FakeFocusable('321'), new FakeFocusable('`!?'), ]); + itemList.notifyOnChanges(); keyManager.onKeydown(createKeyboardEvent('keydown', 192, '`')); // types "`" tick(debounceInterval); @@ -874,6 +887,7 @@ describe('Key managers', () => { const items = itemList.toArray(); items[0].disabled = true; itemList.reset(items); + itemList.notifyOnChanges(); keyManager.onKeydown(createKeyboardEvent('keydown', 79, 'o')); // types "o" tick(debounceInterval); @@ -889,6 +903,7 @@ describe('Key managers', () => { new FakeFocusable('Boromir'), new FakeFocusable('Aragorn'), ]); + itemList.notifyOnChanges(); keyManager.setActiveItem(1); keyManager.onKeydown(createKeyboardEvent('keydown', 66, 'b')); @@ -905,6 +920,7 @@ describe('Key managers', () => { new FakeFocusable('Boromir'), new FakeFocusable('Aragorn'), ]); + itemList.notifyOnChanges(); keyManager.setActiveItem(3); keyManager.onKeydown(createKeyboardEvent('keydown', 66, 'b')); diff --git a/src/cdk/a11y/key-manager/list-key-manager.ts b/src/cdk/a11y/key-manager/list-key-manager.ts index dfb908b7b87e..4929c95c3b03 100644 --- a/src/cdk/a11y/key-manager/list-key-manager.ts +++ b/src/cdk/a11y/key-manager/list-key-manager.ts @@ -63,10 +63,10 @@ export class ListKeyManager { // items aren't being collected via `ViewChildren` or `ContentChildren`). if (_items instanceof QueryList) { this._itemChangesSubscription = _items.changes.subscribe((newItems: QueryList) => { + const itemArray = newItems.toArray(); + this._typeahead?.setItems(itemArray); if (this._activeItem) { - const itemArray = newItems.toArray(); const newIndex = itemArray.indexOf(this._activeItem); - this._typeahead?.setItems(itemArray); if (newIndex > -1 && newIndex !== this._activeItemIndex) { this._activeItemIndex = newIndex; diff --git a/src/cdk/a11y/key-manager/typeahead.ts b/src/cdk/a11y/key-manager/typeahead.ts index ca921a94d547..f36b280c944f 100644 --- a/src/cdk/a11y/key-manager/typeahead.ts +++ b/src/cdk/a11y/key-manager/typeahead.ts @@ -36,6 +36,15 @@ export class Typeahead { this._skipPredicateFn = config.skipPredicate; } + if ( + (typeof ngDevMode === 'undefined' || ngDevMode) && + initialItems.length && + initialItems.some(item => typeof item.getLabel !== 'function') + ) { + console.error('failed', initialItems); + throw new Error('KeyManager items in typeahead mode must implement the `getLabel` method.'); + } + this.setItems(initialItems); this._setupKeyHandler(typeAheadInterval); } @@ -51,14 +60,6 @@ export class Typeahead { } setItems(items: T[]) { - if ( - (typeof ngDevMode === 'undefined' || ngDevMode) && - items.length && - items.some(item => typeof item.getLabel !== 'function') - ) { - throw new Error('KeyManager items in typeahead mode must implement the `getLabel` method.'); - } - this._items = items; } @@ -79,13 +80,12 @@ export class Typeahead { return this._pressedLetters.length > 0; } - // TODO: find a better name? + /** Resets the currently stored sequence of typed letters. */ reset(): void { this._pressedLetters = []; } private _setupKeyHandler(typeAheadInterval: number) { - // TODO: handle unsubscription // Debounce the presses of non-navigational keys, collect the ones that correspond to letters // and convert those letters back into a string. Afterwards find the first item that starts // with that string and select it. diff --git a/src/components-examples/cdk/tree/cdk-tree-custom-key-manager/cdk-tree-custom-key-manager-example.ts b/src/components-examples/cdk/tree/cdk-tree-custom-key-manager/cdk-tree-custom-key-manager-example.ts index f57d7cfa920e..4b2ae494da61 100644 --- a/src/components-examples/cdk/tree/cdk-tree-custom-key-manager/cdk-tree-custom-key-manager-example.ts +++ b/src/components-examples/cdk/tree/cdk-tree-custom-key-manager/cdk-tree-custom-key-manager-example.ts @@ -132,6 +132,10 @@ export class VimTreeKeyManager implements TreeKeyM } } + destroy() { + this.change.complete(); + } + /** Stream that emits any time the focused item changes. */ readonly change = new Subject();