mediawiki_selenium 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +7 -1
- data/UPGRADE.md +1 -1
- data/features/recording.feature +40 -0
- data/features/step_definitions/environment_steps.rb +54 -6
- data/lib/mediawiki_selenium.rb +1 -0
- data/lib/mediawiki_selenium/environment.rb +16 -5
- data/lib/mediawiki_selenium/page_factory.rb +13 -0
- data/lib/mediawiki_selenium/support/hooks.rb +5 -18
- data/lib/mediawiki_selenium/support/modules/headless_helper.rb +116 -0
- data/lib/mediawiki_selenium/version.rb +1 -1
- data/mediawiki_selenium.gemspec +1 -1
- data/spec/environment_spec.rb +18 -2
- data/spec/headless_helper_spec.rb +34 -0
- data/spec/page_factory_spec.rb +23 -3
- metadata +9 -6
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 9883a47e71cdb76841699d8292442f00a6312a63
         | 
| 4 | 
            +
              data.tar.gz: 6af66ee6695ba0e33cb68ade1aa2bae67566cadc
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 1656892e8f622ce63c4683d0a14f5626834d102be62512bbc8c7510adce55467a1b6cc9eee1a5e229f1b6985323997ca86b9cf86b914607d3117d7dd95d28d30
         | 
| 7 | 
            +
              data.tar.gz: 4a7fb08977d4c047721e9329a8e31fdfabf176c4a7efd1d83cee36014e68eb084abe2acfc8dca13bab39c5c5054b61547ab8a045f635c786b9d4d573fef9066e
         | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -37,7 +37,7 @@ Create a `Gemfile` in the root of your MediaWiki-related project that | |
| 37 37 | 
             
            specifies the version of `mediawiki_selenium` you wish to use (typically the
         | 
| 38 38 | 
             
            latest version).
         | 
| 39 39 |  | 
| 40 | 
            -
                gem 'mediawiki_selenium', '~> 1. | 
| 40 | 
            +
                gem 'mediawiki_selenium', '~> 1.5.0'
         | 
| 41 41 |  | 
| 42 42 | 
             
            Install the gem and its dependencies by running `bundle install`. (If
         | 
| 43 43 | 
             
            [Bundler](http://bundler.io/) is not yet installed, install it with
         | 
| @@ -223,6 +223,12 @@ See https://www.mediawiki.org/wiki/Gerrit | |
| 223 223 |  | 
| 224 224 | 
             
            ## Release notes
         | 
| 225 225 |  | 
| 226 | 
            +
            ### 1.5.0 2015-07-23
         | 
| 227 | 
            +
            * Video recording of headless browser sessions are now saved to
         | 
| 228 | 
            +
              `HEADLESS_CAPTURE_PATH` for failed scenarios
         | 
| 229 | 
            +
            * Page objects can now reference the current `Environment` object as `env` in
         | 
| 230 | 
            +
              their page URL ERb
         | 
| 231 | 
            +
             | 
| 226 232 | 
             
            ### 1.4.0 2015-06-26
         | 
| 227 233 | 
             
            * New user factory module provides account fixtures for a greater level of
         | 
| 228 234 | 
             
              isolation/atomicity between scenarios
         | 
    
        data/UPGRADE.md
    CHANGED
    
    
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            @integration
         | 
| 2 | 
            +
            Feature: Recording of headless sessions
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              As a developer writing and running headless tests, it would be helpful to
         | 
| 5 | 
            +
              have a video recording of the session so that troubleshooting/debugging
         | 
| 6 | 
            +
              failures can be done more easily.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              Background:
         | 
| 9 | 
            +
                Given I have `Xvfb` installed
         | 
| 10 | 
            +
                  And I have `avconv` installed
         | 
| 11 | 
            +
                  And I have configured my environment from `ENV` and with:
         | 
| 12 | 
            +
                  """
         | 
| 13 | 
            +
                  headless: true
         | 
| 14 | 
            +
                  headless_display: 20
         | 
| 15 | 
            +
                  headless_capture_path: tmp/log
         | 
| 16 | 
            +
                  """
         | 
| 17 | 
            +
                  And the "tmp/log" directory exists
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              Scenario: A video file is saved upon teardown for failed scenarios
         | 
| 20 | 
            +
                Given the current scenario name is "Some scenario"
         | 
| 21 | 
            +
                  And I have started a browser
         | 
| 22 | 
            +
                When the scenario fails
         | 
| 23 | 
            +
                Then the file "tmp/log/Some scenario.mp4" should exist
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              Scenario: A video file is not saved for passing scenarios
         | 
| 26 | 
            +
                Given the current scenario name is "Some scenario"
         | 
| 27 | 
            +
                  And I have started a browser
         | 
| 28 | 
            +
                When the scenario passes
         | 
| 29 | 
            +
                Then the file "tmp/log/Some scenario.mp4" should not exist
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              Scenario: A video per session is saved
         | 
| 32 | 
            +
                Given the current scenario name is "Some scenario"
         | 
| 33 | 
            +
                  And I have started a browser
         | 
| 34 | 
            +
                  And the scenario fails
         | 
| 35 | 
            +
                  And the next scenario begins
         | 
| 36 | 
            +
                  And the current scenario name is "Some other scenario"
         | 
| 37 | 
            +
                  And I have started a browser
         | 
| 38 | 
            +
                When the scenario fails
         | 
| 39 | 
            +
                Then the file "tmp/log/Some scenario.mp4" should exist
         | 
| 40 | 
            +
                  And the file "tmp/log/Some other scenario.mp4" should exist
         | 
| @@ -1,12 +1,22 @@ | |
| 1 | 
            +
            Before do
         | 
| 2 | 
            +
              @tmp_files = []
         | 
| 3 | 
            +
            end
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            After do
         | 
| 6 | 
            +
              @env.teardown unless @env.nil?
         | 
| 7 | 
            +
              @tmp_files.each { |path| FileUtils.rm_r(path) if File.exist?(path) }
         | 
| 8 | 
            +
            end
         | 
| 9 | 
            +
             | 
| 1 10 | 
             
            Given(/^I have configured my environment with:$/) do |yaml|
         | 
| 2 | 
            -
              @ | 
| 11 | 
            +
              @configs = [YAML.load(yaml)]
         | 
| 12 | 
            +
              @env = MediawikiSelenium::Environment.new(*@configs)
         | 
| 3 13 | 
             
            end
         | 
| 4 14 |  | 
| 5 15 | 
             
            Given(/^I have configured my environment from `ENV`(?: and with:)?$/) do |*args|
         | 
| 6 | 
            -
              configs = [ENV]
         | 
| 7 | 
            -
              configs << YAML.load(args.first) if args.length > 0
         | 
| 16 | 
            +
              @configs = [ENV]
         | 
| 17 | 
            +
              @configs << YAML.load(args.first) if args.length > 0
         | 
| 8 18 |  | 
| 9 | 
            -
              @env = MediawikiSelenium::Environment.new( | 
| 19 | 
            +
              @env = MediawikiSelenium::Environment.new(*@configs)
         | 
| 10 20 | 
             
            end
         | 
| 11 21 |  | 
| 12 22 | 
             
            Given(/^I have set "(.*?)" in my shell$/) do |var|
         | 
| @@ -17,6 +27,44 @@ Given(/^I have set "(.*?)" in my shell$/) do |var| | |
| 17 27 | 
             
              end
         | 
| 18 28 | 
             
            end
         | 
| 19 29 |  | 
| 20 | 
            -
             | 
| 21 | 
            -
               | 
| 30 | 
            +
            Given(/^I have `(.*?)` installed$/) do |cmd|
         | 
| 31 | 
            +
              unless system("which #{cmd} > /dev/null") == true
         | 
| 32 | 
            +
                pending "you must have #{cmd} installed to run this test"
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
            end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            Given(/^the "(.*?)" directory exists$/) do |dir|
         | 
| 37 | 
            +
              @tmp_files << dir unless File.exist?(dir)
         | 
| 38 | 
            +
              FileUtils.mkdir_p(dir)
         | 
| 39 | 
            +
            end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            Given(/^the environment has been setup$/) do
         | 
| 42 | 
            +
              @env.setup
         | 
| 43 | 
            +
            end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            Given(/^the current scenario name is "(.*?)"$/) do |name|
         | 
| 46 | 
            +
              @scenario_name = name
         | 
| 47 | 
            +
            end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            Given(/^the next scenario begins$/) do
         | 
| 50 | 
            +
              @env = MediawikiSelenium::Environment.new(*@configs)
         | 
| 51 | 
            +
            end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            When(/^the scenario ends$/) do
         | 
| 54 | 
            +
              begin
         | 
| 55 | 
            +
                # Avoid a race condition within the headless video recorder by waiting
         | 
| 56 | 
            +
                sleep 0.3
         | 
| 57 | 
            +
                @env.teardown(name: @scenario_name, status: @scenario_status)
         | 
| 58 | 
            +
              ensure
         | 
| 59 | 
            +
                @env = nil
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
            end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            When(/^the scenario (fails|passes)$/) do |status|
         | 
| 64 | 
            +
              @scenario_status = status == 'fails' ? :failed : :passed
         | 
| 65 | 
            +
              step 'the scenario ends'
         | 
| 66 | 
            +
            end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            Then(/^the file "(.*?)" should (not )?exist$/) do |file, negate|
         | 
| 69 | 
            +
              expect(Pathname.new(file)).send(negate ? :to_not : :to, exist)
         | 
| 22 70 | 
             
            end
         | 
    
        data/lib/mediawiki_selenium.rb
    CHANGED
    
    | @@ -4,6 +4,7 @@ module MediawikiSelenium | |
| 4 4 | 
             
              autoload :BrowserFactory, 'mediawiki_selenium/browser_factory'
         | 
| 5 5 | 
             
              autoload :ConfigurationError, 'mediawiki_selenium/configuration_error'
         | 
| 6 6 | 
             
              autoload :Environment, 'mediawiki_selenium/environment'
         | 
| 7 | 
            +
              autoload :HeadlessHelper, 'mediawiki_selenium/support/modules/headless_helper'
         | 
| 7 8 | 
             
              autoload :Initializer, 'mediawiki_selenium/initializer'
         | 
| 8 9 | 
             
              autoload :PageFactory, 'mediawiki_selenium/page_factory'
         | 
| 9 10 | 
             
              autoload :Raita, 'mediawiki_selenium/raita'
         | 
| @@ -104,6 +104,8 @@ module MediawikiSelenium | |
| 104 104 | 
             
                  @_config = configs.map { |config| normalize_config(config) }.reduce(:merge)
         | 
| 105 105 | 
             
                  @_factory_cache = {}
         | 
| 106 106 | 
             
                  @_current_alternatives = {}
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  extend(HeadlessHelper) if headless?
         | 
| 107 109 | 
             
                end
         | 
| 108 110 |  | 
| 109 111 | 
             
                # Whether the given environment is equal to this one. Two environments are
         | 
| @@ -201,6 +203,15 @@ module MediawikiSelenium | |
| 201 203 | 
             
                  self
         | 
| 202 204 | 
             
                end
         | 
| 203 205 |  | 
| 206 | 
            +
                # Whether this environment is configured to run in headless mode (using
         | 
| 207 | 
            +
                # Xvfb via the headless gem).
         | 
| 208 | 
            +
                #
         | 
| 209 | 
            +
                # @return [true, false]
         | 
| 210 | 
            +
                #
         | 
| 211 | 
            +
                def headless?
         | 
| 212 | 
            +
                  lookup(:headless, default: 'false').to_s == 'true'
         | 
| 213 | 
            +
                end
         | 
| 214 | 
            +
             | 
| 204 215 | 
             
                # Executes the given block within the context of an environment that uses
         | 
| 205 216 | 
             
                # a unique browser session and possibly different configuration. Note that
         | 
| 206 217 | 
             
                # any given configuration overrides are scoped with a `:browser_` prefix.
         | 
| @@ -339,23 +350,23 @@ module MediawikiSelenium | |
| 339 350 | 
             
                # close any open browsers and perform their own teardown tasks.
         | 
| 340 351 | 
             
                #
         | 
| 341 352 | 
             
                # @example Teardown environment resources after each scenario completes
         | 
| 342 | 
            -
                #   After do
         | 
| 343 | 
            -
                #     teardown(scenario.status)
         | 
| 353 | 
            +
                #   After do |scenario|
         | 
| 354 | 
            +
                #     teardown(name: scenario.name, status: scenario.status)
         | 
| 344 355 | 
             
                #   end
         | 
| 345 356 | 
             
                #
         | 
| 346 | 
            -
                # @param  | 
| 357 | 
            +
                # @param info [Hash] Hash of test case information.
         | 
| 347 358 | 
             
                #
         | 
| 348 359 | 
             
                # @yield [browser]
         | 
| 349 360 | 
             
                # @yieldparam browser [Watir::Browser] Browser object, before it's closed.
         | 
| 350 361 | 
             
                #
         | 
| 351 | 
            -
                def teardown( | 
| 362 | 
            +
                def teardown(info = {})
         | 
| 352 363 | 
             
                  @_factory_cache.each do |(_, browser_name), factory|
         | 
| 353 364 | 
             
                    factory.each do |browser|
         | 
| 354 365 | 
             
                      yield browser if block_given?
         | 
| 355 366 | 
             
                      browser.close unless keep_browser_open? && browser_name != :phantomjs
         | 
| 356 367 | 
             
                    end
         | 
| 357 368 |  | 
| 358 | 
            -
                    factory.teardown(self, status)
         | 
| 369 | 
            +
                    factory.teardown(self, info[:status] || :passed)
         | 
| 359 370 | 
             
                  end
         | 
| 360 371 | 
             
                end
         | 
| 361 372 |  | 
| @@ -11,12 +11,25 @@ module MediawikiSelenium | |
| 11 11 | 
             
                # `PageObject::PageFactory#on_page`. All page URLs are also qualified
         | 
| 12 12 | 
             
                # using {Environment#wiki_url}.
         | 
| 13 13 | 
             
                #
         | 
| 14 | 
            +
                # Additionally, an instance of the current {Environment} is made available
         | 
| 15 | 
            +
                # as `env` for interpolation of page URLs.
         | 
| 16 | 
            +
                #
         | 
| 17 | 
            +
                # @example Referencing the `env` in page URLs
         | 
| 18 | 
            +
                #   class ArticlePage
         | 
| 19 | 
            +
                #     page_url 'User:<%= env.user %>'
         | 
| 20 | 
            +
                #   end
         | 
| 21 | 
            +
                #
         | 
| 14 22 | 
             
                # @see http://www.rubydoc.info/github/cheezy/page-object
         | 
| 15 23 | 
             
                #
         | 
| 16 24 | 
             
                def on_page(page_class, params = { using_params: {} }, visit = false)
         | 
| 17 25 | 
             
                  @browser = browser if visit || !defined?(@browser)
         | 
| 26 | 
            +
                  env = self
         | 
| 18 27 |  | 
| 19 28 | 
             
                  super(page_class, params, false) do |page|
         | 
| 29 | 
            +
                    page.define_singleton_method(:env) do
         | 
| 30 | 
            +
                      env
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
             | 
| 20 33 | 
             
                    if page.respond_to?(:goto)
         | 
| 21 34 | 
             
                      wiki_url = method(:wiki_url)
         | 
| 22 35 |  | 
| @@ -16,20 +16,6 @@ AfterConfiguration do |config| | |
| 16 16 | 
             
                raita_build = MediawikiSelenium::Raita.build_from(env)
         | 
| 17 17 | 
             
                config.formats << ['MediawikiSelenium::Raita::Logger', { url: raita_url, build: raita_build }]
         | 
| 18 18 | 
             
              end
         | 
| 19 | 
            -
             | 
| 20 | 
            -
              # Initiate headless mode
         | 
| 21 | 
            -
              if ENV['HEADLESS'] == 'true' && ENV['BROWSER'] != 'phantomjs'
         | 
| 22 | 
            -
                require 'headless'
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                headless_options = {}.tap do |options|
         | 
| 25 | 
            -
                  options[:display] = ENV['HEADLESS_DISPLAY'] if ENV.include?('HEADLESS_DISPLAY')
         | 
| 26 | 
            -
                  options[:reuse] = false if ENV['HEADLESS_REUSE'] == 'false'
         | 
| 27 | 
            -
                  options[:destroy_at_exit] = false if ENV['HEADLESS_DESTROY_AT_EXIT'] == 'false'
         | 
| 28 | 
            -
                end
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                headless = Headless.new(headless_options)
         | 
| 31 | 
            -
                headless.start
         | 
| 32 | 
            -
              end
         | 
| 33 19 | 
             
            end
         | 
| 34 20 |  | 
| 35 21 | 
             
            # Enforce a dependency check for all scenarios tagged with @extension- tags
         | 
| @@ -79,10 +65,12 @@ Before do |scenario| | |
| 79 65 | 
             
            end
         | 
| 80 66 |  | 
| 81 67 | 
             
            After do |scenario|
         | 
| 68 | 
            +
              scenario_name = test_name(scenario)
         | 
| 69 | 
            +
             | 
| 82 70 | 
             
              if scenario.respond_to?(:status)
         | 
| 83 71 | 
             
                require 'fileutils'
         | 
| 84 72 |  | 
| 85 | 
            -
                teardown(scenario.status) do |browser|
         | 
| 73 | 
            +
                teardown(name: scenario_name, status: scenario.status) do |browser|
         | 
| 86 74 | 
             
                  # Embed remote session URLs
         | 
| 87 75 | 
             
                  if remote? && browser.driver.respond_to?(:session_id)
         | 
| 88 76 | 
             
                    embed("http://saucelabs.com/jobs/#{browser.driver.session_id}", 'text/url')
         | 
| @@ -92,14 +80,13 @@ After do |scenario| | |
| 92 80 | 
             
                  if scenario.failed? && lookup(:screenshot_failures, default: false) == 'true'
         | 
| 93 81 | 
             
                    screen_dir = lookup(:screenshot_failures_path, default: 'screenshots')
         | 
| 94 82 | 
             
                    FileUtils.mkdir_p screen_dir
         | 
| 95 | 
            -
                    name =  | 
| 83 | 
            +
                    name = scenario_name.gsub(/ /, '_')
         | 
| 96 84 | 
             
                    path = "#{screen_dir}/#{name}.png"
         | 
| 97 85 | 
             
                    browser.screenshot.save path
         | 
| 98 86 | 
             
                    embed path, 'image/png'
         | 
| 99 87 | 
             
                  end
         | 
| 100 | 
            -
             | 
| 101 88 | 
             
                end
         | 
| 102 89 | 
             
              else
         | 
| 103 | 
            -
                teardown
         | 
| 90 | 
            +
                teardown(name: scenario_name)
         | 
| 104 91 | 
             
              end
         | 
| 105 92 | 
             
            end
         | 
| @@ -0,0 +1,116 @@ | |
| 1 | 
            +
            require 'fileutils'
         | 
| 2 | 
            +
            require 'headless'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module MediawikiSelenium
         | 
| 5 | 
            +
              # Adds support to {Environment} for running sessions in a headless mode
         | 
| 6 | 
            +
              # using Xvfb. Video will be recorded for the display and saved for failed
         | 
| 7 | 
            +
              # scenarios if a `headless_capture_path` environment variable is configured.
         | 
| 8 | 
            +
              #
         | 
| 9 | 
            +
              module HeadlessHelper
         | 
| 10 | 
            +
                class << self
         | 
| 11 | 
            +
                  # Creates a global headless display using the given environment's
         | 
| 12 | 
            +
                  # configuration. If a display has already been created once before, it
         | 
| 13 | 
            +
                  # is simply returned.
         | 
| 14 | 
            +
                  #
         | 
| 15 | 
            +
                  # @param env [Environment] Environment for which to start headless.
         | 
| 16 | 
            +
                  #
         | 
| 17 | 
            +
                  # @return [Headless]
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  def create_or_reuse_display(env)
         | 
| 20 | 
            +
                    return @_display unless @_display.nil?
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    options = { video: { provider: :libav, codec: 'libx264' } }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    display = env.lookup(:headless_display, default: nil)
         | 
| 25 | 
            +
                    options[:display] = display unless display.nil?
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    if env.lookup(:headless_reuse, default: true).to_s == 'false'
         | 
| 28 | 
            +
                      options[:reuse] = false
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    if env.lookup(:headless_destroy_at_exit, default: true).to_s == 'false'
         | 
| 32 | 
            +
                      options[:destroy_at_exit] = false
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    @_display = Headless.new(options)
         | 
| 36 | 
            +
                    @_display.start
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    @_display
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  # Destroys the global headless display created by
         | 
| 42 | 
            +
                  # {create_or_reuse_display}.
         | 
| 43 | 
            +
                  #
         | 
| 44 | 
            +
                  def destroy_display
         | 
| 45 | 
            +
                    @_display.destroy if @_display
         | 
| 46 | 
            +
                    @_display = nil
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  # Whether a global headless display has been created.
         | 
| 50 | 
            +
                  #
         | 
| 51 | 
            +
                  # @return [true, false]
         | 
| 52 | 
            +
                  #
         | 
| 53 | 
            +
                  def display_created?
         | 
| 54 | 
            +
                    !@_display.nil?
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                # Starts a headless display and starts recording before the {Environment}
         | 
| 59 | 
            +
                # opens a browser for the first time.
         | 
| 60 | 
            +
                #
         | 
| 61 | 
            +
                # @see Environment#browser
         | 
| 62 | 
            +
                #
         | 
| 63 | 
            +
                def browser
         | 
| 64 | 
            +
                  @_headless_display = HeadlessHelper.create_or_reuse_display(self)
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  if !@_headless_capture && headless_capture?
         | 
| 67 | 
            +
                    @_headless_capture = true
         | 
| 68 | 
            +
                    @_headless_display.video.start_capture
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  super
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                # Whether or not we should perform video capture of the headless display
         | 
| 75 | 
            +
                # for each new browser session.
         | 
| 76 | 
            +
                #
         | 
| 77 | 
            +
                # @return [true, false]
         | 
| 78 | 
            +
                #
         | 
| 79 | 
            +
                def headless_capture?
         | 
| 80 | 
            +
                  !headless_capture_path.nil?
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                # Directory where screenshot/video files of headless sessions will be
         | 
| 84 | 
            +
                # saved. Defaults to writing them to a `log` directory under the workspace
         | 
| 85 | 
            +
                # directory.
         | 
| 86 | 
            +
                #
         | 
| 87 | 
            +
                # @return [String, nil]
         | 
| 88 | 
            +
                #
         | 
| 89 | 
            +
                def headless_capture_path
         | 
| 90 | 
            +
                  lookup(:headless_capture_path, default: nil)
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                # Performs teardown tasks for headless operation, saving any video
         | 
| 94 | 
            +
                # captures to file.
         | 
| 95 | 
            +
                #
         | 
| 96 | 
            +
                # @see Environment#teardown
         | 
| 97 | 
            +
                #
         | 
| 98 | 
            +
                def teardown(info = {})
         | 
| 99 | 
            +
                  super
         | 
| 100 | 
            +
                ensure
         | 
| 101 | 
            +
                  if @_headless_capture
         | 
| 102 | 
            +
                    if info[:status] == :failed
         | 
| 103 | 
            +
                      dir = File.absolute_path(headless_capture_path)
         | 
| 104 | 
            +
                      FileUtils.mkdir_p(dir)
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                      filename = "#{(info[:name] || 'scenario').tr("#{File::SEPARATOR}\000", '-')}.mp4"
         | 
| 107 | 
            +
                      filename = File.join(dir, filename)
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                      @_headless_display.video.stop_and_save(filename)
         | 
| 110 | 
            +
                    else
         | 
| 111 | 
            +
                      @_headless_display.video.stop_and_discard
         | 
| 112 | 
            +
                    end
         | 
| 113 | 
            +
                  end
         | 
| 114 | 
            +
                end
         | 
| 115 | 
            +
              end
         | 
| 116 | 
            +
            end
         | 
    
        data/mediawiki_selenium.gemspec
    CHANGED
    
    | @@ -28,7 +28,7 @@ Gem::Specification.new do |spec| | |
| 28 28 | 
             
              spec.require_paths = ['lib']
         | 
| 29 29 |  | 
| 30 30 | 
             
              spec.add_runtime_dependency 'cucumber', '~> 1.3', '>= 1.3.20'
         | 
| 31 | 
            -
              spec.add_runtime_dependency 'headless', '~>  | 
| 31 | 
            +
              spec.add_runtime_dependency 'headless', '~> 2.0', '>= 2.1.0'
         | 
| 32 32 | 
             
              spec.add_runtime_dependency 'json', '~> 1.8', '>= 1.8.1'
         | 
| 33 33 | 
             
              spec.add_runtime_dependency 'mediawiki_api', '~> 0.4', '>= 0.4.1'
         | 
| 34 34 | 
             
              spec.add_runtime_dependency 'page-object', '~> 1.0'
         | 
    
        data/spec/environment_spec.rb
    CHANGED
    
    | @@ -83,6 +83,22 @@ module MediawikiSelenium | |
| 83 83 | 
             
                  end
         | 
| 84 84 | 
             
                end
         | 
| 85 85 |  | 
| 86 | 
            +
                describe '#initialize' do
         | 
| 87 | 
            +
                  subject { Environment.new(config) }
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  context 'when headless mode is enabled' do
         | 
| 90 | 
            +
                    let(:config) { { headless: 'true' } }
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                    it { is_expected.to be_a(HeadlessHelper) }
         | 
| 93 | 
            +
                  end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                  context 'when headless mode is disabled' do
         | 
| 96 | 
            +
                    let(:config) { { headless: nil } }
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                    it { is_expected.to_not be_a(HeadlessHelper) }
         | 
| 99 | 
            +
                  end
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
             | 
| 86 102 | 
             
                describe '#==' do
         | 
| 87 103 | 
             
                  subject { env == other }
         | 
| 88 104 |  | 
| @@ -381,7 +397,7 @@ module MediawikiSelenium | |
| 381 397 | 
             
                end
         | 
| 382 398 |  | 
| 383 399 | 
             
                describe '#teardown' do
         | 
| 384 | 
            -
                  subject { env.teardown(status) }
         | 
| 400 | 
            +
                  subject { env.teardown(status: status) }
         | 
| 385 401 |  | 
| 386 402 | 
             
                  let(:status) { :passed }
         | 
| 387 403 | 
             
                  let(:browser_instance) { double(Watir::Browser) }
         | 
| @@ -393,7 +409,7 @@ module MediawikiSelenium | |
| 393 409 |  | 
| 394 410 | 
             
                  it 'yields the given block and closes the browser' do
         | 
| 395 411 | 
             
                    expect(browser_instance).to receive(:close)
         | 
| 396 | 
            -
                    expect { |blk| env.teardown(status, &blk) }.to yield_with_args(browser_instance)
         | 
| 412 | 
            +
                    expect { |blk| env.teardown(status: status, &blk) }.to yield_with_args(browser_instance)
         | 
| 397 413 | 
             
                  end
         | 
| 398 414 |  | 
| 399 415 | 
             
                  context 'when keep_browser_open is set to "true"' do
         | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module MediawikiSelenium
         | 
| 4 | 
            +
              describe HeadlessHelper do
         | 
| 5 | 
            +
                let(:env) { Environment.new(config.merge(headless: true)) }
         | 
| 6 | 
            +
                let(:config) { {} }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                describe '.create_or_reuse_display' do
         | 
| 9 | 
            +
                  subject { HeadlessHelper.create_or_reuse_display(env) }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  let(:headless) { double('Headless') }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  before { allow(headless).to receive(:destroy) }
         | 
| 14 | 
            +
                  after { HeadlessHelper.destroy_display }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  context 'called for the first time' do
         | 
| 17 | 
            +
                    it 'creates, starts, and returns a new Headless' do
         | 
| 18 | 
            +
                      expect(Headless).to receive(:new).and_return(headless)
         | 
| 19 | 
            +
                      expect(headless).to receive(:start)
         | 
| 20 | 
            +
                      expect(subject).to be(headless)
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  context 'called a second time' do
         | 
| 25 | 
            +
                    it 'only creates one Headless' do
         | 
| 26 | 
            +
                      expect(Headless).to receive(:new).once.and_return(headless)
         | 
| 27 | 
            +
                      expect(headless).to receive(:start).once
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                      2.times { HeadlessHelper.create_or_reuse_display(env) }
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
            end
         | 
    
        data/spec/page_factory_spec.rb
    CHANGED
    
    | @@ -47,8 +47,6 @@ module MediawikiSelenium | |
| 47 47 |  | 
| 48 48 | 
             
                  context 'when told to visit a page' do
         | 
| 49 49 | 
             
                    let(:visit) { true }
         | 
| 50 | 
            -
                    let(:config) { { mediawiki_url: 'http://an.example/wiki/' } }
         | 
| 51 | 
            -
             | 
| 52 50 | 
             
                    let(:page_object_platform) { double('PageObject::WatirPageObject') }
         | 
| 53 51 |  | 
| 54 52 | 
             
                    before do
         | 
| @@ -57,6 +55,8 @@ module MediawikiSelenium | |
| 57 55 | 
             
                    end
         | 
| 58 56 |  | 
| 59 57 | 
             
                    context 'where the page URL is defined' do
         | 
| 58 | 
            +
                      let(:config) { { mediawiki_url: 'http://an.example/wiki/' } }
         | 
| 59 | 
            +
             | 
| 60 60 | 
             
                      let(:page_class) do
         | 
| 61 61 | 
             
                        Class.new do
         | 
| 62 62 | 
             
                          include ::PageObject
         | 
| @@ -64,15 +64,35 @@ module MediawikiSelenium | |
| 64 64 | 
             
                        end
         | 
| 65 65 | 
             
                      end
         | 
| 66 66 |  | 
| 67 | 
            -
                       | 
| 67 | 
            +
                      before do
         | 
| 68 68 | 
             
                        expect_any_instance_of(page_class).to receive(:platform).
         | 
| 69 69 | 
             
                          and_return(page_object_platform)
         | 
| 70 | 
            +
                      end
         | 
| 70 71 |  | 
| 72 | 
            +
                      it 'qualifies the path with the configured :mediawiki_url' do
         | 
| 71 73 | 
             
                        expect(page_object_platform).to receive(:navigate_to).
         | 
| 72 74 | 
             
                          with('http://an.example/wiki/Special:RandomPage')
         | 
| 73 75 |  | 
| 74 76 | 
             
                        subject
         | 
| 75 77 | 
             
                      end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                      context 'and it contains ERb that references `env`' do
         | 
| 80 | 
            +
                        let(:config) { { mediawiki_url: 'http://an.example/wiki/', mediawiki_user: 'user1' } }
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                        let(:page_class) do
         | 
| 83 | 
            +
                          Class.new do
         | 
| 84 | 
            +
                            include ::PageObject
         | 
| 85 | 
            +
                            page_url 'User:<%= env.user %>'
         | 
| 86 | 
            +
                          end
         | 
| 87 | 
            +
                        end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                        it 'successfully calls the `env` method that was added to the page object' do
         | 
| 90 | 
            +
                          expect(page_object_platform).to receive(:navigate_to).
         | 
| 91 | 
            +
                            with('http://an.example/wiki/User:user1')
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                          subject
         | 
| 94 | 
            +
                        end
         | 
| 95 | 
            +
                      end
         | 
| 76 96 | 
             
                    end
         | 
| 77 97 |  | 
| 78 98 | 
             
                    context 'where the page URL is undefined' do
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: mediawiki_selenium
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.5.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Chris McMahon
         | 
| @@ -13,7 +13,7 @@ authors: | |
| 13 13 | 
             
            autorequire: 
         | 
| 14 14 | 
             
            bindir: bin
         | 
| 15 15 | 
             
            cert_chain: []
         | 
| 16 | 
            -
            date: 2015- | 
| 16 | 
            +
            date: 2015-07-28 00:00:00.000000000 Z
         | 
| 17 17 | 
             
            dependencies:
         | 
| 18 18 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 19 19 | 
             
              name: cucumber
         | 
| @@ -41,20 +41,20 @@ dependencies: | |
| 41 41 | 
             
                requirements:
         | 
| 42 42 | 
             
                - - "~>"
         | 
| 43 43 | 
             
                  - !ruby/object:Gem::Version
         | 
| 44 | 
            -
                    version: ' | 
| 44 | 
            +
                    version: '2.0'
         | 
| 45 45 | 
             
                - - ">="
         | 
| 46 46 | 
             
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            -
                    version: 1.0 | 
| 47 | 
            +
                    version: 2.1.0
         | 
| 48 48 | 
             
              type: :runtime
         | 
| 49 49 | 
             
              prerelease: false
         | 
| 50 50 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 51 | 
             
                requirements:
         | 
| 52 52 | 
             
                - - "~>"
         | 
| 53 53 | 
             
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            -
                    version: ' | 
| 54 | 
            +
                    version: '2.0'
         | 
| 55 55 | 
             
                - - ">="
         | 
| 56 56 | 
             
                  - !ruby/object:Gem::Version
         | 
| 57 | 
            -
                    version: 1.0 | 
| 57 | 
            +
                    version: 2.1.0
         | 
| 58 58 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 59 59 | 
             
              name: json
         | 
| 60 60 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -332,6 +332,7 @@ files: | |
| 332 332 | 
             
            - bin/mediawiki-selenium-init
         | 
| 333 333 | 
             
            - features/api.feature
         | 
| 334 334 | 
             
            - features/basic_usage.feature
         | 
| 335 | 
            +
            - features/recording.feature
         | 
| 335 336 | 
             
            - features/saucelabs.feature
         | 
| 336 337 | 
             
            - features/step_definitions/api_helper_steps.rb
         | 
| 337 338 | 
             
            - features/step_definitions/browser_steps.rb
         | 
| @@ -364,6 +365,7 @@ files: | |
| 364 365 | 
             
            - lib/mediawiki_selenium/support/env.rb
         | 
| 365 366 | 
             
            - lib/mediawiki_selenium/support/hooks.rb
         | 
| 366 367 | 
             
            - lib/mediawiki_selenium/support/modules/api_helper.rb
         | 
| 368 | 
            +
            - lib/mediawiki_selenium/support/modules/headless_helper.rb
         | 
| 367 369 | 
             
            - lib/mediawiki_selenium/support/modules/strict_pending.rb
         | 
| 368 370 | 
             
            - lib/mediawiki_selenium/support/modules/user_factory_helper.rb
         | 
| 369 371 | 
             
            - lib/mediawiki_selenium/support/pages.rb
         | 
| @@ -381,6 +383,7 @@ files: | |
| 381 383 | 
             
            - spec/browser_factory/firefox_spec.rb
         | 
| 382 384 | 
             
            - spec/browser_factory/phantomjs_spec.rb
         | 
| 383 385 | 
             
            - spec/environment_spec.rb
         | 
| 386 | 
            +
            - spec/headless_helper_spec.rb
         | 
| 384 387 | 
             
            - spec/page_factory_spec.rb
         | 
| 385 388 | 
             
            - spec/remote_browser_factory_spec.rb
         | 
| 386 389 | 
             
            - spec/spec_helper.rb
         |