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