1
+ package selenium
2
+
3
+ import (
4
+ "fmt"
5
+ "strings"
6
+ )
7
+
8
+ // SelectElement WebElement that is specific to the Select Dropdown
9
+ type SelectElement struct {
10
+ element WebElement
11
+ isMulti bool
12
+ }
13
+
14
+ // Select Creates a SelectElement
15
+ // @param el The initial WebElement
16
+ func Select (el WebElement ) (se SelectElement , err error ) {
17
+ se = SelectElement {}
18
+
19
+ tagName , err := el .TagName ()
20
+ if err != nil || strings .ToLower (tagName ) != "select" {
21
+ err = fmt .Errorf (`element should have been "select" but was "%s"` , tagName )
22
+ return
23
+ }
24
+
25
+ se .element = el
26
+ mult , err2 := el .GetAttribute ("multiple" )
27
+ se .isMulti = (err2 != nil && strings .ToLower (mult ) != "false" )
28
+
29
+ return
30
+ }
31
+
32
+ // GetElement Gets the raw WebElement
33
+ func (s SelectElement ) GetElement () WebElement {
34
+ return s .element
35
+ }
36
+
37
+ // IsMultiple Whether this select element support selecting multiple options at the same time? This
38
+ // is done by checking the value of the "multiple" attribute.
39
+ func (s SelectElement ) IsMultiple () bool {
40
+ return s .isMulti
41
+ }
42
+
43
+ // GetOptions Returns all of the options of that Select
44
+ func (s SelectElement ) GetOptions () ([]WebElement , error ) {
45
+ return s .element .FindElements (ByTagName , "option" )
46
+ }
47
+
48
+ // GetAllSelectedOptions Returns all of the options of that Select that are selected
49
+ func (s SelectElement ) GetAllSelectedOptions () ([]WebElement , error ) {
50
+ // return getOptions().stream().filter(WebElement::isSelected).collect(Collectors.toList());
51
+
52
+ var opts []WebElement
53
+ return opts , nil
54
+ }
55
+
56
+ // GetFirstSelectedOption Returns the first selected option of the Select Element
57
+ func (s SelectElement ) GetFirstSelectedOption () (opt WebElement , err error ) {
58
+ opts , err := s .GetAllSelectedOptions ()
59
+ if err != nil {
60
+ return
61
+ }
62
+ opt = opts [0 ]
63
+ return
64
+ }
65
+
66
+ // SelectByVisibleText Select all options that display text matching the argument. That is,
67
+ // when given "Bar" this would select an option like:
68
+ //
69
+ // <option value="foo">Bar</option>
70
+ //
71
+ // @param text The visible text to match against
72
+ //
73
+ func (s SelectElement ) SelectByVisibleText (text string ) error {
74
+ // try to find the option via XPATH ...
75
+ options , err := s .element .FindElements (ByXPATH , `.//option[normalize-space(.) = "` + escapeQuotes (text )+ `"]` )
76
+ if err != nil {
77
+ return err
78
+ }
79
+
80
+ for _ , option := range options {
81
+ s .setSelected (option , true )
82
+ if ! s .isMulti {
83
+ return nil
84
+ }
85
+ }
86
+
87
+ matched := len (options ) > 0
88
+ if ! matched && strings .Contains (text , " " ) {
89
+ subStringWithoutSpace := getLongestSubstringWithoutSpace (text )
90
+ var candidates []WebElement
91
+ if subStringWithoutSpace == "" {
92
+ // hmm, text is either empty or contains only spaces - get all options ...
93
+ candidates , err = s .GetOptions ()
94
+ } else {
95
+ // get candidates via XPATH ...
96
+ candidates , err = s .element .FindElements (ByXPATH , `.//option[contains(., "` + escapeQuotes (subStringWithoutSpace )+ `")]` )
97
+ }
98
+
99
+ if err != nil {
100
+ return err
101
+ }
102
+
103
+ trimmed := strings .TrimSpace (text )
104
+
105
+ for _ , option := range candidates {
106
+ o , err := option .Text ()
107
+ if err != nil {
108
+ return err
109
+ }
110
+ if trimmed == strings .TrimSpace (o ) {
111
+ s .setSelected (option , true )
112
+ if ! s .isMulti {
113
+ return nil
114
+ }
115
+ matched = true
116
+ }
117
+ }
118
+ }
119
+ if ! matched {
120
+ return fmt .Errorf ("cannot locate option with text: %s" , text )
121
+ }
122
+ return nil
123
+ }
124
+
125
+ // SelectByIndex Select the option at the given index. This is done by examining the "index" attribute of an
126
+ // element, and not merely by counting.
127
+ //
128
+ // @param idx The option at this index will be selected
129
+ func (s SelectElement ) SelectByIndex (idx int ) error {
130
+ return s .setSelectedByIndex (idx , true )
131
+ }
132
+
133
+ // SelectByValue Select all options that have a value matching the argument. That is, when given "foo" this
134
+ // would select an option like:
135
+ //
136
+ // <option value="foo">Bar</option>
137
+ //
138
+ // @param value The value to match against
139
+
140
+ func (s SelectElement ) SelectByValue (value string ) error {
141
+ opts , err := s .findOptionsByValue (value )
142
+ if err != nil {
143
+ return err
144
+ }
145
+ for _ , option := range opts {
146
+ s .setSelected (option , true )
147
+ if ! s .isMulti {
148
+ return nil
149
+ }
150
+ }
151
+ return nil
152
+ }
153
+
154
+ // DeselectAll Clear all selected entries. This is only valid when the SELECT supports multiple selections.
155
+ func (s SelectElement ) DeselectAll () error {
156
+ if ! s .isMulti {
157
+ return fmt .Errorf ("you may only deselect all options of a multi-select" )
158
+ }
159
+
160
+ opts , err := s .GetOptions ()
161
+ if err != nil {
162
+ return err
163
+ }
164
+ for _ , o := range opts {
165
+ err = s .setSelected (o , false )
166
+ if err != nil {
167
+ return err
168
+ }
169
+ }
170
+ return nil
171
+ }
172
+
173
+ // DeselectByValue Deselect all options that have a value matching the argument. That is, when given "foo" this
174
+ // would deselect an option like:
175
+ //
176
+ // <option value="foo">Bar</option>
177
+ //
178
+ // @param value The value to match against
179
+ func (s SelectElement ) DeselectByValue (value string ) error {
180
+ if ! s .isMulti {
181
+ return fmt .Errorf ("you may only deselect all options of a multi-select" )
182
+ }
183
+
184
+ opts , err := s .findOptionsByValue (value )
185
+ if err != nil {
186
+ return err
187
+ }
188
+ for _ , o := range opts {
189
+ err = s .setSelected (o , false )
190
+ if err != nil {
191
+ return err
192
+ }
193
+ }
194
+ return nil
195
+ }
196
+
197
+ // DeselectByIndex Deselect the option at the given index. This is done by examining the "index" attribute of an
198
+ // element, and not merely by counting.
199
+ //
200
+ // @param index The option at this index will be deselected
201
+ func (s SelectElement ) DeselectByIndex (index int ) error {
202
+ if ! s .isMulti {
203
+ return fmt .Errorf ("you may only deselect all options of a multi-select" )
204
+ }
205
+
206
+ return s .setSelectedByIndex (index , false )
207
+ }
208
+
209
+ // DeselectByVisibleText Deselect all options that display text matching the argument. That is,
210
+ // when given "Bar" this would deselect an option like:
211
+ //
212
+ // <option value="foo">Bar</option>
213
+ //
214
+ // @param text The visible text to match against
215
+ func (s SelectElement ) DeselectByVisibleText (text string ) error {
216
+ if ! s .isMulti {
217
+ return fmt .Errorf ("you may only deselect all options of a multi-select" )
218
+ }
219
+
220
+ options , err := s .element .FindElements (ByXPATH , `.//option[normalize-space(.) = "` + escapeQuotes (text )+ `"]` )
221
+ if err != nil {
222
+ return err
223
+ }
224
+ if len (options ) == 0 {
225
+ return fmt .Errorf ("Cannot locate option with text: " + text )
226
+ }
227
+
228
+ for _ , option := range options {
229
+ err = s .setSelected (option , false )
230
+ if err != nil {
231
+ return err
232
+ }
233
+ }
234
+ return nil
235
+ }
236
+
237
+ func escapeQuotes (str string ) string {
238
+ str1 := strings .Replace (str , `"` , `\"` , - 1 )
239
+ return str1
240
+ }
241
+
242
+ func getLongestSubstringWithoutSpace (s string ) string {
243
+ result := ""
244
+ st := strings .Split (s , " " )
245
+ for _ , t := range st {
246
+ if len (t ) > len (result ) {
247
+ result = t
248
+ }
249
+ }
250
+ return result
251
+ }
252
+
253
+ func (s SelectElement ) findOptionsByValue (value string ) (opts []WebElement , err error ) {
254
+ opts , err = s .element .FindElements (ByXPATH , `.//option[@value = "` + escapeQuotes (value )+ `"]` )
255
+ if err != nil {
256
+ return
257
+ }
258
+ if len (opts ) == 0 {
259
+ err = fmt .Errorf ("Cannot locate option with value: " + value )
260
+ }
261
+
262
+ return
263
+ }
264
+
265
+ func (s SelectElement ) setSelectedByIndex (index int , selected bool ) error {
266
+ idx := fmt .Sprintf ("%d" , index )
267
+ opts , err := s .element .FindElements (ByXPATH , `.//option[@index = "` + idx + `"]` )
268
+ if err != nil {
269
+ return err
270
+ }
271
+ if len (opts ) == 0 {
272
+ err = fmt .Errorf ("Cannot locate option with index: " + idx )
273
+ return err
274
+ }
275
+
276
+ err = s .setSelected (opts [index ], selected )
277
+
278
+ return err
279
+ }
280
+
281
+ func (s SelectElement ) setSelected (option WebElement , selected bool ) (err error ) {
282
+ sel , err := option .IsSelected ()
283
+ if sel != selected && err == nil {
284
+ err = option .Click ()
285
+ }
286
+ return err
287
+ }
0 commit comments