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