8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package test.javafx.scene.web; 27 28 import java.util.concurrent.atomic.AtomicBoolean; 29 import java.util.concurrent.CountDownLatch; 30 import java.util.concurrent.TimeUnit; 31 import javafx.application.Application; 32 import javafx.application.Platform; 33 import javafx.event.Event; 34 import javafx.scene.input.KeyCode; 35 import javafx.scene.input.KeyEvent; 36 import javafx.scene.Scene; 37 import javafx.scene.web.HTMLEditor; 38 import javafx.scene.web.WebView; 39 import javafx.stage.Stage; 40 import org.junit.AfterClass; 41 import org.junit.BeforeClass; 42 import org.junit.Ignore; 43 import org.junit.Test; 44 import test.util.Util; 45 46 import static javafx.concurrent.Worker.State.SUCCEEDED; 47 import static junit.framework.TestCase.fail; 48 import static org.junit.Assert.assertEquals; 49 import static org.junit.Assert.assertNotNull; 50 import static org.junit.Assert.assertTrue; 51 import static test.util.Util.TIMEOUT; 52 53 public class HTMLEditorTest { 54 private static final CountDownLatch launchLatch = new CountDownLatch(1); 55 56 // Maintain one application instance 57 static HTMLEditorTestApp htmlEditorTestApp; 58 59 private HTMLEditor htmlEditor; 60 private WebView webView; 61 62 public static class HTMLEditorTestApp extends Application { 63 Stage primaryStage = null; 64 65 public HTMLEditorTestApp() { 66 super(); 67 } 68 69 @Override 70 public void init() { 71 HTMLEditorTest.htmlEditorTestApp = this; 72 } 73 74 @Override 75 public void start(Stage primaryStage) throws Exception { 76 Platform.setImplicitExit(false); 77 this.primaryStage = primaryStage; 78 launchLatch.countDown(); 79 } 80 } 81 82 @BeforeClass 83 public static void setupOnce() { 84 // Start the Test Application 85 new Thread(() -> Application.launch(HTMLEditorTestApp.class, 86 (String[]) null)).start(); 87 88 try { 89 if (!launchLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) { 90 fail("Timeout waiting for FX runtime to start"); 91 } 92 } catch (InterruptedException exception) { 93 fail("Unexpected exception: " + exception); 94 } 95 96 } 97 98 @AfterClass 99 public static void tearDownOnce() { 100 Platform.exit(); 101 } 102 103 /** 104 * @test 105 * @bug 8090011 106 * Summary Check document focus change behavior on tab key press 107 */ 108 // Currently ignoring this test case due to regression (JDK-8200418). 109 // The newly cloned issue (JDK-8202542) needs to be fixed before 110 // re-enabling this test case. 111 @Test @Ignore("JDK-8202542") 112 public void checkFocusChange() throws Exception { 113 final CountDownLatch editorStateLatch = new CountDownLatch(2); 114 final AtomicBoolean result = new AtomicBoolean(false); 115 Platform.runLater(() -> { 116 HTMLEditor htmlEditor = new HTMLEditor(); 117 Scene scene = new Scene(htmlEditor); 118 htmlEditorTestApp.primaryStage.setScene(scene); 119 WebView webView = (WebView)htmlEditor.lookup(".web-view"); 120 assertNotNull(webView); 121 122 KeyEvent tabKeyEvent = new KeyEvent(null, webView, 123 KeyEvent.KEY_PRESSED, "", "", 124 KeyCode.TAB, false, false, false, false); 125 126 webView.focusedProperty(). 127 addListener((observable, oldValue, newValue) -> { 128 if (newValue) { 129 webView.getEngine(). 130 executeScript("document.body.focus();"); 131 // Check focus change on repeated tab key press 132 for (int i = 0; i < 10; ++i) { 133 Event.fireEvent(webView, tabKeyEvent); 134 } 135 result.set("red".equals(webView.getEngine(). 136 executeScript("document.body.style.backgroundColor"). 137 toString())); 138 htmlEditorTestApp.primaryStage.hide(); 139 editorStateLatch.countDown(); 140 } 141 }); 142 143 webView.getEngine().getLoadWorker().stateProperty(). 144 addListener((observable, oldValue, newValue) -> { 145 if (newValue == SUCCEEDED) { 146 webView.getEngine().executeScript( 147 "document.body.style.backgroundColor='red';" + 148 "document.body.onfocusout = function() {" + 149 "document.body.style.backgroundColor = 'yellow';" + 150 "}"); 151 htmlEditor.requestFocus(); 152 editorStateLatch.countDown(); 153 } 154 }); 155 htmlEditorTestApp.primaryStage.show(); 156 }); 157 158 try { 159 editorStateLatch.await(TIMEOUT, TimeUnit.MILLISECONDS); 160 } catch (InterruptedException ex) { 161 throw new AssertionError(ex); 162 } finally { 163 assertTrue("Focus Change with design mode enabled ", result.get()); 164 } 165 } 166 167 /** 168 * @test 169 * @bug 8088769 170 * Summary Verify CSS styling in HTMLEditor 171 */ 172 @Test 173 public void checkStyleWithCSS() throws Exception { 174 final CountDownLatch editorStateLatch = new CountDownLatch(2); 175 final String editorCommand1 = 176 "document.execCommand('bold', false, 'true');" + 177 "document.execCommand('italic', false, 'true');" + 178 "document.execCommand('insertText', false, 'Hello World');"; 179 final String editorCommand2 = 180 "document.execCommand('selectAll', false, 'true');" + 181 "document.execCommand('delete', false, 'true');" + 182 "document.execCommand('bold', false, 'false');" + 183 "document.execCommand('italic', false, 'false');" + 184 "document.execCommand('underline', false, 'true');" + 185 "document.execCommand('forecolor', false," + 186 " 'rgba(255, 155, 0, 0.4)');" + 187 "document.execCommand('backcolor', false," + 188 " 'rgba(150, 90, 5, 0.5)');" + 189 "document.execCommand('insertText', false, 'Hello HTMLEditor');"; 190 final String expectedHTML = "<html dir=\"ltr\"><head></head><body " + 191 "contenteditable=\"true\"><span style=\"font-weight: bold; " + 192 "font-style: italic;\">Hello World</span></body></html>"; 193 194 Util.runAndWait(() -> { 195 htmlEditor = new HTMLEditor(); 196 Scene scene = new Scene(htmlEditor); 197 htmlEditorTestApp.primaryStage.setScene(scene); 198 webView = (WebView)htmlEditor.lookup(".web-view"); 199 assertNotNull(webView); 200 201 webView.focusedProperty(). 202 addListener((observable, oldValue, newValue) -> { 203 if (newValue) { 204 editorStateLatch.countDown(); 205 } 206 }); 207 208 webView.getEngine().getLoadWorker().stateProperty(). 209 addListener((observable, oldValue, newValue) -> { 210 if (newValue == SUCCEEDED) { 211 htmlEditor.requestFocus(); 212 editorStateLatch.countDown(); 213 } 214 }); 215 htmlEditorTestApp.primaryStage.show(); 216 }); 217 218 try { 219 if (!editorStateLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) { 220 throw new AssertionError("Timeout waiting for callbacks"); 221 } 222 } catch (InterruptedException ex) { 223 throw new AssertionError(ex); 224 } 225 226 Util.runAndWait(() -> { 227 webView.getEngine().executeScript("document.body.focus();"); 228 webView.getEngine().executeScript(editorCommand1); 229 assertEquals(expectedHTML, htmlEditor.getHtmlText()); 230 webView.getEngine().executeScript(editorCommand2); 231 assertEquals(webView.getEngine().executeScript( 232 "document.getElementsByTagName('span')[0].style.textDecoration") 233 .toString(), 234 "underline"); 235 assertEquals(webView.getEngine().executeScript( 236 "document.getElementsByTagName('span')[0].style.fontWeight") 237 .toString(), ""); 238 assertEquals(webView.getEngine().executeScript( 239 "document.getElementsByTagName('span')[0].style.fontStyle") 240 .toString(), ""); 241 testColorEquality("rgba(255, 155, 0, 0.4)", 242 webView.getEngine().executeScript( 243 "document.getElementsByTagName('span')[0].style.color") 244 .toString(), 0.01); 257 actualColor.substring(actualColor.indexOf('(') + 1, 258 actualColor.lastIndexOf(')')).split(","); 259 final String[] expectedValues = 260 expectedColor.substring(expectedColor.indexOf('(') + 1, 261 expectedColor.lastIndexOf(')')).split(","); 262 for (int i = 0; i < 3; i++) { 263 assertEquals(Integer.parseInt(actualValues[i].trim()), 264 Integer.parseInt(expectedValues[i].trim())); 265 } 266 assertEquals(Double.parseDouble(actualValues[3].trim()), 267 Double.parseDouble(expectedValues[3].trim()), delta); 268 } 269 270 /** 271 * @test 272 * @bug 8200418 273 * Summary Check Style property after removeformat 274 */ 275 @Test 276 public void checkStyleProperty() throws Exception { 277 final CountDownLatch editorStateLatch = new CountDownLatch(2); 278 final AtomicBoolean result = new AtomicBoolean(false); 279 Platform.runLater(() -> { 280 HTMLEditor htmlEditor = new HTMLEditor(); 281 Scene scene = new Scene(htmlEditor); 282 htmlEditorTestApp.primaryStage.setScene(scene); 283 htmlEditor.setHtmlText("<html>" + 284 "<head>" + 285 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" + 286 "</head>" + 287 "<body style=\"font-weight: bold\">" + 288 "<p>Test</p>" + 289 "</body>" + 290 "</html>"); 291 292 WebView webView = (WebView)htmlEditor.lookup(".web-view"); 293 assertNotNull(webView); 294 295 webView.focusedProperty(). 296 addListener((observable, oldValue, newValue) -> { 297 if (newValue) { 298 webView.getEngine(). 299 executeScript("document.body.focus();"); 300 webView.getEngine(). 301 executeScript("document.execCommand('selectAll', false, 'true');"); 302 webView.getEngine(). 303 executeScript("document.execCommand('removeFormat', false, null);"); 304 result.set("bold".equals(webView.getEngine(). 305 executeScript("document.body.style.fontWeight"). 306 toString())); 307 htmlEditorTestApp.primaryStage.hide(); 308 editorStateLatch.countDown(); 309 } 310 }); 311 312 webView.getEngine().getLoadWorker().stateProperty(). 313 addListener((observable, oldValue, newValue) -> { 314 if (newValue == SUCCEEDED) { 315 htmlEditor.requestFocus(); 316 editorStateLatch.countDown(); 317 } 318 }); 319 htmlEditorTestApp.primaryStage.show(); 320 }); 321 322 try { 323 editorStateLatch.await(TIMEOUT, TimeUnit.MILLISECONDS); 324 } catch (InterruptedException ex) { 325 throw new AssertionError(ex); 326 } finally { 327 assertTrue("check Style Property with removeFormat ", result.get()); 328 } 329 } 330 } | 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package test.javafx.scene.web; 27 28 import java.util.concurrent.atomic.AtomicReference; 29 import java.util.concurrent.CountDownLatch; 30 import java.util.concurrent.TimeUnit; 31 import javafx.application.Application; 32 import javafx.application.Platform; 33 import javafx.event.Event; 34 import javafx.scene.input.KeyCode; 35 import javafx.scene.input.KeyEvent; 36 import javafx.scene.Scene; 37 import javafx.scene.web.HTMLEditor; 38 import javafx.scene.web.WebView; 39 import javafx.stage.Stage; 40 import org.junit.AfterClass; 41 import org.junit.Before; 42 import org.junit.BeforeClass; 43 import org.junit.Ignore; 44 import org.junit.Test; 45 import test.util.Util; 46 47 import static javafx.concurrent.Worker.State.SUCCEEDED; 48 import static junit.framework.TestCase.fail; 49 import static org.junit.Assert.assertEquals; 50 import static org.junit.Assert.assertNotNull; 51 import static org.junit.Assert.assertTrue; 52 53 public class HTMLEditorTest { 54 private static final CountDownLatch launchLatch = new CountDownLatch(1); 55 56 // Maintain one application instance 57 static HTMLEditorTestApp htmlEditorTestApp; 58 59 private HTMLEditor htmlEditor; 60 private WebView webView; 61 62 public static class HTMLEditorTestApp extends Application { 63 Stage primaryStage = null; 64 65 public HTMLEditorTestApp() { 66 super(); 67 } 68 69 @Override 70 public void init() { 71 HTMLEditorTest.htmlEditorTestApp = this; 72 } 73 74 @Override 75 public void start(Stage primaryStage) throws Exception { 76 Platform.setImplicitExit(false); 77 this.primaryStage = primaryStage; 78 launchLatch.countDown(); 79 } 80 } 81 82 @BeforeClass 83 public static void setupOnce() { 84 // Start the Test Application 85 new Thread(() -> Application.launch(HTMLEditorTestApp.class, 86 (String[]) null)).start(); 87 88 assertTrue("Timeout waiting for FX runtime to start", Util.await(launchLatch)); 89 } 90 91 @AfterClass 92 public static void tearDownOnce() { 93 Platform.exit(); 94 } 95 96 @Before 97 public void setupTestObjects() { 98 Platform.runLater(() -> { 99 htmlEditor = new HTMLEditor(); 100 Scene scene = new Scene(htmlEditor); 101 htmlEditorTestApp.primaryStage.setScene(scene); 102 htmlEditorTestApp.primaryStage.show(); 103 104 webView = (WebView) htmlEditor.lookup(".web-view"); 105 assertNotNull(webView); 106 // Cancel the existing load to make our stateProperty listener 107 // usable 108 webView.getEngine().getLoadWorker().cancel(); 109 }); 110 } 111 112 /** 113 * @test 114 * @bug 8090011 115 * Summary Check document focus change behavior on tab key press 116 */ 117 // Currently ignoring this test case due to regression (JDK-8200418). 118 // The newly cloned issue (JDK-8202542) needs to be fixed before 119 // re-enabling this test case. 120 @Test @Ignore("JDK-8202542") 121 public void checkFocusChange() throws Exception { 122 final CountDownLatch editorStateLatch = new CountDownLatch(1); 123 final AtomicReference<String> result = new AtomicReference<>(); 124 Platform.runLater(() -> { 125 webView.getEngine().getLoadWorker().stateProperty(). 126 addListener((observable, oldValue, newValue) -> { 127 if (newValue == SUCCEEDED) { 128 webView.getEngine().executeScript( 129 "document.body.style.backgroundColor='red';" + 130 "document.body.onfocusout = function() {" + 131 "document.body.style.backgroundColor = 'yellow';" + 132 "}"); 133 htmlEditor.requestFocus(); 134 } 135 }); 136 htmlEditor.setHtmlText(htmlEditor.getHtmlText()); 137 138 KeyEvent tabKeyEvent = new KeyEvent(null, webView, 139 KeyEvent.KEY_PRESSED, "", "", 140 KeyCode.TAB, false, false, false, false); 141 142 webView.focusedProperty(). 143 addListener((observable, oldValue, newValue) -> { 144 if (newValue) { 145 webView.getEngine(). 146 executeScript("document.body.focus();"); 147 // Check focus change on repeated tab key press 148 for (int i = 0; i < 10; ++i) { 149 Event.fireEvent(webView, tabKeyEvent); 150 } 151 result.set(webView.getEngine(). 152 executeScript("document.body.style.backgroundColor"). 153 toString()); 154 htmlEditorTestApp.primaryStage.hide(); 155 editorStateLatch.countDown(); 156 } 157 }); 158 159 }); 160 161 assertTrue("Timeout when waiting for focus change ", Util.await(editorStateLatch)); 162 assertEquals("Focus Change with design mode enabled ", "red", result.get()); 163 } 164 165 /** 166 * @test 167 * @bug 8088769 168 * Summary Verify CSS styling in HTMLEditor 169 */ 170 @Test 171 public void checkStyleWithCSS() throws Exception { 172 final CountDownLatch editorStateLatch = new CountDownLatch(1); 173 final String editorCommand1 = 174 "document.execCommand('bold', false, 'true');" + 175 "document.execCommand('italic', false, 'true');" + 176 "document.execCommand('insertText', false, 'Hello World');"; 177 final String editorCommand2 = 178 "document.execCommand('selectAll', false, 'true');" + 179 "document.execCommand('delete', false, 'true');" + 180 "document.execCommand('bold', false, 'false');" + 181 "document.execCommand('italic', false, 'false');" + 182 "document.execCommand('underline', false, 'true');" + 183 "document.execCommand('forecolor', false," + 184 " 'rgba(255, 155, 0, 0.4)');" + 185 "document.execCommand('backcolor', false," + 186 " 'rgba(150, 90, 5, 0.5)');" + 187 "document.execCommand('insertText', false, 'Hello HTMLEditor');"; 188 final String expectedHTML = "<html dir=\"ltr\"><head></head><body " + 189 "contenteditable=\"true\"><span style=\"font-weight: bold; " + 190 "font-style: italic;\">Hello World</span></body></html>"; 191 192 Util.runAndWait(() -> { 193 webView.getEngine().getLoadWorker().stateProperty(). 194 addListener((observable, oldValue, newValue) -> { 195 if (newValue == SUCCEEDED) { 196 htmlEditor.requestFocus(); 197 } 198 }); 199 htmlEditor.setHtmlText(htmlEditor.getHtmlText()); 200 assertNotNull(webView); 201 202 webView.focusedProperty(). 203 addListener((observable, oldValue, newValue) -> { 204 if (newValue) { 205 editorStateLatch.countDown(); 206 } 207 }); 208 209 }); 210 211 assertTrue("Timeout when waiting for focus change ", Util.await(editorStateLatch)); 212 213 Util.runAndWait(() -> { 214 webView.getEngine().executeScript("document.body.focus();"); 215 webView.getEngine().executeScript(editorCommand1); 216 assertEquals(expectedHTML, htmlEditor.getHtmlText()); 217 webView.getEngine().executeScript(editorCommand2); 218 assertEquals(webView.getEngine().executeScript( 219 "document.getElementsByTagName('span')[0].style.textDecoration") 220 .toString(), 221 "underline"); 222 assertEquals(webView.getEngine().executeScript( 223 "document.getElementsByTagName('span')[0].style.fontWeight") 224 .toString(), ""); 225 assertEquals(webView.getEngine().executeScript( 226 "document.getElementsByTagName('span')[0].style.fontStyle") 227 .toString(), ""); 228 testColorEquality("rgba(255, 155, 0, 0.4)", 229 webView.getEngine().executeScript( 230 "document.getElementsByTagName('span')[0].style.color") 231 .toString(), 0.01); 244 actualColor.substring(actualColor.indexOf('(') + 1, 245 actualColor.lastIndexOf(')')).split(","); 246 final String[] expectedValues = 247 expectedColor.substring(expectedColor.indexOf('(') + 1, 248 expectedColor.lastIndexOf(')')).split(","); 249 for (int i = 0; i < 3; i++) { 250 assertEquals(Integer.parseInt(actualValues[i].trim()), 251 Integer.parseInt(expectedValues[i].trim())); 252 } 253 assertEquals(Double.parseDouble(actualValues[3].trim()), 254 Double.parseDouble(expectedValues[3].trim()), delta); 255 } 256 257 /** 258 * @test 259 * @bug 8200418 260 * Summary Check Style property after removeformat 261 */ 262 @Test 263 public void checkStyleProperty() throws Exception { 264 final CountDownLatch editorStateLatch = new CountDownLatch(1); 265 final AtomicReference<String> result = new AtomicReference<>(); 266 Util.runAndWait(() -> { 267 webView.getEngine().getLoadWorker().stateProperty(). 268 addListener((observable, oldValue, newValue) -> { 269 if (newValue == SUCCEEDED) { 270 htmlEditor.requestFocus(); 271 } 272 }); 273 274 htmlEditor.setHtmlText("<body style='font-weight: bold'> <p> Test </p> </body>"); 275 276 webView.focusedProperty(). 277 addListener((observable, oldValue, newValue) -> { 278 if (newValue) { 279 webView.getEngine(). 280 executeScript("document.body.focus();"); 281 webView.getEngine(). 282 executeScript("document.execCommand('selectAll', false, 'true');"); 283 webView.getEngine(). 284 executeScript("document.execCommand('removeFormat', false, null);"); 285 result.set(webView.getEngine(). 286 executeScript("document.body.style.fontWeight"). 287 toString()); 288 editorStateLatch.countDown(); 289 } 290 }); 291 292 }); 293 294 assertTrue("Timeout when waiting for focus change ", Util.await(editorStateLatch)); 295 assertNotNull("result must have a valid reference ", result.get()); 296 assertEquals("document.body.style.fontWeight must be bold ", "bold", result.get()); 297 } 298 } |