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