1+ using AngleSharp . Dom ;
2+ using AngleSharp . Html . Dom ;
3+ using Bunit ;
4+ using FluentAssertions ;
5+ using Microsoft . AspNetCore . Components ;
6+ using Xunit ;
7+
8+ namespace SimpleBlazorMultiselect . Tests ;
9+
10+ public class EqualityTests : BaseTest
11+ {
12+ [ Fact ]
13+ public void Component_CanDeselect_WhenPrefilledValueItems ( )
14+ {
15+ var options = new List < TestValueItem >
16+ {
17+ new ( "1" , "Apple" ) ,
18+ new ( "2" , "Banana" ) ,
19+ new ( "3" , "Cherry" )
20+ } ;
21+ var selectedItems = new HashSet < TestValueItem >
22+ {
23+ new ( "1" , "Apple" )
24+ } ;
25+
26+ var component = RenderComponent < SimpleMultiselect < TestValueItem > > ( parameters => parameters
27+ . Add ( p => p . Options , options )
28+ . Add ( p => p . SelectedOptions , selectedItems )
29+ . Add ( p => p . StringSelector , item => item . Name )
30+ . Add ( p => p . DefaultText , "Select fruits" )
31+ . Add ( p => p . SelectedOptionsChanged , EventCallback . Factory . Create < HashSet < TestValueItem > > ( this , newSelection => { selectedItems = newSelection ; } ) ) ) ;
32+
33+ var button = component . Find ( "button" ) ;
34+ button . TextContent . Should ( ) . Contain ( "Apple" ) ;
35+ button . Click ( ) ;
36+
37+ // Now only apple should be checked
38+ var appleOption = component . FindAll ( ".dropdown-item" ) [ 0 ] ;
39+ var appleCheckbox = appleOption . QuerySelector < IHtmlInputElement > ( "input[type='checkbox']" ) ;
40+ appleCheckbox . Should ( ) . NotBeNull ( ) ;
41+ appleCheckbox . IsChecked . Should ( ) . BeTrue ( ) ;
42+
43+ appleOption . Click ( ) ;
44+
45+ // After clicking, apple should be deselected
46+ selectedItems . Should ( ) . BeEmpty ( ) ;
47+ button = component . Find ( "button" ) ;
48+ button . TextContent . Should ( ) . Be ( "Select fruits" ) ;
49+ }
50+
51+ [ Fact ]
52+ public void Component_CanDeselect_WhenPrefilledReferenceItems ( )
53+ {
54+ var options = new List < TestReferenceItem >
55+ {
56+ new ( "1" , "Apple" ) ,
57+ new ( "2" , "Banana" ) ,
58+ new ( "3" , "Cherry" )
59+ } ;
60+ var selectedItems = new HashSet < TestReferenceItem >
61+ {
62+ new ( "1" , "Apple" )
63+ } ;
64+
65+ var component = RenderComponent < SimpleMultiselect < TestReferenceItem > > ( parameters => parameters
66+ . Add ( p => p . Options , options )
67+ . Add ( p => p . SelectedOptions , selectedItems )
68+ . Add ( p => p . StringSelector , item => item . Name )
69+ . Add ( p => p . DefaultText , "Select fruits" )
70+ . Add ( p => p . SelectedOptionsChanged , EventCallback . Factory . Create < HashSet < TestReferenceItem > > ( this , newSelection => { selectedItems = newSelection ; } ) ) ) ;
71+
72+ var button = component . Find ( "button" ) ;
73+ button . TextContent . Should ( ) . Contain ( "Apple" ) ;
74+ button . Click ( ) ;
75+
76+ // Now only apple should be checked
77+ var appleOption = component . FindAll ( ".dropdown-item" ) [ 0 ] ;
78+ var appleCheckbox = appleOption . QuerySelector < IHtmlInputElement > ( "input[type='checkbox']" ) ;
79+ appleCheckbox . Should ( ) . NotBeNull ( ) ;
80+ appleCheckbox . IsChecked . Should ( ) . BeTrue ( ) ;
81+
82+ appleOption . Click ( ) ;
83+
84+ // After clicking, apple should be deselected
85+ selectedItems . Should ( ) . BeEmpty ( ) ;
86+ button = component . Find ( "button" ) ;
87+ button . TextContent . Should ( ) . Be ( "Select fruits" ) ;
88+ }
89+
90+ [ Fact ]
91+ public void Component_CanDeselectValueItem_WhenMatchByReference ( )
92+ {
93+ var options = new List < TestValueItem >
94+ {
95+ new ( "1" , "Apple" ) ,
96+ new ( "2" , "Banana" ) ,
97+ new ( "3" , "Cherry" )
98+ } ;
99+ var selectedItems = new HashSet < TestValueItem >
100+ {
101+ new ( "1" , "Apple" )
102+ } ;
103+
104+ var component = RenderComponent < SimpleMultiselect < TestValueItem > > ( parameters => parameters
105+ . Add ( p => p . Options , options )
106+ . Add ( p => p . SelectedOptions , selectedItems )
107+ . Add ( p => p . StringSelector , item => item . Name )
108+ . Add ( p => p . DefaultText , "Select fruits" )
109+ . Add ( p => p . SelectedOptionsChanged , EventCallback . Factory . Create < HashSet < TestValueItem > > ( this , newSelection => { selectedItems = newSelection ; } ) )
110+ . Add ( p => p . MatchByReference , true ) ) ; // Should not matter for value types
111+
112+ var button = component . Find ( "button" ) ;
113+ button . TextContent . Should ( ) . Contain ( "Apple" ) ;
114+ button . Click ( ) ;
115+
116+ // Now only apple should be checked
117+ var appleOption = component . FindAll ( ".dropdown-item" ) [ 0 ] ;
118+ var appleCheckbox = appleOption . QuerySelector < IHtmlInputElement > ( "input[type='checkbox']" ) ;
119+ appleCheckbox . Should ( ) . NotBeNull ( ) ;
120+ appleCheckbox . IsChecked . Should ( ) . BeTrue ( ) ;
121+
122+ appleOption . Click ( ) ;
123+
124+ // After clicking, apple should be deselected
125+ selectedItems . Should ( ) . BeEmpty ( ) ;
126+ button = component . Find ( "button" ) ;
127+ button . TextContent . Should ( ) . Be ( "Select fruits" ) ;
128+ }
129+
130+ [ Fact ]
131+ public void Component_CannotDeselectIdenticalInstance_WhenMatchByReference ( )
132+ {
133+ var options = new List < TestReferenceItem >
134+ {
135+ new ( "1" , "Apple" ) ,
136+ new ( "2" , "Banana" ) ,
137+ new ( "3" , "Cherry" )
138+ } ;
139+ var selectedItems = new HashSet < TestReferenceItem >
140+ {
141+ new ( "1" , "Apple" )
142+ } ;
143+
144+ var component = RenderComponent < SimpleMultiselect < TestReferenceItem > > ( parameters => parameters
145+ . Add ( p => p . Options , options )
146+ . Add ( p => p . SelectedOptions , selectedItems )
147+ . Add ( p => p . StringSelector , item => item . Name )
148+ . Add ( p => p . DefaultText , "Select fruits" )
149+ . Add ( p => p . SelectedOptionsChanged , EventCallback . Factory . Create < HashSet < TestReferenceItem > > ( this , newSelection => { selectedItems = newSelection ; } ) )
150+ . Add ( p => p . MatchByReference , true ) ) ; // This will break the deselection
151+
152+ var button = component . Find ( "button" ) ;
153+ button . TextContent . Should ( ) . Contain ( "Apple" ) ;
154+ button . Click ( ) ;
155+
156+ // Apple should not be checked because the instance is different
157+ // So clicking it will add another apple instead of removing the existing one
158+ var appleOption = component . FindAll ( ".dropdown-item" ) [ 0 ] ;
159+ var appleCheckbox = appleOption . QuerySelector < IHtmlInputElement > ( "input[type='checkbox']" ) ;
160+ appleCheckbox . Should ( ) . NotBeNull ( ) ;
161+ appleCheckbox . IsChecked . Should ( ) . BeFalse ( ) ;
162+
163+ appleOption . Click ( ) ;
164+
165+ // After clicking, we should have two apples
166+ selectedItems . Should ( ) . HaveCount ( 2 ) ;
167+ button = component . Find ( "button" ) ;
168+ button . TextContent . Should ( ) . Be ( "Apple, Apple" ) ;
169+ }
170+ }
0 commit comments