@@ -2,6 +2,9 @@ import { fireEvent, render, screen } from "@testing-library/react";
22import React from "react" ;
33import { Dropdown } from "./index" ;
44
5+ // Значение инпута-комбобокса (getByRole возвращает HTMLElement).
6+ const comboboxValue = ( ) => ( screen . getByRole ( "combobox" ) as HTMLInputElement ) . value ;
7+
58test ( "Dropdown smoke: дропдаун рендерит выбранное значение" , ( ) => {
69 const { container } = render ( < Dropdown < string > items = { [ "a" , "b" ] } value = "a" /> ) ;
710 const input = container . querySelector ( "input" ) ;
@@ -49,14 +52,70 @@ test("Dropdown: у listbox есть пункты role=option прямыми де
4952 }
5053} ) ;
5154
52- // a11y (stage 4): nested-interactive — пункт не самостоятельный интерактивный
53- // элемент: у обёртки нет tabindex, клик по телу пункта ничего не выбирает
54- // (интерактивные контролы — кнопки внутри строк).
55- test ( "Dropdown: пункты не фокусируемы и не выбираются кликом по телу" , ( ) => {
56- render ( < Dropdown < string > items = { [ "a" , "b" ] } value = "a" /> ) ;
55+ // Кликабельность пунктов: клик по телу пункта выбирает значение — инпут
56+ // показывает выбранное, onChange вызывается, список закрывается.
57+ test ( "Dropdown: клик по пункту выбирает значение и закрывает список" , ( ) => {
58+ const onChange = vi . fn ( ) ;
59+ render ( < Dropdown < string > items = { [ "a" , "b" , "c" ] } value = "a" onChange = { onChange } /> ) ;
5760 fireEvent . click ( screen . getByRole ( "button" , { name : "Открыть список" } ) ) ;
58- const option = screen . getAllByRole ( "option" ) [ 0 ] ;
59- expect ( option . hasAttribute ( "tabindex" ) ) . toBe ( false ) ;
60- fireEvent . click ( option ) ;
61- expect ( screen . getByRole ( "listbox" ) ) . not . toBeNull ( ) ;
61+ fireEvent . click ( screen . getAllByRole ( "option" ) [ 1 ] ) ;
62+ expect ( onChange ) . toHaveBeenCalledWith ( "b" ) ;
63+ const input = screen . getByRole ( "combobox" ) as HTMLInputElement ;
64+ expect ( input . value ) . toBe ( "b" ) ;
65+ expect ( screen . queryByRole ( "listbox" ) ) . toBeNull ( ) ;
66+ } ) ;
67+
68+ // a11y (useKeyWithClickEvents): у пункта с onClick есть клавиатурный
69+ // эквивалент — пункт фокусируем (tabIndex) и выбирается по Enter/Space.
70+ test ( "Dropdown: пункт фокусируем и выбирается по Enter" , ( ) => {
71+ const onChange = vi . fn ( ) ;
72+ render ( < Dropdown < string > items = { [ "a" , "b" ] } value = "a" onChange = { onChange } /> ) ;
73+ fireEvent . click ( screen . getByRole ( "button" , { name : "Открыть список" } ) ) ;
74+ const option = screen . getAllByRole ( "option" ) [ 1 ] ;
75+ expect ( option . getAttribute ( "tabindex" ) ) . toBe ( "0" ) ;
76+ fireEvent . keyDown ( option , { key : "Enter" } ) ;
77+ expect ( onChange ) . toHaveBeenCalledWith ( "b" ) ;
78+ expect ( comboboxValue ( ) ) . toBe ( "b" ) ;
79+ } ) ;
80+
81+ // Отключённый пункт (checkDisabledItem) кликом не выбирается.
82+ test ( "Dropdown: клик по отключённому пункту ничего не выбирает" , ( ) => {
83+ const onChange = vi . fn ( ) ;
84+ render (
85+ < Dropdown < string >
86+ items = { [ "a" , "b" ] }
87+ value = "a"
88+ onChange = { onChange }
89+ checkDisabledItem = { ( item ) => item === "b" }
90+ /> ,
91+ ) ;
92+ fireEvent . click ( screen . getByRole ( "button" , { name : "Открыть список" } ) ) ;
93+ fireEvent . click ( screen . getAllByRole ( "option" ) [ 1 ] ) ;
94+ expect ( onChange ) . not . toHaveBeenCalled ( ) ;
95+ expect ( comboboxValue ( ) ) . toBe ( "a" ) ;
96+ } ) ;
97+
98+ // Пункты с собственными контролами (renderItem): их обработчики делают
99+ // stopPropagation — клик по кнопке внутри строки не выбирает пункт.
100+ test ( "Dropdown: кнопка внутри renderItem не выбирает пункт" , ( ) => {
101+ const onChange = vi . fn ( ) ;
102+ render (
103+ < Dropdown < string >
104+ items = { [ "a" , "b" ] }
105+ value = "a"
106+ onChange = { onChange }
107+ renderItem = { ( { item } ) => (
108+ < span >
109+ { item }
110+ < button type = "button" onClick = { ( event ) => event . stopPropagation ( ) } >
111+ x
112+ </ button >
113+ </ span >
114+ ) }
115+ /> ,
116+ ) ;
117+ fireEvent . click ( screen . getByRole ( "button" , { name : "Открыть список" } ) ) ;
118+ fireEvent . click ( screen . getAllByRole ( "option" ) [ 1 ] . querySelector ( "button" ) ! ) ;
119+ expect ( onChange ) . not . toHaveBeenCalled ( ) ;
120+ expect ( comboboxValue ( ) ) . toBe ( "a" ) ;
62121} ) ;
0 commit comments