1   package com.atlassian.pageobjects.elements;
2   
3   import com.atlassian.pageobjects.PageBinder;
4   import com.atlassian.pageobjects.elements.timeout.TimeoutType;
5   import com.atlassian.pageobjects.elements.timeout.Timeouts;
6   import com.atlassian.webdriver.AtlassianWebDriver;
7   import com.atlassian.webdriver.utils.Check;
8   import com.google.common.collect.Lists;
9   import org.openqa.selenium.By;
10  import org.openqa.selenium.RenderedWebElement;
11  import org.openqa.selenium.WebElement;
12  
13  import javax.inject.Inject;
14  import java.util.List;
15  import java.util.concurrent.TimeUnit;
16  
17  import static com.google.common.base.Preconditions.checkNotNull;
18  
19  /**
20   * Implementation of {@link PageElement} that waits for element to be
21   * present before executing each actions.
22   * 
23   */
24  public class WebDriverElement implements PageElement
25  {
26      @Inject
27      protected AtlassianWebDriver driver;
28  
29      @Inject
30      protected PageBinder pageBinder;
31  
32      @Inject
33      protected Timeouts timeouts;
34  
35      protected final WebDriverLocatable locatable;
36      private final TimeoutType defaultTimeout;
37  
38      /**
39       * Creates a WebDriverElement within the driver's search context and default timeout
40       * @param locator The locator mechanism to use.
41       */
42      public WebDriverElement(By locator)
43      {
44          this(locator, TimeoutType.DEFAULT);
45      }
46  
47      /**
48       * Creates a WebDriverElement within the driver's search context and given timeout type.
49       * 
50       * @param locator The locator mechanism to use.
51       * @param timeoutType default timeout of this element
52       */
53      public WebDriverElement(By locator, TimeoutType timeoutType)
54      {
55          this(locator, WebDriverLocators.root(), timeoutType);
56      }
57  
58      /**
59       * Creates a WebDriverElement within a given parent and default timeout.
60       *
61       * @param locator The locator mechanism to use.
62       * @param parent The locatable parent of this element.
63       */
64      public WebDriverElement(By locator, WebDriverLocatable parent)
65      {
66          this(locator, parent, TimeoutType.DEFAULT);
67      }
68  
69      /**
70       * Creates a WebDriverElement within a given parent and given timeout type.
71       *
72       * @param locator The locator mechanism to use.
73       * @param parent The locatable parent of this element.
74       * @param timeoutType default timeout of this element
75       */
76      public WebDriverElement(By locator, WebDriverLocatable parent, TimeoutType timeoutType)
77      {
78          this.locatable = WebDriverLocators.nested(locator, parent);
79          this.defaultTimeout = checkNotNull(timeoutType);
80      }
81  
82      /**
83       * Creates a WebDriverElement with the given locatable and timeout type.
84       *
85       * @param locatable WebDriverLocatable that that locate this element
86       * @param timeoutType default timeout of this element
87       */
88      public WebDriverElement(WebDriverLocatable locatable, TimeoutType timeoutType)
89      {
90          this.locatable = locatable;
91          this.defaultTimeout = checkNotNull(timeoutType);
92      }
93  
94      protected long timeout()
95      {
96          return timeouts.timeoutFor(defaultTimeout);
97      }
98  
99      protected int timeoutInSeconds()
100     {
101         // sucks sucks sucks sucks sucks....
102         return (int) TimeUnit.MILLISECONDS.toSeconds(timeout());
103     }
104 
105     protected WebElement waitForWebElement()
106     {
107         return (WebElement) locatable.waitUntilLocated(driver, timeoutInSeconds());
108     }
109     
110     public boolean isPresent()
111     {
112         return locatable.isPresent(driver, timeoutInSeconds());
113     }
114 
115     public boolean isVisible()
116     {
117         WebElement element = waitForWebElement();
118         return ((RenderedWebElement) element).isDisplayed();
119     }
120 
121     public boolean isEnabled()
122     {
123         return waitForWebElement().isEnabled();
124     }
125 
126     public boolean isSelected()
127     {
128         return waitForWebElement().isSelected();
129     }
130 
131     public boolean hasClass(final String className)
132     {
133         return Check.hasClass(className, waitForWebElement());
134     }
135 
136     public String getAttribute(final String name)
137     {
138         return waitForWebElement().getAttribute(name);
139     }
140 
141     public boolean hasAttribute(final String name, final String value)
142     {
143         return value.equals(getAttribute(name));
144     }
145 
146     public String getText()
147     {
148         return waitForWebElement().getText();
149     }
150 
151     public String getTagName()
152     {
153         return waitForWebElement().getTagName();
154     }
155 
156     public String getValue()
157     {
158         return waitForWebElement().getValue();
159     }
160 
161     public PageElement click()
162     {
163         waitForWebElement().click();
164         return this;
165     }
166 
167     public PageElement type(final CharSequence... keysToSend)
168     {
169         waitForWebElement().sendKeys(keysToSend);
170         return this;
171     }
172 
173     public PageElement select()
174     {
175         waitForWebElement().setSelected();
176         return this;
177     }
178 
179     public PageElement toggle()
180     {
181         waitForWebElement().toggle();
182         return this;
183     }
184 
185     public PageElement clear()
186     {
187         waitForWebElement().clear();
188         return this;
189     }
190 
191     public TimedElement timed()
192     {
193        return pageBinder.bind(WebDriverTimedElement.class, locatable, defaultTimeout);
194     }
195 
196     public PageElementJavascriptExecutor javascript()
197     {
198         return new PageElementJavascriptExecutor(driver, waitForWebElement());
199     }
200 
201     public PageElement find(By locator)
202     {
203         return pageBinder.bind(WebDriverElement.class, locator, locatable);
204     }
205 
206     public PageElement find(By locator, TimeoutType timeoutType)
207     {
208         return pageBinder.bind(WebDriverElement.class, locator, locatable, timeoutType);
209     }
210 
211     public <T extends PageElement> T find(By locator, Class<T> elementClass)
212     {
213         return pageBinder.bind(WebDriverElementMappings.findMapping(elementClass), locator, locatable);
214     }
215 
216     public <T extends PageElement> T find(By locator, Class<T> elementClass, TimeoutType timeoutType)
217     {
218         return pageBinder.bind(WebDriverElementMappings.findMapping(elementClass), locator, locatable, timeoutType);
219     }
220 
221     public List<PageElement> findAll(final By locator)
222     {
223         return findAll(locator, defaultTimeout);
224     }
225 
226     public List<PageElement> findAll(By locator, TimeoutType timeoutType)
227     {
228         return findAll(locator, PageElement.class, timeoutType);
229     }
230 
231     public <T extends PageElement> List<T> findAll(By locator, Class<T> elementClass)
232     {
233         return findAll(locator, elementClass, defaultTimeout);
234     }
235 
236     public <T extends PageElement> List<T> findAll(By locator, Class<T> elementClass, TimeoutType timeoutType)
237     {
238         List<T> elements = Lists.newLinkedList();
239         List<WebElement> webElements = waitForWebElement().findElements(locator);
240 
241         for(int i = 0; i < webElements.size(); i++)
242         {
243             elements.add(pageBinder.bind(WebDriverElementMappings.findMapping(elementClass),
244                     WebDriverLocators.list(webElements.get(i), locator, i, locatable), timeoutType));
245         }
246         return elements;
247     }
248 
249 
250     public PageElement withTimeout(TimeoutType timeoutType)
251     {
252         if (this.defaultTimeout == timeoutType)
253         {
254             return this;
255         }
256         return pageBinder.bind(WebDriverElement.class, locatable, checkNotNull(timeoutType));
257     }
258 }