| // <copyright file="CombinedInputActionsTest.cs" company="Selenium Committers"> |
| // Licensed to the Software Freedom Conservancy (SFC) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The SFC licenses this file |
| // to you 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. |
| // </copyright> |
| |
| using NUnit.Framework; |
| using OpenQA.Selenium.Environment; |
| using System; |
| using System.Collections.ObjectModel; |
| using System.Drawing; |
| using System.Runtime.InteropServices; |
| |
| namespace OpenQA.Selenium.Interactions; |
| |
| [TestFixture] |
| public class CombinedInputActionsTest : DriverTestFixture |
| { |
| [SetUp] |
| public void Setup() |
| { |
| // new Actions(driver).SendKeys(Keys.Null).Perform(); |
| IActionExecutor actionExecutor = driver as IActionExecutor; |
| if (actionExecutor != null) |
| { |
| actionExecutor.ResetInputState(); |
| } |
| } |
| |
| [TearDown] |
| public void ReleaseModifierKeys() |
| { |
| // new Actions(driver).SendKeys(Keys.Null).Perform(); |
| IActionExecutor actionExecutor = driver as IActionExecutor; |
| if (actionExecutor != null) |
| { |
| actionExecutor.ResetInputState(); |
| } |
| } |
| |
| [Test] |
| [IgnoreBrowser(Browser.IE, "IE reports [0,0] as location for <option> elements")] |
| public void PlainClickingOnMultiSelectionList() |
| { |
| driver.Url = formSelectionPage; |
| |
| ReadOnlyCollection<IWebElement> options = driver.FindElements(By.TagName("option")); |
| |
| Actions actionBuider = new Actions(driver); |
| IAction selectThreeOptions = actionBuider.Click(options[1]) |
| .Click(options[2]) |
| .Click(options[3]).Build(); |
| |
| selectThreeOptions.Perform(); |
| |
| IWebElement showButton = driver.FindElement(By.Name("showselected")); |
| showButton.Click(); |
| |
| IWebElement resultElement = driver.FindElement(By.Id("result")); |
| Assert.That(resultElement.Text, Is.EqualTo("cheddar"), "Should have picked the third option only."); |
| } |
| |
| [Test] |
| public void ShouldAllowSettingActivePointerWithKeyBoardActions() |
| { |
| driver.Url = loginPage; |
| |
| IWebElement username = driver.FindElement(By.Id("username-field")); |
| IWebElement password = driver.FindElement(By.Id("password-field")); |
| IWebElement login = driver.FindElement(By.Id("login-form-submit")); |
| |
| Actions actionProvider = new Actions(driver); |
| IAction loginAction = actionProvider |
| .SendKeys(username, "username") |
| .SendKeys(password, "password") |
| .SetActivePointer(PointerKind.Mouse, "test") |
| .MoveToElement(login) |
| .Click() |
| .Build(); |
| |
| loginAction.Perform(); |
| |
| IAlert alert = driver.SwitchTo().Alert(); |
| Assert.That(alert.Text, Is.EqualTo("You have successfully logged in.")); |
| |
| alert.Accept(); |
| } |
| |
| [Test] |
| [IgnoreBrowser(Browser.IE, "IE reports [0,0] as location for <option> elements")] |
| public void ShiftClickingOnMultiSelectionList() |
| { |
| driver.Url = formSelectionPage; |
| |
| ReadOnlyCollection<IWebElement> options = driver.FindElements(By.TagName("option")); |
| |
| Actions actionBuider = new Actions(driver); |
| IAction selectThreeOptions = actionBuider.Click(options[1]) |
| .KeyDown(Keys.Shift) |
| .Click(options[2]) |
| .Click(options[3]) |
| .KeyUp(Keys.Shift).Build(); |
| |
| selectThreeOptions.Perform(); |
| |
| IWebElement showButton = driver.FindElement(By.Name("showselected")); |
| showButton.Click(); |
| |
| IWebElement resultElement = driver.FindElement(By.Id("result")); |
| Assert.That(resultElement.Text, Is.EqualTo("roquefort parmigiano cheddar"), "Should have picked the last three options."); |
| } |
| |
| [Test] |
| [IgnoreBrowser(Browser.IE, "IE reports [0,0] as location for <option> elements")] |
| public void ControlClickingOnMultiSelectionList() |
| { |
| string controlModifier = Keys.Control; |
| if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) |
| { |
| controlModifier = Keys.Command; |
| } |
| |
| driver.Url = formSelectionPage; |
| |
| ReadOnlyCollection<IWebElement> options = driver.FindElements(By.TagName("option")); |
| |
| Actions actionBuider = new Actions(driver); |
| IAction selectThreeOptions = actionBuider.Click(options[1]) |
| .KeyDown(controlModifier) |
| .Click(options[3]) |
| .KeyUp(controlModifier).Build(); |
| |
| selectThreeOptions.Perform(); |
| |
| IWebElement showButton = driver.FindElement(By.Name("showselected")); |
| showButton.Click(); |
| |
| IWebElement resultElement = driver.FindElement(By.Id("result")); |
| Assert.That(resultElement.Text, Is.EqualTo("roquefort cheddar"), "Should have picked the first and third options."); |
| } |
| |
| [Test] |
| public void ControlClickingOnCustomMultiSelectionList() |
| { |
| string controlModifier = Keys.Control; |
| if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) |
| { |
| controlModifier = Keys.Command; |
| } |
| |
| driver.Url = selectableItemsPage; |
| |
| IWebElement reportingElement = driver.FindElement(By.Id("infodiv")); |
| |
| Assert.That(reportingElement.Text, Is.EqualTo("no info")); |
| |
| ReadOnlyCollection<IWebElement> listItems = driver.FindElements(By.TagName("li")); |
| |
| IAction selectThreeItems = new Actions(driver).KeyDown(controlModifier) |
| .Click(listItems[1]) |
| .Click(listItems[3]) |
| .Click(listItems[5]) |
| .KeyUp(controlModifier).Build(); |
| |
| selectThreeItems.Perform(); |
| |
| Assert.That(reportingElement.Text, Is.EqualTo("#item2 #item4 #item6")); |
| |
| // Now click on another element, make sure that's the only one selected. |
| new Actions(driver).Click(listItems[6]).Build().Perform(); |
| Assert.That(reportingElement.Text, Is.EqualTo("#item7")); |
| } |
| |
| [Test] |
| public void CanMoveMouseToAnElementInAnIframeAndClick() |
| { |
| driver.Url = EnvironmentManager.Instance.UrlBuilder.WhereIs("click_tests/click_in_iframe.html"); |
| |
| WaitFor<IWebElement>(() => driver.FindElement(By.Id("ifr")), "Did not find element"); |
| driver.SwitchTo().Frame("ifr"); |
| |
| try |
| { |
| IWebElement link = driver.FindElement(By.Id("link")); |
| |
| new Actions(driver) |
| .MoveToElement(link) |
| .Click() |
| .Perform(); |
| |
| WaitFor(() => driver.Title == "Submitted Successfully!", "Browser title not correct"); |
| } |
| finally |
| { |
| driver.SwitchTo().DefaultContent(); |
| } |
| } |
| |
| [Test] |
| public void CanClickOnLinks() |
| { |
| this.NavigateToClicksPageAndClickLink(); |
| } |
| |
| [Test] |
| public void CanClickOnLinksWithAnOffset() |
| { |
| driver.Url = clicksPage; |
| |
| WaitFor(() => { return driver.FindElement(By.Id("normal")); }, "Could not find element with id 'normal'"); |
| IWebElement link = driver.FindElement(By.Id("normal")); |
| |
| new Actions(driver) |
| .MoveToElement(link, 1, 1) |
| .Click() |
| .Perform(); |
| |
| WaitFor(() => { return driver.Title == "XHTML Test Page"; }, "Browser title is not 'XHTML Test Page'"); |
| } |
| |
| [Test] |
| public void ClickAfterMoveToAnElementWithAnOffsetShouldUseLastMousePosition() |
| { |
| driver.Url = clickEventPage; |
| |
| IWebElement element = driver.FindElement(By.Id("eventish")); |
| Point location = element.Location; |
| Size size = element.Size; |
| |
| new Actions(driver) |
| .MoveToElement(element, 20 - size.Width / 2, 10 - size.Height / 2) |
| .Click() |
| .Perform(); |
| |
| WaitFor<IWebElement>(() => driver.FindElement(By.Id("pageX")), "Did not find element with ID pageX"); |
| |
| int x = Convert.ToInt16(Math.Round(Convert.ToDouble(driver.FindElement(By.Id("pageX")).Text))); |
| int y = Convert.ToInt16(Math.Round(Convert.ToDouble(driver.FindElement(By.Id("pageY")).Text))); |
| |
| Assert.That(FuzzyPositionMatching(location.X + 20, location.Y + 10, string.Format("{0},{1}", x, y)), Is.True); |
| } |
| |
| /** |
| * This test demonstrates the following problem: When the representation of |
| * the mouse in the driver keeps the wrong state, mouse movement will end |
| * up at the wrong coordinates. |
| */ |
| [Test] |
| public void MouseMovementWorksWhenNavigatingToAnotherPage() |
| { |
| NavigateToClicksPageAndClickLink(); |
| |
| IWebElement linkId = driver.FindElement(By.Id("linkId")); |
| new Actions(driver) |
| .MoveToElement(linkId, 1, 1) |
| .Click() |
| .Perform(); |
| |
| WaitFor(() => { return driver.Title == "We Arrive Here"; }, "Browser title is not 'We Arrive Here'"); |
| } |
| |
| [Test] |
| public void ChordControlCutAndPaste() |
| { |
| string controlModifier = Keys.Control; |
| if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) |
| { |
| controlModifier = Keys.Command; |
| } |
| |
| driver.Url = javascriptPage; |
| |
| IWebElement element = driver.FindElement(By.Id("keyReporter")); |
| |
| // Must scroll element into view for W3C-compliant drivers. |
| ((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].scrollIntoView()", element); |
| |
| new Actions(driver) |
| .SendKeys(element, "abc def") |
| .Perform(); |
| |
| Assert.That(element.GetAttribute("value"), Is.EqualTo("abc def")); |
| |
| //TODO: Figure out why calling sendKey(Key.CONTROL + "a") and then |
| //sendKeys("x") does not work on Linux. |
| new Actions(driver).KeyDown(controlModifier) |
| .SendKeys("a" + "x") |
| .Perform(); |
| |
| // Release keys before next step. |
| new Actions(driver).SendKeys(Keys.Null).Perform(); |
| |
| Assert.That(element.GetAttribute("value"), Is.Empty); |
| |
| new Actions(driver).KeyDown(controlModifier) |
| .SendKeys("v") |
| .SendKeys("v") |
| .Perform(); |
| |
| new Actions(driver).SendKeys(Keys.Null).Perform(); |
| |
| Assert.That(element.GetAttribute("value"), Is.EqualTo("abc defabc def")); |
| } |
| |
| [Test] |
| [IgnoreBrowser(Browser.IE, "Edge in IE Mode does not properly handle multiple windows")] |
| [NeedsFreshDriver(IsCreatedBeforeTest = true)] |
| public void CombiningShiftAndClickResultsInANewWindow() |
| { |
| driver.Url = linkedImage; |
| IWebElement link = driver.FindElement(By.Id("link")); |
| string originalTitle = driver.Title; |
| |
| new Actions(driver) |
| .MoveToElement(link) |
| .KeyDown(Keys.Shift) |
| .Click() |
| .KeyUp(Keys.Shift) |
| .Perform(); |
| WaitFor(() => { return driver.WindowHandles.Count > 1; }, "Did not receive new window"); |
| Assert.That(driver.WindowHandles, Has.Exactly(2).Items, "Should have opened a new window."); |
| Assert.That(driver.Title, Is.EqualTo(originalTitle), "Should not have navigated away."); |
| |
| string originalHandle = driver.CurrentWindowHandle; |
| foreach (string newHandle in driver.WindowHandles) |
| { |
| if (newHandle != originalHandle) |
| { |
| driver.SwitchTo().Window(newHandle); |
| driver.Close(); |
| } |
| } |
| |
| driver.SwitchTo().Window(originalHandle); |
| } |
| |
| [Test] |
| [IgnoreBrowser(Browser.IE, "Edge in IE Mode does not properly handle multiple windows")] |
| public void HoldingDownShiftKeyWhileClicking() |
| { |
| driver.Url = clickEventPage; |
| |
| IWebElement toClick = driver.FindElement(By.Id("eventish")); |
| |
| new Actions(driver).MoveToElement(toClick).KeyDown(Keys.Shift).Click().KeyUp(Keys.Shift).Perform(); |
| |
| IWebElement shiftInfo = WaitFor(() => { return driver.FindElement(By.Id("shiftKey")); }, "Could not find element with id 'shiftKey'"); |
| Assert.That(shiftInfo.Text, Is.EqualTo("true")); |
| } |
| |
| [Test] |
| public void CanClickOnSuckerFishStyleMenu() |
| { |
| driver.Url = javascriptPage; |
| |
| // Move to a different element to make sure the mouse is not over the |
| // element with id 'item1' (from a previous test). |
| new Actions(driver).MoveToElement(driver.FindElement(By.Id("dynamo"))).Build().Perform(); |
| |
| IWebElement element = driver.FindElement(By.Id("menu1")); |
| |
| IWebElement target = driver.FindElement(By.Id("item1")); |
| Assert.That(target.Text, Is.Empty); |
| ((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].style.background = 'green'", element); |
| new Actions(driver).MoveToElement(element).Build().Perform(); |
| |
| // Intentionally wait to make sure hover persists. |
| System.Threading.Thread.Sleep(2000); |
| |
| target.Click(); |
| |
| IWebElement result = driver.FindElement(By.Id("result")); |
| WaitFor(() => { return result.Text.Contains("item 1"); }, "Result element does not contain text 'item 1'"); |
| } |
| |
| [Test] |
| public void CanClickOnSuckerFishMenuItem() |
| { |
| driver.Url = javascriptPage; |
| |
| // Move to a different element to make sure the mouse is not over the |
| // element with id 'item1' (from a previous test). |
| new Actions(driver).MoveToElement(driver.FindElement(By.Id("dynamo"))).Build().Perform(); |
| |
| IWebElement element = driver.FindElement(By.Id("menu1")); |
| |
| new Actions(driver).MoveToElement(element).Build().Perform(); |
| |
| IWebElement target = driver.FindElement(By.Id("item1")); |
| |
| Assert.That(target.Displayed, "Target element was not displayed"); |
| target.Click(); |
| |
| IWebElement result = driver.FindElement(By.Id("result")); |
| WaitFor(() => { return result.Text.Contains("item 1"); }, "Result element does not contain text 'item 1'"); |
| } |
| |
| [Test] |
| public void PerformsPause() |
| { |
| DateTime start = DateTime.Now; |
| new Actions(driver).Pause(TimeSpan.FromMilliseconds(1200)).Build().Perform(); |
| Assert.That(DateTime.Now - start > TimeSpan.FromMilliseconds(1200), Is.True); |
| } |
| |
| [Test] |
| public void ShouldHandleClashingDeviceNamesGracefully() |
| { |
| var actionsWithPointer = new Actions(driver) |
| .SetActivePointer(PointerKind.Mouse, "test") |
| .Click(); |
| |
| Assert.That(() => |
| { |
| actionsWithPointer.SetActiveWheel("test"); |
| }, Throws.InvalidOperationException.With.Message.EqualTo("Device under the name \"test\" is not a wheel. Actual input type: Pointer")); |
| |
| var actionsWithKeyboard = new Actions(driver) |
| .SetActiveKeyboard("test") |
| .KeyDown(Keys.Shift).KeyUp(Keys.Shift); |
| |
| Assert.That(() => |
| { |
| actionsWithKeyboard.SetActivePointer(PointerKind.Pen, "test"); |
| }, Throws.InvalidOperationException.With.Message.EqualTo("Device under the name \"test\" is not a pointer. Actual input type: Key")); |
| |
| var actionsWithWheel = new Actions(driver) |
| .SetActiveWheel("test") |
| .ScrollByAmount(0, 0); |
| |
| Assert.That(() => |
| { |
| actionsWithWheel.SetActiveKeyboard("test"); |
| }, Throws.InvalidOperationException.With.Message.EqualTo("Device under the name \"test\" is not a keyboard. Actual input type: Wheel")); |
| } |
| |
| private bool FuzzyPositionMatching(int expectedX, int expectedY, string locationTuple) |
| { |
| string[] splitString = locationTuple.Split(','); |
| int gotX = int.Parse(splitString[0].Trim()); |
| int gotY = int.Parse(splitString[1].Trim()); |
| |
| // Everything within 5 pixels range is OK |
| const int ALLOWED_DEVIATION = 5; |
| return Math.Abs(expectedX - gotX) < ALLOWED_DEVIATION && Math.Abs(expectedY - gotY) < ALLOWED_DEVIATION; |
| } |
| |
| private void NavigateToClicksPageAndClickLink() |
| { |
| driver.Url = clicksPage; |
| |
| WaitFor(() => { return driver.FindElement(By.Id("normal")); }, "Could not find element with id 'normal'"); |
| IWebElement link = driver.FindElement(By.Id("normal")); |
| |
| new Actions(driver) |
| .Click(link) |
| .Perform(); |
| |
| WaitFor(() => { return driver.Title == "XHTML Test Page"; }, "Browser title is not 'XHTML Test Page'"); |
| } |
| } |