1
votes

I've created a little scaffold for create posts with Rails, but instead use the standard form with erb I've created a simple React Component (I use the gem react-rails and browserify-rails).

You can find a sample repo with all the source code here!

The React component looks like this:

class NewPostForm extends React.Component {

  constructor(props) {
    super(props)
    this.state = {}
  }

  render() {
    return(
      <form action="/posts" accept-charset="UTF-8" method="post">
        <input name="utf8" type="hidden" value="✓"/>
        <input type="hidden" name="authenticity_token" value={this.props.authenticityToken}/>

        <div className="field">
          <label for="post_title">Title</label>
          <input type="text" name="post[title]" id="post_title" onChange={(e) => this.setState({title: e.target.value})} />
        </div>

        <div className="field">
          <label for="post_body">Body</label>
          <textarea name="post[body]" id="post_body" onChange={(e) => this.setState({body: e.target.value})}></textarea>
        </div>

        { this.state.title &&
          <div class="actions">
            <input type="submit" name="commit" value="Create Post" data-disable-with="Create Post"/>
          </div>
        }
      </form>
    )
  }

}

Note that the submit button is added to the DOM only if the title input field is filled.

The file app/views/posts/_form.html.erb is this:

<%= react_component 'NewPostForm', {authenticityToken: form_authenticity_token.to_s}, {prerender: true} %>

Now I've created this integration test that use Capybara:

require 'test_helper'

class PostCreationTest < ActionDispatch::IntegrationTest

  test "post creation" do
    visit new_post_path
    fill_in 'post[title]', with: 'Big News'
    fill_in 'post[body]', with: 'Superman is dead!'
    click_button 'Create Post' # <=== DO NOT FIND THIS BUTTON CAUSE IS ADDED WITH REACT
    assert page.has_content?('Post was successfully created.')
  end

end

The test fail with this error:

Run options: --seed 21811

# Running:

E

Error:
PostCreationTest#test_post_creation:
Capybara::ElementNotFound: Unable to find visible button "Create Post"
    test/integration/post_creation_test.rb:9:in `block in <class:PostCreationTest>'


bin/rails test test/integration/post_creation_test.rb:5

In test_helper.rb I've configured Capybara to use poltergeist driver.

Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, {
    js_errors: false,
    phantomjs_options: ['--ignore-ssl-errors=yes', '--ssl-protocol=any'],
    debug: false,
    timeout: 500,
    phantomjs: File.absolute_path(Phantomjs.path)
  })
end
Capybara.javascript_driver = :poltergeist
Capybara.server_port = 3001

If I display always the submit buttom (removing { this.state.title &&) in the react component the test pass successfully.

So, there is a way to make this test works with this setup and React components?

1
Superman is not dead.Tamer Shlash

1 Answers

5
votes

You have a couple of issues here. First is that you're not actually running your test with a JS capable driver. You have configured poltergeist for use with Capybara, but you've never told Capybara to use if for the specific test you want it used by setting Capybara.current_driver - see https://github.com/teamcapybara/capybara#using-capybara-with-minitest Adding Capybara.current_driver = Capybara.javascript_driver for the failing test brings up the next issue you have.

PhantomJS (used by Poltergeist) doesn't currently support ES5.1+ JS or modern CSS so you need to polyfill and transpile back to ES5 levels if you want to use it. This becomes immediately clear if you stop hiding the JS errors in your Poltergeist config (js_errors: true). The initial error because of this is that your code uses the Map class which wasn't added until ES6/2015 so it's not supported by Poltergeist (without polyfill).

As a beginner with Capybara JS testing you're probably better off starting your JS requiring tests using selenium (so you can see exactly what's happening and have support for modern JS/CSS), and then when the tests are working possibly staying with selenium and headless chrome or headless FF.

Capybara.javascript_driver = :selenium # or :selenium_chrome