info.magnolia.integrationtests.uitest.KeyboardShortcutUITest.java Source code

Java tutorial

Introduction

Here is the source code for info.magnolia.integrationtests.uitest.KeyboardShortcutUITest.java

Source

/**
 * This file Copyright (c) 2014-2016 Magnolia International
 * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
 *
 *
 * This file is dual-licensed under both the Magnolia
 * Network Agreement and the GNU General Public License.
 * You may elect to use one or the other of these licenses.
 *
 * This file is distributed in the hope that it will be
 * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
 * Redistribution, except as permitted by whichever of the GPL
 * or MNA you select, is prohibited.
 *
 * 1. For the GPL license (GPL), you can redistribute and/or
 * modify this file under the terms of the GNU General
 * Public License, Version 3, as published by the Free Software
 * Foundation.  You should have received a copy of the GNU
 * General Public License, Version 3 along with this program;
 * if not, write to the Free Software Foundation, Inc., 51
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * 2. For the Magnolia Network Agreement (MNA), this file
 * and the accompanying materials are made available under the
 * terms of the MNA which accompanies this distribution, and
 * is available at http://www.magnolia-cms.com/mna.html
 *
 * Any modifications to this file must keep this entire header
 * intact.
 *
 */
package info.magnolia.integrationtests.uitest;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
import static org.openqa.selenium.support.ui.ExpectedConditions.*;

import info.magnolia.integrationtests.rules.Site;
import info.magnolia.integrationtests.rules.SiteRule;

import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;

/**
 * UI Tests for keyboard shortcuts.
 */
public class KeyboardShortcutUITest extends AbstractPageEditorUITest {

    @Rule
    public SiteRule siteRule = new SiteRule();

    /**
     * Get a confirmation to test by running 'Delete contact' action.
     * Hit the ESCAPE key and verify that a confirmation is closed, and the contact is not deleted.
     */
    @Test
    public void whenEscapePressedOnConfirmationItCloses() {
        // GIVEN
        WebElement confirmation;
        getAppIcon("Contacts").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Contacts");

        // WHEN
        getTreeTableItem("Albert Einstein").click();
        getActionBarItem("Delete contact").click();

        waitUntil(visibilityOfElementLocated(byConfirmationOverlay));
        confirmation = getConfirmationOverlay();

        assertTrue("Delete action should have caused confirmation overlay.", isExisting(confirmation));
        simulateKeyPress(Keys.ESCAPE);

        waitUntil(invisibilityOfElementLocated(byConfirmationOverlay));

        // THEN
        WebElement contact = getTreeTableItem("Albert Einstein");
        assertTrue("Contact should not have been deleted.", isExisting(contact));
    }

    /**
     * Get a dialog to test by running 'Add page' action.
     * Fill in small form, then hit the ESCAPE key and verify that a confirmation is displayed.
     * Hit ESCAPE and verify that the confirmation closes.
     * Hit ESCAPE again and verify that confirmation is displayed.
     * Hit ENTER to confirm and verify the dialog is closed.
     */
    @Test
    public void escapeHandlingOnDialog() {
        //GIVEN
        final String pageName = "testEscapeHandling";
        WebElement confirmation;

        getAppIcon("Pages").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Pages");
        getActionBarItem("Add page").click();
        waitUntil(dialogIsOpen(ADD_NEW_PAGE_DIALOG_TITLE));
        setFormTextFieldText("Page name", pageName);

        // First pass - we cancel the dialog closing.
        // WHEN
        simulateKeyPress(Keys.ESCAPE);
        waitUntil(visibilityOfElementLocated(byConfirmationOverlay));
        // THEN
        confirmation = getConfirmationOverlay();
        assertTrue("ESC key should have caused confirmation overlay.", isExisting(confirmation));

        // WHEN
        simulateKeyPress(Keys.ESCAPE);
        // THEN
        waitUntil(invisibilityOfElementLocated(byConfirmationOverlay));

        // Now do it again, but this time confirm the dialog closing.

        // WHEN
        simulateKeyPress(Keys.ESCAPE);
        waitUntil(visibilityOfElementLocated(byConfirmationOverlay));
        // THEN
        confirmation = getConfirmationOverlay();
        assertTrue("ESC key should have caused confirmation overlay.", isExisting(confirmation));
        // WHEN
        simulateKeyPress(Keys.ENTER);
        // THEN
        waitUntil(invisibilityOfElementLocated(byConfirmationOverlay));
    }

    /**
     * ESCAPE key over page editor is a special case because the pageeditor itself responds to the ESCAPE key,
     * the PageEditor SHOULD NOT handle the escape when a dialog is open.
     *
     * Get a dialog to test by opening the 'About' page and editing the Section Header component.
     * Then hit the ESCAPE key and verify that a confirmation is displayed.
     * Hit ENTER to confirm and verify the dialog is closed.
     * Verify that the sub app is still in editor view - not preview view.
     */
    @Test
    public void escapeHandlingOnDialogOverPageEditor() {
        //GIVEN
        String url;

        getAppIcon("Pages").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Pages");

        doubleClick(getTreeTableItem("ftl-sample-site"));
        waitUntil(appIsLoaded());

        // Open component editor
        switchToPageEditorContent();
        getElement(By.xpath("//h3[text() = 'Main - Component One']")).click();
        getElement(By.xpath("//*[contains(@class, 'focus')]//*[contains(@class, 'icon-edit')]")).click();
        switchToDefaultContent();

        waitUntil(visibilityOfElementLocated(byTabContainingCaption("Settings")));

        // WHEN
        simulateKeyPress(Keys.ESCAPE);
        // THEN
        waitUntil(visibilityOfElementLocated(byConfirmationOverlay));

        // Validate that PageEditor is not in preview mode.
        url = getCurrentDriverUrl();
        assertTrue("Subapp should still be in edit mode.", url.contains("edit"));
        assertFalse("Subapp should still be in edit mode.", url.contains("view"));

        // WHEN
        simulateKeyPress(Keys.ENTER);
        // THEN
        waitUntil(invisibilityOfElementLocated(byConfirmationOverlay));

        // Validate that PageEditor is not in preview mode.
        url = getCurrentDriverUrl();
        assertTrue("Subapp should still be in edit mode.", url.contains("edit"));
        assertFalse("Subapp should still be in edit mode.", url.contains("view"));
    }

    /**
     * Get a detailEditor to test by running 'Add contact' action.
     * Fill in a field, then hit the ESCAPE key and verify that a confirmation is displayed.
     * Hit ESCAPE and verify that the confirmation closes.
     * Hit ESCAPE again and verify that confirmation is displayed.
     * Hit ENTER to confirm and verify the dialog is closed.
     */
    @Test
    public void escapeHandlingOnDetailEditor() {
        // GIVEN
        final String nameFirst = "escapeHandlingOnDetailEditor";
        WebElement confirmation;

        getAppIcon("Contacts").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Contacts");
        getActionBarItem("Add contact").click();
        waitUntil(appIsLoaded());
        openTabWithCaption("Personal");
        waitUntil(tabIsOpen("Personal"));
        setFormTextFieldText("First name", nameFirst);

        // First pass - we cancel the ESCAPE action.
        // WHEN
        simulateKeyPress(Keys.ESCAPE);
        waitUntil(visibilityOfElementLocated(byConfirmationOverlay));
        // THEN
        confirmation = getConfirmationOverlay();
        assertTrue("ESC key should have caused confirmation overlay.", isExisting(confirmation));

        // WHEN
        simulateKeyPress(Keys.ESCAPE);
        // THEN
        waitUntil(invisibilityOfElementLocated(byConfirmationOverlay));

        // Now do it again, but this time confirm the detailEditor closing.

        // WHEN
        simulateKeyPress(Keys.ESCAPE);
        waitUntil(visibilityOfElementLocated(byConfirmationOverlay));
        // THEN
        confirmation = getConfirmationOverlay();
        assertTrue("ESC key should have caused confirmation overlay.", isExisting(confirmation));
        // WHEN
        simulateKeyPress(Keys.RETURN);
        // THEN
        waitUntil(invisibilityOfElementLocated(byConfirmationOverlay));
    }

    /**
     * Get a dialog to test by running 'Add page' action.
     * Fill in small form, then hit the ENTER key.
     * Verify that page was created, then cleanup by deleting it.
     */
    @Test
    @Site
    public void whenEnterPressedOnDialogItCommits() {
        // GIVEN
        final String pageName = "testCommitOnEnter";
        getAppIcon("Pages").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Pages");

        // WHEN
        getActionBarItem("Add page").click();
        waitUntil(dialogIsOpen(ADD_NEW_PAGE_DIALOG_TITLE));
        setFormTextFieldText("Page name", pageName);
        getSelectTabElement("Template").click();

        // Click on selector item
        selectElementOfTabListForLabel("Redirect");

        // We move back to the page name input field, so return is triggered more easily
        // Selenium might get hiccups when stuck in the select field
        moveToElement(getFormTextField("Page name"));

        simulateKeyPress(Keys.RETURN);
        // Instead of waiting for the page dialog to be closed we rather wait for the callback dialog to be open
        waitUntil(dialogIsOpen("Redirect"));
        getDialogCommitButton().click();

        // THEN
        // Check that entry is added
        WebElement newRow = getTreeTableItem(pageName);
        assertTrue("ENTER key should have caused new page to be created.", isExisting(newRow));

        // Cleanup - delete the created page
        deleteTreeTableRow("Delete page", pageName);
        waitUntil(invisibilityOfElementLocated(By.xpath(
                String.format("//*[contains(@class, 'v-table-cell-wrapper') and text() = '%s']", pageName))));
    }

    /**
     * Get a dialog to test by running 'Add page' action.
     * Fill in small form, then focus on a textarea and hit the ENTER key.
     * Verify that the dialog is not closed.
     */
    @Test
    @Site
    public void whenEnterPressedOnDialogInTextAreaItDoesntCommit() {
        // GIVEN
        final String pageName = "testEnterInTextAreaDoesntCommit";
        getAppIcon("Pages").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Pages");

        getActionBarItem("Add page").click();
        waitUntil(dialogIsOpen(ADD_NEW_PAGE_DIALOG_TITLE));
        setFormTextFieldText("Page name", pageName);
        getSelectTabElement("Template").click();
        // Click on selector item.
        selectElementOfTabListForLabel("Home");
        delay(1, "Give time for change event to proceed");

        getDialogCommitButton().click();
        waitUntil(dialogIsOpen("Home"));

        // WHEN
        // Ensure a text area has focus and hit ENTER.
        setFormTextFieldText("Headline", "The headline");
        delay(1, "Wait for changes to be propagated");
        getFormTextAreaField("Abstract").sendKeys(Keys.RETURN);
        delay(1, "Give time for change event to proceed");

        // THEN
        // Check that dialog is still open
        waitUntil(visibilityOfElementLocated(byDialogTitle("Home")));
    }

    /**
     * Get a DetailEditor to test by running 'Add contact' action.
     * Fill in required fields, then focus on something other then textArea and hit the ENTER key.
     * Verify that DetailEditor is closed and new contact is created.
     * Cleanup by deleting the new contact.
     */
    @Test
    public void whenEnterPressedOnDetailEditorItCommits() {
        // GIVEN
        final String nameFirst = "Joe";
        final String nameLast = "Testkeyboard";
        String contactName = nameFirst + " " + nameLast;
        String email = nameFirst + "@" + nameLast + ".com";

        getAppIcon("Contacts").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Contacts");
        getActionBarItem("Add contact").click();
        waitUntil(appIsLoaded());

        fillInRequiredContactFields(nameFirst, nameLast, email);

        // WHEN
        simulateKeyPress(Keys.RETURN);
        delay(2, "");

        // THEN
        //Check that editor is closed
        waitUntil(elementIsGone(byTabContainingCaption(contactName)));

        // Check that entry is added.
        waitUntil(visibilityOfElementLocated(byTreeTableItem(email)));
    }

    /**
     * Get a DetailEditor to test by running 'Add contact' action.
     * Fill in required fields, then focus on a textArea and hit the ENTER key.
     * Verify that DetailEditor remains open.
     */
    @Test
    public void whenEnterPressedOnDetailEditorInTextAreaItDoesntCommit() {
        // GIVEN
        final String nameFirst = "Joe2";
        final String nameLast = "Testkeyboard";
        String email = nameFirst + "@" + nameLast + ".com";

        getAppIcon("Contacts").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Contacts");
        getActionBarItem("Add contact").click();
        waitUntil(appIsLoaded());

        fillInRequiredContactFields(nameFirst, nameLast, email);

        // WHEN
        openTabWithCaption("Address");
        waitUntil(tabIsOpen("Address"));

        getFormTextAreaField("Street address").sendKeys(Keys.RETURN);
        delay(1, "");

        // THEN
        //Check that editor is not closed
        WebElement fieldToCheck = getFormTextAreaField("Street address");
        assertTrue("ENTER key should not have closed the DetailEditor subapp when TextArea has focus.",
                isExisting(fieldToCheck));
    }

    @Test
    public void itemCanBeEditedAfterCreation() throws Exception {
        // GIVEN
        getAppIcon("Configuration").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Configuration");

        getActionBarItem("Add content node").click();
        delay(1, "Wait for node creation");

        // WHEN
        getKeyboard().pressKey(Keys.ENTER);
        delay(1, "Wait for key press");
        getEditedElement().sendKeys("newContentNode");
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.ENTER);
        delay(1, "Wait for key press");

        // THEN
        assertTrue(isTreeTableItemSelected("newContentNode"));
        // cleanup
        getActionBarItem("Delete item").click();
        getDialogConfirmButton().click();
    }

    @Test
    public void focusIsNotLostIfThereIsNotAnotherItemToEdit() throws Exception {
        // GIVEN
        getAppIcon("Configuration").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Configuration");

        getTreeTableItem("server").click();

        // WHEN
        getKeyboard().pressKey(Keys.chord(Keys.SHIFT, Keys.TAB));
        delay(1, "Wait for key press");

        // THEN
        // make sure server node is still selected
        assertTrue(isTreeTableItemSelected("server"));

        // WHEN
        getKeyboard().pressKey(Keys.ENTER);
        delay(1, "Wait for key press");

        // THEN
        // check if we're in inline editing mode
        assertThat(getEditedElement().getTagName(), is("input"));
    }

    @Test
    public void selectionIsOnCorrectRowWhenCyclingUsingTab() throws Exception {
        // GIVEN
        getAppIcon("Configuration").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Configuration");

        getTreeTableItemExpander("server").click();
        getTreeTableItem("server").click();
        getTreeTableItem("admin").click();

        // WHEN
        // edit admin property and cycle 3 times using tab
        getKeyboard().pressKey(Keys.ENTER);
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.TAB);
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.TAB);
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.TAB);
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.ENTER);

        // THEN
        assertTrue(isTreeTableItemSelected("defaultBaseUrl"));

        // WHEN
        // now cycle back to admin property
        getKeyboard().pressKey(Keys.ENTER);
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.chord(Keys.SHIFT, Keys.TAB));
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.chord(Keys.SHIFT, Keys.TAB));
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.chord(Keys.SHIFT, Keys.TAB));
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.ENTER);
        delay(1, "Wait for key press");

        // THEN
        assertTrue(isTreeTableItemSelected("admin"));
    }

    @Test
    public void itIsPossibleToCycleBetweenPropertiesAndNodes() throws Exception {
        // GIVEN
        getAppIcon("Configuration").click();
        waitUntil(appIsLoaded());
        assertAppOpen("Configuration");

        getTreeTableItemExpander("server").click();
        delay(1, "Wait so item gets expanded");
        getTreeTableItem("server").click();
        delay(1, "Wait for item to be selected");
        getTreeTableItem("admin").click();
        delay(1, "Wait for item to be selected");

        // WHEN
        // cycle back to auditLogging node
        getKeyboard().pressKey(Keys.ENTER);
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.chord(Keys.SHIFT, Keys.TAB));
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.chord(Keys.SHIFT, Keys.TAB));
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.chord(Keys.SHIFT, Keys.TAB));
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.ENTER);
        delay(1, "Wait for key press");

        // THEN
        assertTrue(isTreeTableItemSelected("auditLogging"));

        // WHEN
        // now cycle back to admin property
        getKeyboard().pressKey(Keys.ENTER);
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.TAB);
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.TAB);
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.TAB);
        delay(1, "Wait for key press");
        getKeyboard().pressKey(Keys.ENTER);
        delay(1, "Wait for key press");

        // THEN
        assertTrue(isTreeTableItemSelected("admin"));
    }

    private WebElement getEditedElement() {
        return getElement(By.xpath(
                "//input[@type='text' and contains(@class, 'v-textfield v-widget v-has-width v-has-height')]"));
    }

    private WebElement getNextSiblingOfEditedElement() {
        return getEditedElement().findElement(By.xpath("../..")).findElement(By.xpath("following-sibling::*[1]"));
    }

    /**
     * Helper to fill in necessary fields for a contact.
     * @param nameFirst
     * @param nameLast
     */
    private void fillInRequiredContactFields(String nameFirst, String nameLast, String email) {
        openTabWithCaption("Personal");
        waitUntil(tabIsOpen("Personal"));
        setFormTextFieldText("First name", nameFirst);
        setFormTextFieldText("Last name", nameLast);
        openTabWithCaption("Address");
        waitUntil(tabIsOpen("Address"));
        setFormTextFieldText("Organization", "org");
        setFormTextAreaFieldText("Street address", "address-125");
        openTabWithCaption("Contact details");
        waitUntil(tabIsOpen("Contact details"));
        setFormTextFieldText("E-Mail address", email);
    }

}