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