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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 329d08a407bf34d62782833f29ddc148c36e75c0
4
- data.tar.gz: 34f4f2700b159884ddb8b5e6ddf77c935c8fd9ee
3
+ metadata.gz: 9883a47e71cdb76841699d8292442f00a6312a63
4
+ data.tar.gz: 6af66ee6695ba0e33cb68ade1aa2bae67566cadc
5
5
  SHA512:
6
- metadata.gz: b87efa97ee1d7ad227c7d30264daf1b1144a0cedaf3ccb46495a5a68081781fe8ae4cab1db855d7b5dfce880c7ede665e3de58736a4582a521c847c1f16b43e3
7
- data.tar.gz: 84993de521a0a42243a8420d91fdb6a41eef45abbc9281a356197968715652b9b5fad2f809799ec5d716b18e4e081da249c8dd248d3865baff9d26be6aea78b8
6
+ metadata.gz: 1656892e8f622ce63c4683d0a14f5626834d102be62512bbc8c7510adce55467a1b6cc9eee1a5e229f1b6985323997ca86b9cf86b914607d3117d7dd95d28d30
7
+ data.tar.gz: 4a7fb08977d4c047721e9329a8e31fdfabf176c4a7efd1d83cee36014e68eb084abe2acfc8dca13bab39c5c5054b61547ab8a045f635c786b9d4d573fef9066e
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  .bundle
2
2
  /.yardoc/
3
3
  /doc/
4
+ /tmp/
4
5
  .gem
5
6
  *.gem
6
7
  Gemfile.lock
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.4.0'
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
@@ -5,7 +5,7 @@
5
5
  First, update the `Gemfile` in your project's root directory to specify the
6
6
  new version.
7
7
 
8
- gem 'mediawiki_selenium', '~> 1.4.0'
8
+ gem 'mediawiki_selenium', '~> 1.5.0'
9
9
 
10
10
  ## Upgrade gems and dependencies
11
11
 
@@ -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
- @env = MediawikiSelenium::Environment.new(YAML.load(yaml))
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(*configs)
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
- After do
21
- @env.teardown unless @env.nil?
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
@@ -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 status [Symbol] Status of the executed scenario.
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(status = :passed)
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 = test_name(scenario).gsub(/ /, '_')
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
@@ -1,3 +1,3 @@
1
1
  module MediawikiSelenium
2
- VERSION = '1.4.0'
2
+ VERSION = '1.5.0'
3
3
  end
@@ -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', '~> 1.0', '>= 1.0.1'
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'
@@ -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
@@ -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
- it 'qualifies the path with the configured :mediawiki_url' do
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.0
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-06-26 00:00:00.000000000 Z
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: '1.0'
44
+ version: '2.0'
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 1.0.1
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: '1.0'
54
+ version: '2.0'
55
55
  - - ">="
56
56
  - !ruby/object:Gem::Version
57
- version: 1.0.1
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