WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 951b4e3

Browse files
chore: add autocomplete list tests (#115)
* chore: add tests for GuessAutocompleteConfig * chore: add initial autocomplete guess list test * chore: add test for active class on options wrapper * chore: clarify tests * chore: add test for scrolling into view on focus
1 parent fb7f7a0 commit 951b4e3

File tree

3 files changed

+149
-1
lines changed

3 files changed

+149
-1
lines changed

src/components/GuessAutocompleteList.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ const vScrollIntoView: Directive<HTMLElement, boolean> = {
3131
</script>
3232

3333
<template>
34-
<div v-if="options.length > 0" class="options-list" :class="{ active: keyboardFocusIndex >= 0 }">
34+
<div
35+
v-if="options.length > 0"
36+
class="options-list"
37+
:class="{ active: keyboardFocusIndex >= 0 }"
38+
data-testid="options-wrapper"
39+
>
3540
<button
3641
v-for="(option, index) of options"
3742
:key="option"
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { getActiveDescendent, getAutocompleteOptionId } from "../GuessAutocompleteConfig";
2+
3+
describe("GuessAutocompleteConfig", () => {
4+
describe("getAutocompleteOptionId", () => {
5+
it("returns a string identifier for autocomplete option", () => {
6+
expect(getAutocompleteOptionId(0)).toEqual("ac-item-0");
7+
expect(getAutocompleteOptionId(1)).toEqual("ac-item-1");
8+
expect(getAutocompleteOptionId(99)).toEqual("ac-item-99");
9+
});
10+
});
11+
12+
describe("getActiveDescendent", () => {
13+
it("returns the autocomplete option id if focused index is at least 0", () => {
14+
expect(getActiveDescendent(0)).toEqual("ac-item-0");
15+
expect(getActiveDescendent(1)).toEqual("ac-item-1");
16+
expect(getActiveDescendent(99)).toEqual("ac-item-99");
17+
});
18+
19+
it("returns undefined if focused index is less than 0", () => {
20+
expect(getActiveDescendent(-1)).toBeUndefined();
21+
expect(getActiveDescendent(-99)).toBeUndefined();
22+
});
23+
});
24+
});
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { fireEvent, render, screen } from "@testing-library/vue";
2+
import GuessAutocompleteList from "../GuessAutocompleteList.vue";
3+
4+
describe("GuessAutoompleteList", () => {
5+
beforeEach(() => {
6+
// not available in JSDom
7+
Element.prototype.scrollIntoView = () => {};
8+
});
9+
10+
it("only displays if there are options", async () => {
11+
const { rerender } = render(GuessAutocompleteList, {
12+
props: {
13+
options: [],
14+
keyboardFocusIndex: -1,
15+
},
16+
});
17+
18+
expect(screen.queryAllByRole("button")).toHaveLength(0);
19+
20+
await rerender({
21+
options: ["one", "two", "three"],
22+
});
23+
const buttons = screen.queryAllByRole("button");
24+
expect(buttons).toHaveLength(3);
25+
expect(buttons[0]).toHaveTextContent("one");
26+
expect(buttons[1]).toHaveTextContent("two");
27+
expect(buttons[2]).toHaveTextContent("three");
28+
});
29+
30+
it("marks container as active when keyboardFocusIndex is 0 or greater", async () => {
31+
const { rerender } = render(GuessAutocompleteList, {
32+
props: {
33+
options: ["option"],
34+
keyboardFocusIndex: -1,
35+
},
36+
});
37+
38+
expect(screen.getByTestId("options-wrapper")).not.toHaveClass("active");
39+
40+
await rerender({
41+
keyboardFocusIndex: 0,
42+
});
43+
expect(screen.getByTestId("options-wrapper")).toHaveClass("active");
44+
45+
await rerender({
46+
keyboardFocusIndex: 1,
47+
});
48+
expect(screen.getByTestId("options-wrapper")).toHaveClass("active");
49+
});
50+
51+
it("marks particular option as active when the keyboardFocusIndex matches", async () => {
52+
const { rerender } = render(GuessAutocompleteList, {
53+
props: {
54+
options: ["one", "two", "three"],
55+
keyboardFocusIndex: -1,
56+
},
57+
});
58+
59+
const options = screen.getAllByRole("button");
60+
expect(options[0]).not.toHaveClass("active");
61+
expect(options[1]).not.toHaveClass("active");
62+
expect(options[2]).not.toHaveClass("active");
63+
64+
await rerender({
65+
keyboardFocusIndex: 0,
66+
});
67+
expect(options[0]).toHaveClass("active");
68+
expect(options[1]).not.toHaveClass("active");
69+
expect(options[2]).not.toHaveClass("active");
70+
71+
await rerender({
72+
keyboardFocusIndex: 1,
73+
});
74+
expect(options[0]).not.toHaveClass("active");
75+
expect(options[1]).toHaveClass("active");
76+
expect(options[2]).not.toHaveClass("active");
77+
78+
await rerender({
79+
keyboardFocusIndex: 2,
80+
});
81+
expect(options[0]).not.toHaveClass("active");
82+
expect(options[1]).not.toHaveClass("active");
83+
expect(options[2]).toHaveClass("active");
84+
});
85+
86+
it("emits option when clicked", async () => {
87+
const { emitted } = render(GuessAutocompleteList, {
88+
props: {
89+
options: ["one", "two", "three"],
90+
keyboardFocusIndex: -1,
91+
},
92+
});
93+
94+
await fireEvent.click(screen.getByText("two"));
95+
96+
expect(emitted().pick.length).toBe(1);
97+
expect(emitted().pick[0]).toEqual(["two"]);
98+
});
99+
100+
it("scrolls to element when navigated to", async () => {
101+
const { rerender } = render(GuessAutocompleteList, {
102+
props: {
103+
options: ["one", "two", "three"],
104+
keyboardFocusIndex: -1,
105+
},
106+
});
107+
const options = screen.getAllByRole("button");
108+
vi.spyOn(options[0], "scrollIntoView");
109+
vi.spyOn(options[1], "scrollIntoView");
110+
vi.spyOn(options[2], "scrollIntoView");
111+
112+
await rerender({
113+
keyboardFocusIndex: 1,
114+
});
115+
expect(options[0].scrollIntoView).not.toBeCalled();
116+
expect(options[1].scrollIntoView).toBeCalledTimes(1);
117+
expect(options[2].scrollIntoView).not.toBeCalled();
118+
});
119+
});

0 commit comments

Comments
 (0)