blob: 0a1769125706b0b7ccc44fb88e7080bdabb353c5 [file] [log] [blame] [edit]
// <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;
};
}
}