001/* 002 * (C) Copyright 2011-2016 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Sun Seng David TAN 018 * Florent Guillaume 019 * Benoit Delbosc 020 * Antoine Taillefer 021 * Anahide Tchertchian 022 * Guillaume Renard 023 * Mathieu Guillaume 024 * Julien Carsique 025 */ 026package org.nuxeo.functionaltests; 027 028import static org.junit.Assert.assertEquals; 029import static org.junit.Assert.assertTrue; 030import static org.nuxeo.functionaltests.Constants.ADMINISTRATOR; 031 032import java.io.File; 033import java.io.IOException; 034import java.lang.reflect.Constructor; 035import java.lang.reflect.Field; 036import java.net.MalformedURLException; 037import java.net.URL; 038import java.util.ArrayList; 039import java.util.List; 040import java.util.concurrent.TimeUnit; 041 042import org.apache.commons.io.FileUtils; 043import org.apache.commons.lang3.ArrayUtils; 044import org.apache.commons.logging.Log; 045import org.apache.commons.logging.LogFactory; 046import org.junit.After; 047import org.junit.AfterClass; 048import org.junit.BeforeClass; 049import org.junit.Rule; 050import org.junit.rules.MethodRule; 051import org.nuxeo.functionaltests.JavaScriptErrorCollector.JavaScriptErrorIgnoreRule; 052import org.nuxeo.functionaltests.drivers.ChromeDriverProvider; 053import org.nuxeo.functionaltests.drivers.FirefoxDriverProvider; 054import org.nuxeo.functionaltests.drivers.RemoteFirefoxDriverProvider; 055import org.nuxeo.functionaltests.fragment.WebFragment; 056import org.nuxeo.functionaltests.pages.AbstractPage; 057import org.nuxeo.functionaltests.pages.DocumentBasePage; 058import org.nuxeo.functionaltests.pages.DocumentBasePage.UserNotConnectedException; 059import org.nuxeo.functionaltests.pages.FileDocumentBasePage; 060import org.nuxeo.functionaltests.pages.LoginPage; 061import org.nuxeo.functionaltests.pages.NoteDocumentBasePage; 062import org.nuxeo.functionaltests.pages.tabs.CollectionContentTabSubPage; 063import org.nuxeo.functionaltests.proxy.ProxyManager; 064import org.nuxeo.runtime.api.Framework; 065import org.openqa.selenium.By; 066import org.openqa.selenium.NoSuchElementException; 067import org.openqa.selenium.NoSuchWindowException; 068import org.openqa.selenium.NotFoundException; 069import org.openqa.selenium.Proxy; 070import org.openqa.selenium.TimeoutException; 071import org.openqa.selenium.WebDriver; 072import org.openqa.selenium.WebElement; 073import org.openqa.selenium.internal.WrapsElement; 074import org.openqa.selenium.remote.CapabilityType; 075import org.openqa.selenium.remote.Command; 076import org.openqa.selenium.remote.DesiredCapabilities; 077import org.openqa.selenium.remote.DriverCommand; 078import org.openqa.selenium.remote.RemoteWebDriver; 079import org.openqa.selenium.support.PageFactory; 080import org.openqa.selenium.support.ui.FluentWait; 081import org.openqa.selenium.support.ui.Wait; 082 083import com.google.common.collect.ImmutableMap; 084 085/** 086 * Base functions for all pages. 087 */ 088public abstract class AbstractTest { 089 090 /** 091 * @since 5.9.2 092 */ 093 public final static String TEST_USERNAME = "jdoe"; 094 095 /** 096 * @since 5.9.2 097 */ 098 public final static String TEST_PASSWORD = "test"; 099 100 /** 101 * Polling frequency in milliseconds. 102 * 103 * @since 5.9.2 104 */ 105 public static final int POLLING_FREQUENCY_MILLISECONDS = 100; 106 107 public static final int POLLING_FREQUENCY_SECONDS = 1; 108 109 /** 110 * Page Load timeout in seconds. 111 * 112 * @since 5.9.2 113 */ 114 public static final int PAGE_LOAD_TIME_OUT_SECONDS = 60; 115 116 public static final int LOAD_TIMEOUT_SECONDS = 30; 117 118 /** 119 * Driver implicit wait in milliseconds. 120 * 121 * @since 8.3 122 */ 123 public static final int IMPLICIT_WAIT_MILLISECONDS = 200; 124 125 public static final int LOAD_SHORT_TIMEOUT_SECONDS = 2; 126 127 public static final int AJAX_TIMEOUT_SECONDS = 10; 128 129 public static final int AJAX_SHORT_TIMEOUT_SECONDS = 2; 130 131 /** 132 * @since 5.7 133 * @deprecated since 8.3 134 * @see ChromeDriverProvider 135 */ 136 @Deprecated 137 public static final String CHROME_DRIVER_DEFAULT_PATH_LINUX = ChromeDriverProvider.CHROME_DRIVER_DEFAULT_PATH_LINUX; 138 139 /** 140 * @since 5.7 "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" doesn't work 141 * @deprecated since 8.3 142 * @see ChromeDriverProvider 143 */ 144 @Deprecated 145 public static final String CHROME_DRIVER_DEFAULT_PATH_MAC = ChromeDriverProvider.CHROME_DRIVER_DEFAULT_PATH_MAC; 146 147 /** 148 * @since 5.7 149 * @deprecated since 8.3 150 * @see ChromeDriverProvider 151 */ 152 @Deprecated 153 public static final String CHROME_DRIVER_DEFAULT_PATH_WINVISTA = ChromeDriverProvider.CHROME_DRIVER_DEFAULT_PATH_WINVISTA; 154 155 /** 156 * @since 5.7 157 * @deprecated since 8.3 158 * @see ChromeDriverProvider 159 */ 160 @Deprecated 161 public static final String CHROME_DRIVER_DEFAULT_PATH_WINXP = ChromeDriverProvider.CHROME_DRIVER_DEFAULT_PATH_WINXP; 162 163 /** 164 * @since 5.7 165 * @deprecated since 8.3 166 * @see ChromeDriverProvider 167 */ 168 @Deprecated 169 public static final String CHROME_DRIVER_DEFAULT_EXECUTABLE_NAME = ChromeDriverProvider.CHROME_DRIVER_DEFAULT_EXECUTABLE_NAME; 170 171 /** 172 * @since 5.7 173 * @deprecated since 8.3 174 * @see ChromeDriverProvider 175 */ 176 @Deprecated 177 public static final String CHROME_DRIVER_WINDOWS_EXECUTABLE_NAME = ChromeDriverProvider.CHROME_DRIVER_WINDOWS_EXECUTABLE_NAME; 178 179 /** 180 * @deprecated since 8.3 181 * @see ChromeDriverProvider 182 */ 183 @Deprecated 184 public static final String SYSPROP_CHROME_DRIVER_PATH = ChromeDriverProvider.SYSPROP_CHROME_DRIVER_PATH; 185 186 static final Log log = LogFactory.getLog(AbstractTest.class); 187 188 public static final String NUXEO_URL = System.getProperty("nuxeoURL", "http://localhost:8080/nuxeo") 189 .replaceAll("/$", ""); 190 191 public static RemoteWebDriver driver; 192 193 protected static ProxyManager proxyManager; 194 195 /** 196 * Logger method to follow what's being run on server logs and take a screenshot of the last page in case of failure 197 */ 198 @Rule 199 public MethodRule watchman = new LogTestWatchman(driver, NUXEO_URL); 200 201 /** 202 * This method will be executed before any method registered with JUnit After annotation. 203 * 204 * @since 5.8 205 */ 206 public void runBeforeAfters() { 207 ((LogTestWatchman) watchman).runBeforeAfters(); 208 } 209 210 @BeforeClass 211 public static void initDriver() throws Exception { 212 String browser = System.getProperty("browser", "firefox"); 213 // Use the same strings as command-line Selenium 214 if (browser.equals("chrome") || browser.equals("firefox")) { 215 initFirefoxDriver(); 216 } else if (browser.equals("remotefirefox")) { 217 initRemoteFirefoxDriver(); 218 } else if (browser.equals("googlechrome")) { 219 initChromeDriver(); 220 } else { 221 throw new RuntimeException("Browser not supported: " + browser); 222 } 223 driver.manage().timeouts().pageLoadTimeout(PAGE_LOAD_TIME_OUT_SECONDS, TimeUnit.SECONDS); 224 driver.manage().timeouts().implicitlyWait(IMPLICIT_WAIT_MILLISECONDS, TimeUnit.MILLISECONDS); 225 } 226 227 protected static void initFirefoxDriver() throws Exception { 228 proxyManager = new ProxyManager(); 229 Proxy proxy = proxyManager.startProxy(); 230 if (proxy != null) { 231 proxy.setNoProxy(""); 232 } 233 DesiredCapabilities dc = DesiredCapabilities.firefox(); 234 dc.setCapability(CapabilityType.PROXY, proxy); 235 driver = new FirefoxDriverProvider().init(dc); 236 } 237 238 protected static void initRemoteFirefoxDriver() throws Exception { 239 proxyManager = new ProxyManager(); 240 Proxy proxy = proxyManager.startProxy(); 241 if (proxy != null) { 242 proxy.setNoProxy(""); 243 } 244 DesiredCapabilities dc = DesiredCapabilities.firefox(); 245 dc.setCapability(CapabilityType.PROXY, proxy); 246 driver = new RemoteFirefoxDriverProvider().init(dc); 247 } 248 249 protected static void initChromeDriver() throws Exception { 250 proxyManager = new ProxyManager(); 251 Proxy proxy = proxyManager.startProxy(); 252 DesiredCapabilities dc = DesiredCapabilities.chrome(); 253 if (proxy != null) { 254 proxy.setNoProxy(""); 255 dc.setCapability(CapabilityType.PROXY, proxy); 256 } 257 driver = new ChromeDriverProvider().init(dc); 258 } 259 260 /** 261 * @since 9.3 262 */ 263 protected JavaScriptErrorIgnoreRule[] ignores = new JavaScriptErrorIgnoreRule[0]; 264 265 /** 266 * @since 9.3 267 */ 268 public void addAfterTestIgnores(JavaScriptErrorIgnoreRule... ignores) { 269 this.ignores = ArrayUtils.addAll(this.ignores, ignores); 270 } 271 272 /** 273 * @since 7.1 274 */ 275 @After 276 public void checkJavascriptError() { 277 JavaScriptErrorCollector.from(driver).ignore(ignores).checkForErrors(); 278 } 279 280 @AfterClass 281 public static void quitDriver() { 282 if (driver != null) { 283 driver.quit(); 284 driver = null; 285 } 286 287 try { 288 proxyManager.stopProxy(); 289 proxyManager = null; 290 } catch (Exception e) { 291 log.error("Could not stop proxy: " + e.getMessage()); 292 } 293 } 294 295 public static <T> T get(String url, Class<T> pageClassToProxy, JavaScriptErrorIgnoreRule... ignores) { 296 JavaScriptErrorCollector.from(driver).ignore(ignores).checkForErrors(); 297 driver.get(url); 298 return asPage(pageClassToProxy); 299 } 300 301 /** 302 * Opens given url adding hardcoded Seam conversation named "0NXMAIN". 303 * 304 * @since 8.3 305 */ 306 public static void open(String url, JavaScriptErrorIgnoreRule... ignores) { 307 JavaScriptErrorCollector.from(driver).ignore(ignores).checkForErrors(); 308 driver.get(NUXEO_URL + url + "?conversationId=0NXMAIN"); 309 } 310 311 /** 312 * Do not wait for page load. Do not handle error. Do not give explicit error in case of failure. This is a very raw 313 * get. 314 * 315 * @since 6.0 316 */ 317 public static <T> T getWithoutErrorHandler(String url, Class<T> pageClassToProxy) throws IOException { 318 Command command = new Command(AbstractTest.driver.getSessionId(), DriverCommand.GET, 319 ImmutableMap.of("url", url)); 320 AbstractTest.driver.getCommandExecutor().execute(command); 321 return asPage(pageClassToProxy); 322 } 323 324 public static WebDriver getPopup() { 325 return switchToPopup(null); 326 } 327 328 /** 329 * Focus popup that contains text parameter value in his current URL. 330 * 331 * @param text that must be contained in popup URL 332 * @return WebDriver instance to be chained 333 * @since 9.3 334 */ 335 public static WebDriver switchToPopup(String text) { 336 String currentWindow = null; 337 try { 338 currentWindow = driver.getWindowHandle(); 339 } catch (NoSuchWindowException ignored) { 340 // Nothing to do; it can happen when manipulating closed popups 341 } 342 343 for (String popup : driver.getWindowHandles()) { 344 if (popup.equals(currentWindow)) { 345 continue; 346 } 347 348 driver.switchTo().window(popup); 349 if (text == null || driver.getCurrentUrl().contains(text)) { 350 return driver; 351 } 352 } 353 354 throw new NotFoundException("Popup not found: " + text); 355 } 356 357 public static <T> T asPage(Class<T> pageClassToProxy) { 358 T page = instantiatePage(pageClassToProxy); 359 return fillElement(pageClassToProxy, page); 360 } 361 362 public static <T extends WebFragment> T getWebFragment(By by, Class<T> webFragmentClass) { 363 WebElement element = Locator.findElementWithTimeout(by); 364 return getWebFragment(element, webFragmentClass); 365 } 366 367 public static <T extends WebFragment> T getWebFragment(WebElement element, Class<T> webFragmentClass) { 368 T webFragment = instantiateWebFragment(element, webFragmentClass); 369 webFragment = fillElement(webFragmentClass, webFragment); 370 // fillElement somehow overwrite the 'element' field, reset it. 371 webFragment.setElement(element); 372 return webFragment; 373 } 374 375 /** 376 * Fills an instantiated page/form/widget attributes 377 * 378 * @since 5.7 379 */ 380 public static <T> T fillElement(Class<T> pageClassToProxy, T page) { 381 PageFactory.initElements(new VariableElementLocatorFactory(driver, AJAX_TIMEOUT_SECONDS), page); 382 // check all required WebElements on the page and wait for their 383 // loading 384 final List<String> fieldNames = new ArrayList<>(); 385 final List<WrapsElement> elements = new ArrayList<>(); 386 for (Field field : pageClassToProxy.getDeclaredFields()) { 387 if (field.getAnnotation(Required.class) != null) { 388 try { 389 field.setAccessible(true); 390 fieldNames.add(field.getName()); 391 elements.add((WrapsElement) field.get(page)); 392 } catch (Exception e) { 393 throw new RuntimeException(e); 394 } 395 } 396 } 397 398 Wait<T> wait = new FluentWait<>(page).withTimeout(LOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS) 399 .pollingEvery(POLLING_FREQUENCY_MILLISECONDS, TimeUnit.MILLISECONDS); 400 T res; 401 try { 402 res = wait.until(aPage -> { 403 String notLoaded = anyElementNotLoaded(elements, fieldNames); 404 if (notLoaded == null) { 405 return aPage; 406 } else { 407 return null; 408 } 409 }); 410 } catch (TimeoutException e) { 411 throw new TimeoutException("not loaded: " + anyElementNotLoaded(elements, fieldNames), e); 412 } 413 // check if there are JQuery ajax requests to complete 414 if (pageClassToProxy.isAnnotationPresent(WaitForJQueryAjaxOnLoading.class)) { 415 new AjaxRequestManager(driver).waitForJQueryRequests(); 416 } 417 return res; 418 } 419 420 protected static String anyElementNotLoaded(List<WrapsElement> proxies, List<String> fieldNames) { 421 for (int i = 0; i < proxies.size(); i++) { 422 WrapsElement proxy = proxies.get(i); 423 try { 424 // method implemented in LocatingElementHandler 425 proxy.getWrappedElement(); 426 } catch (NoSuchElementException e) { 427 return fieldNames.get(i); 428 } 429 } 430 return null; 431 } 432 433 // private in PageFactory... 434 protected static <T> T instantiatePage(Class<T> pageClassToProxy) { 435 try { 436 try { 437 Constructor<T> constructor = pageClassToProxy.getConstructor(WebDriver.class); 438 return constructor.newInstance(driver); 439 } catch (NoSuchMethodException e) { 440 return pageClassToProxy.newInstance(); 441 } 442 } catch (RuntimeException e) { 443 throw e; 444 } catch (Exception e) { 445 throw new RuntimeException(e); 446 } 447 } 448 449 protected static <T extends WebFragment> T instantiateWebFragment(WebElement element, Class<T> webFragmentClass) { 450 try { 451 try { 452 Constructor<T> constructor = webFragmentClass.getConstructor(WebDriver.class, WebElement.class); 453 return constructor.newInstance(driver, element); 454 } catch (NoSuchMethodException e) { 455 return webFragmentClass.newInstance(); 456 } 457 } catch (RuntimeException e) { 458 throw e; 459 } catch (Exception e) { 460 throw new RuntimeException(e); 461 } 462 } 463 464 public LoginPage getLoginPage() { 465 return get(NUXEO_URL + "/logout", LoginPage.class); 466 } 467 468 public LoginPage logout() { 469 JavaScriptErrorCollector.from(driver).ignore(ignores).checkForErrors(); 470 return getLoginPage(); 471 } 472 473 /** 474 * Logs out without expecting to be redirected to the login page. This can be the case on a simple server 475 * distribution when logged in: the logout action can redirect to the home.html startup page. 476 * 477 * @since 9.2 478 */ 479 public void logoutSimply() { 480 driver.get(NUXEO_URL + "/logout"); 481 } 482 483 /** 484 * navigate to a link text. wait until the link is available and click on it. 485 */ 486 public <T extends AbstractPage> T nav(Class<T> pageClass, String linkText) { 487 WebElement link = Locator.findElementWithTimeout(By.linkText(linkText)); 488 if (link == null) { 489 return null; 490 } 491 link.click(); 492 return asPage(pageClass); 493 } 494 495 /** 496 * Navigate to a specified url 497 * 498 * @param urlString url 499 * @throws MalformedURLException 500 */ 501 public void navToUrl(String urlString) throws MalformedURLException { 502 URL url = new URL(urlString); 503 driver.navigate().to(url); 504 } 505 506 /** 507 * Login as Administrator 508 * 509 * @return the Document base page (by default returned by CAP) 510 * @throws UserNotConnectedException 511 */ 512 public DocumentBasePage login() throws UserNotConnectedException { 513 return login(ADMINISTRATOR, ADMINISTRATOR); 514 } 515 516 public DocumentBasePage login(String username, String password) throws UserNotConnectedException { 517 DocumentBasePage documentBasePage = getLoginPage().login(username, password, DocumentBasePage.class); 518 documentBasePage.checkUserConnected(username); 519 return documentBasePage; 520 } 521 522 /** 523 * Login as default test user. 524 * 525 * @since 5.9.2 526 */ 527 public DocumentBasePage loginAsTestUser() throws UserNotConnectedException { 528 return login(TEST_USERNAME, TEST_PASSWORD); 529 } 530 531 /** 532 * Login using an invalid credential. 533 * 534 * @param username the username 535 * @param password the password 536 */ 537 public LoginPage loginInvalid(String username, String password) { 538 return getLoginPage().login(username, password, LoginPage.class); 539 } 540 541 /** 542 * Init the repository with a test Workspace form the {@code currentPage}. 543 * 544 * @param currentPage the current page 545 * @return the created Workspace page 546 * @throws Exception if initializing repository fails 547 * @deprecated since 8.3 548 */ 549 @Deprecated 550 protected DocumentBasePage initRepository(DocumentBasePage currentPage) throws Exception { 551 return createWorkspace(currentPage, "Test Workspace", "Test Workspace for my dear WebDriver."); 552 } 553 554 /** 555 * Cleans the repository (delete the test Workspace) from the {@code currentPage}. 556 * 557 * @param currentPage the current page 558 * @throws Exception if cleaning repository fails 559 * @deprecated since 8.3 560 */ 561 @Deprecated 562 protected void cleanRepository(DocumentBasePage currentPage) throws Exception { 563 deleteWorkspace(currentPage, "Test Workspace"); 564 } 565 566 /** 567 * Creates a Workspace from the {@code currentPage}. 568 * 569 * @param currentPage the current page 570 * @param workspaceTitle the workspace title 571 * @param workspaceDescription the workspace description 572 * @return the created Workspace page 573 * @deprecated since 8.3: use {@link DocumentBasePage#createWorkspace(String, String)} instead. 574 */ 575 @Deprecated 576 protected DocumentBasePage createWorkspace(DocumentBasePage currentPage, String workspaceTitle, 577 String workspaceDescription) { 578 return currentPage.createWorkspace(workspaceTitle, workspaceDescription); 579 } 580 581 /** 582 * Deletes the Workspace with title {@code workspaceTitle} from the {@code currentPage}. 583 * 584 * @param currentPage the current page 585 * @param workspaceTitle the workspace title 586 * @deprecated since 8.3: use {@link DocumentBasePage#deleteWorkspace(String)} instead. 587 */ 588 @Deprecated 589 protected void deleteWorkspace(DocumentBasePage currentPage, String workspaceTitle) { 590 currentPage.deleteWorkspace(workspaceTitle); 591 } 592 593 /** 594 * Creates a File form the {@code currentPage}. 595 * 596 * @param currentPage the current page 597 * @param fileTitle the file title 598 * @param fileDescription the file description 599 * @param uploadBlob true if a blob needs to be uploaded (temporary file created for this purpose) 600 * @param filePrefix the file prefix 601 * @param fileSuffix the file suffix 602 * @param fileContent the file content 603 * @return the created File page 604 * @throws IOException if temporary file creation fails 605 * @deprecated since 8.3: use {@link DocumentBasePage#createFile(String, String, boolean, String, String, String)} 606 * instead. 607 */ 608 @Deprecated 609 protected FileDocumentBasePage createFile(DocumentBasePage currentPage, String fileTitle, String fileDescription, 610 boolean uploadBlob, String filePrefix, String fileSuffix, String fileContent) throws IOException { 611 return currentPage.createFile(fileTitle, fileDescription, uploadBlob, filePrefix, fileSuffix, fileContent); 612 } 613 614 /** 615 * Creates a Collections container form the {@code currentPage}. 616 * 617 * @param currentPage the current page 618 * @param collectionsTitle the Collections container title 619 * @param fileDescription the collections description 620 * @return the created Collections page 621 * @deprecated since 8.3: use {@link DocumentBasePage#createCollections(String, String)} instead. 622 */ 623 @Deprecated 624 protected DocumentBasePage createCollections(DocumentBasePage currentPage, String collectionsTitle, 625 String fileDescription) { 626 return currentPage.createCollections(collectionsTitle, fileDescription); 627 } 628 629 /** 630 * Creates a Collection form the {@code currentPage}. 631 * 632 * @param currentPage the current page 633 * @param collectionsTitle the Collections container title 634 * @param fileDescription the collection description 635 * @return the created Collections page 636 * @deprecated since 8.3: use {@link DocumentBasePage#createCollection(String, String)} instead. 637 */ 638 @Deprecated 639 protected CollectionContentTabSubPage createCollection(DocumentBasePage currentPage, String collectionsTitle, 640 String fileDescription) { 641 return currentPage.createCollection(collectionsTitle, fileDescription); 642 } 643 644 /** 645 * Creates a temporary file and returns its absolute path. 646 * 647 * @param filePrefix the file prefix 648 * @param fileSuffix the file suffix 649 * @param fileContent the file content 650 * @return the temporary file to upload path 651 * @throws IOException if temporary file creation fails 652 * @since 5.9.3 653 */ 654 public static String getTmpFileToUploadPath(String filePrefix, String fileSuffix, String fileContent) 655 throws IOException { 656 // Create tmp file, deleted on exit 657 File tmpFile = Framework.createTempFile(filePrefix, fileSuffix); 658 tmpFile.deleteOnExit(); 659 FileUtils.writeStringToFile(tmpFile, fileContent); 660 assertTrue(tmpFile.exists()); 661 662 // Check file URI protocol 663 assertEquals("file", tmpFile.toURI().toURL().getProtocol()); 664 665 // Return file absolute path 666 return tmpFile.getAbsolutePath(); 667 } 668 669 /** 670 * Get the current document id stored in the javascript ctx.currentDocument variable of the current page. 671 * 672 * @return the current document id 673 * @since 5.7 674 */ 675 protected String getCurrentDocumentId() { 676 return (String) driver.executeScript("return ctx.currentDocument;"); 677 } 678 679 /** 680 * Creates a Note form the {@code currentPage}. 681 * 682 * @param currentPage the current page 683 * @param noteTitle the note title 684 * @param noteDescription the note description 685 * @param defineNote true if the content of the note needs to be defined 686 * @param noteContent the content of the note 687 * @return the created note page. 688 * @throws IOException 689 * @since 5.9.4 690 * @deprecated since 8.3: use {@link DocumentBasePage#createNote(String, String, boolean, String)} instead. 691 */ 692 @Deprecated 693 protected NoteDocumentBasePage createNote(DocumentBasePage currentPage, String noteTitle, String noteDescription, 694 boolean defineNote, String noteContent) throws IOException { 695 return currentPage.createNote(noteTitle, noteDescription, defineNote, noteContent); 696 } 697 698}