Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fill in Editor textarea using capybara-webkit

I'm using a markdown editor on my page, which I'm trying to target, and fill in, using capybara-webkit, but without any luck.

My template looks like this

<%= simple_form_for form, url: url, method: :put do |f| %>
  <%= f.input :notes, as: :text %>
  <%= f.button :submit, class: 'fluid' %>
<% end %>

<!-- https://github.com/lepture/editor -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/editor/0.1.0/editor.css">
<script src="//cdn.jsdelivr.net/editor/0.1.0/editor.js"></script>
<script src="//cdn.jsdelivr.net/editor/0.1.0/marked.js"></script>

<script !src="">
  (function () {
    var editor = new Editor();
    editor.render();
  })()
</script>

and the rendered html (including the executed editor javascript) looks like this (via the capybara-webkit debugging tools)

<form novalidate="novalidate" class="simple_form simple_form ui form segment new_steps_update" id="new_steps_update" action="/presentations/1/who" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="_method" value="put">
  <div class="field text optional steps_update_notes"><label class="text optional" for="steps_update_notes">Notes</label><textarea class="text optional" name="steps_update[notes]" id="steps_update_notes" style="display: none;"></textarea><div class="editor-toolbar"><a class="icon-bold"></a><a class="icon-italic"></a><i class="separator">|</i><a class="icon-quote"></a><a class="icon-unordered-list"></a><a class="icon-ordered-list"></a><i class="separator">|</i><a class="icon-link"></a><a class="icon-image"></a><i class="separator">|</i><a class="icon-info" href="http://lab.lepture.com/editor/markdown" target="_blank"></a><a class="icon-preview"></a><a class="icon-fullscreen"></a></div><div class="CodeMirror cm-s-paper"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 4px; left: 4px;"><textarea style="position: absolute; padding: 0px; width: 1000px; height: 1em; outline: none; font-size: 4px;" autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0"></textarea></div><div class="CodeMirror-hscrollbar" style="left: 0px;"><div style="height: 1px;"></div></div><div class="CodeMirror-vscrollbar" style=""><div style="width: 1px;"></div></div><div class="CodeMirror-scrollbar-filler" style=""></div><div class="CodeMirror-gutter-filler" style=""></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="min-width: 41.4375px; margin-left: 0px; min-height: 26px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines"><div style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>​</span></pre></div><div style="position: relative; z-index: 1; display: none;"></div><div class="CodeMirror-code" style=""><pre> </pre></div><div class="CodeMirror-cursor" style="left: 4px; top: 0px; height: 17px;"> </div><div class="CodeMirror-cursor CodeMirror-secondarycursor" style="display: none;"> </div></div></div></div></div><div style="position: absolute; height: 30px; width: 1px; top: 26px;"></div><div class="CodeMirror-gutters" style="display: none; height: 420px;"></div></div></div><div class="editor-statusbar"><span class="lines">0</span><span class="words">0</span><span class="cursor">0:0</span></div></div>
  <input type="submit" name="commit" value="Next" class="ui positive submit button fluid">
</form>
<!-- https://github.com/lepture/editor -->
<link rel="stylesheet" href="//cdn.jsdelivr.net/editor/0.1.0/editor.css">
<script src="//cdn.jsdelivr.net/editor/0.1.0/editor.js"></script>
<script src="//cdn.jsdelivr.net/editor/0.1.0/marked.js"></script>

<script !src="">
  (function () {
    var editor = new Editor();
    editor.render();
  })()
</script>

It's a bit difficult to tell, but I think the original textarea (id: step_update_notes) is being replaced by another textarea inside a div with a class of CodeMirror, so I've been trying to target this using capybara, but without luck.

This is my test as it stands now

require 'rails_helper'

RSpec.feature 'Planning a presentation', type: :feature do
  context 'when logged in', js: true do
    let!(:user) { Fabricate(:user, password: 'password') }

    before(:each) do
      page.driver.allow_url('cdn.jsdelivr.net')
      login_user_js(user.email, 'password')
    end

    context 'new presentation' do
      scenario 'complete process' do
        visit presentations_path
        click_link 'Plan a new presentation'

        expect(page).to have_content('About your presentation')
        fill_in 'presentations_create_title', with: 'My presentation'
        click_button 'Next'

        expect(page).to have_content('Step one: Who')

        # this one is unable to find the textarea
        fill_in '.CodeMirror textarea', with: 'My step one who notes'

        # This one seems to complete, but upon submitting the page, the value hasn't set
        find('.CodeMirror textarea').set('My step one who notes')
        click_button 'Next'

        expect(page).to have_content('Step two: Action')
        skip
      end
    end
  end
end
like image 401
Daniel Hollands Avatar asked Nov 01 '22 03:11

Daniel Hollands


2 Answers

So, this isn't the answer that I was expecting, and I'm not sure if this is the best way of doing it, but I found something that works.

Some research revealed that I'm able to populate the content of the Editor using javascript, specifically editor.codemirror.setValue();. So I ensured the editor variable was in the global scope inside an FTAPP object (which may or may not be the best idea), then used the following Capybara code.

require 'rails_helper'

RSpec.feature 'Planning a presentation', type: :feature do
  context 'when logged in', js: true do
    let!(:user) { Fabricate(:user, password: 'password') }

    before(:each) do
      page.driver.allow_url('cdn.jsdelivr.net')
      login_user_js(user.email, 'password')
    end

    context 'new presentation' do
      scenario 'complete process' do
        visit presentations_path
        click_link 'Plan a new presentation'

        expect(page).to have_content('About your presentation')
        fill_in 'presentations_create_title', with: 'My presentation'
        click_button 'Next'

        expect(page).to have_content('Step one: Who')

        page.execute_script('FTAPP.editor.codemirror.setValue("My step one who notes");')

        click_button 'Next'

        expect(page).to have_content('Step two: Action')
        skip
      end
    end
  end
end
like image 82
Daniel Hollands Avatar answered Nov 09 '22 09:11

Daniel Hollands


I also ended up using Javascript to update the content of the editor. But I didn't want to expose the editor variable to the global scope, as Daniel did. But luckily you can use querySelector to find the element. Codemirror attaches itself to the element, so you have access to it, and its methods:

execute_script("document.querySelector('.CodeMirror').CodeMirror.setValue('VALUE')")

like image 27
wnm Avatar answered Nov 09 '22 08:11

wnm