| <!DOCTYPE html> |
| <html> |
| |
| <head> |
| <meta http-equiv="Expire" content="0" /> |
| <title>select_test.html</title> |
| <script type="text/javascript" src="test_bootstrap.js"></script> |
| <script type="text/javascript" src="jquery.min.js"></script> |
| <script type="text/javascript"> |
| goog.require('bot.action'); |
| goog.require('bot.locators'); |
| goog.require('bot.userAgent'); |
| goog.require('goog.array'); |
| goog.require('goog.events'); |
| goog.require('goog.testing.jsunit'); |
| goog.require('goog.userAgent'); |
| </script> |
| <script type="text/javascript"> |
| var singleSelect, multiSelect, radioButtons, checkboxes, changeCount; |
| var gotPointerCaptureCount, lostPointerCaptureCount; |
| |
| function setUpPage() { |
| singleSelect = bot.locators.findElement({ id: 'singleSelect' }); |
| multiSelect = bot.locators.findElement({ id: 'multiSelect' }); |
| checkboxes = bot.locators.findElements({ name: 'checkbox' }); |
| radioButtons = bot.locators.findElements({ name: 'radio' }); |
| } |
| |
| function setUp() { |
| goog.events.removeAll(singleSelect); |
| goog.events.removeAll(multiSelect); |
| for (var i = 0; i < checkboxes.length; ++i) { |
| goog.events.removeAll(checkboxes[i]); |
| } |
| for (var i = 0; i < radioButtons.length; ++i) { |
| goog.events.removeAll(radioButtons[i]); |
| } |
| singleSelect.selectedIndex = 0; |
| goog.array.forEach(multiSelect.options, function (e) { |
| e.selected = false; |
| }); |
| goog.array.forEach(checkboxes, function (e) { |
| e.checked = false; |
| }); |
| goog.array.forEach(radioButtons, function (e) { |
| e.checked = false; |
| }); |
| } |
| |
| function checkActionCompatibility(action) { |
| if (action == bot.action.tap) { |
| return bot.events.SUPPORTS_TOUCH_EVENTS; |
| } |
| return true; |
| } |
| |
| function expectChanges(target) { |
| changeCount = 0; |
| goog.events.listen(target, 'change', function (e) { |
| changeCount++; |
| }); |
| } |
| |
| function assertChanges(expectedCount) { |
| assertEquals('Unexpected number of changes', expectedCount, changeCount); |
| } |
| |
| function expectPointerCaptures(target) { |
| gotPointerCaptureCount = 0; |
| lostPointerCaptureCount = 0; |
| goog.events.listen(target, goog.events.EventType.MSGOTPOINTERCAPTURE, |
| function (e) { |
| gotPointerCaptureCount++; |
| }); |
| goog.events.listen(target, goog.events.EventType.MSLOSTPOINTERCAPTURE, |
| function (e) { |
| lostPointerCaptureCount++; |
| }); |
| } |
| |
| function assertPointerCaptures(expectedCount) { |
| assertEquals('Unexpected number of got captures', expectedCount, |
| gotPointerCaptureCount); |
| assertEquals('Unexpected number of lost captures', expectedCount, |
| lostPointerCaptureCount); |
| } |
| |
| function canSelectAnOptionFromASingleSelect(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| assertFalse(bot.dom.isSelected(singleSelect.options[1])); |
| expectChanges(singleSelect); |
| if (bot.userAgent.IE_DOC_10) { |
| expectPointerCaptures(singleSelect); |
| } |
| action(singleSelect.options[1]); |
| |
| assertChanges(1); |
| if (bot.userAgent.IE_DOC_10) { |
| assertPointerCaptures(1); |
| } |
| assertTrue(bot.dom.isSelected(singleSelect.options[1])); |
| } |
| |
| var testClickCanSelectAnOptionFromASingleSelect = |
| goog.partial(canSelectAnOptionFromASingleSelect, bot.action.click); |
| |
| var testTapCanSelectAnOptionFromASingleSelect = |
| goog.partial(canSelectAnOptionFromASingleSelect, bot.action.tap); |
| |
| function cannotDeselectAnOptionFromASingleSelect(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| assertTrue(bot.dom.isSelected(singleSelect.options[0])); |
| expectChanges(singleSelect); |
| |
| action(singleSelect.options[0]); |
| |
| assertChanges(0); |
| assertTrue(bot.dom.isSelected(singleSelect.options[0])); |
| } |
| |
| var testClickCannotDeselectAnOptionFromASingleSelect = |
| goog.partial(cannotDeselectAnOptionFromASingleSelect, bot.action.click); |
| |
| var testTapCannotDeselectAnOptionFromASingleSelect = |
| goog.partial(cannotDeselectAnOptionFromASingleSelect, bot.action.tap); |
| |
| function cannotSelectAnOptionFromADisabledSelect(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| singleSelect.disabled = true; |
| assertFalse(bot.dom.isSelected(singleSelect.options[1])); |
| expectChanges(singleSelect); |
| |
| action(singleSelect.options[1]); |
| |
| assertChanges(0); |
| assertFalse(bot.dom.isSelected(singleSelect.options[1])); |
| singleSelect.disabled = false; |
| } |
| |
| var testClickCannotSelectAnOptionFromADisabled = |
| goog.partial(cannotSelectAnOptionFromADisabledSelect, bot.action.click); |
| |
| var testTapCannotSelectAnOptionFromADisabled = |
| goog.partial(cannotSelectAnOptionFromADisabledSelect, bot.action.tap); |
| |
| function canSelectAnEnabledOptionFromASelectWithADisabledOption(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| singleSelect.options[1].disabled = true; |
| assertFalse(bot.dom.isSelected(singleSelect.options[2])); |
| expectChanges(singleSelect); |
| |
| action(singleSelect.options[2]); |
| |
| assertChanges(1); |
| assertTrue(bot.dom.isSelected(singleSelect.options[2])); |
| singleSelect.options[1].disabled = false; |
| } |
| |
| var testClickCanSelectAnEnabledOptionFromASelectWithADisabledOption = |
| goog.partial(canSelectAnEnabledOptionFromASelectWithADisabledOption, |
| bot.action.click); |
| |
| var testTapCanSelectAnEnabledOptionFromASelectWithADisabledOption = |
| goog.partial(canSelectAnEnabledOptionFromASelectWithADisabledOption, |
| bot.action.tap); |
| |
| function canToggleOptionsInAMultiSelect(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| multiSelect.options[0].selected = true; |
| expectChanges(multiSelect); |
| |
| action(multiSelect.options[0]); |
| action(multiSelect.options[1]); |
| action(multiSelect.options[2]); |
| |
| assertChanges(3); |
| assertFalse(bot.dom.isSelected(multiSelect.options[0])); |
| assertTrue(bot.dom.isSelected(multiSelect.options[1])); |
| assertTrue(bot.dom.isSelected(multiSelect.options[2])); |
| } |
| |
| var testClickCanToggleOptionsInAMultiSelect = |
| // Disabled on Chrome due to |
| // https://code.google.com/p/chromedriver/issues/detail?id=1073 |
| // Disabled on Safari due to |
| // https://github.com/SeleniumHQ/selenium/issues/461 |
| (goog.userAgent.product.CHROME || goog.userAgent.product.SAFARI) ? |
| goog.nullFunction : |
| goog.partial(canToggleOptionsInAMultiSelect, bot.action.click); |
| |
| var testTapCanToggleOptionsInAMultiSelect = |
| // Disabled on Chrome due to |
| // https://code.google.com/p/chromedriver/issues/detail?id=1073 |
| // Disabled on Safari due to |
| // https://github.com/SeleniumHQ/selenium/issues/461 |
| (goog.userAgent.product.CHROME || goog.userAgent.product.SAFARI) ? |
| goog.nullFunction : |
| goog.partial(canToggleOptionsInAMultiSelect, bot.action.tap); |
| |
| function canToggleCheckboxes(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| // IE <= 8 fires a change event on the next click after the change. |
| checkboxes[0].checked = true; |
| expectChanges(checkboxes[0]); |
| action(checkboxes[0]); |
| assertChanges(1); |
| |
| if (!bot.userAgent.IE_DOC_PRE9) { |
| expectChanges(checkboxes[1]); |
| } |
| action(checkboxes[1]); |
| assertChanges(1); |
| |
| expectChanges(checkboxes[2]); |
| action(checkboxes[2]); |
| assertChanges(1); |
| |
| assertFalse(bot.dom.isSelected(checkboxes[0])); |
| assertTrue(bot.dom.isSelected(checkboxes[1])); |
| assertTrue(bot.dom.isSelected(checkboxes[2])); |
| } |
| |
| var testClickCanToggleCheckboxes = |
| goog.partial(canToggleCheckboxes, bot.action.click); |
| |
| var testTapCanToggleCheckboxes = |
| goog.partial(canToggleCheckboxes, bot.action.tap); |
| |
| function canSelectRadioButtons(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| // IE <= 8 fires a change event on the next click after the change. |
| expectChanges(radioButtons[0]); |
| action(radioButtons[0]); |
| assertChanges(1); |
| |
| assertTrue(bot.dom.isSelected(radioButtons[0])); |
| |
| if (!bot.userAgent.IE_DOC_PRE9) { |
| expectChanges(radioButtons[1]); |
| } |
| action(radioButtons[1]); |
| assertChanges(1); |
| assertTrue(bot.dom.isSelected(radioButtons[1])); |
| |
| expectChanges(radioButtons[2]); |
| action(radioButtons[2]); |
| assertChanges(1); |
| assertTrue(bot.dom.isSelected(radioButtons[2])); |
| } |
| |
| var testClickCanSelectRadioButtons = |
| goog.partial(canSelectRadioButtons, bot.action.click); |
| |
| var testTapCanSelectRadioButtons = |
| goog.partial(canSelectRadioButtons, bot.action.tap); |
| |
| function cannotDeselectRadioButtons(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| radioButtons[0].checked = true; |
| expectChanges(radioButtons[0]); |
| |
| action(radioButtons[0]); |
| assertChanges(0); |
| assertTrue(bot.dom.isSelected(radioButtons[0])); |
| } |
| |
| var testClickCannotDeselectRadioButtons = |
| goog.partial(cannotDeselectRadioButtons, bot.action.click); |
| |
| var testTapCannotDeselectRadioButtons = |
| goog.partial(cannotDeselectRadioButtons, bot.action.tap); |
| |
| function cannotSelectDisabledElements(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| function assertCannotSelectWhenDisabled(elem, isOption) { |
| elem.disabled = true; |
| expectChanges(isOption ? elem.parentNode : elem); |
| |
| action(elem); |
| |
| assertChanges(0); |
| assertFalse(bot.dom.isSelected(elem)); |
| elem.disabled = false; |
| } |
| |
| assertCannotSelectWhenDisabled(singleSelect.options[1], true); |
| assertCannotSelectWhenDisabled(multiSelect.options[0], true); |
| assertCannotSelectWhenDisabled(checkboxes[0], false); |
| assertCannotSelectWhenDisabled(radioButtons[0], false); |
| } |
| |
| var testClickCannotSelectDisabledElements = |
| goog.partial(cannotSelectDisabledElements, bot.action.click); |
| |
| var testTapCannotSelectDisabledElements = |
| goog.partial(cannotSelectDisabledElements, bot.action.tap); |
| |
| function canSelectOptionWhenDefaultPrevented(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| function assertCanSelectWhenDefaultPrevented(elem) { |
| goog.events.listen(elem, 'click', function (e) { |
| e.preventDefault(); |
| }); |
| expectChanges(elem.parentNode); |
| |
| action(elem); |
| |
| assertChanges(1); |
| assertTrue(bot.dom.isSelected(elem)); |
| } |
| |
| assertCanSelectWhenDefaultPrevented(singleSelect.options[1]); |
| assertCanSelectWhenDefaultPrevented(multiSelect.options[0]); |
| } |
| |
| var testClickCanSelectOptionWhenDefaultPrevented = |
| // Disabled on Safari due to |
| // https://github.com/SeleniumHQ/selenium/issues/461 |
| goog.userAgent.product.SAFARI ? |
| goog.nullFunction : |
| goog.partial(canSelectOptionWhenDefaultPrevented, bot.action.click); |
| |
| var testTapCanSelectOptionWhenDefaultPrevented = |
| // Disabled on Chrome due to |
| // https://code.google.com/p/chromedriver/issues/detail?id=1073 |
| // Disabled on Safari due to |
| // https://github.com/SeleniumHQ/selenium/issues/461 |
| (goog.userAgent.product.CHROME || goog.userAgent.product.SAFARI) ? |
| goog.nullFunction : |
| goog.partial(canSelectOptionWhenDefaultPrevented, bot.action.tap); |
| |
| function cannotSelectCheckboxWhenDefaultPrevented(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| var elem = checkboxes[0]; |
| goog.events.listen(elem, 'click', function (e) { |
| e.preventDefault(); |
| }); |
| expectChanges(elem); |
| |
| action(elem); |
| |
| // Some browsers fire change events when the checkbox isn't toggled. |
| assertChanges(firesChangeEventIfNotToggled() ? 1 : 0); |
| assertFalse(bot.dom.isSelected(elem)); |
| } |
| |
| function firesChangeEventIfNotToggled() { |
| if (goog.userAgent.product.CHROME && bot.userAgent.isProductVersion(45)) { |
| // Chrome 45 and above do not fire the change event. |
| return false; |
| } else if (goog.userAgent.WEBKIT || bot.userAgent.IE_DOC_9 || |
| goog.userAgent.EDGE) { |
| // Other browsers with goog.userAgent.WEBKIT fire the change event. |
| // IE 9 standards mode fires the change event. |
| return true; |
| } |
| |
| // All other browsers do not fire the change event. |
| return false; |
| } |
| |
| var testClickCannotSelectCheckboxWhenDefaultPrevented = |
| goog.partial(cannotSelectCheckboxWhenDefaultPrevented, |
| bot.action.click); |
| |
| var testTapCannotSelectCheckboxWhenDefaultPrevented = |
| goog.partial(cannotSelectCheckboxWhenDefaultPrevented, bot.action.tap); |
| |
| function maybeSelectRadioButtonWhenDefaultPrevented(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| var elem = radioButtons[0]; |
| goog.events.listen(elem, 'click', function (e) { |
| e.preventDefault(); |
| }); |
| expectChanges(elem); |
| |
| action(elem); |
| |
| // Chrome < 39 and WebKit select a radio button even when the handler |
| // prevents the default; IE does not. |
| if ((goog.userAgent.product.CHROME && |
| !bot.userAgent.isProductVersion(39)) || |
| (goog.userAgent.WEBKIT && !goog.userAgent.product.CHROME)) { |
| assertChanges(1); |
| assertTrue(bot.dom.isSelected(elem)); |
| } else { |
| // Some browsers fire change events when the checkbox isn't toggled. |
| assertChanges(firesChangeEventIfNotToggled() ? 1 : 0); |
| assertFalse(bot.dom.isSelected(elem)); |
| } |
| } |
| |
| var testClickMaybeSelectRadioButtonWhenDefaultPrevented = |
| goog.partial(maybeSelectRadioButtonWhenDefaultPrevented, |
| bot.action.click); |
| |
| var testTapMaybeSelectRadioButtonWhenDefaultPrevented = |
| goog.partial(maybeSelectRadioButtonWhenDefaultPrevented, |
| bot.action.tap); |
| |
| /** @see http://code.google.com/p/selenium/issues/detail?id=1941 */ |
| function canSelectOptionFromTransparentSelect(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| var style = singleSelect.style; |
| style['opacity'] = '0'; |
| style['filter'] = 'alpha(opacity=0)'; |
| assertEquals(0, bot.dom.getOpacity(singleSelect)); |
| assertFalse(bot.dom.isSelected(singleSelect.options[1])); |
| expectChanges(singleSelect); |
| |
| bot.action.click(singleSelect.options[1]); |
| |
| assertChanges(1); |
| assertTrue(bot.dom.isSelected(singleSelect.options[1])); |
| style['opacity'] = ''; |
| style['filter'] = ''; |
| assertEquals(1, bot.dom.getOpacity(singleSelect)); |
| } |
| |
| var testClickCanSelectOptionFromTransparentSelect = |
| goog.partial(canSelectOptionFromTransparentSelect, bot.action.click); |
| |
| var testTapCanSelectOptionFromTransparentSelect = |
| goog.partial(canSelectOptionFromTransparentSelect, bot.action.tap); |
| |
| function noErrorAfterSelectWhenOnChangePreventsDefault(action) { |
| if (!checkActionCompatibility(action) || |
| (goog.userAgent.IE && !bot.userAgent.isProductVersion(7))) { |
| return; |
| } |
| goog.events.listen(radioButtons[1], 'change', function (e) { |
| e.preventDefault(); |
| }); |
| action(radioButtons[1]); |
| assertTrue(bot.dom.isSelected(radioButtons[1])); |
| |
| // In IE, this second click used to throw an "Unspecified error". |
| action(radioButtons[2]); |
| } |
| |
| var testClickNoErrorAfterSelectWhenOnChangePreventsDefault = |
| goog.partial(noErrorAfterSelectWhenOnChangePreventsDefault, |
| bot.action.click); |
| |
| var testTapNoErrorAfterSelectWhenOnChangePreventsDefault = |
| goog.partial(noErrorAfterSelectWhenOnChangePreventsDefault, |
| bot.action.tap); |
| |
| function selectOptionTriggersJQueryChangeHandler(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| var changes = 0; |
| $('#singleSelect').change(function () { |
| changes++; |
| }); |
| |
| action(singleSelect.options[1]); |
| |
| assertEquals(1, changes); |
| $('#singleSelect').unbind(); |
| } |
| |
| var testClickSelectOptionTriggersJQueryChangeHandler = |
| goog.partial(selectOptionTriggersJQueryChangeHandler, bot.action.click); |
| |
| var testTapSelectOptionTriggersJQueryChangeHandler = |
| goog.partial(selectOptionTriggersJQueryChangeHandler, bot.action.tap); |
| |
| function pointerCaptureFiresOnCheckboxToggle(action) { |
| if (!bot.userAgent.IE_DOC_10) { |
| return; |
| } |
| checkboxes[0].checked = true; |
| expectPointerCaptures(checkboxes[0]); |
| action(checkboxes[0]); |
| // For input elements, the got/lost pointer capture events only fire for |
| // a tap and not for mouse clicks. |
| if (action == bot.action.tap) { |
| assertPointerCaptures(1); |
| } else { |
| assertPointerCaptures(0); |
| } |
| assertFalse(bot.dom.isSelected(checkboxes[0])); |
| } |
| |
| var testClickPointerCaptureFiresOnCheckboxToggle = |
| goog.partial(pointerCaptureFiresOnCheckboxToggle, bot.action.click); |
| |
| var testTapPointerCaptureFiresOnCheckboxToggle = |
| goog.partial(pointerCaptureFiresOnCheckboxToggle, bot.action.tap); |
| |
| function togglesByTheTimeChangeEventFires(action) { |
| if (!checkActionCompatibility(action)) { |
| return; |
| } |
| |
| singleSelect.options[0].selected = true; |
| checkToggleAtChange(action, singleSelect, singleSelect.options[1]); |
| |
| multiSelect.options[0].selected = false; |
| checkToggleAtChange(action, multiSelect, multiSelect.options[0]); |
| |
| radioButtons[0].checked = false; |
| checkToggleAtChange(action, radioButtons[0], radioButtons[0]); |
| |
| checkboxes[0].checked = false; |
| checkToggleAtChange(action, checkboxes[0], checkboxes[0]); |
| |
| function checkToggleAtChange(action, targetElem, toggleElem) { |
| var preState = bot.dom.isSelected(toggleElem); |
| var postState = null; |
| goog.events.listen(targetElem, 'change', function (e) { |
| postState = bot.dom.isSelected(toggleElem); |
| }); |
| action(toggleElem); |
| assertNotNull('change event did not fire', postState); |
| assertNotEquals('element did not toggle', postState, preState); |
| } |
| } |
| |
| var testClickTogglesByTheTimeChangeEventFires = |
| // Disabled on Safari due to |
| // https://github.com/SeleniumHQ/selenium/issues/461 |
| goog.userAgent.product.SAFARI ? |
| goog.nullFunction : |
| goog.partial(togglesByTheTimeChangeEventFires, bot.action.click); |
| |
| var testTapTogglesByTheTimeChangeEventFires = |
| // Disabled on Chrome due to |
| // https://code.google.com/p/chromedriver/issues/detail?id=1073 |
| // Disabled on Safari due to |
| // https://github.com/SeleniumHQ/selenium/issues/461 |
| (goog.userAgent.product.CHROME || goog.userAgent.product.SAFARI) ? |
| goog.nullFunction : |
| goog.partial(togglesByTheTimeChangeEventFires, bot.action.tap); |
| </script> |
| </head> |
| |
| <body> |
| <form action="#" method="get"> |
| <select id="singleSelect"> |
| <option id="singleOption1" value="foo">foo</option> |
| <option id="singleOption2" value="bar">bar</option> |
| <option id="singleOption3" value="baz">baz</option> |
| </select> |
| <br> |
| <select id="multiSelect" multiple> |
| <option id="multiOption1" value="apples">apples</option> |
| <option id="multiOption2" value="oranges">oranges</option> |
| <option id="multiOption3" value="cherries">cherries</option> |
| </select> |
| <br> |
| <input type="checkbox" name="checkbox" value="peas">peas |
| <input type="checkbox" name="checkbox" value="spinach">spinach |
| <input type="checkbox" name="checkbox" value="broccoli">broccoli |
| <br> |
| <input type="radio" name="radio" value="cheese">cheese |
| <input type="radio" name="radio" value="water">water |
| <input type="radio" name="radio" value="bread">bread |
| </form> |
| </body> |
| |
| </html> |