org.xwiki.test.selenium.framework.AbstractXWikiTestCase.java Source code

Java tutorial

Introduction

Here is the source code for org.xwiki.test.selenium.framework.AbstractXWikiTestCase.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.test.selenium.framework;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Map.Entry;
import java.util.Properties;

import org.junit.Assert;
import org.junit.Before;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.xwiki.test.ui.AbstractTest;

import com.thoughtworks.selenium.Selenium;
import com.thoughtworks.selenium.SeleniumException;
import com.thoughtworks.selenium.Wait;
import com.thoughtworks.selenium.webdriven.WebDriverBackedSelenium;

/**
 * All XWiki Selenium tests must extend this class.
 * 
 * @version $Id: c7cb7a6044a1b7056ddb23ce1a8e62d04da4527e $
 */
public abstract class AbstractXWikiTestCase extends AbstractTest implements SkinExecutor {
    public static final String BASEDIR = System.getProperty("basedir");

    public static final String DOC = "selenium.browserbot.getCurrentWindow().document.";

    private static final int WAIT_TIME = 30000;

    private SkinExecutor skinExecutor = new FlamingoSkinExecutor(this);

    private Selenium selenium;

    public void setSkinExecutor(SkinExecutor skinExecutor) {
        this.skinExecutor = skinExecutor;
    }

    public SkinExecutor getSkinExecutor() {
        return this.skinExecutor;
    }

    public Selenium getSelenium() {
        if (this.selenium == null) {
            String baseURL = "http://localhost:" + System.getProperty("xwikiPort", "8080");
            this.selenium = new WebDriverBackedSelenium(getDriver(), baseURL);
        }
        return this.selenium;
    }

    @Before
    public void setUp() {
        loginAsAdmin();
    }

    // Convenience methods wrapping Selenium

    public void open(String url) {
        getSelenium().open(url);
    }

    public void open(String space, String page) {
        open(getUrl(space, page));
    }

    public void open(String space, String page, String action) {
        open(getUrl(space, page, action));
    }

    public void open(String space, String page, String action, String queryString) {
        open(getUrl(space, page, action, queryString));
    }

    public String getTitle() {
        return getSelenium().getTitle();
    }

    public void assertPage(String space, String page) {
        Assert.assertTrue(getTitle().matches(".*\\(" + space + "." + page + "\\) - XWiki"));
    }

    /**
     * Visits the specified page and checks if it exists, coming back to the current page.
     * 
     * @param space the space name
     * @param page the page name
     * @return {@code true} if the specified page exists
     */
    public boolean isExistingPage(String space, String page) {
        String saveUrl = getSelenium().getLocation();

        open(getUrl(space, page));
        boolean exists = isExistingPage();

        // Restore original URL
        open(saveUrl);

        return exists;
    }

    /**
     * @return {@code true} if we are on an existing page, {@code false} otherwise
     */
    public boolean isExistingPage() {
        return !getSelenium().isTextPresent("The requested page could not be found.");
    }

    public void assertTitle(String title) {
        Assert.assertEquals(title, getTitle());
    }

    public boolean isElementPresent(String locator) {
        return getSelenium().isElementPresent(locator);
    }

    public boolean isElementPresentWithoutWaiting(By by) {
        return getDriver().hasElementWithoutWaiting(by);
    }

    public boolean isLinkPresent(String text) {
        return isElementPresent("link=" + text);
    }

    public void clickLinkWithText(String text) {
        clickLinkWithText(text, true);
    }

    public void assertTextPresent(String text) {
        Assert.assertTrue("[" + text + "] isn't present.", getSelenium().isTextPresent(text));
    }

    public void assertTextNotPresent(String text) {
        Assert.assertFalse("[" + text + "] is present.", getSelenium().isTextPresent(text));
    }

    public void assertElementPresent(String elementLocator) {
        Assert.assertTrue("[" + elementLocator + "] isn't present.", isElementPresent(elementLocator));
    }

    public void assertElementNotPresent(String elementLocator) {
        Assert.assertFalse("[" + elementLocator + "] is present.", isElementPresent(elementLocator));
    }

    public void waitPage() {
        waitPage(WAIT_TIME);
    }

    /**
     * @deprecated use {@link #waitPage()} instead
     */
    @Deprecated
    public void waitPage(int nbMillisecond) {
        getSelenium().waitForPageToLoad(String.valueOf(nbMillisecond));
    }

    public void createPage(String space, String page, String content) {
        createPage(space, page, content, null);
    }

    public void createPage(String space, String page, String content, String syntax) {
        // If the page already exists, delete it first
        deletePage(space, page);
        if (syntax == null) {
            editInWikiEditor(space, page);
        } else {
            editInWikiEditor(space, page, syntax);
        }
        setFieldValue("content", content);
        clickEditSaveAndView();
    }

    public void deletePage(String space, String page) {
        open(space, page, "delete", "confirm=1");
    }

    public void restorePage(String space, String page) {
        open(space, page, "view");
        if (getSelenium().isTextPresent("Restore")) {
            clickLinkWithText("Restore", true);
        }
    }

    public void clickLinkWithLocator(String locator) {
        clickLinkWithLocator(locator, true);
    }

    public void clickLinkWithLocator(String locator, boolean wait) {
        assertElementPresent(locator);
        getSelenium().click(locator);
        if (wait) {
            waitPage();
        }
    }

    public void clickLinkWithText(String text, boolean wait) {
        clickLinkWithLocator("link=" + text, wait);
    }

    public boolean isChecked(String locator) {
        return getSelenium().isChecked(locator);
    }

    public String getFieldValue(String fieldName) {
        // Note: We could use getSelenium().getvalue() here. However getValue() is stripping spaces
        // and some of our tests verify that there are leading spaces/empty lines.
        return getSelenium().getEval(
                "selenium.browserbot.getCurrentWindow().document.getElementById(\"" + fieldName + "\").value");
    }

    public void setFieldValue(String fieldName, String value) {
        getSelenium().type(fieldName, value);
    }

    public void checkField(String locator) {
        getSelenium().check(locator);
    }

    public void submit() {
        clickLinkWithXPath("//input[@type='submit']");
    }

    public void submit(String locator) {
        clickLinkWithLocator(locator);
    }

    public void submit(String locator, boolean wait) {
        clickLinkWithLocator(locator, wait);
    }

    public void clickLinkWithXPath(String xpath) {
        clickLinkWithXPath(xpath, true);
    }

    public void clickLinkWithXPath(String xpath, boolean wait) {
        clickLinkWithLocator("xpath=" + xpath, wait);
    }

    public void waitForCondition(String condition) {
        getSelenium().waitForCondition(condition, "" + WAIT_TIME);
    }

    public void waitForTextPresent(final String elementLocator, final String expectedValue) {
        new Wait() {
            public boolean until() {
                return getSelenium().getText(elementLocator).equals(expectedValue);
            }
        }.wait(getSelenium().isElementPresent(elementLocator) ? "Element [" + elementLocator + "] not found"
                : "Element [" + elementLocator + "] found but it doesn't have the expected value [" + expectedValue
                        + "]");
    }

    public void waitForTextContains(final String elementLocator, final String containsValue) {
        new Wait() {
            public boolean until() {
                return getSelenium().getText(elementLocator).indexOf(containsValue) > -1;
            }
        }.wait(getSelenium().isElementPresent(elementLocator) ? "Element [" + elementLocator + "] not found"
                : "Element [" + elementLocator + "] found but it doesn't contain the expected value ["
                        + containsValue + "]");
    }

    public void waitForBodyContains(final String containsValue) {
        new Wait() {
            public boolean until() {
                try {
                    return getSelenium().getBodyText().indexOf(containsValue) > -1;
                } catch (SeleniumException e) {
                    // The page might not be loaded yet and so the BODY element is missing. Try again later.
                    return false;
                }
            }
        }.wait("Body text doesn't contain the value [" + containsValue + "]");
    }

    public void waitForElement(final String elementLocator) {
        new Wait() {
            public boolean until() {
                return getSelenium().isElementPresent(elementLocator);
            }
        }.wait("element [" + elementLocator + "] not found");
    }

    /**
     * Waits until an alert message appears or the timeout expires. You can use {@link Selenium#getAlert()} to assert
     * the alert message afterwards.
     */
    public void waitForAlert() {
        new Wait() {
            public boolean until() {
                return getSelenium().isAlertPresent();
            }
        }.wait("The alert didn't appear.");
    }

    /**
     * Waits until a confirmation message appears or the timeout expires. You can use {@link Selenium#getConfirmation()}
     * to assert the confirmation message afterwards.
     */
    public void waitForConfirmation() {
        new Wait() {
            public boolean until() {
                return getSelenium().isConfirmationPresent();
            }
        }.wait("The confirmation didn't appear.");
    }

    /**
     * Waits for a notification message of the specified type with the given message to be displayed.
     * 
     * @param level the notification type (one of error, warning, done)
     * @param message the notification message
     */
    private void waitForNotificationMessage(String level, String message) {
        String xpath = String.format("//div[contains(@class,'xnotification-%s') and contains(.,'%s')]", level,
                message);
        waitForElement(xpath);
        // In order to improve test speed, clicking on the notification will make it disappear. This also ensures that
        // this method always waits for the last notification message of the specified level.
        try {
            // The notification message may disappear before we get to click on it.
            getSelenium().click(xpath);
        } catch (Exception e) {
            // Ignore.
        }
    }

    public void waitForNotificationErrorMessage(String message) {
        waitForNotificationMessage("error", message);
    }

    public void waitForNotificationWarningMessage(String message) {
        waitForNotificationMessage("warning", message);
    }

    public void waitForNotificationSuccessMessage(String message) {
        waitForNotificationMessage("done", message);
    }

    public void clickButtonAndContinue(String locator) {
        submit(locator, false);
        waitForNotificationSuccessMessage("");
    }

    @Override
    public void clickEditPage() {
        getSkinExecutor().clickEditPage();
    }

    @Override
    public void clickEditPageInWikiSyntaxEditor() {
        getSkinExecutor().clickEditPageInWikiSyntaxEditor();
    }

    @Override
    public void clickEditPageInWysiwyg() {
        getSkinExecutor().clickEditPageInWysiwyg();
    }

    @Override
    public void clickEditPageAccessRights() {
        getSkinExecutor().clickEditPageAccessRights();
    }

    @Override
    public void clickEditPageInlineForm() {
        getSkinExecutor().clickEditPageInlineForm();
    }

    @Override
    public void clickDeletePage() {
        getSkinExecutor().clickDeletePage();
    }

    @Override
    public void clickCopyPage() {
        getSkinExecutor().clickCopyPage();
    }

    @Override
    public void clickShowComments() {
        getSkinExecutor().clickShowComments();
    }

    @Override
    public void clickShowAttachments() {
        getSkinExecutor().clickShowAttachments();
    }

    @Override
    public void clickShowHistory() {
        getSkinExecutor().clickShowHistory();
    }

    @Override
    public void clickShowInformation() {
        getSkinExecutor().clickShowInformation();
    }

    @Override
    public void clickEditPreview() {
        getSkinExecutor().clickEditPreview();
    }

    @Override
    public void clickEditSaveAndContinue() {
        getSkinExecutor().clickEditSaveAndContinue();
    }

    @Override
    public void clickEditCancelEdition() {
        getSkinExecutor().clickEditCancelEdition();
    }

    @Override
    public void clickEditSaveAndView() {
        getSkinExecutor().clickEditSaveAndView();
    }

    /**
     * Clicks on the add property button in the class editor. As a result the specified property is added to the edited
     * class and the class is saved. This method waits for the class to be saved.
     */
    @Override
    public void clickEditAddProperty() {
        getSkinExecutor().clickEditAddProperty();
    }

    /**
     * Clicks on the add object button in the object editor. As a result an object of the specified class is added to
     * the edited document and the document is saved. This method waits for the document to be saved.
     */
    @Override
    public void clickEditAddObject() {
        getSkinExecutor().clickEditAddObject();
    }

    @Override
    public boolean isAuthenticated() {
        return getSkinExecutor().isAuthenticated();
    }

    @Override
    public boolean isAuthenticated(String username) {
        return getSkinExecutor().isAuthenticated(username);
    }

    @Override
    public boolean isAuthenticationMenuPresent() {
        return getSkinExecutor().isAuthenticationMenuPresent();
    }

    @Override
    public void logout() {
        getSkinExecutor().logout();
        recacheSecretToken();
    }

    @Override
    public void login(String username, String password, boolean rememberme) {
        getSkinExecutor().login(username, password, rememberme);
        recacheSecretToken();
    }

    @Override
    public void loginAsAdmin() {
        getSkinExecutor().loginAsAdmin();
        recacheSecretToken();
    }

    /**
     * If the user is not logged in already and if the specified user page exists, it is logged in. Otherwise the user
     * is registered first and then the login is executed.
     * 
     * @param username the user name to login as. If the user is to be created, this will also be used as the user first
     *            name while the user last name will be left blank
     * @param password the password of the user
     * @param rememberMe whether the login should be remembered or not
     */
    public void loginAndRegisterUser(String username, String password, boolean rememberMe) {
        if (!isAuthenticationMenuPresent()) {
            // navigate to the main page
            open("Main", "WebHome");
        }

        // if user is already authenticated, don't login
        if (isAuthenticated(username)) {
            return;
        }

        // try to go to the user page
        open("XWiki", username);
        // if user page doesn't exist, register the user first
        boolean exists = !getSelenium().isTextPresent("The requested page could not be found.");
        if (!exists) {
            if (isAuthenticated()) {
                logout();
            }
            clickRegister();
            fillRegisterForm(username, "", username, password, "");
            submit();
            // assume registration was done successfully, otherwise the register test should fail too
        }

        login(username, password, rememberMe);
    }

    public void fillRegisterForm(String firstName, String lastName, String username, String password,
            String email) {
        setFieldValue("register_first_name", firstName);
        setFieldValue("register_last_name", lastName);
        setFieldValue("xwikiname", username);
        setFieldValue("register_password", password);
        setFieldValue("register2_password", password);
        setFieldValue("register_email", email);
    }

    @Override
    public void clickLogin() {
        getSkinExecutor().clickLogin();
    }

    @Override
    public void clickRegister() {
        getSkinExecutor().clickRegister();
    }

    public String getEditorSyntax() {
        return getSkinExecutor().getEditorSyntax();
    }

    public void setEditorSyntax(String syntax) {
        getSkinExecutor().setEditorSyntax(syntax);
    }

    public void editInWikiEditor(String space, String page) {
        getSkinExecutor().editInWikiEditor(space, page);
    }

    public void editInWikiEditor(String space, String page, String syntax) {
        getSkinExecutor().editInWikiEditor(space, page, syntax);
    }

    public void editInWysiwyg(String space, String page) {
        getSkinExecutor().editInWysiwyg(space, page);
    }

    public void editInWysiwyg(String space, String page, String syntax) {
        getSkinExecutor().editInWysiwyg(space, page, syntax);
    }

    public void clearWysiwygContent() {
        getSkinExecutor().clearWysiwygContent();
    }

    public void keyPressAndWait(String element, String keycode) throws InterruptedException {
        getSelenium().keyPress(element, keycode);
        waitPage();
    }

    public void typeInWysiwyg(String text) {
        getSkinExecutor().typeInWysiwyg(text);
    }

    public void typeInWiki(String text) {
        getSkinExecutor().typeInWiki(text);
    }

    public void typeEnterInWysiwyg() {
        getSkinExecutor().typeEnterInWysiwyg();
    }

    public void typeShiftEnterInWysiwyg() {
        getSkinExecutor().typeShiftEnterInWysiwyg();
    }

    public void clickWysiwygUnorderedListButton() {
        getSkinExecutor().clickWysiwygUnorderedListButton();
    }

    public void clickWysiwygOrderedListButton() {
        getSkinExecutor().clickWysiwygOrderedListButton();
    }

    public void clickWysiwygIndentButton() {
        getSkinExecutor().clickWysiwygIndentButton();
    }

    public void clickWysiwygOutdentButton() {
        getSkinExecutor().clickWysiwygOutdentButton();
    }

    public void clickWikiBoldButton() {
        getSkinExecutor().clickWikiBoldButton();
    }

    public void clickWikiItalicsButton() {
        getSkinExecutor().clickWikiItalicsButton();
    }

    public void clickWikiUnderlineButton() {
        getSkinExecutor().clickWikiUnderlineButton();
    }

    public void clickWikiLinkButton() {
        getSkinExecutor().clickWikiLinkButton();
    }

    public void clickWikiHRButton() {
        getSkinExecutor().clickWikiHRButton();
    }

    public void clickWikiImageButton() {
        getSkinExecutor().clickWikiImageButton();
    }

    public void clickWikiSignatureButton() {
        getSkinExecutor().clickWikiSignatureButton();
    }

    public void assertWikiTextGeneratedByWysiwyg(String text) {
        getSkinExecutor().assertWikiTextGeneratedByWysiwyg(text);
    }

    public void assertHTMLGeneratedByWysiwyg(String xpath) throws Exception {
        getSkinExecutor().assertHTMLGeneratedByWysiwyg(xpath);
    }

    public void assertGeneratedHTML(String xpath) throws Exception {
        getSkinExecutor().assertGeneratedHTML(xpath);
    }

    public void openAdministrationPage() {
        getSkinExecutor().openAdministrationPage();
    }

    public void openAdministrationSection(String section) {
        getSkinExecutor().openAdministrationSection(section);
    }

    public String getUrl(String space, String doc) {
        return getUrl(space, doc, "view");
    }

    public String getUrl(String space, String doc, String action) {
        return getUrl(space, doc, action, null);
    }

    public String getUrl(String space, String doc, String action, String queryString) {
        StringBuilder builder = new StringBuilder("/xwiki/bin/");
        builder.append(action);
        builder.append('/');
        builder.append(space);
        builder.append('/');
        builder.append(doc);

        boolean needToAddSecretToken = !("view".equals(action) || "register".equals(action));
        boolean needToAddQuery = queryString != null && queryString.length() > 0;
        if (needToAddSecretToken || needToAddQuery) {
            builder.append('?');
        }
        if (needToAddSecretToken) {
            builder.append("form_token=");
            builder.append(getSecretToken());
            builder.append('&');
        }
        if (needToAddQuery) {
            builder.append(queryString);
        }
        return builder.toString();
    }

    public void pressKeyboardShortcut(String shortcut, boolean withCtrlModifier, boolean withAltModifier,
            boolean withShiftModifier) throws InterruptedException {
        getSkinExecutor().pressKeyboardShortcut(shortcut, withCtrlModifier, withAltModifier, withShiftModifier);
    }

    /**
     * Set global xwiki configuration options (as if the xwiki.cfg file had been modified). This is useful for testing
     * configuration options.
     * 
     * @param configuration the configuration in {@link Properties} format. For example "param1=value2\nparam2=value2"
     * @throws IOException if an error occurs while parsing the configuration
     */
    public void setXWikiConfiguration(String configuration) throws IOException {
        Properties properties = new Properties();
        properties.load(new ByteArrayInputStream(configuration.getBytes()));
        StringBuffer sb = new StringBuffer();

        // Since we don't have access to the XWiki object from Selenium tests and since we don't want to restart XWiki
        // with a different xwiki.cfg file for each test that requires a configuration change, we use the following
        // trick: We create a document and we access the XWiki object with a Velocity script inside that document.
        for (Entry<Object, Object> param : properties.entrySet()) {
            sb.append("{{velocity}}$xwiki.xWiki.config.setProperty('").append(param.getKey()).append("', '")
                    .append(param.getValue()).append("')").append("\n{{/velocity}}");
        }
        editInWikiEditor("Test", "XWikiConfigurationPageForTest", "xwiki/2.1");
        setFieldValue("content", sb.toString());
        clickEditSaveAndView();
    }

    @Override
    public boolean copyPage(String spaceName, String pageName, String targetSpaceName, String targetPageName) {
        return getSkinExecutor().copyPage(spaceName, pageName, targetSpaceName, targetPageName);
    }

    /**
     * Waits for the specified live table to load.
     * 
     * @param id the live table id
     */
    public void waitForLiveTable(String id) {
        waitForElement("//*[@id = '" + id + "-ajax-loader' and @class = 'xwiki-livetable-loader hidden']");
    }

    /**
     * (Re)-cache the secret token used for CSRF protection. A user with edit rights on Main.WebHome must be logged in.
     * This method must be called before {@link #getSecretToken()} is called and after each re-login.
     * 
     * @since 3.2M1
     * @see #getSecretToken()
     */
    public void recacheSecretToken() {
        getUtil().recacheSecretToken();
    }

    /**
     * Get the secret token used for CSRF protection. Remember to call {@link #recacheSecretToken()} first.
     * 
     * @return anti-CSRF secret token, or empty string if the token is not cached
     * @since 3.2M1
     * @see #recacheSecretToken()
     */
    public String getSecretToken() {
        return getUtil().getSecretToken();
    }

    /**
     * Drags and drops the source element on top of the target element.
     * 
     * @param sourceLocator locates the element to be dragged
     * @param targetLocator locates the element where to drop the dragged element
     */
    public void dragAndDrop(By sourceLocator, By targetLocator) {
        // Selenium#dragAndDropToObject(source, target) is not implemented over WebDriver.
        WebDriver driver = getDriver();
        WebElement source = driver.findElement(sourceLocator);
        WebElement target = driver.findElement(targetLocator);
        // Don't click in the middle of the element because it can contain a link.
        new Actions(driver).moveToElement(source, 1, 1).clickAndHold().release(target).perform();
    }

    /**
     * Makes sure the specified element is not covered by the floating menu which is displayed at the top of the window.
     * Use this method before clicking on an element that can end up beneath the floating menu.
     * 
     * @param locator an element locator
     */
    public void ensureElementIsNotCoveredByFloatingMenu(By locator) {
        WebDriver driver = getDriver();
        // First scroll the element into view, if needed, by moving the mouse to the top left corner of the element.
        new Actions(driver).moveToElement(driver.findElement(locator), 0, 0).perform();
        // Then scroll the page up a bit so that the element is not at the top of the window where the floating menu is.
        driver.findElement(By.xpath("//body")).sendKeys(Keys.ARROW_UP);
    }

    /**
     * Expands the object with the given number of the specified XClass. You need to call this method before editing any
     * of the properties of the specified object using the object editor because the form elements used to edit the
     * object properties have to be visible.
     * 
     * @param className the XClass name
     * @param objectNumber the object number
     */
    public void expandObject(String className, int objectNumber) {
        String objectContentId = String.format("xobject_%s_%s_content", className, objectNumber);
        if (!getDriver().findElement(By.id(objectContentId)).isDisplayed()) {
            // First make sure that the group of objects of the specified class is expanded.
            String objectTitleId = String.format("xobject_%s_%s_title", className, objectNumber);
            WebElement objectTitle = getDriver().findElement(By.id(objectTitleId));
            if (!objectTitle.isDisplayed()) {
                // Expand the group of objects of the specified type.
                getDriver().findElement(By.id(String.format("xclass_%s_title", className))).click();
            }
            // Expand the specified object.
            objectTitle.click();
        }
    }

    /**
     * @param elementLocator the locator used to get the desired element. e.g. By.id("someId")
     * @return true if the element is in the window's viewport, i.e. is scrolled to; false otherwise.
     * @since 6.2
     */
    public boolean isElementInView(By elementLocator) {
        Point elementLocation = getDriver().findElement(elementLocator).getLocation();

        int windowXLeft = Integer.parseInt(getSelenium().getEval("window.scrollX"));
        int windowYTop = Integer.parseInt(getSelenium().getEval("window.scrollY"));

        int width = Integer.parseInt(getSelenium().getEval("document.documentElement.clientWidth"));
        int height = Integer.parseInt(getSelenium().getEval("document.documentElement.clientHeight"));

        int windowXRight = windowXLeft + width;
        int windowYBottom = windowYTop + height;

        return (elementLocation.getX() >= windowXLeft && elementLocation.getX() <= windowXRight
                && elementLocation.getY() >= windowYTop && elementLocation.getY() <= windowYBottom);
    }

    /**
     * Convenience method.
     * @see #isElementInView(By)
     * @since 6.2
     */
    public void assertElementInView(By elementLocator) {
        Assert.assertTrue("[" + elementLocator + "] is not in view.", isElementInView(elementLocator));
    }

    public void clickAdministerWiki() {
        getSkinExecutor().clickAdministerWiki();
    }
}