This is Part 2 of a series of posts about refactoring Nitrolinks out of Pondo. Last time we’ve successfully moved Nitrolinks out of Pondo but we left most of the Nitrolinks-specific tests on the Pondo source code itself. This time we’ll move the tests to Nitrolinks so we can narrow Pondo’s test concerns.
The Plan
Just to recap, here is the plan:
- Move Nitrolinks out into its own gem ✔
- Create tests within Nitrolinks that mirror tests in Pondo
- Remove Nitrolinks-specific tests out of Pondo
- Rewrite Nitrolinks in ES6
We are going to do Step 2.
Prepping
First we need to make sure that we can run tests on the nitrolinks rails engine. Because I manually built the gem using Bundler’s tutorial, I ended up with some pretty bare-bones rails engine code. That’s a good thing. In practice, we don’t want to burden ourselves with extra code we might need in the future but is useless now.
Yet we do need some other things now that we want to make our engine testable.
What we need specifically is a dummy app we can use to plug our engine into so
we can run the test scenarios. Luckily, rails already provides a tool for this
with the rails plugin new
generator.
Running the command on the parent of our root directory:
$ rails plugin new --skip-turbolinks --skip-yarn -TMPOC --mountable nitrolinks-rails
…will add new files and folders to the engine directory. Some of them we need while others we’ll have to clean up.
Here’s what it looks like now after cleaning things up:
├── Gemfile
├── Gemfile.lock
├── MIT-LICENSE
├── README.md
├── Rakefile
├── app
│ └── assets
│ └── javascripts
│ ├── nitrolinks
│ │ ├── rails
│ │ │ └── application.js
│ │ └── utilities.coffee
│ └── nitrolinks.coffee
├── lib
│ ├── nitrolinks
│ │ ├── rails
│ │ │ ├── controller.rb
│ │ │ ├── engine.rb
│ │ │ └── version.rb
│ │ └── rails.rb
│ └── tasks
│ └── nitrolinks
│ └── rails_tasks.rake
├── nitrolinks-rails.gemspec
├── features # renamed from spec
│ └── dummy # Dummy rails app
└── vendor
└── assets
└── javascripts
Moving Tests
These were written as cucumber specs and they work quite well for testing the end-user features. They do make it slow to run the tests. In the future, we’ll figure out a way to use mainly javascript tests for these and concern ourselves with engine-related specs for this engine.
First, we’ll need to copy all of the pondo specs related to nitrolinks to the engine. This is a significant undertaking that it’ll probably fill this whole post with just to describe everything. I’ll just point out the most important changes I did.
Gemfile
source 'https://rubygems.org'
gemspec
group :test do
gem "cucumber-rails", ">= 1.5.0", require: false
gem 'selenium-webdriver'
gem 'chromedriver-helper', '>= 1.1.0'
end
group :test, :development do
gem "slim-rails", "~> 3.1"
gem 'sass-rails', '~> 5.0'
gem 'coffee-rails', '~> 4.2'
end
To use cucumber, I had to add cucumber-rails
and other test dependencies to
the Gemfile itself. I wish I didn’t have to but just adding this on the gemspec
as a development dependency doesn’t work. We also probably don’t need the
:development
group here and just leave all of them to the :test
group. I’ll
remove that in the future.
In hindsight, it might have been better if I just used rspec with capybara and that would have solved a lot of these problems. But I haven’t tried it on a rails engine and the feature specs have already been written anyway so we’ll use cucumber for now.
bin/rails
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails gems
# installed from the root of your application.
ENGINE_ROOT = File.expand_path('../..', __FILE__)
ENGINE_PATH = File.expand_path('../../lib/nitrolinks/rails/engine', __FILE__)
APP_PATH = File.expand_path('../../features/dummy/config/application', __FILE__)
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
# Pick the frameworks you want:
require "action_controller/railtie"
require "action_view/railtie"
require "sprockets/railtie"
require 'rails/engine/commands'
I had to add a bin/rails
script file so that cucumber will know where the
dummy application is. After that, I run the cucumber install task for cucumber.
$ rails generate cucumber:install
Feature Specs
The rest of what I did was just making sure the feature specs copied from pondo would run and removing traces of pondo from the code. That meant a lot of renames and clean up. I’ll have to do a thorough sweep next time in case I missed anything.
Here is the change commit.
What does our specs look now?
$ cucumber
# ... bunch of tests
14 scenarios (14 passed)
55 steps (55 passed)
0m8.182s
And that’s it. We now have a well-tested rails engine. That took more effort than I anticipated but it’s well worth it.