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}