I have a "Copy Link" button in my frontend UI. When clicked, the URL inside an input box is copied to the user's clipboard with this JS:
const copyTextarea = document.querySelector("#copy-link-button");
copyTextarea.focus();
copyTextarea.select();
document.execCommand('copy');
When I try it out locally, this functionality works perfectly so I know the feature itself is working correctly.
However I'm unable to test the copy with Capybara. I know from this post that Capybara does not provide a clipboard API, but my workaround is to -
My test:
# 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");
However nothing gets pasted into that input (input.value
and input.text
return ""
).
Is this a valid approach? Is the issue here with copying the text in the first place or did I make an error in pasting the data?
Thanks!
Note: since the original posting of this Chrome has changed the available permission types. For the headless solution go to https://chromedevtools.github.io/devtools-protocol/tot/Browser/#type-PermissionType to see what permission types are currently available
There are lots of security rules around access to the clipboard content, so trying to get paste working from Capybara is really going to be an exercise in frustration. Additionally most browsers won't actually do anything when ctrl/command v is sent as a keystroke since it's a system triggered action not the browser.
However, since you just want to verify the copy works you don't actually need to trigger the paste, you just need to get around the permission requirements to use the clipboard API. If you're using Chrome (in a non-headless configuration - doesn't currently work headless) you can do that by setting the profile.content_settings.exceptions.clipboard
preference in your driver registration
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
If you are running in headless mode and using up-to-date Capybara and selenium with Chrome another option is to use CDP to grant the permissions
page.driver.browser.execute_cdp('Browser.grantPermissions', origin: page.server_url, permissions: ['clipboardRead', 'clipboardWrite'])
Once you have the permissions worked out you can then use evaluate_async_script
to access the clipboard data
clip_text = page.evaluate_async_script('navigator.clipboard.readText().then(arguments[0])')
Notes:
base
to call send_keys
on an element, just call it on the elementexpect(input.value).to eq("some value")
will lead to flaky tests, instead you should use the Capybara provided matchers like expect(page).to have_field(with: 'some value')
or expect(input).to match_selector(:field, with: 'some value')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With