jenkins-bot has submitted this change and it was merged.

Change subject: Basic RSpec support
......................................................................


Basic RSpec support

Implemented basic RSpec integration.

A `MediawikiSelenium::Environment` instance is created before each
example and exposed as a `mw` method. It looks for and loads an
`environments.yml` configuration in the current working directory.

Indirect/unqualified calls on `mw` methods (e.g. just `on_wiki` instead
of `mw.on_wiki`) are also allowed via dynamic dispatch.

All helpers except for `StrictPending` (which is Cucumber specific) are
supported.

See features/rspec.feature for what an RSpec based integration test
could look like.

Bug: T108273
Change-Id: I97a7522764fd535ef8f3510fd654df8976d70af0
---
M .rubocop.yml
M .yardopts
A features/rspec.feature
A features/step_definitions/rspec_steps.rb
A lib/mediawiki_selenium/rspec.rb
A lib/mediawiki_selenium/rspec/environment.rb
A lib/mediawiki_selenium/rspec/features.rb
M mediawiki_selenium.gemspec
8 files changed, 240 insertions(+), 1 deletion(-)

Approvals:
  Zfilipin: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/.rubocop.yml b/.rubocop.yml
index ef705cb..e19d33c 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,5 +1,11 @@
 AllCops:
   StyleGuideCopsOnly: true
+  Exclude:
+    - 'vendor/**/*'
+    # Features syntax is a vendor file imported from Capybara. Ignore it.
+    - 'lib/mediawiki_selenium/rspec/features.rb'
+    # Ignore anything left around in `tmp`
+    - 'tmp/**/*'
 
 Metrics/LineLength:
   Max: 100
diff --git a/.yardopts b/.yardopts
index ff5185a..2fae928 100644
--- a/.yardopts
+++ b/.yardopts
@@ -2,4 +2,5 @@
 --charset utf-8
 --title "MediaWiki Selenium"
 --markup markdown
+--exclude mediawiki_selenium/rspec/features.rb
 'lib/**/*.rb' - '*.md'
diff --git a/features/rspec.feature b/features/rspec.feature
new file mode 100644
index 0000000..cddb8d1
--- /dev/null
+++ b/features/rspec.feature
@@ -0,0 +1,64 @@
+@integration
+Feature: RSpec integration
+
+  As a developer, I want the option to use a test framework with less
+  indirection so that my tests are more straightforward to implement and
+  easier to reason about.
+
+  Background:
+    Given I have set up my `environments.yml`
+      And the following RSpec support file:
+      """
+      require 'bundler/setup'
+      require 'mediawiki_selenium/rspec'
+      """
+
+  Scenario: RSpec examples have access to the `Environment` via `#mw`
+    Given the following RSpec examples:
+    """
+    describe 'my feature' do
+      describe 'my component' do
+        it 'can access `mw` to implement its tests' do
+          expect(mw).to be_a(MediawikiSelenium::Environment)
+        end
+      end
+    end
+    """
+    When I run `rspec` against my examples
+    Then I should see 1 passing example
+
+  Scenario: Calls to `mw` methods can be unqualified/indirect
+    Given the following RSpec examples:
+    """
+    describe 'my feature' do
+      describe 'my component' do
+        it 'can call `mw` methods indirectly via `self`' do
+          expect(mw).to respond_to(:on_wiki)
+          expect(self).to respond_to(:on_wiki)
+        end
+      end
+    end
+    """
+    When I run `rspec` against my examples
+    Then I should see 1 passing example
+
+  Scenario: An alternative feature/scenario syntax is supported
+    Given the following RSpec examples:
+    """
+    feature 'my feature' do
+      background do
+        # do common stuff
+        @stuff = 'stuff'
+      end
+
+      scenario 'my scenario' do
+        expect(@stuff).to eq('stuff')
+      end
+
+      scenario 'my other scenario' do
+        expect(@stuff).to eq('stuff')
+      end
+    end
+    """
+    When I run `rspec` against my examples
+    Then I should see 2 passing examples
diff --git a/features/step_definitions/rspec_steps.rb 
b/features/step_definitions/rspec_steps.rb
new file mode 100644
index 0000000..f8e7c00
--- /dev/null
+++ b/features/step_definitions/rspec_steps.rb
@@ -0,0 +1,32 @@
+require 'yaml'
+require 'open3'
+
+Given(/^I have set up my `environments\.yml`$/) do
+  step 'the "tmp/rspec/spec" directory exists'
+  File.open('tmp/rspec/environments.yml', 'w') { |io| io.write(YAML.dump({ 
'default' => {} })) }
+end
+
+Given(/^the following RSpec support file:$/) do |content|
+  File.open('tmp/rspec/spec/spec_helper.rb', 'w') { |io| io.write(content) }
+end
+
+Given(/^the following RSpec examples:$/) do |content|
+  content = "require 'spec_helper'\n#{content}"
+  File.open('tmp/rspec/spec/examples_spec.rb', 'w') { |io| io.write(content) }
+end
+
+Given(/^$the following "(.+)" file for use with RSpec$/) do |path, content|
+  File.open(File.join('tmp/rspec', path), 'w') { |io| io.write(content) }
+end
+
+When(/^I run `rspec` against my examples$/) do
+  env = { 'MEDIAWIKI_ENVIRONMENT' => 'default' }
+  cmd = "'#{Gem.bin_path('bundler', 'bundle')}' exec rspec"
+
+  @rspec_output, @rspec_status = Open3.capture2e(env, cmd, chdir: 'tmp/rspec')
+end
+
+Then(/^I should see (\d+) passing examples?$/) do |n|
+  expect(@rspec_status).to be_success, "Examples did not pass. 
Output:\n---\n#{@rspec_output}---\n"
+  expect(@rspec_output).to match(/^#{n} examples?, 0 failures/)
+end
diff --git a/lib/mediawiki_selenium/rspec.rb b/lib/mediawiki_selenium/rspec.rb
new file mode 100644
index 0000000..2596f72
--- /dev/null
+++ b/lib/mediawiki_selenium/rspec.rb
@@ -0,0 +1,51 @@
+require 'rspec/core'
+require 'mediawiki_selenium'
+require 'mediawiki_selenium/rspec/features'
+
+module MediawikiSelenium
+  module RSpec
+    # Returns a name for the given example metadata, derived from its example
+    # groups and description.
+    #
+    # @param metadata [RSpec::Core::Metadata, Hash] Base or nested metadata.
+    #
+    # @return [String]
+    #
+    def self.example_name(metadata)
+      name = metadata[:example_group] ? 
"#{example_name(metadata[:example_group])} " : ''
+      name += metadata[:description_args].first.to_s if 
metadata[:description_args].any?
+      name
+    end
+
+    # Returns a status for the given RSpec example result.
+    #
+    # @param result [Object] Result of `example.run`.
+    #
+    # @return [:passed, :failed, :skipped]
+    #
+    def self.example_status(result)
+      case result
+      when Exception
+        :failed
+      when String
+        :skipped
+      else
+        :passed
+      end
+    end
+
+    autoload :Environment, 'mediawiki_selenium/rspec/environment'
+  end
+end
+
+RSpec.configure do |config|
+  config.include MediawikiSelenium::RSpec::Environment
+
+  config.around(:each) do |example|
+    name = MediawikiSelenium::RSpec.example_name(example.metadata)
+
+    mw.setup(name: name)
+    result = example.run
+    mw.teardown(name: name, status: 
MediawikiSelenium::RSpec.example_status(result))
+  end
+end
diff --git a/lib/mediawiki_selenium/rspec/environment.rb 
b/lib/mediawiki_selenium/rspec/environment.rb
new file mode 100644
index 0000000..e084773
--- /dev/null
+++ b/lib/mediawiki_selenium/rspec/environment.rb
@@ -0,0 +1,36 @@
+module MediawikiSelenium
+  module RSpec
+    module Environment
+      # Sets up and returns a new default environment.
+      #
+      # @return [Environment]
+      #
+      def mw
+        @_mw ||= MediawikiSelenium::Environment.load_default.extend(
+          MediawikiSelenium::ApiHelper,
+          MediawikiSelenium::PageFactory,
+          MediawikiSelenium::ScreenshotHelper,
+          MediawikiSelenium::UserFactoryHelper
+        )
+      end
+
+      private
+
+      # Allow for indirect calls to the {Environment} object.
+      #
+      # @see mw
+      #
+      def method_missing(name, *args, &block)
+        mw.respond_to?(name) ? mw.__send__(name, *args, &block) : super
+      end
+
+      # Allow for indirect calls to the {Environment} object.
+      #
+      # @see mw
+      #
+      def respond_to_missing?(name, include_all = false)
+        mw.respond_to?(name) || super
+      end
+    end
+  end
+end
diff --git a/lib/mediawiki_selenium/rspec/features.rb 
b/lib/mediawiki_selenium/rspec/features.rb
new file mode 100644
index 0000000..6cb9a21
--- /dev/null
+++ b/lib/mediawiki_selenium/rspec/features.rb
@@ -0,0 +1,49 @@
+# This was "derived" from Capybara's RSpec integration
+#
+# 
https://github.com/jnicklas/capybara/blob/master/lib/capybara/rspec/features.rb
+#
+if RSpec::Core::Version::STRING.to_f >= 3.0
+  RSpec.shared_context "MW-Selenium Features", :mw_selenium_feature => true do
+    instance_eval do
+      alias background before
+      alias given let
+      alias given! let!
+    end
+  end
+
+  RSpec.configure do |config|
+    config.alias_example_group_to :feature, :mw_selenium_feature => true, 
:type => :feature
+    config.alias_example_to :scenario
+    config.alias_example_to :xscenario, :skip => "Temporarily disabled with 
xscenario"
+    config.alias_example_to :fscenario, :focus => true
+  end
+else
+  module MediawikiSelenium::RSpec
+    module Features
+      def self.included(base)
+        base.instance_eval do
+          alias :background :before
+          alias :scenario :it
+          alias :xscenario :xit
+          alias :given :let
+          alias :given! :let!
+          alias :feature :describe
+        end
+      end
+    end
+  end
+
+
+  def self.feature(*args, &block)
+    options = if args.last.is_a?(Hash) then args.pop else {} end
+    options[:mw_selenium_feature] = true
+    options[:type] = :feature
+    options[:caller] ||= caller
+    args.push(options)
+
+    #call describe on RSpec in case user has expose_dsl_globally set to false
+    RSpec.describe(*args, &block)
+  end
+
+  RSpec.configuration.include MediawikiSelenium::RSpec::Features, 
:mw_selenium_feature => true
+end
diff --git a/mediawiki_selenium.gemspec b/mediawiki_selenium.gemspec
index a9f0127..6bb7269 100644
--- a/mediawiki_selenium.gemspec
+++ b/mediawiki_selenium.gemspec
@@ -33,6 +33,7 @@
   spec.add_runtime_dependency 'mediawiki_api', '~> 0.4', '>= 0.4.1'
   spec.add_runtime_dependency 'page-object', '~> 1.0'
   spec.add_runtime_dependency 'rest-client', '~> 1.6', '>= 1.6.7'
+  spec.add_runtime_dependency 'rspec-core', '~> 2.14', '>= 2.14.4'
   spec.add_runtime_dependency 'rspec-expectations', '~> 2.14', '>= 2.14.4'
   spec.add_runtime_dependency 'syntax', '~> 1.2', '>= 1.2.0'
   spec.add_runtime_dependency 'thor', '~> 0.19', '>= 0.19.1'
@@ -41,6 +42,5 @@
   spec.add_development_dependency 'yard', '~> 0.8', '>= 0.8.7.4'
   spec.add_development_dependency 'redcarpet', '~> 3.2', '>= 3.2.0'
   spec.add_development_dependency 'rubocop', '~> 0.29.1'
-  spec.add_development_dependency 'rspec-core', '~> 2.14', '>= 2.14.4'
   spec.add_development_dependency 'rspec-mocks', '~> 2.14', '>= 2.14.4'
 end

-- 
To view, visit https://gerrit.wikimedia.org/r/230261
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I97a7522764fd535ef8f3510fd654df8976d70af0
Gerrit-PatchSet: 10
Gerrit-Project: mediawiki/selenium
Gerrit-Branch: master
Gerrit-Owner: Dduvall <[email protected]>
Gerrit-Reviewer: Dduvall <[email protected]>
Gerrit-Reviewer: Hashar <[email protected]>
Gerrit-Reviewer: Zfilipin <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to