From ad27caf73e4fb11e1b1a34a99f741e55f4f16b18 Mon Sep 17 00:00:00 2001 From: PaulDoyle-DEFRA <97455399+PaulDoyle-DEFRA@users.noreply.github.com> Date: Wed, 23 Aug 2023 17:16:49 +0100 Subject: [PATCH] Upgrade Selenium (#113) --- .rubocop.yml | 6 + .rubocop_todo.yml | 82 +++++++++++++ .ruby-version | 2 +- Gemfile | 15 +++ README.md | 9 -- lib/quke.rb | 3 +- lib/quke/Rakefile | 14 --- lib/quke/browserstack_configuration.rb | 4 +- lib/quke/browserstack_status_reporter.rb | 2 +- lib/quke/configuration.rb | 4 +- lib/quke/cuke_runner.rb | 2 +- lib/quke/driver_configuration.rb | 7 +- lib/quke/driver_registration.rb | 2 +- lib/quke/proxy_configuration.rb | 2 +- lib/quke/version.rb | 2 +- quke.gemspec | 23 +--- spec/quke/browserstack_configuration_spec.rb | 69 ++++++----- .../quke/browserstack_status_reporter_spec.rb | 10 +- spec/quke/configuration_spec.rb | 114 +++++++++--------- spec/quke/driver_configuration_spec.rb | 44 +++---- spec/quke/driver_registration_spec.rb | 4 +- spec/quke/proxy_configuration_spec.rb | 14 +-- spec/quke/quke_spec.rb | 6 +- spec/spec_helper.rb | 5 +- spec/support/simplecov.rb | 48 +++++--- 25 files changed, 284 insertions(+), 209 deletions(-) create mode 100644 .rubocop_todo.yml delete mode 100644 lib/quke/Rakefile diff --git a/.rubocop.yml b/.rubocop.yml index 0cd780f..31e3ba5 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,3 +1,9 @@ +inherit_from: .rubocop_todo.yml + inherit_gem: defra_ruby_style: - default.yml + +require: + - rubocop-rake + - rubocop-rspec diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 0000000..6ff8538 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,82 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2023-08-14 14:02:05 UTC using RuboCop version 1.56.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 8 +# Configuration parameters: EnforcedStyle, AllowedGems, Include. +# SupportedStyles: Gemfile, gems.rb, gemspec +# Include: **/*.gemspec, **/Gemfile, **/gems.rb +Gemspec/DevelopmentDependencies: + Exclude: + - 'quke.gemspec' + +# Offense count: 1 +# Configuration parameters: Severity, Include. +# Include: **/*.gemspec +Gemspec/RequiredRubyVersion: + Exclude: + - 'quke.gemspec' + +# Offense count: 1 +# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches. +Lint/DuplicateBranch: + Exclude: + - 'lib/quke/driver_registration.rb' + +# Offense count: 16 +# Configuration parameters: Prefixes, AllowedPatterns. +# Prefixes: when, with, without +RSpec/ContextWording: + Exclude: + - 'spec/quke/configuration_spec.rb' + - 'spec/quke/driver_configuration_spec.rb' + - 'spec/quke/driver_registration_spec.rb' + +# Offense count: 18 +# Configuration parameters: CountAsOne. +RSpec/ExampleLength: + Max: 22 + +# Offense count: 2 +RSpec/ExpectInHook: + Exclude: + - 'spec/quke/quke_spec.rb' + +# Offense count: 2 +RSpec/IdenticalEqualityAssertion: + Exclude: + - 'spec/quke/driver_registration_spec.rb' + +# Offense count: 2 +# Configuration parameters: . +# SupportedStyles: have_received, receive +RSpec/MessageSpies: + EnforcedStyle: receive + +# Offense count: 10 +RSpec/MultipleExpectations: + Max: 17 + +# Offense count: 6 +# Configuration parameters: AllowSubject. +RSpec/MultipleMemoizedHelpers: + Max: 6 + +# Offense count: 83 +# Configuration parameters: EnforcedStyle, IgnoreSharedExamples. +# SupportedStyles: always, named_only +RSpec/NamedSubject: + Exclude: + - 'spec/quke/browserstack_configuration_spec.rb' + - 'spec/quke/browserstack_status_reporter_spec.rb' + - 'spec/quke/configuration_spec.rb' + - 'spec/quke/proxy_configuration_spec.rb' + +# Offense count: 1 +# Configuration parameters: AllowedGroups. +RSpec/NestedGroups: + Max: 4 diff --git a/.ruby-version b/.ruby-version index 8e8299d..be94e6f 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.4.2 +3.2.2 diff --git a/Gemfile b/Gemfile index 55c4b1d..1a7315c 100644 --- a/Gemfile +++ b/Gemfile @@ -4,3 +4,18 @@ source "https://rubygems.org" # Specify your gem's dependencies in quke.gemspec gemspec + +group :development, :test do + gem "defra_ruby_style" + gem "github_changelog_generator" + gem "pry-byebug" + gem "rake" + gem "rdoc" + gem "rspec" + gem "rubocop" + gem "rubocop-rake" + gem "rubocop-rspec" + gem "simplecov", "~> 0.17.1" + gem "simplecov-json", require: false + gem "webmock" +end diff --git a/README.md b/README.md index 4b7ce91..566b064 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ ![Build Status](https://github.com/DEFRA/quke/workflows/CI/badge.svg?branch=main) [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=DEFRA_quke&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=DEFRA_quke) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=DEFRA_quke&metric=coverage)](https://sonarcloud.io/dashboard?id=DEFRA_quke) -[![security](https://hakiri.io/github/DEFRA/quke/main.svg)](https://hakiri.io/github/DEFRA/quke/main) [![Gem Version](https://badge.fury.io/rb/quke.svg)](https://badge.fury.io/rb/quke) [![Licence](https://img.shields.io/badge/Licence-OGLv3-blue.svg)](http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3) @@ -119,14 +118,6 @@ A very simple overview of how things work is that - [Selenium](https://github.com/SeleniumHQ/selenium/tree/master/rb) is used to tell the browsers what to do - each browser has a driver ([Chromedriver](https://chromedriver.chromium.org/), [Geckodriver](https://github.com/mozilla/geckodriver) etc) which can interpret Selenium commands into actual actions -For Quke to work those browser drivers need to be installed. Quke manages this for you using a tool called [Webdrivers](https://github.com/titusfortner/webdrivers). There may be times you want to check the version of these drivers, or force an update to a specific version. - -If your project is using [Rake](https://github.com/ruby/rake) add the following to the `Rakefile` and you can then access a series of helper functions, for example `rake webdrivers:chromedriver:version` - -```ruby -require "quke" -load "quke/Rakefile" -``` ## Development diff --git a/lib/quke.rb b/lib/quke.rb index 91a8686..e65d8b6 100644 --- a/lib/quke.rb +++ b/lib/quke.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "selenium/webdriver" -require "webdrivers" require "capybara" require "quke/version" @@ -13,7 +12,7 @@ require "quke/driver_configuration" require "quke/proxy_configuration" -module Quke #:nodoc: +module Quke # :nodoc: class QukeError < StandardError; end diff --git a/lib/quke/Rakefile b/lib/quke/Rakefile deleted file mode 100644 index 42d2e1b..0000000 --- a/lib/quke/Rakefile +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -# Add support to quke to run the webdrivers rake tasks from host project -# https://github.com/titusfortner/webdrivers#rake-tasks -# -# An acceptance test project that has quke as a dependency can then do the -# following to access these rake tasks directly -# -# # Add to project's `Rakefile` -# require "quke" -# load "quke/Rakefile" -# -require "webdrivers" -load "webdrivers/Rakefile" diff --git a/lib/quke/browserstack_configuration.rb b/lib/quke/browserstack_configuration.rb index 1a0d768..ab13b74 100644 --- a/lib/quke/browserstack_configuration.rb +++ b/lib/quke/browserstack_configuration.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Quke #:nodoc: +module Quke # :nodoc: # Determines the configuration for browserstack, when selected as the driver class BrowserstackConfiguration @@ -108,7 +108,7 @@ def using_browserstack? # ) # def url - return "http://#{@username}:#{@auth_key}@hub.browserstack.com/wd/hub" unless @username == "" + "http://#{@username}:#{@auth_key}@hub.browserstack.com/wd/hub" unless @username == "" end private diff --git a/lib/quke/browserstack_status_reporter.rb b/lib/quke/browserstack_status_reporter.rb index 28ab9a0..85592fc 100644 --- a/lib/quke/browserstack_status_reporter.rb +++ b/lib/quke/browserstack_status_reporter.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Quke #:nodoc: +module Quke # :nodoc: # Used to update the status of a session in Browserstack to mark it as passed # or failed. It does this by making a PUT request to Browserstack's REST API diff --git a/lib/quke/configuration.rb b/lib/quke/configuration.rb index 05a8092..1f84144 100644 --- a/lib/quke/configuration.rb +++ b/lib/quke/configuration.rb @@ -2,7 +2,7 @@ require "yaml" -module Quke #:nodoc: +module Quke # :nodoc: # Manages all configuration for Quke. class Configuration @@ -110,9 +110,7 @@ def pause def stop_on_error # This use of Yaml.load to convert a string to a boolean comes from # http://stackoverflow.com/a/21804027/6117745 - # rubocop:disable Security/YAMLLoad YAML.load(@data["stop_on_error"]) - # rubocop:enable Security/YAMLLoad end # Returns the value set for +display_failures+. diff --git a/lib/quke/cuke_runner.rb b/lib/quke/cuke_runner.rb index 9a39132..15a8f30 100644 --- a/lib/quke/cuke_runner.rb +++ b/lib/quke/cuke_runner.rb @@ -2,7 +2,7 @@ require "cucumber" -module Quke #:nodoc: +module Quke # :nodoc: # Handles executing Cucumber, including sorting the arguments we pass to it class CukeRunner diff --git a/lib/quke/driver_configuration.rb b/lib/quke/driver_configuration.rb index 7d1e59d..bd1e429 100644 --- a/lib/quke/driver_configuration.rb +++ b/lib/quke/driver_configuration.rb @@ -2,7 +2,7 @@ require "quke/configuration" -module Quke #:nodoc: +module Quke # :nodoc: # Helper class that manages the options, switches and capabilities for each of # the different drivers. @@ -54,8 +54,9 @@ def initialize(config) def chrome no_proxy = config.proxy.no_proxy.tr(",", ";") - options = Selenium::WebDriver::Chrome::Options.new - options.headless! if config.headless + args = config.headless ? ["--headless=new"] : [] + + options = Selenium::WebDriver::Options.chrome(args: args) options.add_argument("--proxy-server=#{config.proxy.host}:#{config.proxy.port}") if config.proxy.use_proxy? options.add_argument("--proxy-bypass-list=#{no_proxy}") unless config.proxy.no_proxy.empty? diff --git a/lib/quke/driver_registration.rb b/lib/quke/driver_registration.rb index 9be8401..9c75424 100644 --- a/lib/quke/driver_registration.rb +++ b/lib/quke/driver_registration.rb @@ -3,7 +3,7 @@ require "quke/configuration" require "selenium/webdriver" -module Quke #:nodoc: +module Quke # :nodoc: # Helper class that contains all methods related to registering drivers with # Capybara. diff --git a/lib/quke/proxy_configuration.rb b/lib/quke/proxy_configuration.rb index 0000fbf..1c8a2b7 100644 --- a/lib/quke/proxy_configuration.rb +++ b/lib/quke/proxy_configuration.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Quke #:nodoc: +module Quke # :nodoc: # Manages all proxy configuration for Quke. class ProxyConfiguration diff --git a/lib/quke/version.rb b/lib/quke/version.rb index 44aabcc..c71e5d0 100644 --- a/lib/quke/version.rb +++ b/lib/quke/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -module Quke #:nodoc: +module Quke # :nodoc: VERSION = "0.10.0" end diff --git a/quke.gemspec b/quke.gemspec index 0ffcac3..ab87556 100644 --- a/quke.gemspec +++ b/quke.gemspec @@ -22,7 +22,6 @@ Gem::Specification.new do |spec| spec.files = Dir["{bin,exe,lib}/**/*", "LICENSE", "Rakefile", "README.md"] spec.bindir = "exe" spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } - spec.test_files = Dir["spec/**/*"] spec.require_paths = ["lib"] @@ -33,7 +32,7 @@ Gem::Specification.new do |spec| spec.metadata["allowed_push_host"] = "https://rubygems.org" else raise "RubyGems 2.0 or newer is required to protect against " \ - "public gem pushes." + "public gem pushes." end spec.required_ruby_version = ">= 2.4" @@ -54,14 +53,7 @@ Gem::Specification.new do |spec| # selenium-webdriver is used to drive browsers like Firefox, Chrome and # Internet Explorer. - spec.add_dependency "selenium-webdriver", "~> 3.14" - - # Needed to use Chrome or Firefox for selenium tests. You can opt - # to install each driver separately. However in an effort to make using this - # gem as simple as possible we have gone with using webdrivers. To quote - # from it "Run Selenium tests more easily with automatic installation and - # updates for all supported webdrivers." - spec.add_dependency "webdrivers", "~> 4.0" + spec.add_dependency "selenium-webdriver", "~> 4.1" # Experience has shown that keeping tests dry helps make them more # maintainable over time. One practice that helps is the use of the @@ -84,14 +76,5 @@ Gem::Specification.new do |spec| # and provides an API for managing it. spec.add_dependency "browserstack-local" - spec.add_development_dependency "defra_ruby_style" - spec.add_development_dependency "github_changelog_generator" - # Adds step-by-step debugging and stack navigation capabilities to pry using - # byebug - spec.add_development_dependency "pry-byebug" - spec.add_development_dependency "rake" - spec.add_development_dependency "rdoc" - spec.add_development_dependency "rspec", "~> 3.8" - spec.add_development_dependency "simplecov", "~> 0.17.1" - spec.add_development_dependency "webmock", "~> 3.5" + spec.metadata["rubygems_mfa_required"] = "true" end diff --git a/spec/quke/browserstack_configuration_spec.rb b/spec/quke/browserstack_configuration_spec.rb index cc026a9..0c78a2b 100644 --- a/spec/quke/browserstack_configuration_spec.rb +++ b/spec/quke/browserstack_configuration_spec.rb @@ -5,11 +5,12 @@ RSpec.describe Quke::BrowserstackConfiguration do describe "instantiating" do context "when `.config.yml` is blank or contains no browserstack section" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".no_file.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "returns an instance defaulted to blank values" do expect(subject.username).to eq("") @@ -21,11 +22,12 @@ end context "when `.config.yml` contains a browserstack section" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".simple.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "returns an instance with properties that match the input" do expect(subject.username).to eq("jdoe") @@ -41,10 +43,6 @@ end context "when `.config.yml` contains a browserstack section but credentials are in env vars" do - let(:config) do - Quke::Configuration.file_location = data_path(".browserstack_no_credentials.yml") - Quke::Configuration.new - end subject do stub_const( "ENV", @@ -52,7 +50,12 @@ "BROWSERSTACK_AUTH_KEY" => "123456789VWXYZ", "BROWSERSTACK_LOCAL_KEY" => "123456789REDRU" ) - Quke::BrowserstackConfiguration.new(config) + described_class.new(config) + end + + let(:config) do + Quke::Configuration.file_location = data_path(".browserstack_no_credentials.yml") + Quke::Configuration.new end it "returns an instance with properties that match the input" do @@ -71,27 +74,29 @@ describe "#test_locally?" do context "when `.config.yml` is blank or contains no browserstack section" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".no_file.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "returns false" do - expect(subject.test_locally?).to eq(false) + expect(subject.test_locally?).to be(false) end end context "when the driver is not set to 'browserstack' in `.config.yml`" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".simple.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "returns false" do - expect(subject.test_locally?).to eq(false) + expect(subject.test_locally?).to be(false) end end @@ -102,27 +107,29 @@ # in this scenario to reflect what browserstack's behaviour would be # i.e. it would fail to recognise that running locally is needed. context "when the driver is 'browserstack' and use local testing is set to 'true' (a string) in `.config.yml`" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".as_string.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "returns false" do - expect(subject.test_locally?).to eq(false) + expect(subject.test_locally?).to be(false) end end context "when the driver is 'browserstack' and use local testing is set to true in `.config.yml`" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".browserstack.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "returns true" do - expect(subject.test_locally?).to eq(true) + expect(subject.test_locally?).to be(true) end end @@ -130,11 +137,12 @@ describe "local_testing_args" do context "when `.config.yml` is blank or contains no browserstack section" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".no_file.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "defaults to a blank key, and our standard args for the local binary" do expect(subject.local_testing_args).to eq( @@ -149,11 +157,12 @@ end context "when `.config.yml` contains just proxy details" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".proxy_basic.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "defaults to a blank key, our standard args for the local binary, plus the proxy values" do expect(subject.local_testing_args).to eq( @@ -169,11 +178,12 @@ end context "when `.config.yml` contains both browserstack and proxy details" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".browserstack.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "defaults to a blank key, our standard args for the local binary, plus the proxy values" do expect(subject.local_testing_args).to eq( @@ -192,39 +202,42 @@ describe "#using_browserstack?" do context "when `.config.yml` is blank" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".no_file.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "returns false" do - expect(subject.using_browserstack?).to eq(false) + expect(subject.using_browserstack?).to be(false) end end context "when `.config.yml` DOES NOT specify 'browserstack' as the driver" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".simple.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "returns false" do - expect(subject.using_browserstack?).to eq(false) + expect(subject.using_browserstack?).to be(false) end end context "when `.config.yml` specifies 'browserstack' as the driver" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".browserstack.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "returns true" do - expect(subject.using_browserstack?).to eq(true) + expect(subject.using_browserstack?).to be(true) end end @@ -233,23 +246,25 @@ describe "#url" do context "when `.config.yml` is blank or contains no browserstack section" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".no_file.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "returns nil" do - expect(subject.url).to eq(nil) + expect(subject.url).to be_nil end end context "when `.config.yml` contains a browserstack section" do + subject { described_class.new(config) } + let(:config) do Quke::Configuration.file_location = data_path(".browserstack.yml") Quke::Configuration.new end - subject { Quke::BrowserstackConfiguration.new(config) } it "returns a string for the url to browserstack including the username and password" do expect(subject.url).to eq( diff --git a/spec/quke/browserstack_status_reporter_spec.rb b/spec/quke/browserstack_status_reporter_spec.rb index 62364d1..a1e08a9 100644 --- a/spec/quke/browserstack_status_reporter_spec.rb +++ b/spec/quke/browserstack_status_reporter_spec.rb @@ -6,7 +6,7 @@ subject do Quke::Configuration.file_location = data_path(".no_file.yml") config = Quke::BrowserstackConfiguration.new(Quke::Configuration.new) - Quke::BrowserstackStatusReporter.new(config) + described_class.new(config) end describe "#passed" do @@ -17,7 +17,7 @@ end context "when the session_id is valid" do - before(:each) do + before do stub_request(:put, /browserstack/) .with( body: /passed/, @@ -44,7 +44,7 @@ end context "when the request fails" do - before(:each) do + before do stub_request(:put, /browserstack/) .with( body: /passed/, @@ -75,7 +75,7 @@ end context "when the session_id is valid" do - before(:each) do + before do stub_request(:put, /browserstack/) .with( body: /failed/, @@ -103,7 +103,7 @@ end context "when the request fails" do - before(:each) do + before do stub_request(:put, /browserstack/) .with( body: /passed/, diff --git a/spec/quke/configuration_spec.rb b/spec/quke/configuration_spec.rb index a916412..8ee78d6 100644 --- a/spec/quke/configuration_spec.rb +++ b/spec/quke/configuration_spec.rb @@ -6,14 +6,14 @@ describe "#features_folder" do context "when specified NOT specified in config file" do it "defaults to 'features'" do - Quke::Configuration.file_location = data_path(".no_file.yml") + described_class.file_location = data_path(".no_file.yml") expect(subject.features_folder).to eq("features") end end context "when specified in config file" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".simple.yml") + described_class.file_location = data_path(".simple.yml") expect(subject.features_folder).to eq("spec") end end @@ -22,14 +22,14 @@ describe "#app_host" do context "when NOT specified in the config file" do it "defaults to ''" do - Quke::Configuration.file_location = data_path(".no_file.yml") + described_class.file_location = data_path(".no_file.yml") expect(subject.app_host).to eq("") end end context "when specified in config file" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".simple.yml") + described_class.file_location = data_path(".simple.yml") expect(subject.app_host).to eq("http://localhost:4567") end end @@ -38,14 +38,14 @@ describe "#driver" do context "when NOT specified in the config file" do it "defaults to 'chrome'" do - Quke::Configuration.file_location = data_path(".no_file.yml") + described_class.file_location = data_path(".no_file.yml") expect(subject.driver).to eq("chrome") end end context "when specified in the config file" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".simple.yml") + described_class.file_location = data_path(".simple.yml") expect(subject.driver).to eq("chrome") end end @@ -54,22 +54,22 @@ describe "#headless" do context "when NOT specified in the config file" do it "defaults to false" do - Quke::Configuration.file_location = data_path(".no_file.yml") - expect(subject.headless).to eq(false) + described_class.file_location = data_path(".no_file.yml") + expect(subject.headless).to be(false) end end context "when specified in the config file" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".headless.yml") - expect(subject.headless).to eq(true) + described_class.file_location = data_path(".headless.yml") + expect(subject.headless).to be(true) end end context "when in the config file as a string" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".as_string.yml") - expect(subject.headless).to eq(true) + described_class.file_location = data_path(".as_string.yml") + expect(subject.headless).to be(true) end end end @@ -77,21 +77,21 @@ describe "#pause" do context "when NOT specified in the config file" do it "defaults to 0" do - Quke::Configuration.file_location = data_path(".no_file.yml") + described_class.file_location = data_path(".no_file.yml") expect(subject.pause).to eq(0) end end context "when specified in config file" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".simple.yml") + described_class.file_location = data_path(".simple.yml") expect(subject.pause).to eq(1) end end context "when in the config file as a string" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".as_string.yml") + described_class.file_location = data_path(".as_string.yml") expect(subject.pause).to eq(1) end end @@ -100,22 +100,22 @@ describe "#stop_on_error" do context "when NOT specified in the config file" do it "defaults to false" do - Quke::Configuration.file_location = data_path(".no_file.yml") - expect(subject.stop_on_error).to eq(false) + described_class.file_location = data_path(".no_file.yml") + expect(subject.stop_on_error).to be(false) end end context "when specified in config file" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".simple.yml") - expect(subject.stop_on_error).to eq(true) + described_class.file_location = data_path(".simple.yml") + expect(subject.stop_on_error).to be(true) end end context "when in the config file as a string" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".as_string.yml") - expect(subject.stop_on_error).to eq(true) + described_class.file_location = data_path(".as_string.yml") + expect(subject.stop_on_error).to be(true) end end end @@ -123,22 +123,22 @@ describe "#display_failures" do context "when NOT specified in the config file" do it "defaults to true" do - Quke::Configuration.file_location = data_path(".no_file.yml") - expect(subject.display_failures).to eq(true) + described_class.file_location = data_path(".no_file.yml") + expect(subject.display_failures).to be(true) end end context "when specified in the config file" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".display_failures.yml") - expect(subject.display_failures).to eq(false) + described_class.file_location = data_path(".display_failures.yml") + expect(subject.display_failures).to be(false) end end context "when in the config file as a string" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".as_string.yml") - expect(subject.display_failures).to eq(false) + described_class.file_location = data_path(".as_string.yml") + expect(subject.display_failures).to be(false) end end end @@ -146,29 +146,29 @@ describe "#display_failures?" do context "when `headless` is false and `display_failures` is false" do it "returns false" do - Quke::Configuration.file_location = data_path(".display_failures.yml") - expect(subject.display_failures?).to eq(false) + described_class.file_location = data_path(".display_failures.yml") + expect(subject.display_failures?).to be(false) end end context "when `headless` is true and `display_failures` is false" do it "returns false" do - Quke::Configuration.file_location = data_path(".as_string.yml") - expect(subject.display_failures?).to eq(false) + described_class.file_location = data_path(".as_string.yml") + expect(subject.display_failures?).to be(false) end end context "when `headless` is false and `display_failures` is true" do it "returns false" do - Quke::Configuration.file_location = data_path(".no_file.yml") - expect(subject.display_failures?).to eq(true) + described_class.file_location = data_path(".no_file.yml") + expect(subject.display_failures?).to be(true) end end context "when `headless` is true and `display_failures` is true" do it "returns false" do - Quke::Configuration.file_location = data_path(".should_display_failures.yml") - expect(subject.display_failures?).to eq(false) + described_class.file_location = data_path(".should_display_failures.yml") + expect(subject.display_failures?).to be(false) end end end @@ -176,21 +176,21 @@ describe "#max_wait_time" do context "when NOT specified in the config file" do it "defaults to whatever the Capybara default is" do - Quke::Configuration.file_location = data_path(".no_file.yml") + described_class.file_location = data_path(".no_file.yml") expect(subject.max_wait_time).to eq(Capybara.default_max_wait_time) end end context "when specified in config file" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".simple.yml") + described_class.file_location = data_path(".simple.yml") expect(subject.max_wait_time).to eq(3) end end context "when in the config file as a string" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".as_string.yml") + described_class.file_location = data_path(".as_string.yml") expect(subject.max_wait_time).to eq(3) end end @@ -199,14 +199,14 @@ describe "#user_agent" do context "when NOT specified in the config file" do it "defaults to ''" do - Quke::Configuration.file_location = data_path(".no_file.yml") + described_class.file_location = data_path(".no_file.yml") expect(subject.user_agent).to eq("") end end context "when specified in the config file" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".user_agent.yml") + described_class.file_location = data_path(".user_agent.yml") expect(subject.user_agent).to eq("Mozilla/5.0 (MSIE 10.0; Windows NT 6.1; Trident/5.0)") end end @@ -215,22 +215,22 @@ describe "#print_progress" do context "when NOT specified in the config file" do it "defaults to false" do - Quke::Configuration.file_location = data_path(".no_file.yml") - expect(subject.print_progress).to eq(false) + described_class.file_location = data_path(".no_file.yml") + expect(subject.print_progress).to be(false) end end context "when specified in the config file" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".print_progress.yml") - expect(subject.print_progress).to eq(true) + described_class.file_location = data_path(".print_progress.yml") + expect(subject.print_progress).to be(true) end end context "when in the config file as a string" do it "matches the config file" do - Quke::Configuration.file_location = data_path(".as_string.yml") - expect(subject.print_progress).to eq(true) + described_class.file_location = data_path(".as_string.yml") + expect(subject.print_progress).to be(true) end end end @@ -238,19 +238,19 @@ describe "#custom" do context "when NOT specified in the config file" do it "defaults to nothing" do - Quke::Configuration.file_location = data_path(".no_file.yml") - expect(subject.custom).to be(nil) + described_class.file_location = data_path(".no_file.yml") + expect(subject.custom).to be_nil end end context "when 'custom' in the config file holds simple key value pairs" do it "returns the key value pair if there is just one" do - Quke::Configuration.file_location = data_path(".custom_key_value_pair.yml") + described_class.file_location = data_path(".custom_key_value_pair.yml") expect(subject.custom).to eq("my_key" => "my_value") end it "returns all key value pairs if there are multiples" do - Quke::Configuration.file_location = data_path(".custom_key_value_pairs.yml") + described_class.file_location = data_path(".custom_key_value_pairs.yml") expect(subject.custom).to eq( "my_key1" => "my_value1", "my_key2" => "my_value2", @@ -263,7 +263,7 @@ context "when 'custom' in the config file holds a hierachical object" do it "returns a representation of the object" do - Quke::Configuration.file_location = data_path(".custom_complex_object.yml") + described_class.file_location = data_path(".custom_complex_object.yml") expect(subject.custom).to eq( "my_key" => "my_value", "accounts" => { @@ -299,14 +299,14 @@ context "when there are no additional arguments" do it "returns the default cucumber args value" do - Quke::Configuration.file_location = data_path(".no-file.yml") + described_class.file_location = data_path(".no-file.yml") expect(subject.cucumber_args([])).to eq(format_pretty_args + feature_folder_args) end end context "when `stop_on_error` is true" do it "returns the default cucumber arg values including the '--fail-fast' option" do - Quke::Configuration.file_location = data_path(".stop_on_error.yml") + described_class.file_location = data_path(".stop_on_error.yml") expect(subject.cucumber_args([])).to eq(format_pretty_args + fail_fast_args + feature_folder_args) end @@ -314,20 +314,20 @@ context "when `print_progress` is true" do it "returns the default cucumber arg values including the '--format progress' option" do - Quke::Configuration.file_location = data_path(".print_progress.yml") + described_class.file_location = data_path(".print_progress.yml") expect(subject.cucumber_args([])).to eq(format_progress_args + feature_folder_args) end end context "when there are additional arguments" do it "returns the default cucumber arg values plus the arguments" do - Quke::Configuration.file_location = data_path(".no-file.yml") + described_class.file_location = data_path(".no-file.yml") expect(subject.cucumber_args(additional_args)).to eq(format_pretty_args + feature_folder_args + additional_args) end context "and some arguments have whitespace around them" do it "returns the default cucumber arg values plus the arguments without whitespace" do - Quke::Configuration.file_location = data_path(".no-file.yml") + described_class.file_location = data_path(".no-file.yml") expect(subject.cucumber_args(additional_whitespace_args)).to eq(format_pretty_args + feature_folder_args + additional_args) end end @@ -337,7 +337,7 @@ describe ".file_name" do context "environment variable not set" do it "returns the default value '.config.yml'" do - expect(Quke::Configuration.file_name).to eq(".config.yml") + expect(described_class.file_name).to eq(".config.yml") end end end diff --git a/spec/quke/driver_configuration_spec.rb b/spec/quke/driver_configuration_spec.rb index 4cbfdd2..e6f3558 100644 --- a/spec/quke/driver_configuration_spec.rb +++ b/spec/quke/driver_configuration_spec.rb @@ -10,7 +10,7 @@ it "returns an instance of Chrome::Options where the proxy details are NOT set" do Quke::Configuration.file_location = data_path(".no_file.yml") config = Quke::Configuration.new - expect(Quke::DriverConfiguration.new(config).chrome.args).to eq(Set[]) + expect(described_class.new(config).chrome.args).to eq([]) end end @@ -18,8 +18,8 @@ it "returns an instance of Chrome::Options containing basic proxy settings" do Quke::Configuration.file_location = data_path(".proxy_basic.yml") config = Quke::Configuration.new - expect(Quke::DriverConfiguration.new(config).chrome.args).to eq( - Set[ + expect(described_class.new(config).chrome.args).to eq( + [ "--proxy-server=#{config.proxy.host}:#{config.proxy.port}" ] ) @@ -30,8 +30,8 @@ it "returns an instance of Chrome::Options containing proxy settings including no-proxy details" do Quke::Configuration.file_location = data_path(".proxy.yml") config = Quke::Configuration.new - expect(Quke::DriverConfiguration.new(config).chrome.args).to eq( - Set[ + expect(described_class.new(config).chrome.args).to eq( + [ "--proxy-server=#{config.proxy.host}:#{config.proxy.port}", "--proxy-bypass-list=127.0.0.1;192.168.0.1" ] @@ -43,8 +43,8 @@ it "returns an instance of Chrome::Options containing the specified user-agent" do Quke::Configuration.file_location = data_path(".user_agent.yml") config = Quke::Configuration.new - expect(Quke::DriverConfiguration.new(config).chrome.args).to eq( - Set[ + expect(described_class.new(config).chrome.args).to eq( + [ "--user-agent=#{config.user_agent}" ] ) @@ -55,7 +55,7 @@ it "returns an instance of Chrome::Options set to run the browser in headless mode" do Quke::Configuration.file_location = data_path(".headless.yml") config = Quke::Configuration.new - expect(Quke::DriverConfiguration.new(config).chrome.args).to eq(Set["--headless"]) + expect(described_class.new(config).chrome.args).to eq(["--headless=new"]) end end @@ -67,7 +67,7 @@ it "returns an instance of Firefox::Options where the proxy details are NOT set" do Quke::Configuration.file_location = data_path(".no_file.yml") config = Quke::Configuration.new - profile = Quke::DriverConfiguration.new(config).firefox.profile + profile = described_class.new(config).firefox.profile # See spec/helpers.rb#read_profile_preferences for details of why we # need to test the profile's properties in this way @@ -82,7 +82,7 @@ it "returns an instance of Firefox::Options containing basic proxy settings" do Quke::Configuration.file_location = data_path(".proxy_basic.yml") config = Quke::Configuration.new - profile = Quke::DriverConfiguration.new(config).firefox.profile + profile = described_class.new(config).firefox.profile # See spec/helpers.rb#read_profile_preferences for details of why we # need to test the profile's properties in this way @@ -97,7 +97,7 @@ it "returns an instance of Firefox::Options containing proxy settings including no-proxy details" do Quke::Configuration.file_location = data_path(".proxy.yml") config = Quke::Configuration.new - profile = Quke::DriverConfiguration.new(config).firefox.profile + profile = described_class.new(config).firefox.profile # See spec/helpers.rb#read_profile_preferences for details of why we # need to test the profile's properties in this way @@ -113,7 +113,7 @@ it "returns an instance of Firefox::Options containing the specified user-agent" do Quke::Configuration.file_location = data_path(".user_agent.yml") config = Quke::Configuration.new - profile = Quke::DriverConfiguration.new(config).firefox.profile + profile = described_class.new(config).firefox.profile # See spec/helpers.rb#read_profile_preferences for details of why we # need to test the profile's properties in this way @@ -129,7 +129,7 @@ it "returns an instance of Firefox::Options set to run the browser in headless mode" do Quke::Configuration.file_location = data_path(".headless.yml") config = Quke::Configuration.new - expect(Quke::DriverConfiguration.new(config).chrome.args).to eq(Set["--headless"]) + expect(described_class.new(config).chrome.args).to eq(["--headless=new"]) end end @@ -138,20 +138,12 @@ describe "#browserstack" do context "browserstack details have NOT been set in the .config.yml" do - it "returns capabilities set to Selenium::WebDriver::Remote::Capabilities defaults" do + it "returns an empty set of capabilities" do Quke::Configuration.file_location = data_path(".no_file.yml") config = Quke::Configuration.new - capabilities = Quke::DriverConfiguration.new(config).browserstack - - expect(capabilities.as_json.keys.count).to eq(8) - expect(capabilities["browserName"]).to eq(nil) - expect(capabilities["version"]).to eq(nil) - expect(capabilities["platform"]).to eq(nil) - expect(capabilities["javascriptEnabled"]).to eq(nil) - expect(capabilities["cssSelectorsEnabled"]).to eq(nil) - expect(capabilities["takesScreenshot"]).to eq(nil) - expect(capabilities["nativeEvents"]).to eq(nil) - expect(capabilities["rotatable"]).to eq(nil) + capabilities = described_class.new(config).browserstack + + expect(capabilities.as_json.keys.count).to eq(0) end end @@ -159,7 +151,7 @@ it "returns capabilities that match those set" do Quke::Configuration.file_location = data_path(".browserstack.yml") config = Quke::Configuration.new - capabilities = Quke::DriverConfiguration.new(config).browserstack + capabilities = described_class.new(config).browserstack expected_capabilities = YAML.load_file(data_path(".browserstack.yml"))["browserstack"]["capabilities"] expect(capabilities["build"]).to eq(expected_capabilities["build"]) diff --git a/spec/quke/driver_registration_spec.rb b/spec/quke/driver_registration_spec.rb index 9ab1129..1827780 100644 --- a/spec/quke/driver_registration_spec.rb +++ b/spec/quke/driver_registration_spec.rb @@ -11,7 +11,7 @@ Quke::Configuration.file_location = data_path(".#{driver}.yml") config = Quke::Configuration.new driver_config = Quke::DriverConfiguration.new(config) - driver_reg = Quke::DriverRegistration.new(driver_config, config) + driver_reg = described_class.new(driver_config, config) driver = driver_reg.register(config.driver) expect(driver).to eq(driver) end @@ -23,7 +23,7 @@ Quke::Configuration.file_location = data_path(".invalid.yml") config = Quke::Configuration.new driver_config = Quke::DriverConfiguration.new(config) - driver_reg = Quke::DriverRegistration.new(driver_config, config) + driver_reg = described_class.new(driver_config, config) driver = driver_reg.register(config.driver) expect(driver).to eq(driver) end diff --git a/spec/quke/proxy_configuration_spec.rb b/spec/quke/proxy_configuration_spec.rb index fe62187..eed039a 100644 --- a/spec/quke/proxy_configuration_spec.rb +++ b/spec/quke/proxy_configuration_spec.rb @@ -47,25 +47,25 @@ describe "#use_proxy?" do context "when the instance has been instantiated with no data" do - subject { Quke::ProxyConfiguration.new } + subject { described_class.new } it "returns false" do - expect(subject.use_proxy?).to eq(false) + expect(subject.use_proxy?).to be(false) end end context "when the instance has been instantiated with 'host' set" do - subject { Quke::ProxyConfiguration.new("host" => "10.10.2.70") } + subject { described_class.new("host" => "10.10.2.70") } it "returns true" do - expect(subject.use_proxy?).to eq(true) + expect(subject.use_proxy?).to be(true) end end end describe "#firefox_settings" do context "when the instance has been instantiated with no data" do - subject { Quke::ProxyConfiguration.new } + subject { described_class.new } it "returns an empty hash" do expect(subject.firefox_settings).to eq({}) @@ -73,7 +73,7 @@ end context "when the instance has been instantiated with everything but 'host'" do - subject { Quke::ProxyConfiguration.new("port" => "8080", "no_proxy" => "127.0.0.1") } + subject { described_class.new("port" => "8080", "no_proxy" => "127.0.0.1") } it "returns an empty hash" do expect(subject.firefox_settings).to eq({}) @@ -82,7 +82,7 @@ context "when the instance has been instantiated with data" do subject do - Quke::ProxyConfiguration.new( + described_class.new( "host" => "10.10.2.70", "port" => "8080", "no_proxy" => "127.0.0.1" diff --git a/spec/quke/quke_spec.rb b/spec/quke/quke_spec.rb index 52dce6a..15acc27 100644 --- a/spec/quke/quke_spec.rb +++ b/spec/quke/quke_spec.rb @@ -5,7 +5,7 @@ RSpec.describe Quke do describe ".execute" do context "when the configured driver is 'chrome'" do - before(:example) do + before do Quke::Configuration.file_location = data_path(".chrome.yml") Quke::Quke.config = Quke::Configuration.new end @@ -16,7 +16,7 @@ end context "when the configured driver is 'firefox'" do - before(:example) do + before do Quke::Configuration.file_location = data_path(".firefox.yml") Quke::Quke.config = Quke::Configuration.new end @@ -47,7 +47,7 @@ # project. So at this time we have decided to mark this test as pending # until we can devote more time to identifying a solution. context "when the configured driver is 'browserstack'", skip: "failing in test suite" do - before(:example) do + before do Quke::Configuration.file_location = data_path(".browserstack.yml") Quke::Quke.config = Quke::Configuration.new diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index fcc5ba1..19b03f3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,10 +1,7 @@ # frozen_string_literal: true -require "bundler/setup" - -# Require and run our simplecov initializer as the very first thing we do. -# This is as per its docs https://github.com/colszowka/simplecov#getting-started require "./spec/support/simplecov" +require "bundler/setup" # Requires supporting ruby files with custom matchers and macros, etc, in # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are diff --git a/spec/support/simplecov.rb b/spec/support/simplecov.rb index 47e01bd..6fb2500 100644 --- a/spec/support/simplecov.rb +++ b/spec/support/simplecov.rb @@ -1,29 +1,39 @@ # frozen_string_literal: true require "simplecov" +require "simplecov-json" + +SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new( + [ + SimpleCov::Formatter::HTMLFormatter, + SimpleCov::Formatter::JSONFormatter + ] +) # We start it with the rails param to ensure it includes coverage for all code # started by the rails app, and not just the files touched by our unit tests. # This gives us the most accurate assessment of our unit test coverage # https://github.com/colszowka/simplecov#getting-started -SimpleCov.start("rails") do - # We filter the spec folder, mainly to ensure that any dummy apps don't get - # included in the coverage report. However our intent is that nothing in the - # spec folder should be included - add_filter "/spec/" - # We filter the lib/features/support folder because the only way we can test - # the code in there is to actually run Cucumber with a feature, something - # we're currently trying to avoid in our tests. - add_filter "/lib/features/support/" - # The version file is simply just that, so we do not feel the need to ensure - # we have a test for it - add_filter "lib/quke/version" +unless SimpleCov.running + SimpleCov.start("rails") do + # We filter the spec folder, mainly to ensure that any dummy apps don't get + # included in the coverage report. However our intent is that nothing in the + # spec folder should be included + add_filter "/spec/" + # We filter the lib/features/support folder because the only way we can test + # the code in there is to actually run Cucumber with a feature, something + # we're currently trying to avoid in our tests. + add_filter "/lib/features/support/" + # The version file is simply just that, so we do not feel the need to ensure + # we have a test for it + add_filter "lib/quke/version" - # You can make Simplecov ignore sections of code by wrapping them in # :nocov: - # tags. However without knowledge of this `nocov` doesn't mean a lot so here - # we take advantage of a feature that allows us to use a custom token to do - # the same thing `nocov` does. Now in our code any sections we want to exclude - # from test coverage stats we wrap in # :simplecov_ignore: tokens. - # https://github.com/colszowka/simplecov#ignoringskipping-code - nocov_token "simplecov_ignore" + # You can make Simplecov ignore sections of code by wrapping them in # :nocov: + # tags. However without knowledge of this `nocov` doesn't mean a lot so here + # we take advantage of a feature that allows us to use a custom token to do + # the same thing `nocov` does. Now in our code any sections we want to exclude + # from test coverage stats we wrap in # :simplecov_ignore: tokens. + # https://github.com/colszowka/simplecov#ignoringskipping-code + nocov_token "simplecov_ignore" + end end