Dduvall has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/230261

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.

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
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
7 files changed, 203 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/selenium 
refs/changes/61/230261/1

diff --git a/.rubocop.yml b/.rubocop.yml
index ef705cb..4e2a635 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,5 +1,10 @@
 AllCops:
   StyleGuideCopsOnly: true
+  Exclude:
+    # 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/features/rspec.feature b/features/rspec.feature
new file mode 100644
index 0000000..6cc5fbf
--- /dev/null
+++ b/features/rspec.feature
@@ -0,0 +1,49 @@
+@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 all my examples pass
+
+  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 all my examples pass
diff --git a/features/step_definitions/rspec_steps.rb 
b/features/step_definitions/rspec_steps.rb
new file mode 100644
index 0000000..47dd13f
--- /dev/null
+++ b/features/step_definitions/rspec_steps.rb
@@ -0,0 +1,30 @@
+require 'yaml'
+
+Given(/^I have set up my `environments\.yml`$/) do
+  step 'the "tmp/rspec/spec" directory exists'
+  Pathname.new('tmp/rspec/environments.yml').write(YAML.dump({ 'default' => {} 
}))
+end
+
+Given(/^the following RSpec support file:$/) do |content|
+  Pathname.new('tmp/rspec/spec/spec_helper.rb').write(content)
+end
+
+Given(/^the following RSpec examples:$/) do |content|
+  Pathname.new('tmp/rspec/spec/examples_spec.rb').write("require 
'spec_helper'\n#{content}")
+end
+
+Given(/^$the following "(.+)" file for use with RSpec$/) do |path, content|
+  Pathname.new('tmp/rspec').join(path).write(content)
+end
+
+When(/^I run `rspec` against my examples$/) do
+  tail, head = IO.pipe
+  env = { 'MEDIAWIKI_ENVIRONMENT' => 'default' }
+
+  @rspec_passed = system(env, 'bundle exec rspec', chdir: 'tmp/rspec', err: 
head, out: head)
+  @rspec_output = tail.read_nonblock(10_000)
+end
+
+Then(/^all my examples pass$/) do
+  expect(@rspec_passed).to be(true), "Examples did not pass. Output: 
\n---\n#{@rspec_output}---\n"
+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..f21d96f
--- /dev/null
+++ b/lib/mediawiki_selenium/rspec/environment.rb
@@ -0,0 +1,18 @@
+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
+    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: newchange
Gerrit-Change-Id: I97a7522764fd535ef8f3510fd654df8976d70af0
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/selenium
Gerrit-Branch: master
Gerrit-Owner: Dduvall <[email protected]>

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

Reply via email to