Sometimes you’ll run into an app that has functionality hidden behind a right-click menu (a.k.a. a context menu). These menus tend to be system-level menus that are untouchable by Selenium. So how do you test this functionality?
By leveraging Selenium’s Action Builder we can issue a right-click command (a.k.a. a contextClick
).
We can then select an option from the menu by traversing it with keyboard arrow keys (which we can issue with the Action Builder’s sendKeys
command).
Example
Java
// filename: RightClick.java
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
public class RightClick {
WebDriver driver;
@Before
public void setUp() throws Exception {
driver = new FirefoxDriver();
}
@After
public void tearDown() throws Exception {
driver.quit();
}
@Test
public void rightClickTest() throws InterruptedException {
driver.get("http://the-internet.herokuapp.com/context_menu");
WebElement menu = driver.findElement(By.id("hot-spot"));
Actions action = new Actions(driver);
action.contextClick(menu)
.sendKeys(Keys.ARROW_DOWN)
.sendKeys(Keys.ARROW_DOWN)
.sendKeys(Keys.ARROW_DOWN)
.sendKeys(Keys.ENTER)
.perform();
Alert alert = driver.switchTo().alert();
assertThat(alert.getText(), is(equalTo("You selected a context menu")));
}
}
Python
# filename: right_click.py
import unittest
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
class RightClick(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
def tearDown(self):
self.driver.quit()
def test_example_1(self):
driver = self.driver
driver.get('http://the-internet.herokuapp.com/context_menu')
menu_area = driver.find_element_by_id('hot-spot')
ActionChains(driver).context_click(
menu_area).send_keys(
Keys.ARROW_DOWN).send_keys(
Keys.ARROW_DOWN).send_keys(
Keys.ARROW_DOWN).send_keys(
Keys.ENTER).perform()
alert = driver.switch_to.alert
assert alert.text == 'You selected a context menu'
if __name__ == "__main__":
unittest.main()
Ruby
# filename: right_click.rb
require 'selenium-webdriver'
require 'rspec-expectations'
include RSpec::Matchers
def setup
@driver = Selenium::WebDriver.for :firefox
end
def teardown
@driver.quit
end
def run
setup
yield
teardown
end
run do
@driver.get 'http://the-internet.herokuapp.com/context_menu'
menu_area = @driver.find_element id: 'hot-spot'
@driver.action.context_click(menu_area).send_keys(
:arrow_down).send_keys(
:arrow_down).send_keys(
:arrow_down).send_keys(
:enter).perform
alert = @driver.switch_to.alert
expect(alert.text).to eq('You selected a context menu')
end
C#
// filename: RightClick.cs
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Interactions;
public class RightClick
{
IWebDriver Driver;
[SetUp]
public void SetUp()
{
Driver = new FirefoxDriver();
}
[TearDown]
public void TearDown()
{
Driver.Quit();
}
[Test]
public void RightClickExample()
{
Driver.Navigate().GoToUrl("http://the-internet.herokuapp.com/context_menu");
IWebElement MenuArea = Driver.FindElement(By.Id("hot-spot"));
Actions Builder = new Actions(Driver);
Builder.ContextClick(MenuArea)
.SendKeys(Keys.ArrowDown)
.SendKeys(Keys.ArrowDown)
.SendKeys(Keys.ArrowDown)
.SendKeys(Keys.ArrowDown)
.SendKeys(Keys.ArrowDown)
.SendKeys(Keys.Enter)
.Perform();
IAlert Alert = Driver.SwitchTo().Alert();
Assert.That(Alert.Text.Equals("You selected a context menu"));
}
}
When you save this file and run it here is what will happen:
- Open the browser
- Visit the page
- Find and right-click the area of the page that renders a custom context menu
- Navigate to the context menu option with keyboard keys
- JavaScript alert appears
- Grab the text of the JavaScript alert
- Assert that the text from the alert is what we expect
- Close the browser