From 642919f33a585704438c775857817c0b103667f5 Mon Sep 17 00:00:00 2001 From: Kyle McGough Date: Sat, 11 Jan 2020 12:24:15 -0800 Subject: [PATCH] Moved browser variables to the Kinchan module, did some refactoring, and wrote a few tests --- .rspec | 1 + Gemfile | 2 +- Gemfile.lock | 21 ++++++-- README.md | 6 +-- bin/bundle | 114 +++++++++++++++++++++++++++++++++++++++++ bin/htmldiff | 29 +++++++++++ bin/ldiff | 29 +++++++++++ bin/rake | 29 +++++++++++ bin/rspec | 29 +++++++++++ kinchan.gemspec | 2 + lib/kinchan.rb | 44 +++++++++++----- lib/kinchan/version.rb | 2 +- spec/kinchan_spec.rb | 29 +++++++++++ spec/spec_helper.rb | 100 ++++++++++++++++++++++++++++++++++++ 14 files changed, 415 insertions(+), 22 deletions(-) create mode 100644 .rspec create mode 100755 bin/bundle create mode 100755 bin/htmldiff create mode 100755 bin/ldiff create mode 100755 bin/rake create mode 100755 bin/rspec create mode 100644 spec/kinchan_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..c99d2e7 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/Gemfile b/Gemfile index 6c69e1c..5a5c3fe 100644 --- a/Gemfile +++ b/Gemfile @@ -3,4 +3,4 @@ source "https://rubygems.org" # Specify your gem's dependencies in kinchan.gemspec gemspec -gem "rake", "~> 12.0" +gem "rake", "~> 13.0" diff --git a/Gemfile.lock b/Gemfile.lock index 4229a8b..6d16b50 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,10 +9,24 @@ GEM remote: https://rubygems.org/ specs: childprocess (3.0.0) - rake (12.3.2) + diff-lcs (1.3) + rake (13.0.1) require_all (3.0.0) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + rspec-core (3.9.1) + rspec-support (~> 3.9.1) + rspec-expectations (3.9.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.9.0) + rspec-mocks (3.9.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.9.0) + rspec-support (3.9.2) rubyzip (2.0.0) - selenium-webdriver (3.142.6) + selenium-webdriver (3.142.7) childprocess (>= 0.5, < 4.0) rubyzip (>= 1.2.2) @@ -21,7 +35,8 @@ PLATFORMS DEPENDENCIES kinchan! - rake (~> 12.0) + rake (~> 13.0) + rspec (~> 3.9.0) BUNDLED WITH 2.1.2 diff --git a/README.md b/README.md index 20e120b..717d49d 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Task's do not need to be in the same scope, as long as the task exists Kinchan w before running your task you can modify the selenium browser options like so ```ruby -Kinchan::Task.browser = :chrome -Kinchan::Task.browser_options = Selenium::WebDriver::Chrome::Options.new -Kinchan::Task.browser_options.add_argument('--headless') +Kinchan.browser = :chrome +Kinchan.browser_options = Selenium::WebDriver::Chrome::Options.new +Kinchan.browser_options.add_argument('--headless') ``` diff --git a/bin/bundle b/bin/bundle new file mode 100755 index 0000000..a71368e --- /dev/null +++ b/bin/bundle @@ -0,0 +1,114 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundle' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "rubygems" + +m = Module.new do + module_function + + def invoked_as_script? + File.expand_path($0) == File.expand_path(__FILE__) + end + + def env_var_version + ENV["BUNDLER_VERSION"] + end + + def cli_arg_version + return unless invoked_as_script? # don't want to hijack other binstubs + return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` + bundler_version = nil + update_index = nil + ARGV.each_with_index do |a, i| + if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN + bundler_version = a + end + next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ + bundler_version = $1 + update_index = i + end + bundler_version + end + + def gemfile + gemfile = ENV["BUNDLE_GEMFILE"] + return gemfile if gemfile && !gemfile.empty? + + File.expand_path("../../Gemfile", __FILE__) + end + + def lockfile + lockfile = + case File.basename(gemfile) + when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) + else "#{gemfile}.lock" + end + File.expand_path(lockfile) + end + + def lockfile_version + return unless File.file?(lockfile) + lockfile_contents = File.read(lockfile) + return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ + Regexp.last_match(1) + end + + def bundler_version + @bundler_version ||= + env_var_version || cli_arg_version || + lockfile_version + end + + def bundler_requirement + return "#{Gem::Requirement.default}.a" unless bundler_version + + bundler_gem_version = Gem::Version.new(bundler_version) + + requirement = bundler_gem_version.approximate_recommendation + + return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") + + requirement += ".a" if bundler_gem_version.prerelease? + + requirement + end + + def load_bundler! + ENV["BUNDLE_GEMFILE"] ||= gemfile + + activate_bundler + end + + def activate_bundler + gem_error = activation_error_handling do + gem "bundler", bundler_requirement + end + return if gem_error.nil? + require_error = activation_error_handling do + require "bundler/version" + end + return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) + warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" + exit 42 + end + + def activation_error_handling + yield + nil + rescue StandardError, LoadError => e + e + end +end + +m.load_bundler! + +if m.invoked_as_script? + load Gem.bin_path("bundler", "bundle") +end diff --git a/bin/htmldiff b/bin/htmldiff new file mode 100755 index 0000000..091820c --- /dev/null +++ b/bin/htmldiff @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'htmldiff' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("diff-lcs", "htmldiff") diff --git a/bin/ldiff b/bin/ldiff new file mode 100755 index 0000000..073e19f --- /dev/null +++ b/bin/ldiff @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'ldiff' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("diff-lcs", "ldiff") diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..9275675 --- /dev/null +++ b/bin/rake @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rake' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rake", "rake") diff --git a/bin/rspec b/bin/rspec new file mode 100755 index 0000000..a6c7852 --- /dev/null +++ b/bin/rspec @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rspec' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rspec-core", "rspec") diff --git a/kinchan.gemspec b/kinchan.gemspec index a7e6b9a..0d9de0d 100644 --- a/kinchan.gemspec +++ b/kinchan.gemspec @@ -27,4 +27,6 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'selenium-webdriver', ['~> 3.142.6'] spec.add_runtime_dependency 'require_all', ['~> 3.0.0'] + + spec.add_development_dependency 'rspec', ['~> 3.9.0'] end diff --git a/lib/kinchan.rb b/lib/kinchan.rb index e427ae5..422c833 100644 --- a/lib/kinchan.rb +++ b/lib/kinchan.rb @@ -5,21 +5,37 @@ require 'require_all' module Kinchan - class Error < StandardError; end + @browser = :chrome + @browser_options = nil + + def self.browser + @browser + end + + def self.browser= b + @browser = b + end + + def self.browser_options + @browser_options + end + + def self.browser_options= bo + @browser_options = bo + end class Task singleton_class.send(:attr_accessor, :browser) singleton_class.send(:attr_accessor, :browser_options) singleton_class.send(:attr_reader, :descendants) @descendants = [] - @browser = :chrome - @browser_options = nil - @@browser_webdriver = nil def initialize(**options) @before_tasks = [] @after_tasks = [] @options = options + + Task.start_browser end def self.inherited(subclass) @@ -30,24 +46,24 @@ def self.find_task(task_symbol) Task.descendants.select { |task| task.name.split('::').last.downcase == task_symbol.to_s.downcase }[0] end + def self.start_browser + if Kinchan.browser_options.nil? + @@browser_webdriver = Selenium::WebDriver.for Kinchan.browser + else + @@browser_webdriver = Selenium::WebDriver.for(Kinchan.browser, options: Kinchan.browser_options) + end + end + def self.restart_browser unless @@browser_webdriver.nil? @@browser_webdriver.close - @@browser_webdriver = Selenium::WebDriver.for Task.browser + @@browser_webdriver = Selenium::WebDriver.for Kinchan.browser end end def execute(browser); end def run - if @@browser_webdriver.nil? - if Task.browser_options.nil? - @@browser_webdriver = Selenium::WebDriver.for Task.browser - else - @@browser_webdriver = Selenium::WebDriver.for(Task.browser, options: Task.browser_options) - end - end - @before_tasks.each do |task_hash| task = Task.find_task(task_hash[:task]) task.new(**task_hash[:options]).public_send('run') unless task.nil? @@ -63,4 +79,4 @@ def run end end -require_all 'tasks' +require_all 'tasks' if File.directory?('tasks') diff --git a/lib/kinchan/version.rb b/lib/kinchan/version.rb index 4908d19..00b1cf8 100644 --- a/lib/kinchan/version.rb +++ b/lib/kinchan/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Kinchan - VERSION = '0.1.0' + VERSION = '0.2.0' end diff --git a/spec/kinchan_spec.rb b/spec/kinchan_spec.rb new file mode 100644 index 0000000..cdb2a8d --- /dev/null +++ b/spec/kinchan_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +require_relative '../lib/kinchan' + +RSpec.describe Kinchan do + it 'defines the default browser' do + expect(Kinchan.browser).to eq(:chrome) + end + + it 'allows the browser to be redefined' do + Kinchan.browser = :firefox + expect(Kinchan.browser).to eq(:firefox) + end + + it "doesn't specify default browser options" do + expect(Kinchan.browser_options).to eq(nil) + end + + it 'allows the browser options to be defined' do + Kinchan.browser_options = :dummy_options + expect(Kinchan.browser_options).to eq(:dummy_options) + end +end + +RSpec.describe Kinchan::Task do + it 'can find defined tasks' do + class NuTask < Kinchan::Task; end + expect(Kinchan::Task.find_task(:nutask)).to eq(NuTask) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..251aa51 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,100 @@ +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = "doc" + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end