com.cognifide.qa.bb.aem.dialog.classic.field.AemRichText.java Source code

Java tutorial

Introduction

Here is the source code for com.cognifide.qa.bb.aem.dialog.classic.field.AemRichText.java

Source

/*-
 * #%L
 * Bobcat
 * %%
 * Copyright (C) 2016 Cognifide Ltd.
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package com.cognifide.qa.bb.aem.dialog.classic.field;

import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;

import com.cognifide.qa.bb.aem.DialogComponent;
import com.cognifide.qa.bb.constants.Timeouts;
import com.cognifide.qa.bb.frame.FrameSwitcher;
import com.cognifide.qa.bb.provider.selenium.BobcatWait;
import com.cognifide.qa.bb.qualifier.CurrentScope;
import com.cognifide.qa.bb.qualifier.Frame;
import com.cognifide.qa.bb.qualifier.PageObject;
import com.google.inject.Inject;

/**
 * Richtext field in a AemDialog.
 */
@PageObject
@DialogComponent("rich text")
public class AemRichText implements Configurable {

    /**
     * Locator of richtext's toolbar.
     */
    public static final String RT_TOOLBAR = "div.x-html-editor-tb";

    /**
     * Locator of buttons in richtext's toolbar.
     */
    public static final String RT_BUTTON_CSS = RT_TOOLBAR + " button.x-edit-";

    private static final String CLASS_ATTRIBUTE = "class";

    private static final String SELECTED_BUTTON = "div.x-html-editor-wrap table.x-btn-pressed button";

    /**
     * Button class name
     */
    private static final String BUTTON_CLASS_NAME = "x-btn-icon";

    /**
     * "disabled" class value
     */
    private static final String DISABLED_CLASS_NAME = "disabled";

    /**
     * "innerHTML" attribute
     */
    private static final String INNER_HTML_ATTRIBUTE = "innerHTML";

    @Inject
    @CurrentScope
    private WebElement currentScope;

    @Inject
    private FrameSwitcher frameSwitcher;

    @Inject
    private WebDriver webDriver;

    @Inject
    private Actions actions;

    @Inject
    private BobcatWait bobcatWait;

    private String frameName;

    /**
     * Clicks the button indicated by the parameter.
     *
     * @param button button
     * @return This instance.
     */
    @Frame("$cq")
    public AemRichText click(final RtButton button) {
        if (!buttonSelected(button)) {
            bobcatWait.withTimeout(Timeouts.BIG).until(driver -> {
                String valueBefore = getTextAreaInnerHtml();
                enableRichTextIfDisabled();
                webDriver.findElement(By.cssSelector(RT_BUTTON_CSS + button.getCss())).click();
                return !valueBefore.equals(getTextAreaInnerHtml());
            }, 2);
        }
        return this;
    }

    /**
     * Types the provided text into richtext's text area.
     *
     * @param text text
     * @return This instance.
     */
    public AemRichText type(CharSequence text) {
        switchToTextArea();
        try {
            actions.sendKeys(text).perform();
            return this;
        } finally {
            frameSwitcher.switchBack();
        }
    }

    /**
     * Clears the content of richtext's text area.
     *
     * @return This instance.
     */
    public AemRichText clear() {
        switchToTextArea();
        try {
            bobcatWait.withTimeout(Timeouts.BIG).until(driver -> {
                actions.sendKeys(Keys.chord(Keys.CONTROL, "a")).sendKeys(Keys.BACK_SPACE).sendKeys(Keys.BACK_SPACE)
                        .perform();
                WebElement activeElement = webDriver.switchTo().activeElement();
                String text = activeElement.getText();
                return text.isEmpty();
            }, 2);
            return this;
        } finally {
            frameSwitcher.switchBack();
        }
    }

    /**
     * Types the provided text into richtext's text area and then types "enter".
     *
     * @param text text
     * @return This instance.
     */
    public AemRichText typeLine(CharSequence text) {
        return type(text).typeNewLine();
    }

    /**
     * Enters new line sign into text area.
     *
     * @return This instance.
     */
    public AemRichText typeNewLine() {
        return type("\n");
    }

    /**
     * Selects all text from the text area.
     *
     * @return This instance.
     */
    public AemRichText selectAll() {
        switchToTextArea();
        try {
            actions.sendKeys(Keys.chord(Keys.CONTROL, "a")).perform();
            return this;
        } finally {
            frameSwitcher.switchBack();
        }
    }

    /**
     * Sets the cursor at the beginning of the current line.
     *
     * @return This instance.
     */
    public AemRichText setCursorAtStartingPos() {
        return type(Keys.HOME);
    }

    /**
     * Sets the cursor at the end of the current line.
     *
     * @return This instance.
     */
    public AemRichText setCursorAtEndPos() {
        return type(Keys.END);
    }

    /**
     * Reads whole text from the text area and returns it.
     *
     * @return Text from the text area.
     */
    public String read() {
        switchToTextArea();
        try {
            return webDriver.findElement(By.xpath(".//body")).getText();
        } finally {
            frameSwitcher.switchBack();
        }
    }

    /**
     * Selects text in the text area between indices provided as parameters.
     *
     * @param startPos the beginning position
     * @param endPos   the ending position
     * @return This instance.
     */
    public AemRichText selectText(int startPos, int endPos) {
        switchToTextArea();
        try {
            actions.sendKeys(Keys.chord(Keys.CONTROL, Keys.HOME)).perform();
            for (int i = 0; i < startPos; i++) {
                actions.sendKeys(Keys.ARROW_RIGHT).perform();
            }
            actions.keyDown(Keys.SHIFT);
            for (int i = 0; i < endPos - startPos; i++) {
                actions.sendKeys(Keys.ARROW_RIGHT);
            }
            actions.keyUp(Keys.SHIFT).perform();
            return this;
        } finally {
            frameSwitcher.switchBack();
        }
    }

    /**
     * @return Reads and returns contents of the richtext's text area, with HTML formatting.
     */
    public String getInnerHTML() {
        switchToTextArea();
        try {
            return webDriver.findElement(By.xpath(".//body")).getAttribute(INNER_HTML_ATTRIBUTE);
        } finally {
            frameSwitcher.switchBack();
        }
    }

    @Override
    public void setValue(String value) {
        clear().type(value);
    }

    private void switchToTextArea() {
        boolean isRichtextDisabled = isRichtextDisabled();
        if (StringUtils.isEmpty(frameName)) {
            frameName = currentScope.findElement(By.tagName("iframe")).getAttribute("name");
        }
        frameSwitcher.switchTo("/$cq/" + frameName);
        if (isRichtextDisabled) {
            webDriver.switchTo().activeElement().click();
        }
    }

    private String getTextAreaInnerHtml() {
        switchToTextArea();
        String value = webDriver.switchTo().activeElement().getAttribute(INNER_HTML_ATTRIBUTE);
        frameSwitcher.switchBack();
        return value;
    }

    private boolean buttonSelected(RtButton button) {
        return webDriver.findElement(By.cssSelector(SELECTED_BUTTON)).getAttribute(CLASS_ATTRIBUTE)
                .contains(button.getCss());
    }

    private void enableRichTextIfDisabled() {
        if (isRichtextDisabled()) {
            bobcatWait.withTimeout(Timeouts.SMALL).until(driver -> {
                type(StringUtils.EMPTY);
                return !isRichtextDisabled();
            }, 1);
        }
    }

    private boolean isRichtextDisabled() {
        return currentScope.findElement(By.className(BUTTON_CLASS_NAME)).getAttribute(CLASS_ATTRIBUTE)
                .contains(DISABLED_CLASS_NAME);
    }
}