使用 Selinum + Capybara 模拟剪贴板 copy/paste

Emulating a clipboard copy/paste with Selinum + Capybara

我的前端有一个 "Copy Link" 按钮 UI。单击时,将输入框内的 URL 复制到用户剪贴板,并使用此 JS:

const copyTextarea = document.querySelector("#copy-link-button");
copyTextarea.focus();
copyTextarea.select();
document.execCommand('copy');

当我在本地试用时,此功能完美运行,因此我知道该功能本身运行正常。

但是我无法用 Capybara 测试副本。我从 得知 Capybara 不提供剪贴板 API,但我的解决方法是 -

  1. 使用 "Copy Link" 按钮复制 link
  2. 导航到其他一些 input/text 字段
  3. 使用 CTRL+V 粘贴到字段中并读取字段内容以验证

我的测试:

# Copy the link
page.find("#copy-link-button").click
wait_for_ajax

# Visit some other page that I know has an input/text field
visit account_settings_path

input = page.find("#user_email")

# Clear the field
fill_in("user[email]", with: "")

# Paste in the contents of the clipboard
input.base.send_keys([:control, "v"])

# Validate
expect(input.value).to eq("some value");

但是没有任何内容被粘贴到该输入中(input.valueinput.text return "")。

这是一种有效的方法吗?问题是首先复制文本还是我在粘贴数据时出错?

谢谢!

注意:由于此 Chrome 的原始发布已经更改了可用的权限类型。对于无头解决方案,请转到 https://chromedevtools.github.io/devtools-protocol/tot/Browser/#type-PermissionType 查看当前可用的权限类型


有很多关于访问剪贴板内容的安全规则,所以试图从 Capybara 中粘贴工作确实是一个令人沮丧的练习。此外,当 ctrl/command v 作为击键发送时,大多数浏览器实际上不会执行任何操作,因为它是系统触发的操作而不是浏览器。

但是,由于您只是想验证复制是否有效,因此实际上不需要触发粘贴,您只需要绕过使用剪贴板的权限要求即可 API。如果您使用的是 Chrome(在非无头配置中 - 当前无法无头工作),您可以通过在驱动程序注册中设置 profile.content_settings.exceptions.clipboard 首选项来做到这一点

Capybara.register_driver :chrome do |app|
  options = Selenium::WebDriver::Chrome::Options.new
  options.add_preference('profile.content_settings.exceptions.clipboard', {
    '*': {'setting': 1}
  })
  Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end

如果您 运行 处于无头模式并且使用最新的 Capybara 和 selenium Chrome 另一种选择是使用 CDP 授予权限

page.driver.browser.execute_cdp('Browser.grantPermissions', origin: page.server_url, permissions: ['clipboardRead', 'clipboardWrite'])

获得权限后,您可以使用 evaluate_async_script 访问剪贴板数据

clip_text = page.evaluate_async_script('navigator.clipboard.readText().then(arguments[0])')

备注:

  1. 不需要用base在元素上调用send_keys,直接在元素
  2. 上调用即可
  3. expect(input.value).to eq("some value") 会导致不稳定的测试,相反你应该使用 Capybara 提供的匹配器,比如 expect(page).to have_field(with: 'some value')expect(input).to match_selector(:field, with: 'some value')