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