Browse Source

Redesign ComboBox filtering, highlighting and selection behaviour.

(#15502, #9369)

Changes:
- When opening the popup, the first suggestion is always highlighted by
default unless adding new items is allowed.
- When filter matches currently selected item, that item will be
highlighted instead of the first item.
- Hitting enter or tab will always select the highlighted item.
- Closing the suggestions list by clicking outside the list no longer
selects an item to prevent accidental selections.

Test changes:
- Extended ComboBoxElement to help test filtering.
- Updated and tweaked ComboBoxResetValueTest,
ComboBoxIdenticalItemsTest and ComboboxScrollableWindowTest.
- Added ComboBoxSelectingTest and
ComboBoxSelectingWithNewItemsAllowedTest.
- Updated some tests that were using keyboard navigation.

Change-Id: Ia7745b624bdb0b1a1bb498157ebcb37bee219d76
tags/7.5.0.alpha1
Sauli Tähkäpää 9 years ago
parent
commit
acb889336f
18 changed files with 807 additions and 235 deletions
  1. 24
    36
      client/src/com/vaadin/client/ui/VFilterSelect.java
  2. 6
    1
      client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java
  3. 41
    33
      uitest/src/com/vaadin/tests/components/combobox/ComboBoxIdenticalItemsTest.java
  4. 4
    4
      uitest/src/com/vaadin/tests/components/combobox/ComboBoxResetValue.java
  5. 43
    99
      uitest/src/com/vaadin/tests/components/combobox/ComboBoxResetValueTest.java
  6. 2
    4
      uitest/src/com/vaadin/tests/components/combobox/ComboBoxScrollingWithArrowsTest.java
  7. 57
    0
      uitest/src/com/vaadin/tests/components/combobox/ComboBoxSelecting.java
  8. 214
    0
      uitest/src/com/vaadin/tests/components/combobox/ComboBoxSelectingTest.java
  9. 52
    0
      uitest/src/com/vaadin/tests/components/combobox/ComboBoxSelectingWithNewItemsAllowed.java
  10. 293
    0
      uitest/src/com/vaadin/tests/components/combobox/ComboBoxSelectingWithNewItemsAllowedTest.java
  11. 8
    10
      uitest/src/com/vaadin/tests/components/window/ComboboxScrollableWindowTest.java
  12. 8
    17
      uitest/src/com/vaadin/tests/fonticon/FontIconsTest.java
  13. 54
    0
      uitest/src/com/vaadin/tests/tb3/newelements/ComboBoxElement.java
  14. 0
    5
      uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxBorder.html
  15. 1
    6
      uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxCombinedWithEnterShortcut.html
  16. 0
    10
      uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html
  17. 0
    5
      uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxNavigation.html
  18. 0
    5
      uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxSQLContainerFilteredValueChange.html

+ 24
- 36
client/src/com/vaadin/client/ui/VFilterSelect.java View File

@@ -813,6 +813,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,

clearItems();
final Iterator<FilterSelectSuggestion> it = suggestions.iterator();
boolean isFirstIteration = true;
while (it.hasNext()) {
final FilterSelectSuggestion s = it.next();
final MenuItem mi = new MenuItem(s.getDisplayString(), true, s);
@@ -821,9 +822,21 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
WidgetUtil.sinkOnloadForImages(mi.getElement());

this.addItem(mi);
if (s == currentSuggestion) {

// By default, first item on the list is always highlighted,
// unless adding new items is allowed.
if (isFirstIteration && !allowNewItem) {
selectItem(mi);
}

// If the filter matches the current selection, highlight that
// instead of the first item.
if (tb.getText().equals(s.getReplacementString())
&& s == currentSuggestion) {
selectItem(mi);
}

isFirstIteration = false;
}
}

@@ -1178,8 +1191,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/** For internal use only. May be removed or replaced in the future. */
public boolean updateSelectionWhenReponseIsReceived = false;

private boolean tabPressedWhenPopupOpen = false;

/** For internal use only. May be removed or replaced in the future. */
public boolean initDone = false;

@@ -1421,8 +1432,10 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
return;
}
if (!filter.equals(lastFilter)) {
// we are on subsequent page and text has changed -> reset page
if ("".equals(filter)) {
// when filtering, let the server decide the page unless we've
// set the filter to empty and explicitly said that we want to see
// the results starting from page 0.
if ("".equals(filter) && page != 0) {
// let server decide
page = -1;
} else {
@@ -1437,7 +1450,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,

lastFilter = filter;
currentPage = page;

}

/** For internal use only. May be removed or replaced in the future. */
@@ -1768,16 +1780,12 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
selectPrevPage();
event.stopPropagation();
break;
case KeyCodes.KEY_TAB:
tabPressedWhenPopupOpen = true;
filterOptions(currentPage);
// onBlur() takes care of the rest
break;
case KeyCodes.KEY_ESCAPE:
reset();
DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
event.stopPropagation();
break;
case KeyCodes.KEY_TAB:
case KeyCodes.KEY_ENTER:
if (suggestionPopup.menu.getKeyboardSelectedItem() == null) {
/*
@@ -1785,17 +1793,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* text (causes popup to open) and then pressing enter.
*/
if (!allowNewItem) {
/*
* New items are not allowed: If there is only one
* suggestion, select that. If there is more than one
* suggestion Enter key should work as Escape key. Otherwise
* do nothing.
*/
if (currentSuggestions.size() == 1) {
onSuggestionSelected(currentSuggestions.get(0));
} else if (currentSuggestions.size() > 1) {
reset();
}
onSuggestionSelected(currentSuggestions
.get(suggestionPopup.menu.getSelectedIndex()));
} else {
// Handle addition of new items.
suggestionPopup.menu.doSelectedItemAction();
@@ -1863,7 +1862,9 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
break;
default:
if (textInputEnabled) {
filterOptions(currentPage);
// when filtering, we always want to see the results on the
// first page first.
filterOptions(0);
}
break;
}
@@ -2069,19 +2070,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,

focused = false;
if (!readonly) {
// much of the TAB handling takes place here
if (tabPressedWhenPopupOpen) {
tabPressedWhenPopupOpen = false;
waitingForFilteringResponse = false;
suggestionPopup.menu.doSelectedItemAction();
suggestionPopup.hide();
} else if ((!suggestionPopup.isAttached() && waitingForFilteringResponse)
|| suggestionPopup.isJustClosed()) {
// typing so fast the popup was never opened, or it's just
// closed
waitingForFilteringResponse = false;
suggestionPopup.menu.doSelectedItemAction();
}
if (selectedOptionKey == null) {
setPromptingOn();
} else if (currentSuggestion != null) {

+ 6
- 1
client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java View File

@@ -166,7 +166,12 @@ public class ComboBoxConnector extends AbstractFieldConnector implements
) {

String[] selectedKeys = uidl.getStringArrayVariable("selected");
if (selectedKeys.length > 0) {

// when filtering with empty filter, server sets the selected key
// to "", which we don't select here. Otherwise we won't be able to
// reset back to the item that was selected before filtering
// started.
if (selectedKeys.length > 0 && !selectedKeys[0].equals("")) {
performSelection(selectedKeys[0]);
} else {
resetSelection();

+ 41
- 33
uitest/src/com/vaadin/tests/components/combobox/ComboBoxIdenticalItemsTest.java View File

@@ -15,62 +15,70 @@
*/
package com.vaadin.tests.components.combobox;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;

import com.vaadin.testbench.By;
import com.vaadin.testbench.parallel.BrowserUtil;
import com.vaadin.tests.tb3.MultiBrowserTest;
import com.vaadin.tests.tb3.newelements.ComboBoxElement;

/**
* Test for identical item captions in ComboBox.
*
* @author Vaadin Ltd
*/
public class ComboBoxIdenticalItemsTest extends MultiBrowserTest {

private WebElement select;

/* This test has been directly ported from a TB2 test */
@Test
public void identicalItemsKeyboardTest() throws Exception {
public void identicalItemsKeyboardTest() {
openTestURL();
int delay = BrowserUtil.isPhantomJS(getDesiredCapabilities()) ? 500 : 0;

// wait for the UI to be fully loaded
waitForElementVisible(By.className("v-filterselect"));
waitForElementVisible(By.id("Log"));
ComboBoxElement combobox = $(ComboBoxElement.class).first();

select = findElement(By
.vaadin("/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]"));
select.click();
combobox.sendKeys(delay, Keys.ARROW_DOWN, getReturn());
waitUntilLogText("1. Item one-1 selected");

Keys[] downDownEnter = new Keys[] { Keys.ARROW_DOWN, Keys.ARROW_DOWN,
Keys.ENTER };
sendKeys(downDownEnter);
assertLogText("1. Item one-1 selected");
getReturn() };

sendKeys(downDownEnter);
assertLogText("2. Item one-2 selected");
combobox.sendKeys(delay, downDownEnter);
waitUntilLogText("2. Item one-2 selected");

sendKeys(downDownEnter);
assertLogText("3. Item two selected");
combobox.sendKeys(delay, downDownEnter);
waitUntilLogText("3. Item two selected");

sendKeys(new Keys[] { Keys.ARROW_UP, Keys.ARROW_UP, Keys.ARROW_UP,
Keys.ENTER });
assertLogText("4. Item one-1 selected");
combobox.sendKeys(delay, new Keys[] { Keys.ARROW_UP, Keys.ARROW_UP,
Keys.ARROW_UP, getReturn() });
waitUntilLogText("4. Item one-1 selected");
}

private void assertLogText(String expected) throws Exception {
String text = findElement(By.vaadin("PID_SLog_row_0")).getText();
Assert.assertTrue("Expected '" + expected + "' found '" + text + "'",
text.equals(expected));
private Keys getReturn() {
if (BrowserUtil.isPhantomJS(getDesiredCapabilities())) {
return Keys.ENTER;
}
return Keys.RETURN;
}

private void sendKeys(Keys[] keys) throws Exception {
for (Keys key : keys) {
select.sendKeys(key);
// wait a while between the key presses, at least PhantomJS fails if
// they are sent too fast
sleep(10);
}
private void waitUntilLogText(final String expected) {
waitUntil(new ExpectedCondition<Boolean>() {
private String text;

@Override
public Boolean apply(WebDriver input) {
text = findElement(By.vaadin("PID_SLog_row_0")).getText();
return text.equals(expected);
}

@Override
public String toString() {
return String.format(
"log content to update. Expected: '%s' (was: '%s')",
expected, text);
}
});
}
}

+ 4
- 4
uitest/src/com/vaadin/tests/components/combobox/ComboBoxResetValue.java View File

@@ -12,8 +12,8 @@ import com.vaadin.ui.VerticalLayout;
public class ComboBoxResetValue extends AbstractTestUI {

protected static final String EMPTY_VALUE = "Empty value";
protected static final String NULL_SELECTION_ALLOWED_WITH_SET_NULL_SELECTION_ITEM_ID = "nullSelectionAllowedWithSetNullSelectionItemId";
protected static final String NULL_SELECTION_ALLOWED_WITHOUT_NULL_SELECTION_ITEM_ID = "nullSelectionAllowedWithoutNullSelectionItemId";
protected static final String WITH_SET_NULL_SELECTION_ITEM_ID = "nullSelectionAllowedWithSetNullSelectionItemId";
protected static final String WITHOUT_NULL_SELECTION_ITEM_ID = "nullSelectionAllowedWithoutNullSelectionItemId";
protected static final String NULL_SELECTION_NOT_ALLOWED = "nullSelectionNotAllowed";

@Override
@@ -40,7 +40,7 @@ public class ComboBoxResetValue extends AbstractTestUI {

protected ComboBox getComboBoxWithNullSelectionAllowedWithSetNullSelectionItemId() {
ComboBox cb = new ComboBox();
cb.setId(NULL_SELECTION_ALLOWED_WITH_SET_NULL_SELECTION_ITEM_ID);
cb.setId(WITH_SET_NULL_SELECTION_ITEM_ID);
cb.setImmediate(true);
cb.setNullSelectionAllowed(true);

@@ -54,7 +54,7 @@ public class ComboBoxResetValue extends AbstractTestUI {

protected ComboBox getComboBoxWithNullSelectionAllowedWithoutNullSelectionItemId() {
ComboBox cb = new ComboBox();
cb.setId(NULL_SELECTION_ALLOWED_WITHOUT_NULL_SELECTION_ITEM_ID);
cb.setId(WITHOUT_NULL_SELECTION_ITEM_ID);
cb.setImmediate(true);
cb.setNullSelectionAllowed(true);


+ 43
- 99
uitest/src/com/vaadin/tests/components/combobox/ComboBoxResetValueTest.java View File

@@ -15,152 +15,96 @@
*/
package com.vaadin.tests.components.combobox;

import static org.junit.Assert.assertEquals;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Test;
import org.openqa.selenium.Keys;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;

import com.vaadin.testbench.By;
import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
import com.vaadin.tests.tb3.newelements.ComboBoxElement;

public class ComboBoxResetValueTest extends MultiBrowserTest {

static final String FILTER_STRING = "filter";
private ComboBoxElement comboBoxWithNullSelectionItemId;
private ComboBoxElement comboBoxWithoutNullSelectionItemId;
private ComboBoxElement comboBoxWithNullNotAllowed;

@Override
public void setup() throws Exception {
super.setup();

@Test
public void testNullSelectionAllowedAndSetNullSelectionItemId() {
openTestURL();

ComboBoxElement comboBoxWebElement = $(ComboBoxElement.class)
.id(ComboBoxResetValue.NULL_SELECTION_ALLOWED_WITH_SET_NULL_SELECTION_ITEM_ID);
comboBoxWithNullSelectionItemId = $(ComboBoxElement.class).id(
ComboBoxResetValue.WITH_SET_NULL_SELECTION_ITEM_ID);

comboBoxWithoutNullSelectionItemId = $(ComboBoxElement.class).id(
ComboBoxResetValue.WITHOUT_NULL_SELECTION_ITEM_ID);

comboBoxWithNullNotAllowed = $(ComboBoxElement.class).id(
ComboBoxResetValue.NULL_SELECTION_NOT_ALLOWED);

clickResetButton();
}

openPopup(comboBoxWebElement);
@Test
public void testNullSelectionAllowedAndSetNullSelectionItemId() {
comboBoxWithNullSelectionItemId.openPopup();

assertEquals("There should be selected: "
+ ComboBoxResetValue.EMPTY_VALUE,
ComboBoxResetValue.EMPTY_VALUE, getSelectedInPopupValue());
assertThatNullSelectionItemSelected(comboBoxWithNullSelectionItemId);
}

@Test
public void testFilterNullSelectionAllowedAndSetNullSelectionItemId() {
openTestURL();
comboBoxWithNullSelectionItemId.sendKeys("foo", Keys.TAB);

ComboBoxElement comboBoxWebElement = $(ComboBoxElement.class)
.id(ComboBoxResetValue.NULL_SELECTION_ALLOWED_WITH_SET_NULL_SELECTION_ITEM_ID);
clickResetButton();
printFilterAndRemoveIt(getComboBoxInput(comboBoxWebElement));

assertEquals("There should be " + ComboBoxResetValue.EMPTY_VALUE,
ComboBoxResetValue.EMPTY_VALUE,
getComboBoxValue(comboBoxWebElement));
assertThatNullSelectionItemSelected(comboBoxWithNullSelectionItemId);
}

@Test
public void testNullSelectionAllowedWithoutNullSelectionItemId() {
openTestURL();
comboBoxWithoutNullSelectionItemId.openPopup();

ComboBoxElement comboBoxWebElement = $(ComboBoxElement.class)
.id(ComboBoxResetValue.NULL_SELECTION_ALLOWED_WITHOUT_NULL_SELECTION_ITEM_ID);
clickResetButton();

openPopup(comboBoxWebElement);

// not sure about expected result here.. Should be first empty string
// selected or not after reseting..
assertEquals("There should be no selection", null,
getSelectedInPopupValue());
assertThatSelectionIsEmpty(comboBoxWithoutNullSelectionItemId);
}

@Test
public void testFilterNullSelectionAllowedWithoutNullSelectionItemId() {
openTestURL();
comboBoxWithoutNullSelectionItemId.sendKeys("foo", Keys.TAB);

ComboBoxElement comboBoxWebElement = $(ComboBoxElement.class)
.id(ComboBoxResetValue.NULL_SELECTION_ALLOWED_WITHOUT_NULL_SELECTION_ITEM_ID);
clickResetButton();
printFilterAndRemoveIt(getComboBoxInput(comboBoxWebElement));

assertEquals("There should be empty value", "",
getComboBoxValue(comboBoxWebElement));
assertThatSelectionIsEmpty(comboBoxWithoutNullSelectionItemId);
}

@Test
public void testNullSelectionNotAllowed() {
openTestURL();
comboBoxWithNullNotAllowed.openPopup();

ComboBoxElement comboBoxWebElement = $(ComboBoxElement.class).id(
ComboBoxResetValue.NULL_SELECTION_NOT_ALLOWED);
clickResetButton();

openPopup(comboBoxWebElement);

assertEquals("There should be no selection", null,
getSelectedInPopupValue());
assertThatSelectionIsEmpty(comboBoxWithNullNotAllowed);
}

@Test
public void testFilterNullSelectionNotAllowed() {
openTestURL();
comboBoxWithNullNotAllowed.sendKeys("1", Keys.TAB);
comboBoxWithNullNotAllowed.sendKeys(Keys.BACK_SPACE, Keys.TAB);

ComboBoxElement comboBoxWebElement = $(ComboBoxElement.class).id(
ComboBoxResetValue.NULL_SELECTION_NOT_ALLOWED);
clickResetButton();
printFilterAndRemoveIt(getComboBoxInput(comboBoxWebElement));

assertEquals("There should be empty value", "",
getComboBoxValue(comboBoxWebElement));
assertThat("Selection changed when it shouldn't have.",
comboBoxWithNullNotAllowed.getText(), is("1"));
}

private void openPopup(ComboBoxElement comboBox) {
if (!isElementPresent(By.vaadin("#popup"))) {
comboBox.openPopup();
}
private void assertThatNullSelectionItemSelected(ComboBoxElement comboBox) {
assertThat("Null selection item not selected.", comboBox.getText(),
is(ComboBoxResetValue.EMPTY_VALUE));
}

private String getSelectedInPopupValue() {
try {
WebElement selectedSpan = driver.findElement(By
.cssSelector(".gwt-MenuItem-selected span"));
return selectedSpan.getText();
} catch (NoSuchElementException e) {
return null;
} catch (WebDriverException e) {
if (e.getMessage() != null
&& e.getMessage().contains("Unable to find element")) {
return null;
}
throw e;
}
private void assertThatSelectionIsEmpty(ComboBoxElement comboBox) {
assertThat("Something selected when should be empty.",
comboBox.getText(), is(""));
}

private void clickResetButton() {
ButtonElement resetButton = $(ButtonElement.class).first();
// workaround because of IE10 that doesn't always respond to click
resetButton.focus();
resetButton.sendKeys(Keys.ENTER);
}

private void printFilterAndRemoveIt(WebElement target) {
Actions actions = new Actions(getDriver());
actions.click(target).perform();
actions.sendKeys(Keys.chord(Keys.CONTROL, "a")).perform(); // Select all
actions.sendKeys(FILTER_STRING);
actions.sendKeys(Keys.ENTER).sendKeys(Keys.ESCAPE).sendKeys(Keys.TAB); // hack
actions.perform();
}

private String getComboBoxValue(ComboBoxElement comboBox) {
return getComboBoxInput(comboBox).getAttribute("value");
}

private WebElement getComboBoxInput(ComboBoxElement comboBox) {
return comboBox.findElement(By.tagName("input"));
resetButton.click();
}
}

+ 2
- 4
uitest/src/com/vaadin/tests/components/combobox/ComboBoxScrollingWithArrowsTest.java View File

@@ -64,8 +64,7 @@ public class ComboBoxScrollingWithArrowsTest extends MultiBrowserTest {
public void scrollDownArrowKeyTest() throws InterruptedException {
WebElement dropDownComboBox = getDropDown();

// go to the last item and then one more
for (int i = 0; i < PAGESIZE + 1; i++) {
for (int i = 0; i < PAGESIZE; i++) {
dropDownComboBox.sendKeys(Keys.DOWN);
}

@@ -82,8 +81,7 @@ public class ComboBoxScrollingWithArrowsTest extends MultiBrowserTest {
public void scrollUpArrowKeyTest() throws InterruptedException {
WebElement dropDownComboBox = getDropDown();

// go to the last item and then one more
for (int i = 0; i < PAGESIZE + 1; i++) {
for (int i = 0; i < PAGESIZE; i++) {
dropDownComboBox.sendKeys(Keys.DOWN);
}


+ 57
- 0
uitest/src/com/vaadin/tests/components/combobox/ComboBoxSelecting.java View File

@@ -0,0 +1,57 @@
package com.vaadin.tests.components.combobox;

import com.vaadin.data.Property;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Label;
import com.vaadin.ui.TextField;

public class ComboBoxSelecting extends AbstractTestUI {
protected ComboBox comboBox;

@Override
protected void setup(VaadinRequest request) {
comboBox = new ComboBox();
final Label label = new Label();
label.setId("value");

comboBox.setTextInputAllowed(true);
comboBox.setNullSelectionAllowed(true);
comboBox.setNullSelectionItemId(null);

for (char c = 'a'; c <= 'z'; c++) {
for (int i = 0; i < 100; i++) {
comboBox.addItem("" + c + i);
}
}

comboBox.addValueChangeListener(new Property.ValueChangeListener() {
@Override
public void valueChange(Property.ValueChangeEvent event) {
Object value = event.getProperty().getValue();
if (value != null) {
label.setValue(value.toString());
} else {
label.setValue("null");
}

}
});

// Had to add an extra text field for our old Firefox browsers, because
// tab will otherwise send the focus to address bar and FF 24 won't fire
// a key event properly. Nice!
addComponents(comboBox, label, new TextField());
}

@Override
protected String getTestDescription() {
return "Clearing the filter and hitting enter should select the null item";
}

@Override
protected Integer getTicketNumber() {
return 15502;
}
}

+ 214
- 0
uitest/src/com/vaadin/tests/components/combobox/ComboBoxSelectingTest.java View File

@@ -0,0 +1,214 @@
package com.vaadin.tests.components.combobox;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.Test;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;

import com.vaadin.testbench.By;
import com.vaadin.testbench.elements.LabelElement;
import com.vaadin.testbench.parallel.BrowserUtil;
import com.vaadin.tests.tb3.MultiBrowserTest;
import com.vaadin.tests.tb3.newelements.ComboBoxElement;

public class ComboBoxSelectingTest extends MultiBrowserTest {

private ComboBoxElement comboBoxElement;

@Override
public void setup() throws Exception {
super.setup();

openTestURL();
waitForElementPresent(By.className("v-filterselect"));
comboBoxElement = $(ComboBoxElement.class).first();
}

@Test
public void firstSuggestionIsSelectedWithEnter() {
typeInputAndHitEnter("a");

assertThatSelectedValueIs("a0");
}

@Test
public void firstSuggestionIsSelectedWithTab() {
typeInputAndHitTab("a");

assertThatSelectedValueIs("a0");
}

@Test
public void nullIsSelected() {
typeInputAndHitEnter("a");
assertThatSelectedValueIs("a0");

clearInputAndHitEnter();

assertThatSelectedValueIs("", "null");
}

@Test
public void itemFromSecondPageIsSelected() {
typeInputAndHitEnter("a20");

assertThatSelectedValueIs("a20");
}

@Test
public void selectingNullFromSecondPage() {
typeInputAndHitEnter("a20");
assertThatSelectedValueIs("a20");

clearInputAndHitEnter();
assertThatSelectedValueIs("", "null");
}

@Test
public void selectionRemainsAfterOpeningPopup() {
typeInputAndHitEnter("a20");
assertThatSelectedValueIs("a20");

openPopup();
assertThatSelectedValueIs("a20");
}

@Test
public void noSelectionAfterMouseOut() {
typeInputAndHitEnter("a20");
comboBoxElement.sendKeys(Keys.ARROW_DOWN, Keys.ARROW_DOWN);

findElement(By.className("v-app")).click();

assertThatSelectedValueIs("a20");
}

@Test
public void cancelResetsSelection() {
sendKeysToInput("a20");
cancelSelection();

assertThatSelectedValueIs("");
}

@Test
public void inputFieldResetsToSelectedText() {
typeInputAndHitEnter("z5");

sendKeysToInput(Keys.BACK_SPACE, Keys.BACK_SPACE);
cancelSelection();

assertThatSelectedValueIs("z5");
}

@Test
public void emptyValueIsSelectedWithTab() {
typeInputAndHitEnter("z5");

assertThatSelectedValueIs("z5");
// longer delay for this one because otherwise it keeps failing when run
// on local machine
comboBoxElement.sendKeys(200, Keys.BACK_SPACE, Keys.BACK_SPACE,
Keys.TAB);
assertThatSelectedValueIs("", "null");

sendKeysToInput("z5");
cancelSelection();
assertThatSelectedValueIs("", "null");
}

@Test
public void arrowNavigatedValueIsSelectedWithEnter() {
sendKeysToInput("z");
sendKeysToInput(Keys.DOWN, Keys.DOWN, getReturn());

assertThatSelectedValueIs("z2");
}

@Test
public void arrowNavigatedValueIsSelectedWithTab() {
sendKeysToInput("z");
sendKeysToInput(Keys.DOWN, Keys.DOWN, Keys.TAB);

assertThatSelectedValueIs("z2");
}

private void clearInputAndHitEnter() {
sendKeysToInput(Keys.BACK_SPACE, Keys.BACK_SPACE, Keys.BACK_SPACE);
sendKeysToInput(getReturn());
}

private void typeInputAndHitEnter(String input) {
clearInputAndType(input);
sendKeysToInput(getReturn());
}

private void typeInputAndHitTab(String input) {
clearInputAndType(input);
sendKeysToInput(Keys.TAB);
}

private void clearInputAndType(String input) {
comboBoxElement.clear();
sendKeysToInput(input);
}

private void sendKeysToInput(CharSequence... keys) {
comboBoxElement.sendKeys(keys);
}

private Keys getReturn() {
if (BrowserUtil.isPhantomJS(getDesiredCapabilities())) {
return Keys.ENTER;
} else {
return Keys.RETURN;
}
}

private void openPopup() {
// Need to wait to make sure popup is closed first.
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
comboBoxElement.openPopup();
}

private void cancelSelection() {
if (BrowserUtil.isFirefox(getDesiredCapabilities())) {
findElement(By.className("v-app")).click();
} else {
sendKeysToInput(Keys.ESCAPE);
}
}

private void assertThatSelectedValueIs(final String value) {
assertThatSelectedValueIs(value, value);
}

private void assertThatSelectedValueIs(final String value,
final String labelValue) {
assertThat(comboBoxElement.getText(), is(value));

waitUntil(new ExpectedCondition<Boolean>() {
private String actualValue;

@Override
public Boolean apply(WebDriver input) {
actualValue = $(LabelElement.class).id("value").getText();
return actualValue.equals(labelValue);
}

@Override
public String toString() {
// Timed out after 10 seconds waiting for ...
return String.format("label value to match '%s' (was: '%s')",
labelValue, actualValue);
}
});
}
}

+ 52
- 0
uitest/src/com/vaadin/tests/components/combobox/ComboBoxSelectingWithNewItemsAllowed.java View File

@@ -0,0 +1,52 @@
/*
* Copyright 2000-2014 Vaadin 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.
*/
package com.vaadin.tests.components.combobox;

import com.vaadin.data.Property;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Label;

public class ComboBoxSelectingWithNewItemsAllowed extends ComboBoxSelecting {

@Override
protected void setup(VaadinRequest request) {
super.setup(request);
comboBox.setNewItemsAllowed(true);

final Label label = new Label(String.valueOf(comboBox.getItemIds()
.size()));
label.setCaption("Item count:");
label.setId("count");
comboBox.addValueChangeListener(new Property.ValueChangeListener() {

@Override
public void valueChange(Property.ValueChangeEvent event) {
label.setValue(String.valueOf(comboBox.getItemIds().size()));
}
});
addComponent(label);
}

@Override
protected String getTestDescription() {
return "ComboBox should select value on TAB also when new items are allowed.";
}

@Override
protected Integer getTicketNumber() {
return 9369;
}
}

+ 293
- 0
uitest/src/com/vaadin/tests/components/combobox/ComboBoxSelectingWithNewItemsAllowedTest.java View File

@@ -0,0 +1,293 @@
/*
* Copyright 2000-2014 Vaadin 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.
*/
package com.vaadin.tests.components.combobox;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.Test;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;

import com.vaadin.testbench.By;
import com.vaadin.testbench.elements.LabelElement;
import com.vaadin.testbench.parallel.BrowserUtil;
import com.vaadin.tests.tb3.MultiBrowserTest;
import com.vaadin.tests.tb3.newelements.ComboBoxElement;

public class ComboBoxSelectingWithNewItemsAllowedTest extends MultiBrowserTest {
private ComboBoxElement comboBoxElement;
private LabelElement labelElement;

@Override
public void setup() throws Exception {
super.setup();

openTestURL();
waitForElementPresent(By.className("v-filterselect"));
comboBoxElement = $(ComboBoxElement.class).first();
labelElement = $(LabelElement.class).id("count");
}

@Test
public void checkDefaults() {
assertInitialItemCount();
}

@Test
public void itemIsAddedWithEnter() {
typeInputAndHitEnter("a");

assertOneMoreThanInitial();
assertThatSelectedValueIs("a");
}

@Test
public void itemIsAddedWithTab() {
typeInputAndHitTab("a");

assertOneMoreThanInitial();
assertThatSelectedValueIs("a");
}

@Test
public void matchingSuggestionIsSelectedWithEnter() {
typeInputAndHitEnter("a0");

assertInitialItemCount();
assertThatSelectedValueIs("a0");
}

@Test
public void matchingSuggestionIsSelectedWithTab() {
typeInputAndHitTab("a0");

assertInitialItemCount();
assertThatSelectedValueIs("a0");
}

@Test
public void nullIsSelected() {
typeInputAndHitEnter("a");
assertOneMoreThanInitial();
assertThatSelectedValueIs("a");

clearInputAndHitEnter();

assertOneMoreThanInitial();
assertThatSelectedValueIs("", "null");
}

@Test
public void itemFromSecondPageIsSelected() {
typeInputAndHitEnter("a20");

assertInitialItemCount();
assertThatSelectedValueIs("a20");
}

@Test
public void selectingNullFromSecondPage() {
typeInputAndHitEnter("a20");
assertInitialItemCount();
assertThatSelectedValueIs("a20");

clearInputAndHitEnter();
assertInitialItemCount();
assertThatSelectedValueIs("", "null");
}

@Test
public void selectionRemainsAfterOpeningPopup() {
typeInputAndHitEnter("a20");
assertInitialItemCount();
assertThatSelectedValueIs("a20");

openPopup();
assertThatSelectedValueIs("a20");
}

@Test
public void noSelectionAfterMouseOut() {
typeInputAndHitEnter("a20");
comboBoxElement.sendKeys(Keys.ARROW_DOWN, Keys.ARROW_DOWN);

findElement(By.className("v-app")).click();

assertInitialItemCount();
assertThatSelectedValueIs("a20");
}

@Test
public void cancelResetsSelection() {
sendKeysToInput("a20");
cancelSelection();

assertInitialItemCount();
assertThatSelectedValueIs("");
}

@Test
public void inputFieldResetsToSelectedText() {
typeInputAndHitEnter("z5");

sendKeysToInput(Keys.BACK_SPACE, Keys.BACK_SPACE);
cancelSelection();

assertInitialItemCount();
assertThatSelectedValueIs("z5");
}

@Test
public void emptyValueIsSelectedWithTab() {
typeInputAndHitEnter("z5");

assertInitialItemCount();
assertThatSelectedValueIs("z5");
// longer delay for this one because otherwise it keeps failing when run
// on local machine
comboBoxElement.sendKeys(200, Keys.BACK_SPACE, Keys.BACK_SPACE,
Keys.TAB);
assertInitialItemCount();
assertThatSelectedValueIs("", "null");

sendKeysToInput("z5");
cancelSelection();
assertInitialItemCount();
assertThatSelectedValueIs("", "null");
}

@Test
public void arrowNavigatedValueIsSelectedWithEnter() {
sendKeysToInput("z");
sendKeysToInput(Keys.DOWN, Keys.DOWN, getReturn());

assertInitialItemCount();
assertThatSelectedValueIs("z1");
}

@Test
public void arrowNavigatedValueIsSelectedWithTab() {
sendKeysToInput("z");
sendKeysToInput(Keys.DOWN, Keys.DOWN, Keys.TAB);

assertInitialItemCount();
assertThatSelectedValueIs("z1");
}

private void clearInputAndHitEnter() {
sendKeysToInput(Keys.BACK_SPACE, Keys.BACK_SPACE, Keys.BACK_SPACE);
sendKeysToInput(getReturn());
}

private void typeInputAndHitEnter(String input) {
clearInputAndType(input);
sendKeysToInput(getReturn());
}

private void typeInputAndHitTab(String input) {
clearInputAndType(input);
sendKeysToInput(Keys.TAB);
}

private void clearInputAndType(String input) {
comboBoxElement.clear();
sendKeysToInput(input);
}

private void sendKeysToInput(CharSequence... keys) {
comboBoxElement.sendKeys(keys);
}

private Keys getReturn() {
if (BrowserUtil.isPhantomJS(getDesiredCapabilities())) {
return Keys.ENTER;
} else {
return Keys.RETURN;
}
}

private void openPopup() {
// Need to wait to make sure popup is closed first.
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
comboBoxElement.openPopup();
}

private void cancelSelection() {
if (BrowserUtil.isFirefox(getDesiredCapabilities())) {
findElement(By.className("v-app")).click();
} else {
sendKeysToInput(Keys.ESCAPE);
}
}

private void assertThatSelectedValueIs(final String value) {
assertThatSelectedValueIs(value, value);
}

private void assertThatSelectedValueIs(final String value,
final String labelValue) {
assertThat(comboBoxElement.getText(), is(value));

waitUntil(new ExpectedCondition<Boolean>() {
private String actualValue;

@Override
public Boolean apply(WebDriver input) {
actualValue = $(LabelElement.class).id("value").getText();
return actualValue.equals(labelValue);
}

@Override
public String toString() {
// Timed out after 10 seconds waiting for ...
return String.format("label value to match '%s' (was: '%s')",
labelValue, actualValue);
}
});
}

private void assertInitialItemCount() {
// wait for a bit in case the count is updating
try {
sleep(1000);
} catch (InterruptedException ignore) {
}
assertThat("Wrong initial item count.", labelElement.getText(),
is("2600"));
}

private void assertOneMoreThanInitial() {
waitUntil(new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver input) {
return "2601".equals(labelElement.getText());
}

@Override
public String toString() {
// Timed out after 10 seconds waiting for ...
return String.format("item count to become 2601 (was: %s)",
labelElement.getText());
}
});
}
}

+ 8
- 10
uitest/src/com/vaadin/tests/components/window/ComboboxScrollableWindowTest.java View File

@@ -24,10 +24,12 @@ import org.openqa.selenium.WebElement;
import com.vaadin.testbench.By;
import com.vaadin.testbench.commands.TestBenchElementCommands;
import com.vaadin.tests.tb3.MultiBrowserTest;
import com.vaadin.tests.tb3.newelements.ComboBoxElement;
import com.vaadin.tests.tb3.newelements.WindowElement;

/**
* Tests that a ComboBox at the bottom of a Window remains visible when clicked.
*
* @since
* @author Vaadin Ltd
*/
public class ComboboxScrollableWindowTest extends MultiBrowserTest {
@@ -36,20 +38,16 @@ public class ComboboxScrollableWindowTest extends MultiBrowserTest {
public void testWindowScrollbars() throws Exception {
openTestURL();

WebElement window = driver.findElement(By.id(WINDOW_ID));
WindowElement window = $(WindowElement.class).id(WINDOW_ID);
WebElement scrollableElement = window.findElement(By
.className("v-scrollable"));
TestBenchElementCommands scrollable = testBenchElement(scrollableElement);
scrollable.scroll(1000);
WebElement comboBox = driver.findElement(By.id(COMBOBOX_ID));
WebElement selectButton = driver.findElement(By
.className("v-filterselect-button"));
selectButton.click();

// Wait for the browser before taking a screenshot
Thread.sleep(1000);
compareScreen(getScreenshotBaseName());
ComboBoxElement comboBox = $(ComboBoxElement.class).id(COMBOBOX_ID);
comboBox.openPopup();
waitForElementPresent(By.className("v-filterselect-suggestpopup"));

compareScreen("combobox-open");
}

}

+ 8
- 17
uitest/src/com/vaadin/tests/fonticon/FontIconsTest.java View File

@@ -20,11 +20,10 @@ import static org.junit.Assert.assertEquals;
import java.io.IOException;

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

import com.vaadin.tests.tb3.MultiBrowserTest;
import com.vaadin.tests.tb3.newelements.ComboBoxElement;

public class FontIconsTest extends MultiBrowserTest {

@@ -37,29 +36,21 @@ public class FontIconsTest extends MultiBrowserTest {
@Test
public void comboBoxItemIconsOnKeyboardNavigation() throws Exception {
openTestURL();
WebElement comboBoxInput = getDriver().findElement(
By.className("v-filterselect-input"));
ComboBoxElement comboBox = $(ComboBoxElement.class).first();

// No initial value.
assertEquals("", comboBoxInput.getText());
assertEquals("", comboBox.getText());

// Navigate to the first item with keyboard navigation.
sendKeys(comboBoxInput, Keys.ARROW_DOWN, Keys.ARROW_DOWN,
Keys.ARROW_DOWN);
comboBox.sendKeys(400, Keys.ARROW_DOWN, Keys.ARROW_DOWN);

// Value must be "One" without any extra characters.
// See ticket #14660
assertEquals("One", comboBoxInput.getAttribute("value"));
assertEquals("One", comboBox.getText());

// Check also the second item.
sendKeys(comboBoxInput, Keys.ARROW_DOWN);
assertEquals("Two", comboBoxInput.getAttribute("value"));
}

private void sendKeys(WebElement element, Keys... keys) throws Exception {
for (Keys key : keys) {
element.sendKeys(key);
sleep(10); // For PhantomJS.
}
comboBox.sendKeys(Keys.ARROW_DOWN);
assertEquals("Two", comboBox.getText());
}
}

+ 54
- 0
uitest/src/com/vaadin/tests/tb3/newelements/ComboBoxElement.java View File

@@ -0,0 +1,54 @@
package com.vaadin.tests.tb3.newelements;

import org.junit.Assert;
import org.openqa.selenium.WebElement;

import com.vaadin.testbench.By;
import com.vaadin.testbench.elementsbase.ServerClass;

@ServerClass("com.vaadin.ui.ComboBox")
public class ComboBoxElement extends
com.vaadin.testbench.elements.ComboBoxElement {

public WebElement getInputField() {
return findElement(By.vaadin("#textbox"));
}

@Override
public String getText() {
return getInputField().getAttribute("value");
}

@Override
public void clear() {
getInputField().clear();
}

@Override
public void sendKeys(CharSequence... keysToSend) {
sendKeys(50, keysToSend);
}

/**
* Use this method to simulate typing into an element, which may set its
* value.
*
* @param delay
* delay after sending each individual key (mainly needed for
* PhantomJS)
* @param keysToSend
* keys to type into the element
*/
public void sendKeys(int delay, CharSequence... keysToSend) {
WebElement input = getInputField();

for (CharSequence key : keysToSend) {
input.sendKeys(key);
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
}
}
}

+ 0
- 5
uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxBorder.html View File

@@ -31,11 +31,6 @@
<td>vaadin=runComboBoxBorder::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]#textbox</td>
<td>down</td>
</tr>
<tr>
<td>pressSpecialKey</td>
<td>vaadin=runComboBoxBorder::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]#textbox</td>
<td>down</td>
</tr>
<tr>
<td>pressSpecialKey</td>
<td>vaadin=runComboBoxBorder::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]#textbox</td>

+ 1
- 6
uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxCombinedWithEnterShortcut.html View File

@@ -3,7 +3,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="selenium.base" href="http://arturwin.office.itmill.com:8888/" />
<link rel="selenium.base" href="http://localhost:8888/" />
<title>New Test</title>
</head>
<body>
@@ -31,11 +31,6 @@
<td>vaadin=runcomvaadintestscomponentscomboboxComboBoxCombinedWithEnterShortcut::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td>
<td>down</td>
</tr>
<tr>
<td>pressSpecialKey</td>
<td>vaadin=runcomvaadintestscomponentscomboboxComboBoxCombinedWithEnterShortcut::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td>
<td>down</td>
</tr>
<tr>
<td>pressSpecialKey</td>
<td>vaadin=runcomvaadintestscomponentscomboboxComboBoxCombinedWithEnterShortcut::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td>

+ 0
- 10
uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html View File

@@ -137,16 +137,6 @@
<td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VFilterSelect[0]/domChild[0]</td>
<td>down</td>
</tr>
<tr>
<td>pressSpecialKey</td>
<td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VFilterSelect[0]/domChild[0]</td>
<td>down</td>
</tr>
<tr>
<td>pressSpecialKey</td>
<td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VFilterSelect[0]/domChild[0]</td>
<td>down</td>
</tr>
<tr>
<td>screenCapture</td>
<td></td>

+ 0
- 5
uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxNavigation.html View File

@@ -46,11 +46,6 @@
<td></td>
<td></td>
</tr>
<tr>
<td>pressSpecialKey</td>
<td>vaadin=runcomvaadintestscomponentscomboboxComboBoxNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]/domChild[0]</td>
<td>down</td>
</tr>
<tr>
<td>waitForVaadin</td>
<td></td>

+ 0
- 5
uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxSQLContainerFilteredValueChange.html View File

@@ -21,11 +21,6 @@
<td>vaadin=runcomvaadintestscomponentscomboboxComboBoxSQLContainerFilteredValueChange::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]#textbox</td>
<td>a</td>
</tr>
<tr>
<td>pressSpecialKey</td>
<td>vaadin=runcomvaadintestscomponentscomboboxComboBoxSQLContainerFilteredValueChange::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]#textbox</td>
<td>down</td>
</tr>
<tr>
<td>pressSpecialKey</td>
<td>vaadin=runcomvaadintestscomponentscomboboxComboBoxSQLContainerFilteredValueChange::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]#textbox</td>

Loading…
Cancel
Save