{"id":7491,"date":"2018-05-07T14:08:17","date_gmt":"2018-05-07T17:08:17","guid":{"rendered":"http:\/\/blog.plataformatec.com.br\/?p=7491"},"modified":"2018-05-07T18:29:17","modified_gmt":"2018-05-07T21:29:17","slug":"setting-up-rails-with-webpacker-react-and-jest","status":"publish","type":"post","link":"http:\/\/blog.plataformatec.com.br\/2018\/05\/setting-up-rails-with-webpacker-react-and-jest\/","title":{"rendered":"Setting up Rails with Webpack(er), React and Jest."},"content":{"rendered":"
This article has a clear purpose: present a quick and easy way to setup Rails + Webpacker + React + Jest. So if your team is considering, or has already decided, to use React, this is the right article for you. The open source community went through a long journey of features to bring Rails and modern Javascript together. You’ll see that combining React with Rails is easier than ever.<\/p>\n
We need to make two concepts very clear before we start. There are two names that look similar, but they are NOT the same. Let’s get started!<\/p>\n In this section we will create a new Rails application to be used in the example. If you already have an Rails app, you can skip to Add Webpacker Gem and React<\/a>.<\/p>\n Create a new Rails application by running:<\/p>\n A folder called Prepare your database by running these commands:<\/p>\n Let’s create a view to put our React app later on.<\/p>\n Inside Place any content inside Great! Now we have a running webserver and should be ready to go to the next section.<\/p>\n At this point we have a view, in which we will render a React component. Now, it is time to add Webpacker which will integrate files generated by Webpack to the Rails assets. As the “Rails doctrine” says convention over configuration<\/a>, Webpacker add Webpack and configure it so you can start hacking.<\/p>\n Note: If you are doing this in an existing application, Webpacker can operate alongside sprockets. You should discuss with your team whether you should migrate your assets to Webpack or not, according to your context.<\/em><\/p>\n Go to Run the command to install:<\/p>\n With the gem installed we need to run the task to setup React and Webpack with Rails. To do that, you need to have Yarn installed. You can follow this guide<\/a>.<\/p>\n Go to Go to localhost:3000<\/a> and it should show All right, React and Webpack are all set and ready to go! However, we are not fully done yet. The reason behind React existing in the first place, is that UI can be very complex and even though React(and other frameworks) tries to simplify it, we still have to create a lot of logic in an React application. To ensure that our components are working correctly we need to test them!<\/p>\n In this section we will add Jest, a test framework, created by the Facebook team, the same team behind React. You can use other test library, but I chose Jest because of its syntax that relates to RSpec, works with all major javascript libraries, provides a good bundle of utilities, and the setup is simpler.<\/p>\n We need to add Jest with Yarn because now we are using the javascript ecosystem.<\/p>\n Jest has many configurations, but we want to keep it as short as possible, since the defaults are pretty good. But there are two items that you need do adapt in order for it to work nicely with Rails.<\/p>\n The Without The root configuration indicates the directory of your tests file. Add to your On your You can try run Please, notice that the adapter’s version depends on the version of react that you are using.<\/p>\n Now, to setup enzyme and its adapter we will create a file to setup the tests, and you can add other configurations like setup Mocha and Chai.<\/p>\n Inside Add the setup path to Jest:<\/p>\n Ok, now we have Jest ready to go, with Now it is time to dive into Jest tests and ensure that the component behave like we expect. We will import the The component created by Webpacker looks something like this:<\/p>\n Add at the end of the file the following line to export the component. We can only test exported components in our Jest test files.<\/p>\n I won’t go in depth on how React works, let’s play along with that component. The component should render a Open the test file with your favorite text editor. We need to import the component, Enzyme, and React in order to render the component.<\/p>\n Please notice that we have imported only Let’s describe the component and create an expectation of having Next run Now you have a full Rails + React + tests setup. To extend that setup you could add Redux to manage state or Mocha\/Chai to test, but either way, from now on it is just a matter of following documentation to add the frameworks as any Yarn + Webpack setup, then Webpacker should run without hassle. If you have any question about this tutorial, feel free to leave a comment below.<\/p>\n","protected":false},"excerpt":{"rendered":" Setting up Rails with Webpack(er), React and Jest. An opinionated and straightforward way. This article has a clear purpose: present a quick and easy way to setup Rails + Webpacker + React + Jest. So if your team is considering, or has already decided, to use React, this is the right article for you. The … \u00bb<\/a><\/p>\n","protected":false},"author":68,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[],"aioseo_notices":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/7491"}],"collection":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/users\/68"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/comments?post=7491"}],"version-history":[{"count":13,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/7491\/revisions"}],"predecessor-version":[{"id":7502,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/7491\/revisions\/7502"}],"wp:attachment":[{"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/media?parent=7491"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/categories?post=7491"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/tags?post=7491"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}Webpack<\/code> and
Webpacker<\/code>. Webpack is a javascript bundler and task runner that runs on top of Node.js and thanks to its amazing community, there are a lot of modules to add features to it without or with little specific knowledge and configuration. Webpacker is a ruby gem created by the Rails Core Team to integrate Webpack to the Rails asset pipeline. So that means Webpacker is a way to have the Webpack functionality within a Rails application.<\/p>\n
Rails setup<\/h3>\n
$ rails new rails_app --skip-coffee --skip-javascript\n<\/code><\/pre>\n
rails_app<\/code> will be created. It is worth mentioning that you could add a flag
--webpack=react<\/code> and it would skip some steps, but in my experience, most of the projects will, or at least should, add React in a later development stage.<\/p>\n
$ cd rails_app\n<\/code><\/pre>\n
$ bin\/rails db:setup\n<\/code><\/pre>\n
$ bin\/rails generate controller home\n$ touch app\/views\/home\/index.html.erb\n<\/code><\/pre>\n
config\/routes.rb<\/code> set the root to
home#index<\/code>.<\/p>\n
# on config\/routes.rb\n\nRails.application.routes.draw do\n root to: 'home#index'\nend\n<\/code><\/pre>\n
app\/views\/home\/index.html.erb<\/code> and run
$ rails server<\/code>. Now you can visit
localhost:3000<\/code> and see your view’s content there. The
index<\/code> will be used to render the React component.<\/p>\n
Add Webpacker Gem and React<\/h3>\n
Gemfile<\/code> and add the Webpacker gem.<\/p>\n
# on Gemfile\n\ngem 'webpacker'\n<\/code><\/pre>\n
$ bundle install\n<\/code><\/pre>\n
$ bin\/rails webpacker:install\n$ bin\/rails webpacker:install:react\n<\/code><\/pre>\n
app\/views\/home\/index.html.erb<\/code> and add the
hello_react<\/code> import.<\/p>\n
\/* anywhere in app\/views\/index.html.erb *\/\n\n<%= javascript_pack_tag 'hello_react' %>\n<\/code><\/pre>\n
Hello React!<\/code><\/p>\n
Add Jest<\/h3>\n
$ yarn add --dev jest babel-jest babel-preset-es2015\n<\/code><\/pre>\n
moduleDirectories<\/code> configuration indicates where to find modules. I think it’s useful to add the Rails javascript folder to the
moduleDirectories<\/code> configuration because it will be easier to import the files to be tested. For example, use the following directory structures:<\/p>\n
app\n| - javascript\n| | - packs\n| | | - index.js\n...\nspec\n| - javascript\n| | - packs\n| | | - index.spec.js\n<\/code><\/pre>\n
moduleDirectories<\/code> configuration, to import
app\/javascript\/packs\/index.js<\/code> in
spec\/javascript\/packs\/index.spec.js<\/code>, you’ll need to configure the import using a relative path that will look like this:
..\/..\/..\/app\/javascript\/packs\/index.js<\/code>. It’s very painful to maintain relative paths in a long-term project, especially when you need to rename directories and move files.
\nAs it is suggested by Kyle Fox<\/a> here<\/a>, add app\/javascript<\/code> to the modules directory of Jest. Then you can use only
packs\/index.js<\/code> to import from
index.spec.js<\/code>.<\/p>\n
\nJest will look for files to run and will match the files with *spec.js<\/code> or
*test.js<\/code>, so it is important to set the root for Jest otherwise it will try to run
test.js<\/code> on
config\/webpack<\/code> as a test. I will use
spec\/javascript<\/code> because I like the RSpec folder organization, but you can change to any folder you want.<\/p>\n
package.json<\/code> the custom Jest configuration.<\/p>\n
\/* On your package.json *\/\n\n\"jest\": {\n \"roots\": [\n \"spec\/javascript\"\n ],\n \"moduleDirectories\": [\n \"node_modules\",\n \"app\/javascript\"\n ]\n}\n<\/code><\/pre>\n
.babelrc<\/code>, add the
es2015<\/code> preset to ensure your ES6 is working fine throughout you app and your tests.<\/p>\n
\/* On your .babelrc *\/\n\n{\n \"presets\": [\n \"es2015\",\n ...\n ]\n}\n<\/code><\/pre>\n
yarn jest<\/code>, but it will fail. You don’t have any test yet, so, let’s create one. We’re going to test a React component generated by Webpacker, we will talk about it soon. We need to add the
enzyme<\/code> library to render React components in the test environment. We need to add an adapter together with Enzyme to render our React components. Run the following command:<\/p>\n
$ yarn add --dev enzyme enzyme-adapter-react-16\n<\/code><\/pre>\n
$ touch spec\/javascript\/setupTests.js\n<\/code><\/pre>\n
setupTests.js<\/code> put:<\/p>\n
\/* On spec\/javascript\/setupTests.js *\/\n\nimport Enzyme from 'enzyme'\nimport EnzymeAdapter from 'enzyme-adapter-react-16'\n\nEnzyme.configure({ adapter: new EnzymeAdapter() })\n<\/code><\/pre>\n
\/* On your .babelrc *\/\n\n\"jest\": {\n \"roots\": [\n \"spec\/javascript\"\n ],\n \"moduleDirectories\": [\n \"node_modules\",\n \"app\/javascript\"\n ],\n \"setupTestFrameworkScriptFile\": \".\/spec\/javascript\/setupTests.js\"\n}\n<\/code><\/pre>\n
enzyme<\/code> to render our components. We can go to the next section to create tests for our component.<\/p>\n
Testing with Jest + Enzyme<\/h3>\n
hello_react<\/code> component and test it by rendering and checking its content.<\/p>\n
\/* On app\/javascript\/packs\/hello_react.jsx *\/\n\nimport React from 'react'\nimport ReactDOM from 'react-dom'\nimport PropTypes from 'prop-types'\n\nconst Hello = props => (\n\n\n\/* Add at the end of app\/javascript\/packs\/hello_react.jsx *\/\n\nexport default Hello\n<\/code><\/pre>\n
div<\/code> with
Hello {name}!<\/code> inside. So, lets create a test for that.<\/p>\n
$ touch spec\/javascript\/packs\/hello_react.spec.js\n<\/code><\/pre>\n
\/* On spec\/javascript\/packs\/hello_react.spec.js *\/\n\nimport React from 'react'\nimport { shallow } from 'enzyme'\nimport HelloReact from 'packs\/hello_react'\n<\/code><\/pre>\n
shallow<\/code> from
enzyme<\/code>.
shallow<\/code> improves the test performance by only rendering the component and its children, and it prevents rendering the entire DOM tree. However, you might need other rendering types, in this case, check the Enzyme’s documentation<\/a>.<\/p>\n
Hello David!<\/code> or any other name we pass to the
HelloReact<\/code> component.<\/p>\n
\/* On spec\/javascript\/packs\/hello_react.spec.js *\/\n\ndescribe('HelloReact component', () => {\n describe('when a name is given as a prop', () => {\n it('render Hello Caique!', () => {\n expect(shallow().text()).toBe('Hello Caique!')\n })\n })\n\n describe('when no name is given', () => {\n it('render Hello David!', () => {\n expect(shallow().text()).toBe('Hello David!')\n })\n })\n})\n<\/code><\/pre>\n
$ yarn test<\/code> to see if the tests were successful and that’s it.<\/p>\n