Writing auto tests is a part of development process, which is quite commonly doubted by a customer. At the same time, it is extremely important for continuous integration and system stability. Learn how to write auto smoke tests for Ember Rails Stack and why it is so important.
Why Write Smoke Tests?
Quite often a customer questions the necessity to write auto tests. He’d rather focus on getting more new features, which is easy to understand. But at the same time auto-smoke tests, as well as refactoring, are the basics of the stable system.
5 Things You Need to Know about Refactoring before You Spoil It All
For example, if your application is using a database, where the first log was created in 2005 and business logic and the amount of dependencies are increasing with every release, sooner or later you will find yourself in a big trouble. The amount required to smoke test the whole application will only be increasing and might even occupy a bigger part of your budget than actual development.
That’s why we eventually convinced our customer to allocate some time on writing and adjusting testing. It is better to start doing as soon as possible (when your trouble is still little). In this article we will cover how we managed auto tests in one of our projects and what results we received.
About the Project
The Project we use for the example has the following stack:
- Rails 4.1.6;
- Ruby 2.1.3;
- Ember.js 2.5.0;
- Node 4.4.7;
The instruction provided would also work for testing Angular applications with minor changes.
How to start
Let’s assume we write tests for an already existing application. In case you don’t have your application developed yet, have a look at this article first.
The first thing we do for an existing application to write some tests is to add a few gems to Gemfile:
[ruby]gem “cucumber-rails”, require: false
gem “database_cleaner”
gem “capybara-webkit”
gem “factory_girl_rails”, “~> 4.0”
gem “selenium-webdriver”
gem “rspec”[/ruby]
Now let’s run installation:
[ruby]$ bundle install
$ rails generate cucumber:install[/ruby]
After the gems are installed, we need to prepare configuration for our app:
[ruby]# features/support/env.rb
require “cucumber/rails”
require “capybara”
require “capybara/rails”
require “capybara/cucumber”
require “capybara/session”
require “capybara/rspec”[/ruby]
[ruby]#World(FactoryGirl::Syntax::Methods)
Capybara.register_driver :chrome do |app|
Capybara::Selenium::Driver.new(app, browser: :chrome)
end[/ruby]
[ruby]Capybara.javascript_driver = :chrome
Capybara.default_max_wait_time = 10[/ruby]
[ruby]
Capybara.configure do |config|
# Don’t start rails
config.run_server = false
# Set capybara’s driver. Use your own favorite
config.default_driver = :webkit
# Make all requests to the Ember app
config.app_host = ‘http://127.0.0.1:4200’
end[/ruby]
In our config we add all required Capybara modules and state that we are going to use factory-girl. Besides, we adjust browser where tests are going to run (we added selenium-webdriver to Gemfile for that). After that, we state that the application will be looking at 4200 port, where Ember server runs.
How to Avoid Most Common Mistakes Using Ember
Now, when we are ready, let’s write our first test. Let’s check whether we can launch our application and get to the first page.
[ruby]#features/login.feature
@javascript
Feature: Login
When a user visits “/”, they should see form to login
Scenario: User views login-page
When I visit “/”
Then I should see “SIGN IN”[/ruby]
In the first line, we put an instruction for Capybara to run javascript for testing. Without it tests won’t run.
Now let’s describe scenario steps:
[ruby]#features/steps/login.rb
When(/^I visit “(.*?)”$/) do |path|
visit path
end
Then(/^I should see “(.*?)”$/) do |text|
page.should have_content(text)
end[/ruby]
Now let’s run a test, by typing rake in command line.
After we made sure everything is working fine, it’s time to check how Ember works with Rails. Let’s try to log in and go to home page (in our application it is available for logged Users only).
To do that we need a User from database. And the factory-girl we mentioned in the gemfile works perfectly for that.
Let’s create the following file:
[ruby]#test/factories/user.rb
FactoryGirl.define do
factory :user do
username ‘testuser’
password ‘password’
email ‘[email protected]’
role ‘standard’
end
factory :admin, class: User do
username ‘testadmin’
password ‘password’
email ‘[email protected]’
role ‘admin’
end
end[/ruby]
Now we have an instrument for creating a User. Let’s try to log in.
To do that let’s complicate our login feature a little:
[ruby]#feature/login.feature
@javascript
Feature: Login
When a user visits “/”, they should see form to login, after filling which they should be redirected to home-page[/ruby]
[ruby]Scenario: User views login-page
When I visit “/”
Then I should see “SIGN IN”
Then I sign in
Then I should be redirected to home-page[/ruby]
Since now we have more steps, we need to add defnitions for them in steps_definition:
[ruby]#features/steps/login.rb
When(/^I visit “(.*?)”$/) do |path|
visit path
end
Then(/^I should see “(.*?)”$/) do |text|
page.should have_content(text)
end
Then(/^I sign in$/) do
user = create(:admin)
within(“.signin-block__form”) do
fill_in ‘username’, with: user.username
fill_in ‘password’, with: “password”
end
click_button ‘Sign in’
end
Then(/^I should be redirected to home-page$/) do
page.should have_content(‘Notifications’)
page.should have_content(‘Tasks’)
page.should have_content(‘Requests’)
end[/ruby]
At sign in steps we find by id the inputs we need. So make sure you specified them, Besides, we can’t get a password from a saved User, so we have to add a password at this step statically.
In our example we figure out whether we are on home-page by whether ‘Notifications’, ‘Tasks’ and ‘Requests’ are visible.
We have looked into the main things we need to cover an application with tests:
- Text/div search on a page,
- Input fill in,
- Button click with reference to rails API,
- Creating objects in database before using them on frontend.
Also check:
7 Gems which will make your Rails code look awesome!
Continuous Integration
Now it’s time for another part of our testing – continuous integration.
Continuous integration (CI) is the major principle of software development, which can make your life easier. In practice to facilitate the project and environment setup there are ready-to-go solutions – CI platforms. To cut a long story short CI platform is a kind of system, which tracks your source control and in case there are any, automatically gathers them, builds, runs tests (of course, if you have written them) and maybe does something else.
In case of a fail, it notifies all interested parties – first and foremost the last committer.
It’s good to know that you have done everything right. It’s also good to know when you know you have done something wrong even before it did any harm. That’s why CI tools are highly recommended.
For a number of reasons, we have chosen Circle CI system. For our project free account was more than enough. You sign up via your GitHub or BitBucket account (where your project is stored). On a Dashboard in a Projects tab, you choose one of the projects for your User (we need the one where API is stored). After that, you need to go to project settings and select in Permissions a link to Checkout SSH Keys. SSH key specified in this section will be used to access your project code.
Now let’s set the project itself so that Circle CI would know what to do. Create circle.yml file. Make sure it is located not in config folder, but in the root.
In this file, we describe all configs, which we will need to run tests.
In the documentation, you will easily find an example of this file and details on which settings are responsible for what. That’s why we will highlight only those parts that require special attention.
[xml]## Customize the test machine
machine:
# Version of ruby to use
ruby:
version: 2.1.3
node:
version: 5.10.1
## Customize dependencies
dependencies:
pre:
# !Important note
# circleCI runs every command in a separate subshell, so cd command, if
# specified separately, does not have any effect on the next commands,
# to execute commands consequentially between them we use ‘&&’
– cd .. && git clone [email protected]:name-of-organisation/frontend-project.git
– cd ../frontend-project && git checkout master
– cd ../frontend-project && npm install -g bower && bower install && npm install
– cd ../frontend-project && npm install -g ember-cli
– cd ../frontend-project && ember build –environment=circleci
cache_directories:
– “~/frontend-project/node_modules”
– “~/frontend-project/bower_components”
## Customize database setup
database:
override:
– bundle exec rake db:create db:schema:load
## Customize test commands
test:
pre:
– cd ~/frontend-project && ember server:
background: true
– cd ~/api-project && bundle exec rails server -p 4000 –environment test:
background: true
override:
– bundle exec rake[/xml]
Let’s summarize what we pay attention to:
- Don’t forget to specify Ruby and Node versions we need
- In dependencies, we download and install you Frontend project. Every new line in the file is run in a separate terminal (subshell). That’s why from every new line we need to go again from Project API folder to Project Frontend folder.
- When we start testing, we need both servers to be running, that’s why before running the tests, we run servers in the background and only after that run the tests.
Quite often to launch a project we need some secret-variables, which we don’t want to store in a free access. In Circle CI one can create environment variables with the values of our variables (Project Settings -> Environment variables). In this case one can write a special secrets.ci.yml file, where all secret variables taken from the environment are written:
[xml]test:
secret_key_base: <%= ENV[‘secret_key_base’] %>
encryption_key: <%= ENV[‘encryption_key’] %>
access_key_id: <%= ENV[‘access_key_id’] %>
secret_access_key: <%= ENV[‘secret_access_key’] %>
bucket: <%= ENV[‘bucket’] %>
cdn: <%= ENV[‘cdn’] %>[/xml]
We also need to add a line to circle.yml file (to dependencies: pre: section):
[ruby]- mv -v config/secrets.ci.yml config/secrets.yml[/ruby]
A huge advantage of Circle CI is that one can make a build with SSH access. This means that Circle CI will run the script you created and at the same time you within half an hour will be able to go to server and check what’s happening there or run commands yourself.
The only negative part of it is that to test frontend for every branch you will have to change your configuration file since in it we statically specify project branch to be used.
Besides sending an email web-notification, Circle CI shows test results nicely on the Dashboard:
From this page, we can go to every separate build and check what happened when it was building. From the same page we can launch the rebuild with SSH access:
After you completed all the settings you can track successful project builds after every commit. And in case of test fails you will receive an email about it and will always know about the problems or what a great developer you are!
19 Ruby on Rails Gems which Can Amaze
Hope, this was useful. Feel free to ask any questions and we will be glad to answer them.