diff --git a/.gitignore b/.gitignore index c81fb40..5264e68 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ chromedriver.log # Capybara related artifacts capybara-*.html output.html + +# Ignore your project specific config.yml config file +config.yml diff --git a/Gemfile b/Gemfile index 9c2c9bc..c5587a9 100644 --- a/Gemfile +++ b/Gemfile @@ -61,6 +61,10 @@ gem 'sinatra' # Sinatra recommends using Thin. Thin is a "Tiny, fast & funny HTTP server" gem 'thin' +# Gives us a simpler way to load code. Essentially using this we can require +# everything in our lib folder with just a single line of code in app.rb +gem 'require_all' + # This groups covers gems which should be installed if you are actively working # on Quke itself. group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 6f4814a..06df78a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -65,6 +65,7 @@ GEM rb-fsevent (0.9.7) rb-inotify (0.9.7) ffi (>= 0.5.0) + require_all (1.3.3) rerun (0.11.0) listen (~> 3.0) rspec-expectations (3.4.0) @@ -106,6 +107,7 @@ DEPENDENCIES launchy poltergeist rake + require_all rerun rspec-expectations selenium-webdriver diff --git a/README.md b/README.md index 50d5473..627e639 100644 --- a/README.md +++ b/README.md @@ -98,28 +98,33 @@ If you want more control and access to all the options available to cucumber (se bundle exec cucumber ``` -### Options +## Options -Quke recognises 2 options which are read from environment variables. The easiest way to do this is on the command line. +Quke recognises 3 options -- **DRIVER** - Tells Quke which browser to use for testing - - `DRIVER=chrome bundle exec cucumber` -- **PAUSE** - Add a pause (in seconds) between steps so you can visually track how the browser is responding - - `PAUSE=1 bundle exec rake chrome` +- **app_host** - Set the root url. You can then use it directly using Capybara with `visit('/Main_Page')` or `visit('/')` rather than having to repeat the full url each time +- **driver** - Tell Quke which browser to use for testing. Options are *chrome*, *firefox* and *poltergeist* (*poltergeist* is the default) +- **pause** - Add a pause (in seconds) between steps so you can visually track how the browser is responding. The default is *0* -You can combine these options along with arguments to be passed to Cucumber +You can set your options using either a [yaml](http://yaml.org/) config file named `config.yml` to the root of the project (see [config.example.yml](/config.example.yml)), or using environment variables. -```bash -DRIVER=chrome PAUSE=1 bundle exec cucumber -t @smoke -``` +- `export APP_HOST='https://en.wikipedia.org/wiki'` +- `export DRIVER=chrome` +- `export PAUSE=1` + +### Precedence + +Environment variables take precedence over the config file. This is to make it easier to define things that don't change often in the config file, combined with the flexibility of setting environment variables at runtime using the command line. + +So imagine we have set `app_host: 'https://en.wikipedia.org/wiki'` in our `config.yml`, we can switch between the browsers to test using this syntax -This is telling Quke to use Chrome as its browser for testing, to pause for 1 second between steps, and to run only those features and scenarios tagged with `@smoke`. +- `DRIVER=chrome bundle exec cucumber` ### Why `bundle exec`? Using `bundle exec` at the start of each command is to ensure we are using the version of a *thing* that was installed in the context of Quke, which in our case is Cucumber. While a command may work without it, doing so is unreliable and should be avoided. -### Confirming it works +## Confirming it works Included in Quke are some feature tests which can be used for reference, but also to confirm you have it setup and working correctly. They run against an internal demo web app which you'll need to start before executing the tests. diff --git a/config.example.yml b/config.example.yml new file mode 100644 index 0000000..582167f --- /dev/null +++ b/config.example.yml @@ -0,0 +1,16 @@ +# Normally Capybara expects to be testing an in-process Rack application, but +# we're using it to talk to a remote host. Users of Quke can set what this will +# be by simply setting `app_host`. You can then use it directly using +# Capybara `visit('/Main_Page')` or `visit('/')` rather than having to repeat +# the full url each time. When using the Site_Prism page_objects use +# `set_url '/Main_Page'`. The default is ''. +app_host: 'https://en.wikipedia.org/wiki' + +# Tells Quke which browser to use for testing. Choices are firefox, chrome and +# poltergeist, with the default being poltergeist. +driver: chrome + +# Add a pause (in seconds) between steps so you can visually track how the +# browser is responding. On useful if using a non-headless browser. The default +# is 0. +pause: 1 diff --git a/features/support/env.rb b/features/support/env.rb index 4cfaa77..e3fe5c6 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -2,6 +2,10 @@ require 'capybara/cucumber' require 'capybara/poltergeist' require 'site_prism' +require 'require_all' + +# load all ruby files in the directory "lib" and its subdirectories +require_all 'lib' # To run the scenarios in browser (default: Firefox), use the following # command line: @@ -23,14 +27,11 @@ # selectors in your step definitions to use the XPath syntax. # Capybara.default_selector = :xpath -# Normally Capybara expects to be testing an in-process Rack application, but -# we're using it to talk to a remote host. Users of quke can set what this will -# be by simply setting the environment variable APP_HOST. An example would be -# APP_HOST='https://en.wikipedia.org/wiki'. You can then use it directly using -# Capybara `visit('/Main_Page')` or `visit('/')`. In your page_objects -# `set_url '/Main_Page'` -$app_host = (ENV['APP_HOST'] || '') -Capybara.app_host = $app_host +# Instantiate our Config object which collates the options and settings used +# by Quke or its dependencies, from environment variables, the config.yml file +# and any defaults Quke uses. +$config = Quke::Config.new +Capybara.app_host = $config.app_host # Here we are registering the poltergeist driver with capybara. There are a # number of options for how to configure poltergeist, and we can even pass @@ -71,7 +72,7 @@ # poltergeist # We capture the value as a global env var so if necessary choice of browser # can be referenced elsewhere, for example in any debug output. -$driver = case (ENV['DRIVER'] || '').downcase.strip +$driver = case $config.driver when 'firefox' :firefox when 'chrome' @@ -95,11 +96,6 @@ # which can get in the way when trying to work with Quke in your projects. Capybara.save_path = 'tmp/' -# We capture the value as a global env var so if necessary length of time -# between page interactions can be referenced elsewhere, for example in any -# debug output. -$pause = (ENV['PAUSE'] || 0).to_i - # By default, SitePrism element and section methods do not utilize Capybara's # implicit wait methodology and will return immediately if the element or # section requested is not found on the page. Adding the following code diff --git a/features/support/hooks/quke/after_step.rb b/features/support/hooks/quke/after_step.rb index 3284124..1a96754 100644 --- a/features/support/hooks/quke/after_step.rb +++ b/features/support/hooks/quke/after_step.rb @@ -1,5 +1,5 @@ # We use cucumber's AfterStep hook to insert our pause between pages if # one was set AfterStep do - sleep($pause) + sleep($config.pause) end diff --git a/lib/quke/config.rb b/lib/quke/config.rb new file mode 100644 index 0000000..3cc9805 --- /dev/null +++ b/lib/quke/config.rb @@ -0,0 +1,52 @@ +require 'yaml' + +module Quke + # Go away + class Config + class << self + def file_location + @file_location ||= File.expand_path( + '../../config.yml', + File.dirname(__FILE__) + ) + end + end + + def initialize + @data = load_data + end + + def app_host + @data['app_host'] + end + + def driver + @data['driver'] + end + + def pause + @data['pause'] + end + + private + + # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize + def load_data + yml_data = load_yml_data + yml_data.merge( + 'app_host' => (ENV['APP_HOST'] || yml_data['app_host'] || '').downcase.strip, + 'driver' => (ENV['DRIVER'] || yml_data['driver'] || '').downcase.strip, + 'pause' => (ENV['PAUSE'] || yml_data['pause'] || '0').downcase.strip.to_i + ) + end + # rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize + + def load_yml_data + if File.exist? self.class.file_location + YAML.load_file self.class.file_location + else + {} + end + end + end +end