Skip to content

Commit 18bf21a

Browse files
committed
add select object handler
this commit is from tebeka/selenium#238
1 parent b706335 commit 18bf21a

File tree

1 file changed

+301
-0
lines changed

1 file changed

+301
-0
lines changed

select.go

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

0 commit comments

Comments
 (0)