Skip to content

Commit e2c54c6

Browse files
authored
Merge pull request #1 from Diggernaut/select-support
Added support for selectElement
2 parents e9100b7 + 28963fb commit e2c54c6

File tree

1 file changed

+287
-0
lines changed

1 file changed

+287
-0
lines changed

select.go

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
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

Comments
 (0)