Path: blob/trunk/dotnet/test/common/Interactions/BasicMouseInterfaceTest.cs
2868 views
// <copyright file="BasicMouseInterfaceTest.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.Drawing; namespace OpenQA.Selenium.Interactions; [TestFixture] public class BasicMouseInterfaceTest : DriverTestFixture { [SetUp] public void SetupTest() { IActionExecutor actionExecutor = driver as IActionExecutor; if (actionExecutor != null) { actionExecutor.ResetInputState(); } } [Test] public void ShouldSetActivePointer() { Actions actionProvider = new Actions(driver); actionProvider.SetActivePointer(PointerKind.Mouse, "test mouse"); PointerInputDevice device = actionProvider.GetActivePointer(); Assert.That(device.DeviceName, Is.EqualTo("test mouse")); } [Test] public void ShouldAllowDraggingElementWithMouseMovesItToAnotherList() { PerformDragAndDropWithMouse(); IWebElement dragInto = driver.FindElement(By.Id("sortable1")); Assert.That(dragInto.FindElements(By.TagName("li")), Has.Exactly(6).Items); } // This test is very similar to DraggingElementWithMouse. The only // difference is that this test also verifies the correct events were fired. [Test] public void DraggingElementWithMouseFiresEvents() { PerformDragAndDropWithMouse(); IWebElement dragReporter = driver.FindElement(By.Id("dragging_reports")); // This is failing under HtmlUnit. A bug was filed. Assert.That(dragReporter.Text, Does.Match("Nothing happened\\. (?:DragOut *)+DropIn RightItem 3")); } [Test] public void ShouldAllowDoubleClickThenNavigate() { driver.Url = javascriptPage; IWebElement toDoubleClick = driver.FindElement(By.Id("doubleClickField")); Actions actionProvider = new Actions(driver); IAction dblClick = actionProvider.DoubleClick(toDoubleClick).Build(); dblClick.Perform(); driver.Url = droppableItems; } [Test] public void ShouldAllowDragAndDrop() { driver.Url = droppableItems; DateTime waitEndTime = DateTime.Now.Add(TimeSpan.FromSeconds(15)); while (!IsElementAvailable(driver, By.Id("draggable")) && (DateTime.Now < waitEndTime)) { System.Threading.Thread.Sleep(200); } if (!IsElementAvailable(driver, By.Id("draggable"))) { throw new Exception("Could not find draggable element after 15 seconds."); } IWebElement toDrag = driver.FindElement(By.Id("draggable")); IWebElement dropInto = driver.FindElement(By.Id("droppable")); Actions actionProvider = new Actions(driver); IAction holdDrag = actionProvider.ClickAndHold(toDrag).Build(); IAction move = actionProvider.MoveToElement(dropInto).Build(); IAction drop = actionProvider.Release(dropInto).Build(); holdDrag.Perform(); move.Perform(); drop.Perform(); dropInto = driver.FindElement(By.Id("droppable")); string text = dropInto.FindElement(By.TagName("p")).Text; Assert.That(text, Is.EqualTo("Dropped!")); } [Test] public void ShouldAllowDoubleClick() { driver.Url = javascriptPage; IWebElement toDoubleClick = driver.FindElement(By.Id("doubleClickField")); Actions actionProvider = new Actions(driver); IAction dblClick = actionProvider.DoubleClick(toDoubleClick).Build(); dblClick.Perform(); Assert.That(toDoubleClick.GetAttribute("value"), Is.EqualTo("DoubleClicked")); } [Test] public void ShouldAllowContextClick() { driver.Url = javascriptPage; IWebElement toContextClick = driver.FindElement(By.Id("doubleClickField")); Actions actionProvider = new Actions(driver); IAction contextClick = actionProvider.ContextClick(toContextClick).Build(); contextClick.Perform(); Assert.That(toContextClick.GetAttribute("value"), Is.EqualTo("ContextClicked")); } [Test] [IgnoreBrowser(Browser.Remote, "API not implemented in driver")] public void ShouldAllowMoveAndClick() { driver.Url = javascriptPage; IWebElement toClick = driver.FindElement(By.Id("clickField")); Actions actionProvider = new Actions(driver); IAction contextClick = actionProvider.MoveToElement(toClick).Click().Build(); contextClick.Perform(); Assert.That(toClick.GetAttribute("value"), Is.EqualTo("Clicked"), "Value should change to Clicked."); } [Test] [IgnoreBrowser(Browser.Chrome, "Not working properly in RBE, works locally with pinned browsers")] [IgnoreBrowser(Browser.Edge, "Not working properly in RBE, works locally with pinned browsers")] [IgnoreBrowser(Browser.Firefox, "Not working properly in RBE, works locally with pinned browsers")] public void ShouldMoveToLocation() { driver.Url = mouseInteractionPage; Actions actionProvider = new Actions(driver); actionProvider.MoveToLocation(100, 200).Build().Perform(); IWebElement location = driver.FindElement(By.Id("absolute-location")); var coordinates = location.Text.Split(','); Assert.That(coordinates[0].Trim(), Is.EqualTo("100")); Assert.That(coordinates[1].Trim(), Is.EqualTo("200")); } [Test] public void ShouldNotMoveToANullLocator() { driver.Url = javascriptPage; Assert.That(() => new Actions(driver).MoveToElement(null).Perform(), Throws.InstanceOf<ArgumentException>()); } [Test] [IgnoreBrowser(Browser.Chrome, "Drivers correctly click at current mouse position without another move, preserving mouse position.")] [IgnoreBrowser(Browser.Edge, "Drivers correctly click at current mouse position without another move, preserving mouse position.")] [IgnoreBrowser(Browser.Firefox, "Drivers correctly click at current mouse position without another move, preserving mouse position.")] [IgnoreBrowser(Browser.IE, "Drivers correctly click at current mouse position without another move, preserving mouse position.")] [IgnoreBrowser(Browser.Safari, "Drivers correctly click at current mouse position without another move, preserving mouse position.")] public void MousePositionIsNotPreservedInActionsChain() { driver.Url = javascriptPage; IWebElement toMoveTo = driver.FindElement(By.Id("clickField")); new Actions(driver).MoveToElement(toMoveTo).Perform(); Assert.That(() => new Actions(driver).Click().Perform(), Throws.InstanceOf<WebDriverException>()); } [Test] [IgnoreBrowser(Browser.All, "Behaviour not finalized yet regarding linked images.")] public void MovingIntoAnImageEnclosedInALink() { driver.Url = linkedImage; // Note: For some reason, the Accessibility API in Firefox will not be available before we // click on something. As a work-around, click on a different element just to get going. driver.FindElement(By.Id("linkToAnchorOnThisPage")).Click(); IWebElement linkElement = driver.FindElement(By.Id("linkWithEnclosedImage")); // Image is 644 x 41 - move towards the end. // Note: The width of the link element itself is correct - 644 pixels. However, // the height is 17 pixels and the rectangle containing it is *underneath* the image. // For this reason, this action will fail. new Actions(driver).MoveToElement(linkElement, 500, 30).Click().Perform(); WaitFor(TitleToBe("We Arrive Here"), "Title was not expected value"); } [Test] [IgnoreBrowser(Browser.Chrome, "Moving outside of view port throws exception in spec-compliant driver")] [IgnoreBrowser(Browser.Edge, "Moving outside of view port throws exception in spec-compliant driver")] [IgnoreBrowser(Browser.Firefox, "Moving outside of view port throws exception in spec-compliant driver")] [IgnoreBrowser(Browser.IE, "Moving outside of view port throws exception in spec-compliant driver")] [IgnoreBrowser(Browser.Safari, "Moving outside of view port throws exception in spec-compliant driver")] public void MovingMouseBackAndForthPastViewPort() { driver.Url = EnvironmentManager.Instance.UrlBuilder.WhereIs("veryLargeCanvas.html"); IWebElement firstTarget = driver.FindElement(By.Id("r1")); new Actions(driver).MoveToElement(firstTarget).Click().Perform(); IWebElement resultArea = driver.FindElement(By.Id("result")); String expectedEvents = "First"; WaitFor(ElementTextToEqual(resultArea, expectedEvents), "Element text did not equal " + expectedEvents); // Move to element with id 'r2', at (2500, 50) to (2580, 100) new Actions(driver).MoveByOffset(2540 - 150, 75 - 125).Click().Perform(); expectedEvents += " Second"; WaitFor(ElementTextToEqual(resultArea, expectedEvents), "Element text did not equal " + expectedEvents); // Move to element with id 'r3' at (60, 1500) to (140, 1550) new Actions(driver).MoveByOffset(100 - 2540, 1525 - 75).Click().Perform(); expectedEvents += " Third"; WaitFor(ElementTextToEqual(resultArea, expectedEvents), "Element text did not equal " + expectedEvents); // Move to element with id 'r4' at (220,180) to (320, 230) new Actions(driver).MoveByOffset(270 - 100, 205 - 1525).Click().Perform(); expectedEvents += " Fourth"; WaitFor(ElementTextToEqual(resultArea, expectedEvents), "Element text did not equal " + expectedEvents); } [Test] public void ShouldClickElementInIFrame() { driver.Url = clicksPage; try { driver.SwitchTo().Frame("source"); IWebElement element = driver.FindElement(By.Id("otherframe")); new Actions(driver).MoveToElement(element).Click().Perform(); driver.SwitchTo().DefaultContent().SwitchTo().Frame("target"); WaitFor(() => { return driver.FindElement(By.Id("span")).Text == "An inline element"; }, "Could not find element with text 'An inline element'"); } finally { driver.SwitchTo().DefaultContent(); } } [Test] public void ShouldAllowUsersToHoverOverElements() { driver.Url = javascriptPage; IWebElement element = driver.FindElement(By.Id("menu1")); IWebElement item = driver.FindElement(By.Id("item1")); Assert.That(item.Text, Is.EqualTo("")); ((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].style.background = 'green'", element); Actions actionBuilder = new Actions(driver); actionBuilder.MoveToElement(element).Perform(); item = driver.FindElement(By.Id("item1")); Assert.That(item.Text, Is.EqualTo("Item 1")); } [Test] public void HoverPersists() { 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"))).Perform(); IWebElement element = driver.FindElement(By.Id("menu1")); IWebElement item = driver.FindElement(By.Id("item1")); Assert.That(item.Text, Is.Empty); ((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].style.background = 'green'", element); new Actions(driver).MoveToElement(element).Perform(); // Intentionally wait to make sure hover persists. System.Threading.Thread.Sleep(2000); WaitFor(ElementTextToNotEqual(item, ""), "Element text was empty after timeout"); Assert.That(item.Text, Is.EqualTo("Item 1")); } [Test] public void MovingMouseByRelativeOffset() { driver.Url = mouseTrackerPage; IWebElement trackerDiv = driver.FindElement(By.Id("mousetracker")); new Actions(driver).MoveToElement(trackerDiv).Build().Perform(); IWebElement reporter = driver.FindElement(By.Id("status")); WaitFor(FuzzyMatchingOfCoordinates(reporter, 50, 200), "Coordinate matching was not within tolerance"); new Actions(driver).MoveByOffset(10, 20).Build().Perform(); WaitFor(FuzzyMatchingOfCoordinates(reporter, 60, 220), "Coordinate matching was not within tolerance"); } [Test] public void MovingMouseToRelativeElementOffset() { driver.Url = mouseTrackerPage; IWebElement trackerDiv = driver.FindElement(By.Id("mousetracker")); Size size = trackerDiv.Size; new Actions(driver).MoveToElement(trackerDiv, 95 - size.Width / 2, 195 - size.Height / 2).Build().Perform(); IWebElement reporter = driver.FindElement(By.Id("status")); WaitFor(FuzzyMatchingOfCoordinates(reporter, 95, 195), "Coordinate matching was not within tolerance"); } [Test] public void MovingMouseToRelativeZeroElementOffset() { driver.Url = mouseTrackerPage; IWebElement trackerDiv = driver.FindElement(By.Id("mousetracker")); Size size = trackerDiv.Size; new Actions(driver).MoveToElement(trackerDiv, -size.Width / 2, -size.Height / 2).Perform(); IWebElement reporter = driver.FindElement(By.Id("status")); WaitFor(FuzzyMatchingOfCoordinates(reporter, 0, 0), "Coordinate matching was not within tolerance"); } [Test] [NeedsFreshDriver(IsCreatedBeforeTest = true)] public void MoveRelativeToBody() { driver.Url = mouseTrackerPage; new Actions(driver).MoveByOffset(50, 100).Build().Perform(); IWebElement reporter = driver.FindElement(By.Id("status")); WaitFor(FuzzyMatchingOfCoordinates(reporter, 40, 20), "Coordinate matching was not within tolerance"); } [Test] public void MoveMouseByOffsetOverAndOutOfAnElement() { driver.Url = mouseOverPage; IWebElement greenbox = driver.FindElement(By.Id("greenbox")); IWebElement redbox = driver.FindElement(By.Id("redbox")); Point greenboxPosition = greenbox.Location; Point redboxPosition = redbox.Location; int shiftX = redboxPosition.X - greenboxPosition.X; int shiftY = redboxPosition.Y - greenboxPosition.Y; Size greenBoxSize = greenbox.Size; int xOffset = 2 - greenBoxSize.Width / 2; int yOffset = 2 - greenBoxSize.Height / 2; new Actions(driver).MoveToElement(greenbox, xOffset, yOffset).Perform(); WaitFor(ElementColorToBe(redbox, Color.Green), "element color was not green"); new Actions(driver).MoveToElement(greenbox, xOffset, yOffset).MoveByOffset(shiftX, shiftY).Perform(); WaitFor(ElementColorToBe(redbox, Color.Red), "element color was not red"); new Actions(driver).MoveToElement(greenbox, xOffset, yOffset).MoveByOffset(shiftX, shiftY).MoveByOffset(-shiftX, -shiftY).Perform(); WaitFor(ElementColorToBe(redbox, Color.Green), "element color was not red"); } [Test] public void CanMouseOverAndOutOfAnElement() { driver.Url = mouseOverPage; IWebElement greenbox = driver.FindElement(By.Id("greenbox")); IWebElement redbox = driver.FindElement(By.Id("redbox")); Size greenSize = greenbox.Size; Size redSize = redbox.Size; new Actions(driver).MoveToElement(greenbox, 1 - greenSize.Width / 2, 1 - greenSize.Height / 2).Perform(); Assert.That(redbox.GetCssValue("background-color"), Is.EqualTo("rgba(0, 128, 0, 1)").Or.EqualTo("rgb(0, 128, 0)")); new Actions(driver).MoveToElement(redbox).Perform(); Assert.That(redbox.GetCssValue("background-color"), Is.EqualTo("rgba(255, 0, 0, 1)").Or.EqualTo("rgb(255, 0, 0)")); new Actions(driver).MoveToElement(redbox, redSize.Width / 2 + 2, redSize.Height / 2 + 2).Perform(); Assert.That(redbox.GetCssValue("background-color"), Is.EqualTo("rgba(0, 128, 0, 1)").Or.EqualTo("rgb(0, 128, 0)")); } private Func<bool> FuzzyMatchingOfCoordinates(IWebElement element, int x, int y) { return () => { return FuzzyPositionMatching(x, y, element.Text); }; } private bool FuzzyPositionMatching(int expectedX, int expectedY, String locationTuple) { string[] splitString = locationTuple.Split(','); int gotX = Convert.ToInt16(Math.Round(Convert.ToDouble(splitString[0].Trim()))); int gotY = Convert.ToInt16(Math.Round(Convert.ToDouble(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 PerformDragAndDropWithMouse() { driver.Url = draggableLists; IWebElement dragReporter = driver.FindElement(By.Id("dragging_reports")); IWebElement toDrag = driver.FindElement(By.Id("rightitem-3")); IWebElement dragInto = driver.FindElement(By.Id("sortable1")); IAction holdItem = new Actions(driver).ClickAndHold(toDrag).Build(); IAction moveToSpecificItem = new Actions(driver).MoveToElement(driver.FindElement(By.Id("leftitem-4"))).Build(); IAction moveToOtherList = new Actions(driver).MoveToElement(dragInto).Build(); IAction drop = new Actions(driver).Release(dragInto).Build(); Assert.That(dragReporter.Text, Is.EqualTo("Nothing happened.")); holdItem.Perform(); moveToSpecificItem.Perform(); moveToOtherList.Perform(); Assert.That(dragReporter.Text, Does.Match("Nothing happened\\. (?:DragOut *)+")); drop.Perform(); } private bool IsElementAvailable(IWebDriver driver, By locator) { try { driver.FindElement(locator); return true; } catch (NoSuchElementException) { return false; } } private Func<bool> TitleToBe(string desiredTitle) { return () => driver.Title == desiredTitle; } private Func<bool> ValueToBe(IWebElement element, string desiredValue) { return () => element.GetDomProperty("value") == desiredValue; } private Func<bool> ElementTextToEqual(IWebElement element, string text) { return () => element.Text == text; } private Func<bool> ElementTextToNotEqual(IWebElement element, string text) { return () => element.Text != text; } private Func<bool> ElementColorToBe(IWebElement element, Color color) { return () => { string rgb = string.Format("rgb({0}, {1}, {2})", color.R, color.G, color.B); string rgba = string.Format("rgba({0}, {1}, {2}, 1)", color.R, color.G, color.B); string value = element.GetCssValue("background-color"); return value == rgb || value == rgba; }; } }