Actions接口

用于向 Web 浏览器提供虚拟化设备输入操作的低级接口.

除了高级元素交互之外, Actions 接口 还提供了对指定输入设备 可以执行的确切操作的精细控制. Selenium为3种输入源提供了接口: 键盘设备的键输入, 鼠标, 笔或触摸设备的输入, 以及滚轮设备的滚轮输入 (在Selenium 4.2中引入). Selenium允许您构建分配给特定输入的独立操作命令, 会将他们链接在一起, 并调用关联的执行方法以一次执行它们.

Action构造器

在从遗留JSON Wire协议迁移到 新的W3C WebDriver协议的过程中, 低级的操作构建块变得特别详细. 它非常强大, 但每个输入设备都有多种使用方法, 如果您需要管理多个设备, 则负责确保他们之间的同步正确.

值得庆幸的是, 您可能不需要学习如何直接使用低级命令, 因为您可能要执行的几乎所有操作, 都已提供了相应的简便方法, 这些方法可以为您组合较低级别的命令. 请分别参阅相应的键盘, 鼠标, 滚轮 页面.

暂停

指针移动和滚轮滚动 允许用户设置操作的持续时间, 但有时您只需要在操作之间等待一下, 即可正常工作.

        WebElement clickable = driver.findElement(By.id("clickable"));
        new Actions(driver)
                .moveToElement(clickable)
                .pause(Duration.ofSeconds(1))
                .clickAndHold()
                .pause(Duration.ofSeconds(1))
                .sendKeys("abc")
                .perform();
Show full example
package dev.selenium.actions_api;

import dev.selenium.BaseChromeTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.RemoteWebDriver;

import java.time.Duration;

public class ActionsTest extends BaseChromeTest {
    @Test
    public void pause() {
        driver.get("https://www.selenium.dev/selenium/web/mouse_interaction.html");

        long start = System.currentTimeMillis();

        WebElement clickable = driver.findElement(By.id("clickable"));
        new Actions(driver)
                .moveToElement(clickable)
                .pause(Duration.ofSeconds(1))
                .clickAndHold()
                .pause(Duration.ofSeconds(1))
                .sendKeys("abc")
                .perform();

        long duration = System.currentTimeMillis() - start;
        Assertions.assertTrue(duration > 2000);
        Assertions.assertTrue(duration < 3000);
    }

    @Test
    public void releasesAll() {
        driver.get("https://www.selenium.dev/selenium/web/mouse_interaction.html");

        WebElement clickable = driver.findElement(By.id("clickable"));
        Actions actions = new Actions(driver);
        actions.clickAndHold(clickable)
                .keyDown(Keys.SHIFT)
                .sendKeys("a")
                .perform();

        ((RemoteWebDriver) driver).resetInputState();

        actions.sendKeys("a").perform();
        Assertions.assertEquals("A", String.valueOf(clickable.getAttribute("value").charAt(0)));
        Assertions.assertEquals("a", String.valueOf(clickable.getAttribute("value").charAt(1)));
    }
}
    clickable = driver.find_element(By.ID, "clickable")
    ActionChains(driver)\
        .move_to_element(clickable)\
        .pause(1)\
        .click_and_hold()\
        .pause(1)\
        .send_keys("abc")\
        .perform()
Show full example
from time import time

from selenium.webdriver import Keys, ActionChains
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.by import By


def test_pauses(driver):
    driver.get('https://selenium.dev/selenium/web/mouse_interaction.html')

    start = time()

    clickable = driver.find_element(By.ID, "clickable")
    ActionChains(driver)\
        .move_to_element(clickable)\
        .pause(1)\
        .click_and_hold()\
        .pause(1)\
        .send_keys("abc")\
        .perform()

    duration = time() - start
    assert duration > 2
    assert duration < 3


def test_releases_all(driver):
    driver.get('https://selenium.dev/selenium/web/mouse_interaction.html')

    clickable = driver.find_element(By.ID, "clickable")
    ActionChains(driver)\
        .click_and_hold(clickable)\
        .key_down(Keys.SHIFT)\
        .key_down("a")\
        .perform()

    ActionBuilder(driver).clear_actions()

    ActionChains(driver).key_down('a').perform()

    assert clickable.get_attribute('value')[0] == "A"
    assert clickable.get_attribute('value')[1] == "a"

Selenium v4.2

            IWebElement clickable = driver.FindElement(By.Id("clickable"));
            new Actions(driver)
                .MoveToElement(clickable)
                .Pause(TimeSpan.FromSeconds(1))
                .ClickAndHold()
                .Pause(TimeSpan.FromSeconds(1))
                .SendKeys("abc")
                .Perform();
Show full example
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Interactions;

namespace SeleniumDocs.ActionsAPI
{
    [TestClass]
    public class ActionsTest : BaseChromeTest
    {
        [TestMethod]
        public void Pause()
        {
            driver.Url = "https://selenium.dev/selenium/web/mouse_interaction.html";

            DateTime start = DateTime.Now;

            IWebElement clickable = driver.FindElement(By.Id("clickable"));
            new Actions(driver)
                .MoveToElement(clickable)
                .Pause(TimeSpan.FromSeconds(1))
                .ClickAndHold()
                .Pause(TimeSpan.FromSeconds(1))
                .SendKeys("abc")
                .Perform();

            TimeSpan duration = DateTime.Now - start;
            Assert.IsTrue(duration > TimeSpan.FromSeconds(2));
            Assert.IsTrue(duration < TimeSpan.FromSeconds(3));
        }

        [TestMethod]
        public void ReleaseAll()
        {
            driver.Url = "https://selenium.dev/selenium/web/mouse_interaction.html";
            
            IWebElement clickable = driver.FindElement(By.Id("clickable"));
            var actions = new Actions(driver);
            actions.ClickAndHold(clickable)
                .KeyDown(Keys.Shift)
                .SendKeys("a")
                .Perform();

            ((WebDriver)driver).ResetInputState();

            actions.SendKeys("a").Perform();
            var value = clickable.GetAttribute("value");
            Assert.AreEqual("A", value[..1]);
            Assert.AreEqual("a", value.Substring(1, 1));
        }
    }
}

Selenium v4.2

    clickable = driver.find_element(id: 'clickable')
    driver.action
          .move_to(clickable)
          .pause(duration: 1)
          .click_and_hold
          .pause(duration: 1)
          .send_keys('abc')
          .perform
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Actions' do
  let(:driver) { start_session }

  it 'pauses' do
    driver.get 'https://www.selenium.dev/selenium/web/mouse_interaction.html'
    start = Time.now

    clickable = driver.find_element(id: 'clickable')
    driver.action
          .move_to(clickable)
          .pause(duration: 1)
          .click_and_hold
          .pause(duration: 1)
          .send_keys('abc')
          .perform

    duration = Time.now - start
    expect(duration).to be > 2
    expect(duration).to be < 3
  end

  it 'releases all' do
    driver.get 'https://www.selenium.dev/selenium/web/mouse_interaction.html'

    clickable = driver.find_element(id: 'clickable')
    action = driver.action
                   .click_and_hold(clickable)
                   .key_down(:shift)
                   .key_down('a')
    action.perform

    driver.action.release_actions

    action.key_down('a').perform
    expect(clickable.attribute('value')[0]).to eq 'A'
    expect(clickable.attribute('value')[-1]).to eq 'a'
  end
end
    const clickable = await driver.findElement(By.id('clickable'))
    await driver.actions()
      .move({ origin: clickable })
      .pause(1000)
      .press()
      .pause(1000)
      .sendKeys('abc')
      .perform()
Show full example
const { By, Key, Browser, Builder} = require('selenium-webdriver')
const assert = require('assert')

describe('Actions API - Pause and Release All Actions', function() {
  let driver

  before(async function() {
    driver = await new Builder().forBrowser('chrome').build();
  })

  after(async () => await driver.quit())

  it('Pause', async function() {
    await driver.get('https://selenium.dev/selenium/web/mouse_interaction.html')

    const start = Date.now()

    const clickable = await driver.findElement(By.id('clickable'))
    await driver.actions()
      .move({ origin: clickable })
      .pause(1000)
      .press()
      .pause(1000)
      .sendKeys('abc')
      .perform()

    const end = Date.now() - start
    assert.ok(end > 2000)
    assert.ok(end < 4000)
  })

  it('Clear', async function() {
    await driver.get('https://selenium.dev/selenium/web/mouse_interaction.html')

    const clickable = driver.findElement(By.id('clickable'))
    await driver.actions()
      .click(clickable)
      .keyDown(Key.SHIFT)
      .sendKeys('a')
      .perform()

    await driver.actions().clear()
    await driver.actions().sendKeys('a').perform()

    const value = await clickable.getAttribute('value')
    assert.deepStrictEqual('A', value.substring(0, 1))
    assert.deepStrictEqual('a', value.substring(1, 2))
  })
})
        val clickable = driver.findElement(By.id("clickable"))
        Actions(driver)
            .moveToElement(clickable)
            .pause(Duration.ofSeconds(1))
            .clickAndHold()
            .pause(Duration.ofSeconds(1))
            .sendKeys("abc")
            .perform() 
Show full example
package dev.selenium.actions_api

import dev.selenium.BaseTest
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.openqa.selenium.By
import org.openqa.selenium.Keys
import org.openqa.selenium.WebElement
import org.openqa.selenium.interactions.Actions
import org.openqa.selenium.remote.RemoteWebDriver

import java.time.Duration

class ActionsTest : BaseTest() {

    @Test
    fun pause() {
        driver.get("https://www.selenium.dev/selenium/web/mouse_interaction.html")

        val start = System.currentTimeMillis()

        val clickable = driver.findElement(By.id("clickable"))
        Actions(driver)
            .moveToElement(clickable)
            .pause(Duration.ofSeconds(1))
            .clickAndHold()
            .pause(Duration.ofSeconds(1))
            .sendKeys("abc")
            .perform() 

        val duration = System.currentTimeMillis() - start
        Assertions.assertTrue(duration > 2000)
        Assertions.assertTrue(duration < 4000)
    }

    @Test
    fun releasesAll() {
        driver.get("https://www.selenium.dev/selenium/web/mouse_interaction.html")

        val clickable = driver.findElement(By.id("clickable"))
        val actions = Actions(driver)
        actions.clickAndHold(clickable)
                .keyDown(Keys.SHIFT)
                .sendKeys("a")
                .perform()

        (driver as RemoteWebDriver).resetInputState()

        actions.sendKeys("a").perform()
        Assertions.assertEquals("A", clickable.getAttribute("value")!!.get(0).toString())
        Assertions.assertEquals("a", clickable.getAttribute("value")!!.get(1).toString())
    }
}

释放所有Actions

需要注意的重要一点是, 驱动程序会记住整个会话中所有输入项的状态. 即使创建actions类的新实例, 按下的键和指针的位置 也将处于以前执行的操作离开它们的任何状态.

有一种特殊的方法来释放所有当前按下的键和指针按钮. 此方法在每种语言中的实现方式不同, 因为它不会使用perform方法执行.

        ((RemoteWebDriver) driver).resetInputState();
Show full example
package dev.selenium.actions_api;

import dev.selenium.BaseChromeTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.RemoteWebDriver;

import java.time.Duration;

public class ActionsTest extends BaseChromeTest {
    @Test
    public void pause() {
        driver.get("https://www.selenium.dev/selenium/web/mouse_interaction.html");

        long start = System.currentTimeMillis();

        WebElement clickable = driver.findElement(By.id("clickable"));
        new Actions(driver)
                .moveToElement(clickable)
                .pause(Duration.ofSeconds(1))
                .clickAndHold()
                .pause(Duration.ofSeconds(1))
                .sendKeys("abc")
                .perform();

        long duration = System.currentTimeMillis() - start;
        Assertions.assertTrue(duration > 2000);
        Assertions.assertTrue(duration < 3000);
    }

    @Test
    public void releasesAll() {
        driver.get("https://www.selenium.dev/selenium/web/mouse_interaction.html");

        WebElement clickable = driver.findElement(By.id("clickable"));
        Actions actions = new Actions(driver);
        actions.clickAndHold(clickable)
                .keyDown(Keys.SHIFT)
                .sendKeys("a")
                .perform();

        ((RemoteWebDriver) driver).resetInputState();

        actions.sendKeys("a").perform();
        Assertions.assertEquals("A", String.valueOf(clickable.getAttribute("value").charAt(0)));
        Assertions.assertEquals("a", String.valueOf(clickable.getAttribute("value").charAt(1)));
    }
}
    ActionBuilder(driver).clear_actions()
Show full example
from time import time

from selenium.webdriver import Keys, ActionChains
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.by import By


def test_pauses(driver):
    driver.get('https://selenium.dev/selenium/web/mouse_interaction.html')

    start = time()

    clickable = driver.find_element(By.ID, "clickable")
    ActionChains(driver)\
        .move_to_element(clickable)\
        .pause(1)\
        .click_and_hold()\
        .pause(1)\
        .send_keys("abc")\
        .perform()

    duration = time() - start
    assert duration > 2
    assert duration < 3


def test_releases_all(driver):
    driver.get('https://selenium.dev/selenium/web/mouse_interaction.html')

    clickable = driver.find_element(By.ID, "clickable")
    ActionChains(driver)\
        .click_and_hold(clickable)\
        .key_down(Keys.SHIFT)\
        .key_down("a")\
        .perform()

    ActionBuilder(driver).clear_actions()

    ActionChains(driver).key_down('a').perform()

    assert clickable.get_attribute('value')[0] == "A"
    assert clickable.get_attribute('value')[1] == "a"
            ((WebDriver)driver).ResetInputState();
Show full example
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Interactions;

namespace SeleniumDocs.ActionsAPI
{
    [TestClass]
    public class ActionsTest : BaseChromeTest
    {
        [TestMethod]
        public void Pause()
        {
            driver.Url = "https://selenium.dev/selenium/web/mouse_interaction.html";

            DateTime start = DateTime.Now;

            IWebElement clickable = driver.FindElement(By.Id("clickable"));
            new Actions(driver)
                .MoveToElement(clickable)
                .Pause(TimeSpan.FromSeconds(1))
                .ClickAndHold()
                .Pause(TimeSpan.FromSeconds(1))
                .SendKeys("abc")
                .Perform();

            TimeSpan duration = DateTime.Now - start;
            Assert.IsTrue(duration > TimeSpan.FromSeconds(2));
            Assert.IsTrue(duration < TimeSpan.FromSeconds(3));
        }

        [TestMethod]
        public void ReleaseAll()
        {
            driver.Url = "https://selenium.dev/selenium/web/mouse_interaction.html";
            
            IWebElement clickable = driver.FindElement(By.Id("clickable"));
            var actions = new Actions(driver);
            actions.ClickAndHold(clickable)
                .KeyDown(Keys.Shift)
                .SendKeys("a")
                .Perform();

            ((WebDriver)driver).ResetInputState();

            actions.SendKeys("a").Perform();
            var value = clickable.GetAttribute("value");
            Assert.AreEqual("A", value[..1]);
            Assert.AreEqual("a", value.Substring(1, 1));
        }
    }
}
    driver.action.release_actions
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Actions' do
  let(:driver) { start_session }

  it 'pauses' do
    driver.get 'https://www.selenium.dev/selenium/web/mouse_interaction.html'
    start = Time.now

    clickable = driver.find_element(id: 'clickable')
    driver.action
          .move_to(clickable)
          .pause(duration: 1)
          .click_and_hold
          .pause(duration: 1)
          .send_keys('abc')
          .perform

    duration = Time.now - start
    expect(duration).to be > 2
    expect(duration).to be < 3
  end

  it 'releases all' do
    driver.get 'https://www.selenium.dev/selenium/web/mouse_interaction.html'

    clickable = driver.find_element(id: 'clickable')
    action = driver.action
                   .click_and_hold(clickable)
                   .key_down(:shift)
                   .key_down('a')
    action.perform

    driver.action.release_actions

    action.key_down('a').perform
    expect(clickable.attribute('value')[0]).to eq 'A'
    expect(clickable.attribute('value')[-1]).to eq 'a'
  end
end
    await driver.actions().clear()
Show full example
const { By, Key, Browser, Builder} = require('selenium-webdriver')
const assert = require('assert')

describe('Actions API - Pause and Release All Actions', function() {
  let driver

  before(async function() {
    driver = await new Builder().forBrowser('chrome').build();
  })

  after(async () => await driver.quit())

  it('Pause', async function() {
    await driver.get('https://selenium.dev/selenium/web/mouse_interaction.html')

    const start = Date.now()

    const clickable = await driver.findElement(By.id('clickable'))
    await driver.actions()
      .move({ origin: clickable })
      .pause(1000)
      .press()
      .pause(1000)
      .sendKeys('abc')
      .perform()

    const end = Date.now() - start
    assert.ok(end > 2000)
    assert.ok(end < 4000)
  })

  it('Clear', async function() {
    await driver.get('https://selenium.dev/selenium/web/mouse_interaction.html')

    const clickable = driver.findElement(By.id('clickable'))
    await driver.actions()
      .click(clickable)
      .keyDown(Key.SHIFT)
      .sendKeys('a')
      .perform()

    await driver.actions().clear()
    await driver.actions().sendKeys('a').perform()

    const value = await clickable.getAttribute('value')
    assert.deepStrictEqual('A', value.substring(0, 1))
    assert.deepStrictEqual('a', value.substring(1, 2))
  })
})
        (driver as RemoteWebDriver).resetInputState()
Show full example
package dev.selenium.actions_api

import dev.selenium.BaseTest
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.openqa.selenium.By
import org.openqa.selenium.Keys
import org.openqa.selenium.WebElement
import org.openqa.selenium.interactions.Actions
import org.openqa.selenium.remote.RemoteWebDriver

import java.time.Duration

class ActionsTest : BaseTest() {

    @Test
    fun pause() {
        driver.get("https://www.selenium.dev/selenium/web/mouse_interaction.html")

        val start = System.currentTimeMillis()

        val clickable = driver.findElement(By.id("clickable"))
        Actions(driver)
            .moveToElement(clickable)
            .pause(Duration.ofSeconds(1))
            .clickAndHold()
            .pause(Duration.ofSeconds(1))
            .sendKeys("abc")
            .perform() 

        val duration = System.currentTimeMillis() - start
        Assertions.assertTrue(duration > 2000)
        Assertions.assertTrue(duration < 4000)
    }

    @Test
    fun releasesAll() {
        driver.get("https://www.selenium.dev/selenium/web/mouse_interaction.html")

        val clickable = driver.findElement(By.id("clickable"))
        val actions = Actions(driver)
        actions.clickAndHold(clickable)
                .keyDown(Keys.SHIFT)
                .sendKeys("a")
                .perform()

        (driver as RemoteWebDriver).resetInputState()

        actions.sendKeys("a").perform()
        Assertions.assertEquals("A", clickable.getAttribute("value")!!.get(0).toString())
        Assertions.assertEquals("a", clickable.getAttribute("value")!!.get(1).toString())
    }
}

键盘操作

一种适用于任何与网页交互的按键输入设备的表现形式.

Mouse actions

A representation of any pointer device for interacting with a web page.

Pen actions

A representation of a pen stylus kind of pointer input for interacting with a web page.

Scroll wheel actions

A representation of a scroll wheel input device for interacting with a web page.