1   package com.atlassian.selenium;
2   
3   import com.atlassian.performance.EventTime;
4   import com.atlassian.performance.TimeRecorder;
5   import com.thoughtworks.selenium.Selenium;
6   import com.atlassian.selenium.pageobjects.PageElement;
7   import junit.framework.Assert;
8   import org.apache.log4j.Logger;
9   
10  import java.util.Arrays;
11  
12  /**
13   * This provides helper methods for selenium assertions.  This
14   * mostly means waiting for events to occur (i.e. a dropdown to
15   * appear after a certain timeout, etc)
16   */
17  public class SeleniumAssertions
18  {
19      private static final Logger log = Logger.getLogger(SeleniumAssertions.class);
20      private final Selenium client;
21      private final long conditionCheckInterval;
22      private final long defaultMaxWait;
23      private final TimeRecorder recorder;
24  
25      public SeleniumAssertions(Selenium client, SeleniumConfiguration config, TimeRecorder recorder)
26      {
27          this.client = client;
28          this.conditionCheckInterval = config.getConditionCheckInterval();
29          this.defaultMaxWait = config.getActionWait();
30          this.recorder = recorder;
31      }
32      
33      
34      /**
35       * Temporarily bring back the old constructor so that some older codes compile.
36       */
37      public SeleniumAssertions(Selenium client, SeleniumConfiguration config)
38      {
39          this.client = client;
40          this.conditionCheckInterval = config.getConditionCheckInterval();
41          this.defaultMaxWait = config.getActionWait();
42          this.recorder = new TimeRecorder("Unnamed Test");
43      }    
44  
45      private String defIfNull(String def, String alt)
46      {
47          if(alt == null)
48          {
49              return def;
50          }
51          else
52          {
53              return alt;
54          }
55      }
56  
57  
58      public ByTimeoutConfiguration generateByTimeoutConfig(Condition condition, String locator, long maxWait)
59      {
60          return new ByTimeoutConfiguration(condition, locator, true, maxWait, conditionCheckInterval, null);
61      }
62  
63  
64      public ByTimeoutConfiguration generateByTimeoutConfig(Condition condition, PageElement elem, long maxWait)
65      {
66          return new ByTimeoutConfiguration(condition, elem, maxWait, conditionCheckInterval, null);
67      }
68  
69      public void visibleByTimeout(String locator)
70      {
71         visibleByTimeout(locator, defaultMaxWait);
72      }
73  
74      public void visibleByTimeout(PageElement element)
75      {
76          visibleByTimeout(element, defaultMaxWait);
77      }
78  
79      /**
80       * This will wait until an element is visible.  If it doesnt become visible in
81       * maxMillis fail.
82       *
83       * @param locator   the selenium element locator
84       * @param maxMillis how long to wait as most in milliseconds
85       */
86      public void visibleByTimeout(String locator, long maxMillis)
87      {
88          byTimeout(generateByTimeoutConfig(Conditions.isVisible(locator), locator, maxMillis));
89      }
90  
91      public void visibleByTimeout(PageElement element, long maxMillis)
92      {
93          byTimeout(generateByTimeoutConfig(Conditions.isVisible(element.getLocator()), element, maxMillis));
94      }
95  
96      public void notVisibleByTimeout(String locator)
97      {
98          byTimeout(Conditions.isNotVisible(locator));
99      }
100 
101     public void notVisibleByTimeout(PageElement element)
102     {
103         notVisibleByTimeout(element, defaultMaxWait);
104     }
105 
106     public void notVisibleByTimeout(String locator, long maxMillis)
107     {
108         byTimeout(generateByTimeoutConfig(Conditions.isNotVisible(locator), locator, maxMillis));
109     }
110 
111     public void notVisibleByTimeout(PageElement element, long maxMillis)
112     {
113         byTimeout(generateByTimeoutConfig(Conditions.isNotVisible(element.getLocator()), element, maxMillis));
114     }
115 
116     public void elementPresentByTimeout(String locator)
117     {
118         elementPresentByTimeout(locator, defaultMaxWait);
119     }
120 
121     public void elementPresentByTimeout(PageElement element)
122     {
123         elementPresentByTimeout(element, defaultMaxWait);
124     }
125 
126     public void elementPresentByTimeout(String locator, long maxMillis)
127     {
128         byTimeout(generateByTimeoutConfig(Conditions.isPresent(locator), locator, maxMillis));
129     }
130 
131     public void elementPresentByTimeout(PageElement element, long maxMillis)
132     {
133         byTimeout(generateByTimeoutConfig(Conditions.isPresent(element.getLocator()), element, maxMillis));
134     }
135 
136 
137     public void elementPresentUntilTimeout(String locator)
138     {
139         untilTimeout(Conditions.isPresent(locator));
140     }
141 
142     public void elementPresentUntilTimeout(PageElement element)
143     {
144         elementPresentUntilTimeout(element.getLocator());        
145     }
146 
147     public void elementPresentUntilTimeout(String locator, long maxMillis)
148     {
149         untilTimeout(Conditions.isPresent(locator), maxMillis);
150     }
151 
152     public void elementPresentUntilTimeout(PageElement element, long maxMillis)
153     {
154         elementPresentUntilTimeout(element.getLocator(), maxMillis);
155     }
156     
157     public void elementNotPresentByTimeout(String locator)
158     {
159         elementNotPresentByTimeout(locator, defaultMaxWait);
160     }
161 
162     public void elementNotPresentByTimeout(PageElement element)
163     {
164         elementNotPresentByTimeout(element, defaultMaxWait);
165     }
166 
167     public void elementNotPresentUntilTimeout(String locator)
168     {
169         untilTimeout(Conditions.isNotPresent(locator));
170     }
171 
172     public void elementNotPresentUntilTimeout(PageElement element)
173     {
174         elementNotPresentUntilTimeout(element.getLocator());
175     }
176 
177     public void elementNotPresentUntilTimeout(String locator, long maxMillis)
178     {
179         untilTimeout(Conditions.isNotPresent(locator), maxMillis);
180     }
181 
182     public void elementNotPresentUntilTimeout(PageElement element, long maxMillis)
183     {
184         elementNotPresentUntilTimeout(element.getLocator(), maxMillis);
185     }
186     
187     public void textPresentByTimeout(String text, long maxMillis)
188     {
189         byTimeout(Conditions.isTextPresent(text), maxMillis);
190     }
191 
192     public void textPresentByTimeout(String text)
193     {
194         byTimeout(Conditions.isTextPresent(text));
195     }
196 
197     public void textNotPresentByTimeout(String text, long maxMillis)
198     {
199         byTimeout(Conditions.isTextNotPresent(text), maxMillis);
200     }
201 
202     public void textNotPresentByTimeout(String text)
203     {
204         byTimeout(Conditions.isTextNotPresent(text));
205     }
206 
207     /**
208      * This will wait until an element is not present.  If it doesnt become not present in
209      * maxMillis
210      *
211      * @param locator   the selenium element locator
212      * @param maxMillis how long to wait as most in milliseconds
213      */
214     public void elementNotPresentByTimeout(String locator, long maxMillis)
215     {
216         byTimeout(generateByTimeoutConfig(Conditions.isNotPresent(locator), locator, maxMillis));
217     }
218 
219     public void elementNotPresentByTimeout(PageElement element, long maxMillis)
220     {
221         byTimeout(generateByTimeoutConfig(Conditions.isNotPresent(element.getLocator()), element, maxMillis));
222     }
223 
224     public void byTimeout(Condition condition)
225     {
226         byTimeout(condition, defaultMaxWait);
227     }
228 
229     public void byTimeout(Condition condition, long maxWaitTime)
230     {
231         byTimeout(new ByTimeoutConfiguration(condition, null, true, maxWaitTime, conditionCheckInterval, null));
232     }
233 
234 
235     public void byTimeout(ByTimeoutConfiguration config)
236     {
237         EventTime et = EventTime.timeEvent(config.getKey(), config.getAutoGeneratedKey(), new TimedWaitFor(config, client));
238         recorder.record(et);
239         if(et.getTimedOut())
240         {
241             log.error("Page source:\n" + client.getHtmlSource());
242 
243             throw new AssertionError(prepareAssertionText(config.getAssertMessage(),
244                                                           "Waited " + config.getMaxWaitTime() + " ms for [" + config.getCondition().errorMessage() + "], but it never became true."));
245         }
246     }
247 
248     private String prepareAssertionText(String userTxt, String systemTxt)
249     {
250         if(userTxt != null)
251         {
252             return userTxt + " \n" + systemTxt;
253         }
254         else
255         {
256             return systemTxt;
257         }
258     }
259 
260     public void untilTimeout(Condition condition)
261     {
262         untilTimeout(condition, defaultMaxWait);
263     }
264 
265     public void untilTimeout(Condition condition, long maxWaitTime)
266     {
267         long startTime = System.currentTimeMillis();
268         while (true)
269         {
270             if (System.currentTimeMillis() - startTime >= maxWaitTime)
271             {
272                 break;
273             }
274 
275             if (!condition.executeTest(client))
276             {
277                 log.error("Page source:\n" + client.getHtmlSource());
278                 throw new AssertionError("Condition [" + condition.errorMessage() + "], became before timeout.");
279             }
280 
281             try
282             {
283                 Thread.sleep(conditionCheckInterval);
284             }
285             catch (InterruptedException e)
286             {
287                 throw new RuntimeException("Thread was interupted", e);
288             }
289         }
290     }
291 
292     /**
293      * @param text Asserts that text is present in the current page
294      */
295     public void textPresent(String text)
296     {
297         Assert.assertTrue("Expected text not found in response: '" + text + "'", client.isTextPresent(text));
298     }
299 
300     /**
301      * @param text Asserts that text is not present in the current page
302      */
303     public void textNotPresent(String text)
304     {
305         Assert.assertFalse("Un-expected text found in response: '" + text + "'", client.isTextPresent(text));
306     }
307 
308     /**
309      * Asserts that a given element has a specified value
310      * @param locator Locator for element using the standard selenium locator syntax
311      * @param value The value the element is expected to contain
312      */
313     public void formElementEquals(String locator, String value)
314     {
315         Assert.assertEquals("Element with id '" + locator + "' did not have the expected value '" + value + "'", value, client.getValue(locator));
316     }
317 
318     /**
319      * Asserts that a given element is present
320      * @param locator Locator for the element that should be present given using the standard selenium locator syntax
321      */
322     public void elementPresent(String locator)
323     {
324         Assert.assertTrue("Expected element not found in response: '" + locator + "'", client.isElementPresent(locator));
325     }
326 
327     public void elementPresent(PageElement element)
328     {
329         elementPresent(element.getLocator());
330     }
331 
332 
333     /**
334      * Asserts that a given element is not present on the current page
335      * @param locator Locator for the element that should not be present given using the standard selenium locator syntax
336      */
337     public void elementNotPresent(String locator)
338     {
339         Assert.assertFalse("Un-expected element found in response: '" + locator + "'", client.isElementPresent(locator));
340     }
341 
342     public void elementNotPresent(PageElement element)
343     {
344         elementNotPresent(element.getLocator());
345     }
346 
347     /**
348      * Asserts that a given element is present and is visible. Under some browsers just calling the seleinium.isVisible method
349      * on an element that doesn't exist causes selenium to throw an exception.
350      * @param locator Locator for the element that should be visible specified in the standard selenium syntax
351      */
352     public void elementVisible(String locator)
353     {
354         Assert.assertTrue("Expected element not visible in response: '" + locator + "'", client.isElementPresent(locator) && client.isVisible(locator));
355     }
356 
357 
358     public void elementVisible(PageElement element)
359     {
360         elementVisible(element.getLocator());
361     }
362     
363     /**
364      * Asserts that a given element is not present and visible. Calling selenium's native selenium.isVisible method on
365      * an element that doesn't exist causes selenium to throw an exception
366      * @param locator Locator for the element that should not be visible specified in the standard selenium syntax
367      */
368     public void elementNotVisible(String locator)
369     {
370         Assert.assertFalse("Un-expected element visible in response: '" + locator + "'", client.isElementPresent(locator) && client.isVisible(locator));
371     }
372 
373 
374     public void elementNotVisible(PageElement element)
375     {
376         elementNotVisible(element.getLocator());
377     }
378     /**
379      * Asserts that a given element is visible and also contains the given text.
380      * @param locator Locator for the element that should be visible specified in the standard selenium syntax
381      * @param text the text that the element should contain
382      */
383     public void elementVisibleContainsText(String locator, String text)
384     {
385         elementVisible(locator);
386         elementContainsText(locator, text);
387     }
388 
389     public void elementVisibleContainsText(PageElement element, String text)
390     {
391         elementVisibleContainsText(element.getLocator(), text);
392     }
393 
394     /**
395      * Asserts that a particular piece of HTML is present in the HTML source. It is recommended that the elementPresent, elementHasText or some other method
396      * be used because browsers idiosyncratically add white space to the HTML source
397      * @param html Lower case representation of HTML string that should not be present
398      */
399     public void htmlPresent(String html)
400     {
401         Assert.assertTrue("Expected HTML not found in response: '" + html + "'", client.getHtmlSource().toLowerCase().indexOf(html) >= 0);
402     }
403 
404     /**
405      * Asserts that a particular piece of HTML is not present in the HTML source. It is recommended that the elementNotPresent, elementDoesntHaveText or
406      * some other method be used because browsers idiosyncratically add white space to the HTML source
407      * @param html Lower case representation of HTML string that should not be present
408      */
409     public void htmlNotPresent(String html)
410     {
411         Assert.assertFalse("Unexpected HTML found in response: '" + html + "'", client.getHtmlSource().toLowerCase().indexOf(html) >= 0);
412     }
413 
414     /**
415      * Asserts that the element specified by the locator contains the specified text
416      * @param locator Locator given in standard selenium syntax
417      * @param text The text that the element designated by the locator should contain
418      */
419     public void elementHasText(String locator, String text)
420     {
421         Assert.assertTrue("Element(s) with locator '" + locator +"' did not contain text '"+ text + "'", (client.getText(locator).indexOf(text) >= 0));
422     }
423 
424     public void elementHasText(PageElement element, String text)
425     {
426         elementHasText(element.getLocator(), text);
427     }
428 
429     /**
430      * Asserts that the element specified by the locator does not contain the specified text
431      * @param locator Locator given in standard selenium syntax
432      * @param text The text that the element designated by the locator should not contain
433      */
434     public void elementDoesntHaveText(String locator, String text)
435     {
436         Assert.assertFalse("Element(s) with locator '" + locator +"' did contained text '"+ text + "'", (client.getText(locator).indexOf(text) >= 0));
437     }
438 
439     public void elementDoesntHaveText(PageElement element, String text)
440     {
441         elementDoesntHaveText(element.getLocator(), text);
442     }
443 
444     /**
445      * Asserts that the element given by the locator has an attribute which contains the required value.
446      * @param locator Locator given in standard selenium syntax
447      * @param attribute The element attribute
448      * @param value The value expected to be found in the element's attribute
449      */
450     public void attributeContainsValue(String locator, String attribute, String value)
451     {
452         String attributeValue = client.getAttribute(locator + "@" + attribute);
453         Assert.assertTrue("Element with locator '" + locator + "' did not contain value '" + value + "' in attribute '" + attribute + "=" + attributeValue + "'", (attributeValue.indexOf(value) >= 0));
454     }
455 
456     public void attributeContainsValue(PageElement element, String attribute, String value)
457     {
458         attributeContainsValue(element.getLocator(), attribute, value);
459     }
460 
461     /**
462      * Asserts that the element given by the locator has an attribute which does not contain the given value.
463      * @param locator Locator given in standard selenium syntax
464      * @param attribute The element attribute
465      * @param value The value expected to be found in the element's attribute
466      */
467     public void attributeDoesntContainValue(String locator, String attribute, String value)
468     {
469         String attributeValue = client.getAttribute(locator + "@" + attribute);
470         Assert.assertFalse("Element with locator '" + locator + "' did not contain value '" + value + "' in attribute '" + attribute + "'", (attributeValue.indexOf(value) >= 0));
471     }
472 
473     public void attributeDoesntContainValue(PageElement element, String attribute, String value)
474     {
475         attributeDoesntContainValue(element.getLocator(), attribute, value);
476     }
477 
478     /**
479      * Asserts that a link containing the given text appears on the page
480      * @param text The text that a link on the page should contain
481      * @see #linkVisibleWithText(String) also
482      */
483     public void linkPresentWithText(String text)
484     {
485         Assert.assertTrue("Expected link with text not found in response: '" + text + "'", client.isElementPresent("link=" + text));
486     }
487 
488     /**
489      * Asserts that no link exists on the page containing the given text
490      * @param text The text that no link on the page should contain
491      */
492     public void linkNotPresentWithText(String text)
493     {
494         Assert.assertFalse("Unexpected link with text found in response: '" + text + "'", client.isElementPresent("link=" + text));
495     }
496 
497     /**
498      * Asserts that a link containin the given text is present and visible.
499      * @param text The text that a link on the page should contain
500      */
501     public void linkVisibleWithText(String text)
502     {
503         linkPresentWithText(text);
504         Assert.assertTrue("Expected link with text not visible: '" + text + "'", client.isVisible("link=" + text));
505     }
506 
507     /**
508      * Asserts that two elements (located by selenium syntax) are vertically within deltaPixels of each other.
509      * @param locator1 Locator for element 1 given in standard selenium syntax
510      * @param locator2 Locator for element 2 given in standard selenium syntax
511      * @param deltaPixels The maximum allowable distance between the two element
512      */
513     public void elementsVerticallyAligned(String locator1, String locator2, int deltaPixels)
514     {
515         int middle1 = client.getElementPositionTop(locator1).intValue() + (client.getElementHeight(locator1).intValue() / 2);
516         int middle2 = client.getElementPositionTop(locator2).intValue() + (client.getElementHeight(locator2).intValue() / 2);
517         String message = "Vertical position of element '" + locator1 + "' (" + middle1 + ") was not within " + deltaPixels +
518             " pixels of the vertical position of element '" + locator2 + "' (" + middle2 + ")";
519         Assert.assertTrue(message, Math.abs(middle1 - middle2) <= deltaPixels);
520     }
521 
522     public void elementsVerticallyAligned(PageElement element1, PageElement element2, int deltaPixels)
523     {
524         elementsVerticallyAligned(element1.getLocator(), element2.getLocator(), deltaPixels);
525     }
526 
527     public void elementsSameHeight(final String locator1, final String locator2, final int deltaPixels)
528     {
529         int height1 = client.getElementHeight(locator1).intValue();
530         int height2 = client.getElementHeight(locator2).intValue();
531         String message = "Height of element '" + locator1 + "' (" + height1 + ") was not within " + deltaPixels +
532             " pixels of the height of element '" + locator2 + "' (" + height2 + ")";
533         Assert.assertTrue(message, Math.abs(height1 - height2) <= deltaPixels);
534     }
535 
536     public void elementsSameHeight(PageElement element1, PageElement element2, final int deltaPixels)
537     {
538         elementsSameHeight(element1.getLocator(), element2.getLocator(), deltaPixels);
539     }
540 
541     /**
542      * Asserts that an element contains the given text.
543      */
544     public void elementContainsText(String locator, String text)
545     {
546         String elementText = client.getText(locator);
547         Assert.assertTrue("Element(s) with locator '" + locator +"' did not contain text '"+ text + "', but contained '" + elementText + "'",
548             elementText.indexOf(text) >= 0);
549     }
550 
551     public void elementContainsText(PageElement element, String text)
552     {
553         elementContainsText(element.getLocator(), text);        
554     }
555 
556 
557     /**
558      * Asserts that an element does not contain the given text.
559      */
560     public void elementDoesNotContainText(String locator, String text)
561     {
562         Assert.assertFalse("Element(s) with locator '" + locator +"' did contained text '"+ text + "'",
563             client.getText(locator).indexOf(text) >= 0);
564     }
565 
566     public void elementDoesNotContainText(PageElement element, String text)
567     {
568         elementDoesNotContainText(element.getLocator(), text);        
569     }
570 
571     public void windowClosed(String windowName)
572     {
573         Assert.assertFalse(Arrays.asList(client.getAllWindowNames()).contains(windowName));
574     }
575 
576     public void windowOpen(String windowName)
577     {
578         Assert.assertTrue(Arrays.asList(client.getAllWindowNames()).contains(windowName));
579     }
580 }