View Javadoc
1   /*
2    * Copyright (c) 2002-2017 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package com.gargoylesoftware.htmlunit;
16  
17  import java.util.ArrayList;
18  import java.util.Arrays;
19  import java.util.List;
20  
21  import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
22  import com.gargoylesoftware.htmlunit.html.HtmlElement;
23  import com.gargoylesoftware.htmlunit.html.HtmlInput;
24  import com.gargoylesoftware.htmlunit.html.HtmlPage;
25  
26  /**
27   * Utility class which contains standard assertions for HTML pages.
28   *
29   * @author Daniel Gredler
30   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
31   * @author Ahmed Ashour
32   */
33  public final class WebAssert {
34  
35      /**
36       * Private to prevent instantiation.
37       */
38      private WebAssert() {
39          // Empty.
40      }
41  
42      /**
43       * Verifies that the specified page's title equals the specified expected title.
44       *
45       * @param page the page to check
46       * @param title the expected title
47       */
48      public static void assertTitleEquals(final HtmlPage page, final String title) {
49          final String s = page.getTitleText();
50          if (!s.equals(title)) {
51              final String msg = "Actual page title '" + s + "' does not match expected page title '" + title + "'.";
52              throw new AssertionError(msg);
53          }
54      }
55  
56      /**
57       * Verifies that the specified page's title contains the specified substring.
58       *
59       * @param page the page to check
60       * @param titlePortion the substring which the page title is expected to contain
61       */
62      public static void assertTitleContains(final HtmlPage page, final String titlePortion) {
63          final String s = page.getTitleText();
64          if (s.indexOf(titlePortion) == -1) {
65              final String msg = "Page title '" + s + "' does not contain the substring '" + titlePortion + "'.";
66              throw new AssertionError(msg);
67          }
68      }
69  
70      /**
71       * Verifies that the specified page's title matches the specified regular expression.
72       *
73       * @param page the page to check
74       * @param regex the regular expression that the page title is expected to match
75       */
76      public static void assertTitleMatches(final HtmlPage page, final String regex) {
77          final String s = page.getTitleText();
78          if (!s.matches(regex)) {
79              final String msg = "Page title '" + s + "' does not match the regular expression '" + regex + "'.";
80              throw new AssertionError(msg);
81          }
82      }
83  
84      /**
85       * Verifies that the specified page contains an element with the specified ID.
86       *
87       * @param page the page to check
88       * @param id the expected ID of an element in the page
89       */
90      public static void assertElementPresent(final HtmlPage page, final String id) {
91          try {
92              page.getHtmlElementById(id);
93          }
94          catch (final ElementNotFoundException e) {
95              final String msg = "The page does not contain an element with ID '" + id + "'.";
96              throw new AssertionError(msg);
97          }
98      }
99  
100     /**
101      * Verifies that the specified page contains an element matching the specified XPath expression.
102      *
103      * @param page the page to check
104      * @param xpath the XPath expression which is expected to match an element in the page
105      */
106     public static void assertElementPresentByXPath(final HtmlPage page, final String xpath) {
107         final List<?> elements = page.getByXPath(xpath);
108         if (elements.isEmpty()) {
109             final String msg = "The page does not contain any elements matching the XPath expression '" + xpath
110                             + "'.";
111             throw new AssertionError(msg);
112         }
113     }
114 
115     /**
116      * Verifies that the specified page does not contain an element with the specified ID.
117      *
118      * @param page the page to check
119      * @param id the ID of an element which expected to not exist on the page
120      */
121     public static void assertElementNotPresent(final HtmlPage page, final String id) {
122         try {
123             page.getHtmlElementById(id);
124         }
125         catch (final ElementNotFoundException e) {
126             return;
127         }
128         final String msg = "The page contains an element with ID '" + id + "'.";
129         throw new AssertionError(msg);
130     }
131 
132     /**
133      * Verifies that the specified page does not contain an element matching the specified XPath
134      * expression.
135      *
136      * @param page the page to check
137      * @param xpath the XPath expression which is expected to not match an element in the page
138      */
139     public static void assertElementNotPresentByXPath(final HtmlPage page, final String xpath) {
140         final List<?> elements = page.getByXPath(xpath);
141         if (!elements.isEmpty()) {
142             final String msg = "The page does not contain any elements matching the XPath expression '" + xpath
143                             + "'.";
144             throw new AssertionError(msg);
145         }
146     }
147 
148     /**
149      * Verifies that the specified page contains the specified text.
150      *
151      * @param page the page to check
152      * @param text the text to check for
153      */
154     public static void assertTextPresent(final HtmlPage page, final String text) {
155         if (page.asText().indexOf(text) == -1) {
156             final String msg = "The page does not contain the text '" + text + "'.";
157             throw new AssertionError(msg);
158         }
159     }
160 
161     /**
162      * Verifies that the element on the specified page which matches the specified ID contains the
163      * specified text.
164      *
165      * @param page the page to check
166      * @param text the text to check for
167      * @param id the ID of the element which is expected to contain the specified text
168      */
169     public static void assertTextPresentInElement(final HtmlPage page, final String text, final String id) {
170         try {
171             final HtmlElement element = page.getHtmlElementById(id);
172             if (element.asText().indexOf(text) == -1) {
173                 final String msg = "The element with ID '" + id + "' does not contain the text '" + text + "'.";
174                 throw new AssertionError(msg);
175             }
176         }
177         catch (final ElementNotFoundException e) {
178             final String msg = "Unable to verify that the element with ID '" + id + "' contains the text '" + text
179                             + "' because the specified element does not exist.";
180             throw new AssertionError(msg);
181         }
182     }
183 
184     /**
185      * Verifies that the specified page does not contain the specified text.
186      *
187      * @param page the page to check
188      * @param text the text to check for
189      */
190     public static void assertTextNotPresent(final HtmlPage page, final String text) {
191         if (page.asText().contains(text)) {
192             final String msg = "The page contains the text '" + text + "'.";
193             throw new AssertionError(msg);
194         }
195     }
196 
197     /**
198      * Verifies that the element on the specified page which matches the specified ID does not
199      * contain the specified text.
200      *
201      * @param page the page to check
202      * @param text the text to check for
203      * @param id the ID of the element which is expected to not contain the specified text
204      */
205     public static void assertTextNotPresentInElement(final HtmlPage page, final String text, final String id) {
206         try {
207             final HtmlElement element = page.getHtmlElementById(id);
208             if (element.asText().contains(text)) {
209                 final String msg = "The element with ID '" + id + "' contains the text '" + text + "'.";
210                 throw new AssertionError(msg);
211             }
212         }
213         catch (final ElementNotFoundException e) {
214             final String msg = "Unable to verify that the element with ID '" + id + "' does not contain the text '"
215                             + text + "' because the specified element does not exist.";
216             throw new AssertionError(msg);
217         }
218     }
219 
220     /**
221      * Verifies that the specified page contains a link with the specified ID.
222      *
223      * @param page the page to check
224      * @param id the ID of the link which the page is expected to contain
225      */
226     public static void assertLinkPresent(final HtmlPage page, final String id) {
227         try {
228             page.getDocumentElement().getOneHtmlElementByAttribute("a", "id", id);
229         }
230         catch (final ElementNotFoundException e) {
231             final String msg = "The page does not contain a link with ID '" + id + "'.";
232             throw new AssertionError(msg);
233         }
234     }
235 
236     /**
237      * Verifies that the specified page does not contain a link with the specified ID.
238      *
239      * @param page the page to check
240      * @param id the ID of the link which the page is expected to not contain
241      */
242     public static void assertLinkNotPresent(final HtmlPage page, final String id) {
243         try {
244             page.getDocumentElement().getOneHtmlElementByAttribute("a", "id", id);
245             // Not expected.
246             final String msg = "The page contains a link with ID '" + id + "'.";
247             throw new AssertionError(msg);
248         }
249         catch (final ElementNotFoundException e) {
250             // Expected.
251         }
252     }
253 
254     /**
255      * Verifies that the specified page contains a link with the specified text. The specified text
256      * may be a substring of the entire text contained by the link.
257      *
258      * @param page the page to check
259      * @param text the text which a link in the specified page is expected to contain
260      */
261     public static void assertLinkPresentWithText(final HtmlPage page, final String text) {
262         boolean found = false;
263         for (final HtmlAnchor a : page.getAnchors()) {
264             if (a.asText().contains(text)) {
265                 found = true;
266                 break;
267             }
268         }
269         if (!found) {
270             final String msg = "The page does not contain a link with text '" + text + "'.";
271             throw new AssertionError(msg);
272         }
273     }
274 
275     /**
276      * Verifies that the specified page does not contain a link with the specified text. The
277      * specified text may be a substring of the entire text contained by the link.
278      *
279      * @param page the page to check
280      * @param text the text which a link in the specified page is not expected to contain
281      */
282     public static void assertLinkNotPresentWithText(final HtmlPage page, final String text) {
283         boolean found = false;
284         for (final HtmlAnchor a : page.getAnchors()) {
285             if (a.asText().contains(text)) {
286                 found = true;
287                 break;
288             }
289         }
290         if (found) {
291             final String msg = "The page contains a link with text '" + text + "'.";
292             throw new AssertionError(msg);
293         }
294     }
295 
296     /**
297      * Verifies that the specified page contains a form with the specified name.
298      *
299      * @param page the page to check
300      * @param name the expected name of a form on the page
301      */
302     public static void assertFormPresent(final HtmlPage page, final String name) {
303         try {
304             page.getFormByName(name);
305         }
306         catch (final ElementNotFoundException e) {
307             final String msg = "The page does not contain a form named '" + name + "'.";
308             throw new AssertionError(msg);
309         }
310     }
311 
312     /**
313      * Verifies that the specified page does not contain a form with the specified name.
314      *
315      * @param page the page to check
316      * @param name the name of a form which should not exist on the page
317      */
318     public static void assertFormNotPresent(final HtmlPage page, final String name) {
319         try {
320             page.getFormByName(name);
321         }
322         catch (final ElementNotFoundException e) {
323             return;
324         }
325         final String msg = "The page contains a form named '" + name + "'.";
326         throw new AssertionError(msg);
327     }
328 
329     /**
330      * Verifies that the specified page contains an input element with the specified name.
331      *
332      * @param page the page to check
333      * @param name the name of the input element to look for
334      */
335     public static void assertInputPresent(final HtmlPage page, final String name) {
336         final String xpath = "//input[@name='" + name + "']";
337         final List<?> list = page.getByXPath(xpath);
338         if (list.isEmpty()) {
339             throw new AssertionError("Unable to find an input element named '" + name + "'.");
340         }
341     }
342 
343     /**
344      * Verifies that the specified page does not contain an input element with the specified name.
345      *
346      * @param page the page to check
347      * @param name the name of the input element to look for
348      */
349     public static void assertInputNotPresent(final HtmlPage page, final String name) {
350         final String xpath = "//input[@name='" + name + "']";
351         final List<?> list = page.getByXPath(xpath);
352         if (!list.isEmpty()) {
353             throw new AssertionError("Unable to find an input element named '" + name + "'.");
354         }
355     }
356 
357     /**
358      * Verifies that the input element with the specified name on the specified page contains the
359      * specified value.
360      *
361      * @param page the page to check
362      * @param name the name of the input element to check
363      * @param value the value to check for
364      */
365     public static void assertInputContainsValue(final HtmlPage page, final String name, final String value) {
366         final String xpath = "//input[@name='" + name + "']";
367         final List<?> list = page.getByXPath(xpath);
368         if (list.isEmpty()) {
369             throw new AssertionError("Unable to find an input element named '" + name + "'.");
370         }
371         final HtmlInput input = (HtmlInput) list.get(0);
372         final String s = input.getValueAttribute();
373         if (!s.equals(value)) {
374             throw new AssertionError("The input element named '" + name + "' contains the value '" + s
375                             + "', not the expected value '" + value + "'.");
376         }
377     }
378 
379     /**
380      * Verifies that the input element with the specified name on the specified page does not
381      * contain the specified value.
382      *
383      * @param page the page to check
384      * @param name the name of the input element to check
385      * @param value the value to check for
386      */
387     public static void assertInputDoesNotContainValue(final HtmlPage page, final String name, final String value) {
388         final String xpath = "//input[@name='" + name + "']";
389         final List<?> list = page.getByXPath(xpath);
390         if (list.isEmpty()) {
391             throw new AssertionError("Unable to find an input element named '" + name + "'.");
392         }
393         final HtmlInput input = (HtmlInput) list.get(0);
394         final String s = input.getValueAttribute();
395         if (s.equals(value)) {
396             throw new AssertionError("The input element named '" + name + "' contains the value '" + s
397                             + "', not the expected value '" + value + "'.");
398         }
399     }
400 
401     /**
402      * <p>Many HTML elements are "tabbable" and can have a <tt>tabindex</tt> attribute
403      * that determines the order in which the components are navigated when
404      * pressing the tab key. To ensure good usability for keyboard navigation,
405      * all tabbable elements should have the <tt>tabindex</tt> attribute set.</p>
406      *
407      * <p>This method verifies that all tabbable elements have a valid value set for
408      * the <tt>tabindex</tt> attribute.</p>
409      *
410      * @param page the page to check
411      */
412     public static void assertAllTabIndexAttributesSet(final HtmlPage page) {
413         final List<String> tags =
414             Arrays.asList(new String[] {"a", "area", "button", "input", "object", "select", "textarea"});
415 
416         for (final String tag : tags) {
417             for (final HtmlElement element : page.getDocumentElement().getElementsByTagName(tag)) {
418                 final Short tabIndex = element.getTabIndex();
419                 if (tabIndex == null || tabIndex == HtmlElement.TAB_INDEX_OUT_OF_BOUNDS) {
420                     final String s = element.getAttribute("tabindex");
421                     throw new AssertionError("Illegal value for tab index: '" + s + "'.");
422                 }
423             }
424         }
425     }
426 
427     /**
428      * Many HTML components can have an <tt>accesskey</tt> attribute which defines a hot key for
429      * keyboard navigation. This method verifies that all the <tt>accesskey</tt> attributes on the
430      * specified page are unique.
431      *
432      * @param page the page to check
433      */
434     public static void assertAllAccessKeyAttributesUnique(final HtmlPage page) {
435         final List<String> list = new ArrayList<>();
436         for (final HtmlElement element : page.getHtmlElementDescendants()) {
437             final String key = element.getAttribute("accesskey");
438             if (key != null && !key.isEmpty()) {
439                 if (list.contains(key)) {
440                     throw new AssertionError("The access key '" + key + "' is not unique.");
441                 }
442                 list.add(key);
443             }
444         }
445     }
446 
447     /**
448      * Verifies that all element IDs in the specified page are unique.
449      *
450      * @param page the page to check
451      */
452     public static void assertAllIdAttributesUnique(final HtmlPage page) {
453         final List<String> list = new ArrayList<>();
454         for (final HtmlElement element : page.getHtmlElementDescendants()) {
455             final String id = element.getId();
456             if (id != null && !id.isEmpty()) {
457                 if (list.contains(id)) {
458                     throw new AssertionError("The element ID '" + id + "' is not unique.");
459                 }
460                 list.add(id);
461             }
462         }
463     }
464 
465     /**
466      * Assert that the specified parameter is not null. Throw a NullPointerException
467      * if a null is found.
468      * @param description the description to pass into the NullPointerException
469      * @param object the object to check for null
470      */
471     public static void notNull(final String description, final Object object) {
472         if (object == null) {
473             throw new NullPointerException(description);
474         }
475     }
476 }