View Javadoc
1   /*
2    * Copyright (c) 2002-2025 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    * https://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 org.htmlunit.libraries;
16  
17  import java.io.IOException;
18  import java.nio.charset.StandardCharsets;
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.eclipse.jetty.server.Server;
23  import org.htmlunit.WebClient;
24  import org.htmlunit.WebDriverTestCase;
25  import org.htmlunit.WebRequest;
26  import org.htmlunit.WebResponse;
27  import org.htmlunit.WebResponseData;
28  import org.htmlunit.WebServerTestCase;
29  import org.htmlunit.http.HttpStatus;
30  import org.htmlunit.junit.SetExpectedAlertsBeforeTestExecutionCallback;
31  import org.htmlunit.util.WebConnectionWrapper;
32  import org.junit.jupiter.api.AfterAll;
33  import org.junit.jupiter.api.Assertions;
34  import org.junit.jupiter.api.BeforeEach;
35  import org.openqa.selenium.By;
36  import org.openqa.selenium.NoSuchElementException;
37  import org.openqa.selenium.StaleElementReferenceException;
38  import org.openqa.selenium.WebDriver;
39  import org.openqa.selenium.WebElement;
40  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
41  
42  /**
43   * Base class for jQuery Tests.
44   *
45   * @author Ronald Brill
46   */
47  public abstract class JQueryTestBase extends WebDriverTestCase {
48  
49      protected static final class OnlyLocalConnectionWrapper extends WebConnectionWrapper {
50          private static final WebResponseData RESPONSE_DATA =
51                  new WebResponseData("not found".getBytes(StandardCharsets.US_ASCII),
52                          HttpStatus.NOT_FOUND_404, HttpStatus.NOT_FOUND_404_MSG,
53                          new ArrayList<>());
54  
55  
56          protected OnlyLocalConnectionWrapper(final WebClient webClient) {
57              super(webClient);
58          }
59  
60          @Override
61          public WebResponse getResponse(final WebRequest request) throws IOException {
62              final String url = request.getUrl().toExternalForm();
63  
64              if (url.contains("localhost")) {
65                  return super.getResponse(request);
66              }
67  
68  
69              return new WebResponse(RESPONSE_DATA, request, 0);
70          }
71      }
72  
73      private static Server SERVER_;
74  
75      /**
76       * Returns the jQuery version being tested.
77       * @return the jQuery version being tested
78       */
79      abstract String getVersion();
80  
81      /**
82       * Runs the specified test.
83       * @param testName the test name
84       * @throws Exception if an error occurs
85       */
86      protected void runTest(final String testName) throws Exception {
87          final String testNumber = readTestNumber(testName);
88          if (testNumber == null) {
89              assertEquals("Test number not found for: " + testName,
90                      SetExpectedAlertsBeforeTestExecutionCallback.NO_ALERTS_DEFINED, getExpectedAlerts());
91              return;
92          }
93          final long runTime = 60 * DEFAULT_WAIT_TIME.toMillis();
94          final long endTime = System.currentTimeMillis() + runTime;
95  
96          try {
97              final WebDriver webDriver = getWebDriver();
98  
99              if (webDriver instanceof HtmlUnitDriver) {
100                 final WebClient webClient = ((HtmlUnitDriver) webDriver).getWebClient();
101                 new OnlyLocalConnectionWrapper(webClient);
102             }
103 
104 
105             final String url = buildUrl(testNumber);
106             webDriver.get(url);
107 
108             while (!getResultElementText(webDriver).startsWith("Tests completed")) {
109                 Thread.sleep(42);
110 
111                 if (System.currentTimeMillis() > endTime) {
112                     final String result = "Test #" + testNumber
113                                             + " runs too long (longer than " + runTime / 1000 + "s)";
114                     assertEquals(getExpectedAlerts()[0], result);
115                     return;
116                 }
117             }
118 
119             final String result = getResultDetailElementText(webDriver, testNumber);
120             final String expected = testName + " (" + getExpectedAlerts()[0] + ")";
121             if (!expected.contains(result)) {
122                 System.out.println("--------------------------------------------");
123                 System.out.println("URL:      " + url);
124                 System.out.println("Test:     " + webDriver.findElement(By.id("qunit-tests")).getText());
125                 System.out.println("Result:   " + result);
126                 System.out.println("Failures: ");
127                 final List<WebElement> failures = webDriver.findElements(By.cssSelector(".qunit-assert-list li.fail"));
128                 for (final WebElement webElement : failures) {
129                     System.out.println("  " + webElement.getText());
130                 }
131                 System.out.println("--------------------------------------------");
132 
133                 Assertions.fail("'" + expected + "' does not contain '" + result);
134             }
135         }
136         catch (final Exception e) {
137             e.printStackTrace();
138             Throwable t = e;
139             while ((t = t.getCause()) != null) {
140                 t.printStackTrace();
141             }
142             throw e;
143         }
144     }
145 
146     private static String getResultElementText(final WebDriver webdriver) {
147         // if the elem is not available or stale we return an empty string
148         // this will force a second try
149         try {
150             final WebElement elem = webdriver.findElement(By.id("qunit-testresult"));
151             try {
152                 return elem.getText();
153             }
154             catch (final StaleElementReferenceException e) {
155                 return "";
156             }
157         }
158         catch (final NoSuchElementException e) {
159             return "";
160         }
161     }
162 
163     /**
164      * Determine test number for test name.
165      * @param testName the name
166      * @return the test number
167      * @throws Exception in case of problems
168      */
169     protected String readTestNumber(final String testName) throws Exception {
170         final String testResults = loadExpectation("/libraries/jQuery/"
171                                         + getVersion() + "/expectations/results", ".txt");
172         final String[] lines = testResults.split("\n");
173         for (int i = 0; i < lines.length; i++) {
174             final String line = lines[i];
175             final int pos = line.indexOf(testName);
176             if (pos != -1
177                     && line.indexOf('(', pos + testName.length() + 3) == -1) {
178                 return Integer.toString(i + 1);
179             }
180         }
181 
182         return null;
183     }
184 
185     /**
186      * @param testNumber the number of the test to run
187      * @return the test url
188      */
189     protected String buildUrl(final String testNumber) {
190         return URL_FIRST + "jquery/test/index.html?dev&testNumber=" + testNumber;
191     }
192 
193     /**
194      * @param webdriver the web driver
195      * @param testNumber the number of the test to run
196      * @return the test result details
197      */
198     protected String getResultDetailElementText(final WebDriver webdriver, final String testNumber) {
199         final WebElement output = webdriver.findElement(By.id("qunit-test-output0"));
200         String result = output.getText();
201         result = result.substring(0, result.indexOf("Rerun")).trim();
202         return result;
203     }
204 
205     /**
206      * @throws Exception if an error occurs
207      */
208     @BeforeEach
209     public void aaa_startSesrver() throws Exception {
210         if (SERVER_ == null) {
211             SERVER_ = WebServerTestCase.createWebServer("src/test/resources/libraries/jQuery/" + getVersion(), null);
212         }
213     }
214 
215     /**
216      * @throws Exception if an error occurs
217      */
218     @AfterAll
219     public static void zzz_stopServer() throws Exception {
220         if (SERVER_ != null) {
221             SERVER_.stop();
222             SERVER_.destroy();
223             SERVER_ = null;
224         }
225     }
226 }