How can I fill a CKEditor area within Capybara, assuming I'm using a javascript capable driver like capybara-webkit or selenium?
问题:
回答1:
Inspired from what I found here, I came up with the solution of using javascript to both set the data on the hidden textarea
and on the CKEditor
object. Neither seemed sufficient, depending on the circumstances.
def fill_in_ckeditor(locator, opts)
content = opts.fetch(:with).to_json # convert to a safe javascript string
page.execute_script <<-SCRIPT
CKEDITOR.instances['#{locator}'].setData(#{content});
$('textarea##{locator}').text(#{content});
SCRIPT
end
# Example:
fill_in_ckeditor 'email_body', :with => 'This is my message!'
回答2:
A small addition to Marc-André's awesome answer
If you are using nested form or multiple textareas in the same page generated IDs are pretty ugly and hard to write into tests (e.g. person_translations_attributes_2_biography
) with this small addition to his method you can locate ckeditors using their labels instead of ID
# Used to fill ckeditor fields
# @param [String] locator label text for the textarea or textarea id
def fill_in_ckeditor(locator, params = {})
# Find out ckeditor id at runtime using its label
locator = find('label', text: locator)[:for] if page.has_css?('label', text: locator)
# Fill the editor content
page.execute_script <<-SCRIPT
var ckeditor = CKEDITOR.instances.#{locator}
ckeditor.setData('#{params[:with]}')
ckeditor.focus()
ckeditor.updateElement()
SCRIPT
end
In this way instead of this
fill_in_ckeditor 'person_translations_attributes_2_biography', with: 'Some text'
you can write this
fill_in_ckeditor 'Biography', with: 'Some text'
回答3:
RSpec + Capybara support file to work with ckeditor instances
module Ckeditor
class Instance
attr_reader :capybara
private :capybara
def initialize(instance_id, capybara)
@instance_id, @capybara = instance_id, capybara
end
def val(value)
capybara.execute_script "jQuery('textarea##{@instance_id}').val('#{value}')"
end
def reload_all
capybara.execute_script "for(var instance in CKEDITOR.instances) { if(CKEDITOR.instances.hasOwnProperty(instance)) {CKEDITOR.instances[instance].destroy(true);} }"
capybara.execute_script "CKEDITOR.replaceAll();"
end
end
end
# usage
# rte = Ckeditor::Instance.new(:my_instance_id, page)
# rte.val 'foo'
# rte.reload_all
# NOTE: page is provided by Capybara
https://gist.github.com/3308129
回答4:
For me Marc-André's answer switches iframe context in webkit driver. See this capybara-webkit issue
I found another way to fill in ckeditor input which doesn't change iframe context:
def fill_in_ckeditor(id, with:)
within_frame find("#cke_#{id} iframe") do
find('body').base.send_keys with
end
end
and call it
fill_in_ckeditor 'comment', with: 'This is my message!'
Works both with webkit and selenium drivers
Inspired by this post