如何使用Capybara + Poltergeist将文本设置到Summernote文本区域

4
我有一个文本域,它使用了Summernote,并且我设置了onChange事件。我想使用RSpec + Capybara + Poltergeist编写测试来确认onChange事件是否起作用。
据我所知,在浏览器中显示的文本区实际上是带有“note-editable”CSS类的div标签。我该如何设置文本并触发onChange事件?
我写了下面这段代码,但是出现了错误Capybara::ElementNotFound: Unable to find field "Some label":
visit edit_foo_path
fill_in 'Some label', with: 'Foo bar'

编辑

我为这个问题创建了一个示例应用程序:

https://github.com/JunichiIto/summernote-rspec-sandbox

HTML源代码

<!DOCTYPE html>
<html>
<head>
  <title>SummernoteRspecSandbox</title>
  <link rel="stylesheet" media="all" href="/assets/application.self-f866ffa01bf26be2b8a8ac982e49d917be3b9a46604dfdc9fc8c139b62409465.css?body=1" data-turbolinks-track="true" />
  <script src="/assets/jquery.self-d03a5518f45df77341bdbe6201ba3bfa547ebba8ed64f0ea56bfa5f96ea7c074.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/jquery_ujs.self-ca5248a2fad13d6bd58ea121318d642f195f0b2dd818b30615f785ff365e8d1f.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/bootstrap.self-2bbd2c0465f01b1f8270958ddfc2e62a08915f295a35d22df2971eb936cf3c64.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/summernote.self-612431947ae9c3f1f0283dbbbc757153947f8e5de408f9bd8886b1232e8a54f7.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/blogs.self-b9a3bc0ee16e0bc44fb466bd5c7833ebec276447634d25729280397c65cff176.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/application.self-f8806224e027f3e3f0138ea9ce99319e298dfdb323304d1f1be6eae8e8c74724.js?body=1" data-turbolinks-track="true"></script>
  <meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="4iu31ugTgvMERb1xQRjtcySSssjMthLWclgiHMe60aHGMeC3IMeNKZlkfFSKT33hNuvDqUUgUNTUaQEcoBl9mw==" />
</head>
<body>

<h1>New Blog</h1>

<form class="new_blog" id="new_blog" action="/blogs" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" /><input type="hidden" name="authenticity_token" value="TBkcVk38/42Cx9coe717KKpb1H2cmDpv8kz7LREfkiloA0s3hSjwVx/mFg2w6uu6uCKlHBUOeG1Ufdgtdrw+Ew==" />

  <div class="field">
    <label for="blog_title">Title</label><br>
    <input type="text" name="blog[title]" id="blog_title" />
  </div>
  <div class="field">
    <label for="blog_content">Content</label><br>
    <textarea class="summernote" name="blog[content]" id="blog_content">
</textarea>
  </div>
  <div class="actions">
    <input type="submit" name="commit" value="Create Blog" />
  </div>
</form>

<a href="/blogs">Back</a>


</body>
</html>

CoffeeScript

$ ->
  $('.summernote').summernote()

RSpec

require 'rails_helper'

feature 'Blogs' do
  scenario 'Create blog' do
    visit new_blog_path
    fill_in 'Title', with: 'Hello, world!'
    fill_in 'Content', with: 'This is awesome blog.'
    click_button 'Create Blog'
    expect(page).to have_content 'Blog was successfully created.'
    expect(page).to have_content 'Hello, world!'
    expect(page).to have_content 'This is awesome blog.'
  end

  scenario 'Create blog with JS', js: true do
    visit new_blog_path
    fill_in 'Title', with: 'Hello, world!'
    pending 'Capybara::ElementNotFound: Unable to find field "Content"'
    fill_in 'Content', with: 'This is awesome blog.'
    click_button 'Create Blog'
    expect(page).to have_content 'Blog was successfully created.'
    expect(page).to have_content 'Hello, world!'
    expect(page).to have_content 'This is awesome blog.'
  end
end

请问您能否展示完整的HTML代码? - Richlewis
我添加了详细信息。如果您需要更多,请告诉我。 - Junichi Ito
我主要使用ID和类作为定位器,但在许多情况下也可以使用名称,在您的情况下,请尝试fill_in 'blog[content]' with: text herefill_in '#blog_content' with: text here - Richlewis
2个回答

4
在将Summernote更新到0.8.2之后,find('div[contenteditable]').set('This is awesome blog.')不起作用。
我必须通过execute_script调用Summernote API,例如:
script = <<-JS
$('.some-field').summernote('editor.insertText', 'This is awesome blog.');
JS
execute_script(script)

编辑

在将Summernote更新到0.8.2版本后,find('div[contenteditable]').set('This is awesome blog.')不起作用了。

抱歉,这不是我想要说的。应该像这样说:

在将Summernote更新到0.8.2版本后,find('div[contenteditable]').set('This is awesome blog.')无法触发Summernote的onChange回调函数。因此,我不得不调用execute_script

我必须在我的规范测试中测试onChange的行为。

编辑2

正如Thomas Walpole所写,可以使用send_keys方法代替execute_script。感谢Thomas Walpole!

find('div[contenteditable]').send_keys('This is awesome blog.')

在测试时,仅在绝对必要的情况下才应该转向JS来设置值,因为这样完全绕过了用户使用您的应用程序时生成的事件,并使您的测试大多毫无意义。Summernote 0.8.2中没有任何东西应该改变它的行为-这里有一个gist显示它仍然可以与Poltergeist一起工作https://gist.github.com/twalpole/b43ed98f458cea47ce3c230cf6e638e7-所以我假设您的应用程序中发生了其他更改以破坏您的测试。 - Thomas Walpole
你是对的。正如我编辑时,我必须调用execute_script来在我的规范中触发onChange回调函数。 - Junichi Ito
这是因为Poltergeist在设置元素值时不使用send_keys(可能很快就会改变)。如果要在不执行JS的情况下获得所需内容,请执行以下操作:find('div[contenteditable]').send_keys([:ctrl, 'a'], 'This is awesome blog.')。您可能需要先执行find('div[contenteditable]').click,但这应该会触发更改事件。(注意:根据您所在的平台,您可能需要将:ctrl换成:meta或:alt,或者根本不需要[:ctrl,'a'],如果没有任何先前的内容需要替换) - Thomas Walpole

3

Capybaras的fill_in只能与html表单元素一起使用。由于您页面的JS版本使用带有contenteditable属性的DIV作为文本区域,以填充#fill_in将不起作用。相反,您需要找到div并直接调用#set。在您的项目中,以下内容应该可以工作

find('div[contenteditable]').set('This is awesome blog.')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接