Skip to content

Commit d9970db

Browse files
authored
test(cdk-experimental/ui-patterns): listbox navigation tests (#30767)
* test(cdk-experimental/ui-patterns): listbox navigation tests * fixup! test(cdk-experimental/ui-patterns): listbox navigation tests * fixup! test(cdk-experimental/ui-patterns): listbox navigation tests * fixup! test(cdk-experimental/ui-patterns): listbox navigation tests
1 parent 9fb4018 commit d9970db

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

Diff for: src/cdk-experimental/ui-patterns/listbox/BUILD.bazel

+18
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
load("//tools:defaults.bzl", "ng_web_test_suite")
12
load("//tools:defaults2.bzl", "ts_project")
23

34
package(default_visibility = ["//visibility:public"])
@@ -18,3 +19,20 @@ ts_project(
1819
"//src/cdk-experimental/ui-patterns/behaviors/signal-like",
1920
],
2021
)
22+
23+
ts_project(
24+
name = "unit_test_sources",
25+
testonly = True,
26+
srcs = glob(["**/*.spec.ts"]),
27+
deps = [
28+
":listbox",
29+
"//:node_modules/@angular/core",
30+
"//src/cdk/keycodes",
31+
"//src/cdk/testing/private",
32+
],
33+
)
34+
35+
ng_web_test_suite(
36+
name = "unit_tests",
37+
deps = [":unit_test_sources"],
38+
)
+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import {signal} from '@angular/core';
10+
import {ListboxInputs, ListboxPattern} from './listbox';
11+
import {OptionPattern} from './option';
12+
import {createKeyboardEvent} from '@angular/cdk/testing/private';
13+
14+
type TestInputs = ListboxInputs<string>;
15+
type TestOption = OptionPattern<string>;
16+
type TestListbox = ListboxPattern<string>;
17+
18+
describe('Listbox Pattern', () => {
19+
function getListbox(inputs: Partial<TestInputs> & Pick<TestInputs, 'items'>) {
20+
return new ListboxPattern({
21+
items: inputs.items,
22+
value: inputs.value ?? signal([]),
23+
activeIndex: inputs.activeIndex ?? signal(0),
24+
typeaheadDelay: inputs.typeaheadDelay ?? signal(0.5),
25+
wrap: inputs.wrap ?? signal(true),
26+
disabled: inputs.disabled ?? signal(false),
27+
skipDisabled: inputs.skipDisabled ?? signal(true),
28+
multiselectable: inputs.multiselectable ?? signal(false),
29+
focusMode: inputs.focusMode ?? signal('roving'),
30+
textDirection: inputs.textDirection ?? signal('ltr'),
31+
orientation: inputs.orientation ?? signal('vertical'),
32+
selectionMode: inputs.selectionMode ?? signal('explicit'),
33+
});
34+
}
35+
36+
function getOptions(listbox: TestListbox, values: string[]): TestOption[] {
37+
return values.map((value, index) => {
38+
return new OptionPattern({
39+
value: signal(value),
40+
id: signal(`option-${index}`),
41+
disabled: signal(false),
42+
searchTerm: signal(value),
43+
listbox: signal(listbox),
44+
element: signal({focus: () => {}} as HTMLElement),
45+
});
46+
});
47+
}
48+
49+
function getPatterns(values: string[], inputs: Partial<TestInputs> = {}) {
50+
const options = signal<TestOption[]>([]);
51+
const listbox = getListbox({...inputs, items: options});
52+
options.set(getOptions(listbox, values));
53+
return {listbox, options};
54+
}
55+
56+
function getDefaultPatterns(inputs: Partial<TestInputs> = {}) {
57+
return getPatterns(
58+
[
59+
'Apple',
60+
'Apricot',
61+
'Banana',
62+
'Blackberry',
63+
'Blueberry',
64+
'Cantaloupe',
65+
'Cherry',
66+
'Clementine',
67+
'Cranberry',
68+
],
69+
inputs,
70+
);
71+
}
72+
73+
describe('Navigation', () => {
74+
it('should navigate next on ArrowDown', () => {
75+
const {listbox} = getDefaultPatterns();
76+
const event = createKeyboardEvent('keydown', 40, 'ArrowDown');
77+
expect(listbox.inputs.activeIndex()).toBe(0);
78+
listbox.onKeydown(event);
79+
expect(listbox.inputs.activeIndex()).toBe(1);
80+
});
81+
82+
it('should navigate prev on ArrowUp', () => {
83+
const event = createKeyboardEvent('keydown', 38, 'ArrowUp');
84+
const {listbox} = getDefaultPatterns({
85+
activeIndex: signal(1),
86+
});
87+
expect(listbox.inputs.activeIndex()).toBe(1);
88+
listbox.onKeydown(event);
89+
expect(listbox.inputs.activeIndex()).toBe(0);
90+
});
91+
92+
it('should navigate next on ArrowRight (horizontal)', () => {
93+
const event = createKeyboardEvent('keydown', 39, 'ArrowRight');
94+
const {listbox} = getDefaultPatterns({
95+
orientation: signal('horizontal'),
96+
});
97+
expect(listbox.inputs.activeIndex()).toBe(0);
98+
listbox.onKeydown(event);
99+
expect(listbox.inputs.activeIndex()).toBe(1);
100+
});
101+
102+
it('should navigate prev on ArrowLeft (horizontal)', () => {
103+
const event = createKeyboardEvent('keydown', 37, 'ArrowLeft');
104+
const {listbox} = getDefaultPatterns({
105+
activeIndex: signal(1),
106+
orientation: signal('horizontal'),
107+
});
108+
expect(listbox.inputs.activeIndex()).toBe(1);
109+
listbox.onKeydown(event);
110+
expect(listbox.inputs.activeIndex()).toBe(0);
111+
});
112+
113+
it('should navigate next on ArrowLeft (horizontal & rtl)', () => {
114+
const event = createKeyboardEvent('keydown', 38, 'ArrowLeft');
115+
const {listbox} = getDefaultPatterns({
116+
textDirection: signal('rtl'),
117+
orientation: signal('horizontal'),
118+
});
119+
expect(listbox.inputs.activeIndex()).toBe(0);
120+
listbox.onKeydown(event);
121+
expect(listbox.inputs.activeIndex()).toBe(1);
122+
});
123+
124+
it('should navigate prev on ArrowRight (horizontal & rtl)', () => {
125+
const event = createKeyboardEvent('keydown', 39, 'ArrowRight');
126+
const {listbox} = getDefaultPatterns({
127+
activeIndex: signal(1),
128+
textDirection: signal('rtl'),
129+
orientation: signal('horizontal'),
130+
});
131+
expect(listbox.inputs.activeIndex()).toBe(1);
132+
listbox.onKeydown(event);
133+
expect(listbox.inputs.activeIndex()).toBe(0);
134+
});
135+
136+
it('should navigate to the first option on Home', () => {
137+
const event = createKeyboardEvent('keydown', 36, 'Home');
138+
const {listbox} = getDefaultPatterns({
139+
activeIndex: signal(8),
140+
});
141+
expect(listbox.inputs.activeIndex()).toBe(8);
142+
listbox.onKeydown(event);
143+
expect(listbox.inputs.activeIndex()).toBe(0);
144+
});
145+
146+
it('should navigate to the last option on End', () => {
147+
const event = createKeyboardEvent('keydown', 35, 'End');
148+
const {listbox} = getDefaultPatterns();
149+
expect(listbox.inputs.activeIndex()).toBe(0);
150+
listbox.onKeydown(event);
151+
expect(listbox.inputs.activeIndex()).toBe(8);
152+
});
153+
});
154+
});

0 commit comments

Comments
 (0)