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:

  1. Move Nitrolinks out into its own gem ✔
  2. Create tests within Nitrolinks that mirror tests in Pondo
  3. Remove Nitrolinks-specific tests out of Pondo
  4. 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.