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.junit.Assert.fail;
18  
19  import java.time.Duration;
20  import java.util.List;
21  
22  import org.apache.commons.lang3.StringUtils;
23  import org.eclipse.jetty.server.Server;
24  import org.htmlunit.WebDriverTestCase;
25  import org.htmlunit.WebServerTestCase;
26  import org.htmlunit.junit.BrowserRunner;
27  import org.junit.AfterClass;
28  import org.junit.Before;
29  import org.junit.runner.RunWith;
30  import org.openqa.selenium.By;
31  import org.openqa.selenium.NoSuchElementException;
32  import org.openqa.selenium.StaleElementReferenceException;
33  import org.openqa.selenium.WebDriver;
34  import org.openqa.selenium.WebElement;
35  
36  /**
37   * Base class for the <a href="http://dojotoolkit.org/">Dojo
38   * JavaScript library tests.</a>.
39   *
40   * Timeout was changed in: /util/doh/runner.js, line # 682
41   *
42   * @author Ahmed Ashour
43   * @author Daniel Gredler
44   * @author Ronald Brill
45   */
46  @RunWith(BrowserRunner.class)
47  public abstract class DojoTestBase extends WebDriverTestCase {
48  
49      private static final String BASE_FILE_PATH = "libraries/dojo";
50  
51      private static Server SERVER_;
52  
53      /**
54       * @return the Dojo version being tested
55       */
56      abstract String getVersion();
57  
58      abstract String getUrl(String module);
59  
60      void test(final String module) throws Exception {
61          test(module, 60);
62      }
63  
64      void test(final String module, final long waitTime) throws Exception {
65          try {
66  
67              final WebDriver webdriver = getWebDriver();
68              webdriver.get(getUrl(module));
69  
70              final long runTime = waitTime * Duration.ofSeconds(1).toMillis();
71              final long endTime = System.currentTimeMillis() + runTime;
72  
73              // wait a bit to let the tests start
74              String status = getResultElementText(webdriver);
75              while (!"Tests Running".equals(status)) {
76                  Thread.sleep(42);
77  
78                  if (System.currentTimeMillis() > endTime) {
79                      // don't fail here, maybe we missed the start
80                      break;
81                  }
82                  status = getResultElementText(webdriver);
83              }
84  
85              while (!"Stopped".equals(status)) {
86                  Thread.sleep(42);
87  
88                  if (System.currentTimeMillis() > endTime) {
89                      fail("Test runs too long (longer than " + runTime / 1000 + "s)");
90                  }
91                  status = getResultElementText(webdriver);
92              }
93  
94              for (int i = 0; i < 10; i++) {
95                  try {
96                      Thread.sleep(100);
97  
98                      final WebElement output = webdriver.findElement(By.id("logBody"));
99                      final List<WebElement> lines = output.findElements(By.xpath(".//div"));
100 
101                     final StringBuilder result = new StringBuilder();
102                     for (final WebElement webElement : lines) {
103                         final String text = webElement.getText();
104                         if (StringUtils.isNotBlank(text)) {
105                             result.append(text);
106                             result.append("\n");
107                         }
108                     }
109 
110                     String expFileName = StringUtils.replace(module, ".", "");
111                     expFileName = StringUtils.replace(expFileName, "_", "");
112                     expFileName = StringUtils.replace(expFileName, "/", "_");
113                     String expected = loadExpectation(expFileName);
114                     expected = StringUtils.replace(expected, "\r\n", "\n");
115 
116                     assertEquals(normalize(expected), normalize(result.toString()));
117                     // assertEquals(expected, result.toString());
118 
119                     // success
120                     break;
121                 }
122                 catch (final AssertionError ignored) {
123                     // fails, give it another try
124                 }
125             }
126         }
127         catch (final Exception e) {
128             e.printStackTrace();
129             Throwable t = e;
130             while ((t = t.getCause()) != null) {
131                 t.printStackTrace();
132             }
133             throw e;
134         }
135     }
136 
137     private static String normalize(final String text) {
138         StringBuilder normalized = new StringBuilder();
139 
140         for (int i = 0; i < text.length(); i++) {
141             char ch = text.charAt(i);
142             if (ch == 'f'
143                     && (text.indexOf("function ", i) == i
144                             || text.indexOf("function(", i) == i)) {
145                 if (normalized.toString().endsWith("(")) {
146                     normalized.delete(normalized.length() - 1, normalized.length());
147                 }
148                 normalized = new StringBuilder(normalized.toString().trim());
149 
150                 normalized.append("  function...");
151                 int count = 1;
152                 i = text.indexOf("{", i);
153                 while (i < text.length()) {
154                     i++;
155                     ch = text.charAt(i);
156                     if ('{' == ch) {
157                         count++;
158                     }
159                     else if ('}' == ch) {
160                         count--;
161                     }
162                     if (count == 0) {
163                         break;
164                     }
165                 }
166                 if (normalized.toString().endsWith(")")) {
167                     normalized.delete(normalized.length() - 1, normalized.length());
168                 }
169             }
170             else if (ch == 'T' && text.indexOf("TypeError: ", i) == i) {
171                 normalized.append("TypeError:...");
172                 while (i < text.length()) {
173                     i++;
174                     ch = text.charAt(i);
175                     if ('\r' == ch || '\n' == ch) {
176                         break;
177                     }
178                 }
179             }
180             else {
181                 normalized.append(ch);
182             }
183         }
184         return normalized.toString().replaceAll("\\d+ ms", "x ms");
185     }
186 
187     private String loadExpectation(final String expFileName) throws Exception {
188         final String resourcePrefix = "/" + BASE_FILE_PATH + "/" + getVersion() + "/expectations/" + expFileName;
189         return loadExpectation(resourcePrefix, ".txt");
190     }
191 
192     private static String getResultElementText(final WebDriver webdriver) {
193         // if the elem is not available or stale we return an empty string
194         // this will force a second try
195         try {
196             final WebElement elem = webdriver.findElement(By.id("runningStatus"));
197             try {
198                 return elem.getText();
199             }
200             catch (final StaleElementReferenceException e) {
201                 return "";
202             }
203         }
204         catch (final NoSuchElementException e) {
205             return "";
206         }
207     }
208 
209     /**
210      * @throws Exception if an error occurs
211      */
212     @Before
213     public void startSesrver() throws Exception {
214         if (SERVER_ == null) {
215             SERVER_ = WebServerTestCase.createWebServer("src/test/resources/"
216                         + BASE_FILE_PATH + "/" + getVersion(), null);
217         }
218     }
219 
220     /**
221      * @throws Exception if an error occurs
222      */
223     @AfterClass
224     public static void stopServer() throws Exception {
225         if (SERVER_ != null) {
226             SERVER_.stop();
227             SERVER_.destroy();
228             SERVER_ = null;
229         }
230     }
231 }