From f757be4f77c96dc75a022efe758e19c0efa98a1a Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Thu, 28 Jun 2018 13:13:32 +0300 Subject: [PATCH 01/14] Remove poltergeist gem, which is unused --- Gemfile | 1 - spec/rails_helper.rb | 1 - spec/support/capybara.rb | 2 -- 3 files changed, 4 deletions(-) diff --git a/Gemfile b/Gemfile index 7682cdc4e..9d2259cb2 100644 --- a/Gemfile +++ b/Gemfile @@ -111,7 +111,6 @@ group :development, :test do gem 'factory_bot_rails' gem 'capybara' gem 'rspec-rails', '~> 3.6' - gem 'poltergeist' # debug gem 'pry', '0.10.1' diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index c6110a8c2..aead0dfa5 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -2,7 +2,6 @@ ENV['RAILS_ENV'] ||= 'test' require 'spec_helper' require File.expand_path('../../config/environment', __FILE__) require 'rspec/rails' -require 'capybara/poltergeist' require 'paper_trail/frameworks/rspec' require 'money-rails/test_helpers' require 'support/requests/session_helpers' diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index 7ef5009c6..5434f1a84 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -4,5 +4,3 @@ RSpec.configure do |config| config.include CapybaraViewMacros, type: :view config.include CapybaraViewMacros, type: :presenter end - -Capybara.javascript_driver = :poltergeist From f327bdf6b656a40c35f5c05f4d2a01e69ff2f788 Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Fri, 29 Jun 2018 10:43:01 +0300 Subject: [PATCH 02/14] Rewrite mobile id spec to a test --- .../registrar/sign_in/mobile_id_spec.rb | 20 ------------ test/integration/registrar/sign_in_test.rb | 32 +++++++++++++++++++ 2 files changed, 32 insertions(+), 20 deletions(-) delete mode 100644 spec/features/registrar/sign_in/mobile_id_spec.rb create mode 100644 test/integration/registrar/sign_in_test.rb diff --git a/spec/features/registrar/sign_in/mobile_id_spec.rb b/spec/features/registrar/sign_in/mobile_id_spec.rb deleted file mode 100644 index bc26daff5..000000000 --- a/spec/features/registrar/sign_in/mobile_id_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'rails_helper' - -RSpec.feature 'Mobile ID login', db: true do - given!(:api_user) { create(:api_user, identity_code: 1234) } - - background do - digidoc_client = instance_double(Digidoc::Client, authenticate: OpenStruct.new(user_id_code: 1234), session_code: 1234) - allow(Digidoc::Client).to receive(:new).and_return(digidoc_client) - end - - scenario 'login with phone number' do - visit registrar_login_path - click_on 'login-with-mobile-id-btn' - - fill_in 'user[phone]', with: '1234' - click_button 'Login' - - expect(page).to have_text('Confirmation sms was sent to your phone. Verification code is') - end -end diff --git a/test/integration/registrar/sign_in_test.rb b/test/integration/registrar/sign_in_test.rb new file mode 100644 index 000000000..ffbbf352e --- /dev/null +++ b/test/integration/registrar/sign_in_test.rb @@ -0,0 +1,32 @@ +require 'test_helper' + +class SignInTest < ActionDispatch::IntegrationTest + def setup + super + WebMock.allow_net_connect! + + @user = users(:api_bestnames) + @user.identity_code = '1234' + @user.save + end + + def test_mobile_id_sign_in_page + mock_client = Minitest::Mock.new + mock_client.expect(:authenticate, OpenStruct.new(user_id_code: '1234'), + [{ phone: "+3721234", + message_to_display: "Authenticating", + service_name: "Testimine" }]) + mock_client.expect(:session_code, 1234) + + Digidoc::Client.stub(:new, mock_client) do + visit registrar_login_path + + click_on 'login-with-mobile-id-btn' + + fill_in 'user[phone]', with: '1234' + click_button 'Login' + + assert(page.has_text?('Confirmation sms was sent to your phone. Verification code is')) + end + end +end From 6e820592bce67ad602dddc1ee9d32f9c7f986a05 Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Fri, 29 Jun 2018 11:16:25 +0300 Subject: [PATCH 03/14] Add selenium-webdriver gem --- Gemfile | 1 + Gemfile.lock | 17 ++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index 9d2259cb2..53993a1b8 100644 --- a/Gemfile +++ b/Gemfile @@ -111,6 +111,7 @@ group :development, :test do gem 'factory_bot_rails' gem 'capybara' gem 'rspec-rails', '~> 3.6' + gem 'selenium-webdriver' # debug gem 'pry', '0.10.1' diff --git a/Gemfile.lock b/Gemfile.lock index 9a88e782b..6932af4ad 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -134,8 +134,9 @@ GEM rack (>= 1.0.0) rack-test (>= 0.5.4) xpath (~> 2.0) + childprocess (0.9.0) + ffi (~> 1.0, >= 1.0.11) chronic (0.10.2) - cliver (0.3.2) coderay (1.1.0) coercible (1.0.0) descendants_tracker (~> 0.0.1) @@ -180,6 +181,7 @@ GEM factory_bot_rails (4.8.2) factory_bot (~> 4.8.2) railties (>= 3.0.0) + ffi (1.9.25) figaro (1.1.1) thor (~> 0.14) globalid (0.4.1) @@ -276,10 +278,6 @@ GEM orm_adapter (0.5.0) pdfkit (0.6.2) pg (0.19.0) - poltergeist (1.14.0) - capybara (~> 2.1) - cliver (~> 0.3.1) - websocket-driver (>= 0.2.0) polyamorous (1.3.1) activerecord (>= 3.0) pry (0.10.1) @@ -368,6 +366,7 @@ GEM rspec-support (3.6.0) ruby_parser (3.8.4) sexp_processor (~> 4.1) + rubyzip (1.2.1) safe_yaml (1.0.4) sass (3.4.23) sass-rails (5.0.6) @@ -390,6 +389,9 @@ GEM select2-rails (3.5.9.3) thor (~> 0.14) selectize-rails (0.12.1) + selenium-webdriver (3.13.0) + childprocess (~> 0.5) + rubyzip (~> 1.2) sexp_processor (4.8.0) simplecov (0.15.1) docile (~> 1.1.0) @@ -440,9 +442,6 @@ GEM addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff - websocket-driver (0.6.5) - websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.2) whenever (0.9.4) chronic (>= 0.6.3) xpath (2.0.0) @@ -491,7 +490,6 @@ DEPENDENCIES paper_trail! pdfkit (= 0.6.2) pg (= 0.19.0) - poltergeist pry (= 0.10.1) puma que (= 0.10.0) @@ -507,6 +505,7 @@ DEPENDENCIES sdoc (= 0.4.1) select2-rails (= 3.5.9.3) selectize-rails (= 0.12.1) + selenium-webdriver simplecov simpleidn (= 0.0.7) uglifier From b164a585237823164b3d65493a646cbcbfb380ce Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Fri, 29 Jun 2018 11:25:55 +0300 Subject: [PATCH 04/14] Add new base test class definition --- test/test_helper.rb | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index a55776fd2..7069df7ac 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -11,6 +11,7 @@ require 'minitest/mock' require 'capybara/rails' require 'capybara/minitest' require 'webmock/minitest' +require 'selenium/webdriver' require 'support/rails5_assetions' # Remove once upgraded to Rails 5 Setting.address_processing = false @@ -38,4 +39,29 @@ class ActionDispatch::IntegrationTest Capybara.reset_sessions! Capybara.use_default_driver end -end \ No newline at end of file +end + +class JavascriptIntegrationTest < ActionDispatch::IntegrationTest + Capybara.register_driver(:chrome) do |app| + options = ::Selenium::WebDriver::Chrome::Options.new + + options.add_argument("--headless") + options.add_argument("--no-sandbox") + options.add_argument("--disable-dev-shm-usage") + options.add_argument("--window-size=1400,1400") + + Capybara::Selenium::Driver.new(Rails.application, browser: :chrome, options: options) + end + + Capybara.register_server(:silent_puma) do |app, port, _host| + require "rack/handler/puma" + Rack::Handler::Puma.run(app, Port: port, Threads: "0:2", Silent: true) + end + + def setup + super + + Capybara.current_driver = :chrome + Capybara.server = :silent_puma + end +end From e1f77c1d0366a1a099d35ef9f4a42b06242ccaf1 Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Mon, 9 Jul 2018 10:13:22 +0300 Subject: [PATCH 05/14] Add database cleaner to tests that cannot run in a transaction --- test/test_helper.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test_helper.rb b/test/test_helper.rb index 7069df7ac..2ef18f98f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -13,6 +13,7 @@ require 'capybara/minitest' require 'webmock/minitest' require 'selenium/webdriver' require 'support/rails5_assetions' # Remove once upgraded to Rails 5 +require 'database_cleaner' Setting.address_processing = false Setting.registry_country_code = 'US' @@ -42,6 +43,8 @@ class ActionDispatch::IntegrationTest end class JavascriptIntegrationTest < ActionDispatch::IntegrationTest + DatabaseCleaner.strategy = :truncation + Capybara.register_driver(:chrome) do |app| options = ::Selenium::WebDriver::Chrome::Options.new @@ -59,9 +62,17 @@ class JavascriptIntegrationTest < ActionDispatch::IntegrationTest end def setup + DatabaseCleaner.start + super Capybara.current_driver = :chrome Capybara.server = :silent_puma end + + def teardown + super + + DatabaseCleaner.clean + end end From 0e86214d1cbfb2ffe4ae49207c3eb479e09201c1 Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Mon, 9 Jul 2018 10:35:57 +0300 Subject: [PATCH 06/14] Rewrite test to find the flash message --- test/integration/registrar/sign_in_test.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/integration/registrar/sign_in_test.rb b/test/integration/registrar/sign_in_test.rb index ffbbf352e..cdf4dcd90 100644 --- a/test/integration/registrar/sign_in_test.rb +++ b/test/integration/registrar/sign_in_test.rb @@ -1,6 +1,8 @@ require 'test_helper' -class SignInTest < ActionDispatch::IntegrationTest +class RegistrarSignInTest < JavascriptIntegrationTest + self.use_transactional_fixtures = false + def setup super WebMock.allow_net_connect! @@ -26,7 +28,9 @@ class SignInTest < ActionDispatch::IntegrationTest fill_in 'user[phone]', with: '1234' click_button 'Login' - assert(page.has_text?('Confirmation sms was sent to your phone. Verification code is')) + flash_message = page.find('div.bg-success') + assert_equal('Confirmation sms was sent to your phone. Verification code is .', + flash_message.text) end end end From f5422d7058f670066a75b6c6a28412bfe95939e6 Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Mon, 9 Jul 2018 10:37:46 +0300 Subject: [PATCH 07/14] Add chrome addon to travis CI --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a5fec1a71..55a35651a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,3 +19,4 @@ services: - postgresql addons: postgresql: "9.4" + chrome: stable From 1c09901466d60a89d7478a07efaab68b7b778967 Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Mon, 9 Jul 2018 10:45:26 +0300 Subject: [PATCH 08/14] Move puma to development, test group --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 53993a1b8..e1c3858ba 100644 --- a/Gemfile +++ b/Gemfile @@ -104,7 +104,6 @@ gem 'active_model-errors_details' # Backport from Rails 5, https://github.com/ra group :development do # deploy gem 'mina', '0.3.1' # for fast deployment - gem 'puma' end group :development, :test do @@ -121,6 +120,7 @@ group :development, :test do gem 'sdoc', '0.4.1' # bundle exec rake doc:rails generates the API under doc/api. gem 'railroady', '1.3.0' # to generate database diagrams gem 'autodoc' + gem 'puma' end group :staging do From c1dd115b28e19ac9f335727ac449e1e227276892 Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Mon, 9 Jul 2018 10:54:24 +0300 Subject: [PATCH 09/14] Add chromedriver to travis configuration --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index 55a35651a..430d7fbb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,13 @@ cache: bundler env: - DB=postgresql bundler_args: --without development staging production +before_install: + - "wget -N http://chromedriver.storage.googleapis.com/2.40/chromedriver_linux64.zip -P ~/" + - "unzip ~/chromedriver_linux64.zip -d ~/" + - "rm ~/chromedriver_linux64.zip" + - "sudo mv -f ~/chromedriver /usr/local/share/" + - "sudo chmod +x /usr/local/share/chromedriver" + - "sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver" before_script: - "cp config/application-example.yml config/application.yml" - "cp config/database-travis.yml config/database.yml" From 2bcedd0facf40195a29747d5bc1fa3481acbccd9 Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Mon, 9 Jul 2018 12:45:48 +0300 Subject: [PATCH 10/14] Move transactional fixtures to base class --- test/integration/registrar/sign_in_test.rb | 2 -- test/test_helper.rb | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/integration/registrar/sign_in_test.rb b/test/integration/registrar/sign_in_test.rb index cdf4dcd90..2b82c4301 100644 --- a/test/integration/registrar/sign_in_test.rb +++ b/test/integration/registrar/sign_in_test.rb @@ -1,8 +1,6 @@ require 'test_helper' class RegistrarSignInTest < JavascriptIntegrationTest - self.use_transactional_fixtures = false - def setup super WebMock.allow_net_connect! diff --git a/test/test_helper.rb b/test/test_helper.rb index 2ef18f98f..ffef79e0c 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -43,6 +43,7 @@ class ActionDispatch::IntegrationTest end class JavascriptIntegrationTest < ActionDispatch::IntegrationTest + self.use_transactional_fixtures = false DatabaseCleaner.strategy = :truncation Capybara.register_driver(:chrome) do |app| From 0fa30591a8a44b78188ff247d01101e3353e019f Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Mon, 9 Jul 2018 16:10:40 +0300 Subject: [PATCH 11/14] Add mocked challenge_id to be displayed inside flash message --- test/integration/registrar/sign_in_test.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/integration/registrar/sign_in_test.rb b/test/integration/registrar/sign_in_test.rb index 2b82c4301..f8e1caf50 100644 --- a/test/integration/registrar/sign_in_test.rb +++ b/test/integration/registrar/sign_in_test.rb @@ -12,7 +12,8 @@ class RegistrarSignInTest < JavascriptIntegrationTest def test_mobile_id_sign_in_page mock_client = Minitest::Mock.new - mock_client.expect(:authenticate, OpenStruct.new(user_id_code: '1234'), + mock_client.expect(:authenticate, + OpenStruct.new(user_id_code: '1234', challenge_id: '1234'), [{ phone: "+3721234", message_to_display: "Authenticating", service_name: "Testimine" }]) @@ -27,7 +28,7 @@ class RegistrarSignInTest < JavascriptIntegrationTest click_button 'Login' flash_message = page.find('div.bg-success') - assert_equal('Confirmation sms was sent to your phone. Verification code is .', + assert_equal('Confirmation sms was sent to your phone. Verification code is 1234.', flash_message.text) end end From 3acd605b9079b6735a639cae1244be4e28b549b3 Mon Sep 17 00:00:00 2001 From: Maciej Szlosarczyk Date: Tue, 10 Jul 2018 17:10:26 +0300 Subject: [PATCH 12/14] Change inheritance structure to match the one from Rails 5 more In the future, ApplicationSystemTestCase should inherit from ActionDispatch::SystemTestCase and JavaScriptApplicationSystemTestCase could possibly be removed if the `driven_by` method works as it is promised in Rails documentation: http://api.rubyonrails.org/v5.2/classes/ActionDispatch/SystemTestCase.html Consider introducing another class between ActionDispatch::IntegrationTest and other items inheriting from it, as the general Rails practice seems to have `ApplicationIntegrationTest`, as we do have `ApplicationRecord` and `ApplicationController`. --- test/application_system_test_case.rb | 42 +++++++++++++++++++ .../registrar/sign_in_test.rb | 2 +- test/test_helper.rb | 40 +----------------- 3 files changed, 45 insertions(+), 39 deletions(-) create mode 100644 test/application_system_test_case.rb rename test/{integration => system}/registrar/sign_in_test.rb (93%) diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb new file mode 100644 index 000000000..6c06ef937 --- /dev/null +++ b/test/application_system_test_case.rb @@ -0,0 +1,42 @@ +require 'test_helper' + +require 'database_cleaner' +require 'selenium/webdriver' + +class ApplicationSystemTestCase < ActionDispatch::IntegrationTest; end + +class JavaScriptApplicationSystemTestCase < ApplicationSystemTestCase + self.use_transactional_fixtures = false + DatabaseCleaner.strategy = :truncation + + Capybara.register_driver(:chrome) do |_app| + options = ::Selenium::WebDriver::Chrome::Options.new + + options.add_argument('--headless') + options.add_argument('--no-sandbox') + options.add_argument('--disable-dev-shm-usage') + options.add_argument('--window-size=1400,1400') + + Capybara::Selenium::Driver.new(Rails.application, browser: :chrome, options: options) + end + + Capybara.register_server(:silent_puma) do |app, port, _host| + require 'rack/handler/puma' + Rack::Handler::Puma.run(app, Port: port, Threads: '0:2', Silent: true) + end + + def setup + DatabaseCleaner.start + + super + + Capybara.current_driver = :chrome + Capybara.server = :silent_puma + end + + def teardown + super + + DatabaseCleaner.clean + end +end diff --git a/test/integration/registrar/sign_in_test.rb b/test/system/registrar/sign_in_test.rb similarity index 93% rename from test/integration/registrar/sign_in_test.rb rename to test/system/registrar/sign_in_test.rb index f8e1caf50..9af5522f9 100644 --- a/test/integration/registrar/sign_in_test.rb +++ b/test/system/registrar/sign_in_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class RegistrarSignInTest < JavascriptIntegrationTest +class RegistrarAreaSignInTest < JavaScriptApplicationSystemTestCase def setup super WebMock.allow_net_connect! diff --git a/test/test_helper.rb b/test/test_helper.rb index ffef79e0c..500861f75 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -11,9 +11,9 @@ require 'minitest/mock' require 'capybara/rails' require 'capybara/minitest' require 'webmock/minitest' -require 'selenium/webdriver' require 'support/rails5_assetions' # Remove once upgraded to Rails 5 -require 'database_cleaner' + +require 'application_system_test_case' Setting.address_processing = false Setting.registry_country_code = 'US' @@ -41,39 +41,3 @@ class ActionDispatch::IntegrationTest Capybara.use_default_driver end end - -class JavascriptIntegrationTest < ActionDispatch::IntegrationTest - self.use_transactional_fixtures = false - DatabaseCleaner.strategy = :truncation - - Capybara.register_driver(:chrome) do |app| - options = ::Selenium::WebDriver::Chrome::Options.new - - options.add_argument("--headless") - options.add_argument("--no-sandbox") - options.add_argument("--disable-dev-shm-usage") - options.add_argument("--window-size=1400,1400") - - Capybara::Selenium::Driver.new(Rails.application, browser: :chrome, options: options) - end - - Capybara.register_server(:silent_puma) do |app, port, _host| - require "rack/handler/puma" - Rack::Handler::Puma.run(app, Port: port, Threads: "0:2", Silent: true) - end - - def setup - DatabaseCleaner.start - - super - - Capybara.current_driver = :chrome - Capybara.server = :silent_puma - end - - def teardown - super - - DatabaseCleaner.clean - end -end From 9bfc5d6be84ea591e00022413c5ef1730b5c07cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Wed, 11 Jul 2018 15:44:41 +0300 Subject: [PATCH 13/14] Changelog update 180712 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 838ff6ea4..ecefbb279 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +12.07.2018 +* Implemented JavaScript testing framework to catch web UI problems [#900](https://github.com/internetee/registry/issues/900) + 10.07.2018 * Nameserver bulk change returns list of affected doamins [#835](https://github.com/internetee/registry/issues/835) From ceeed8d23fda8ab2232385dcd3dd91e3a09c97ea Mon Sep 17 00:00:00 2001 From: Artur Beljajev Date: Wed, 11 Jul 2018 20:24:55 +0300 Subject: [PATCH 14/14] Update "webmock" gem --- Gemfile.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6932af4ad..9d9f99da9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -99,8 +99,8 @@ GEM minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - addressable (2.5.1) - public_suffix (~> 2.0, >= 2.0.2) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) airbrake (6.0.0) airbrake-ruby (~> 2.0) airbrake-ruby (2.0.0) @@ -206,7 +206,7 @@ GEM haml (>= 4.0.6, < 5.0) html2haml (>= 1.0.1) railties (>= 4.0.1) - hashdiff (0.3.4) + hashdiff (0.3.7) hashie (3.5.5) hashie-forbidden_attributes (0.1.1) hashie (>= 3.0) @@ -284,7 +284,7 @@ GEM coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - public_suffix (2.0.5) + public_suffix (3.0.2) puma (3.8.2) que (0.10.0) que-web (0.4.0) @@ -438,7 +438,7 @@ GEM wasabi (3.5.0) httpi (~> 2.0) nokogiri (>= 1.4.2) - webmock (3.0.1) + webmock (3.4.2) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff