leifcr-capybara-screenshot 1.0.14

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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +13 -0
  5. data/Appraisals +19 -0
  6. data/CHANGELOG.md +256 -0
  7. data/Gemfile +9 -0
  8. data/LICENSE +19 -0
  9. data/README.md +315 -0
  10. data/Rakefile +40 -0
  11. data/capybara-screenshot.gemspec +39 -0
  12. data/gemfiles/cucumber.1.3.gemfile +11 -0
  13. data/gemfiles/cucumber.2.4.gemfile +11 -0
  14. data/gemfiles/latest.gemfile +10 -0
  15. data/gemfiles/rspec.3.0.gemfile +11 -0
  16. data/gemfiles/spinach.0.8.gemfile +11 -0
  17. data/lib/capybara-screenshot/callbacks.rb +44 -0
  18. data/lib/capybara-screenshot/capybara.rb +26 -0
  19. data/lib/capybara-screenshot/cucumber.rb +28 -0
  20. data/lib/capybara-screenshot/helpers.rb +28 -0
  21. data/lib/capybara-screenshot/minitest.rb +36 -0
  22. data/lib/capybara-screenshot/pruner.rb +48 -0
  23. data/lib/capybara-screenshot/rspec/base_reporter.rb +21 -0
  24. data/lib/capybara-screenshot/rspec/html_embed_reporter.rb +25 -0
  25. data/lib/capybara-screenshot/rspec/html_link_reporter.rb +37 -0
  26. data/lib/capybara-screenshot/rspec/json_reporter.rb +19 -0
  27. data/lib/capybara-screenshot/rspec/text_reporter.rb +39 -0
  28. data/lib/capybara-screenshot/rspec/textmate_link_reporter.rb +19 -0
  29. data/lib/capybara-screenshot/rspec.rb +95 -0
  30. data/lib/capybara-screenshot/s3_saver.rb +64 -0
  31. data/lib/capybara-screenshot/saver.rb +131 -0
  32. data/lib/capybara-screenshot/spinach.rb +26 -0
  33. data/lib/capybara-screenshot/testunit.rb +39 -0
  34. data/lib/capybara-screenshot/version.rb +5 -0
  35. data/lib/capybara-screenshot.rb +217 -0
  36. data/spec/cucumber/cucumber_spec.rb +89 -0
  37. data/spec/cucumber/step_definitions/step_definitions.rb +18 -0
  38. data/spec/cucumber/support/env.rb +17 -0
  39. data/spec/feature/minitest_spec.rb +79 -0
  40. data/spec/feature/testunit_spec.rb +77 -0
  41. data/spec/rspec/rspec_spec.rb +158 -0
  42. data/spec/spec_helper.rb +34 -0
  43. data/spec/spinach/spinach_spec.rb +60 -0
  44. data/spec/spinach/support/spinach_failure.rb +41 -0
  45. data/spec/support/aruba.rb +2 -0
  46. data/spec/support/common_setup.rb +67 -0
  47. data/spec/support/html_reporter_context.rb +28 -0
  48. data/spec/support/test_app.rb +13 -0
  49. data/spec/unit/base_reporter_spec.rb +25 -0
  50. data/spec/unit/capybara-screenshot_rspec_spec.rb +48 -0
  51. data/spec/unit/capybara-screenshot_spec.rb +121 -0
  52. data/spec/unit/capybara_spec.rb +50 -0
  53. data/spec/unit/pruner_spec.rb +108 -0
  54. data/spec/unit/rspec_reporters/html_embed_reporter_spec.rb +18 -0
  55. data/spec/unit/rspec_reporters/html_link_reporter_spec.rb +27 -0
  56. data/spec/unit/rspec_reporters/text_reporter_spec.rb +98 -0
  57. data/spec/unit/rspec_reporters/textmate_link_reporter_spec.rb +39 -0
  58. data/spec/unit/s3_saver_spec.rb +132 -0
  59. data/spec/unit/saver_spec.rb +366 -0
  60. metadata +264 -0
@@ -0,0 +1,158 @@
1
+ require 'spec_helper'
2
+
3
+ describe Capybara::Screenshot::RSpec, :type => :aruba do
4
+ describe "used with RSpec" do
5
+ include CommonSetup
6
+
7
+ before do
8
+ Capybara::Screenshot.capybara_tmp_path = expand_path('tmp')
9
+ end
10
+
11
+ def run_failing_case(code, error_message, format=nil)
12
+ run_case code, format: format
13
+ if error_message.kind_of?(Regexp)
14
+ expect(last_command_started.output).to match(error_message)
15
+ else
16
+ expect(last_command_started.output).to include(error_message)
17
+ end
18
+ end
19
+
20
+ def run_case(code, options = {})
21
+ write_file('spec/test_failure.rb', <<-RUBY)
22
+ #{ensure_load_paths_valid}
23
+ require 'rspec'
24
+ require 'capybara'
25
+ require 'capybara/rspec'
26
+ require 'capybara-screenshot'
27
+ require 'capybara-screenshot/rspec'
28
+
29
+ #{setup_test_app}
30
+ #{code}
31
+ RUBY
32
+
33
+ cmd = cmd_with_format(options[:format])
34
+ run_simple_with_retry cmd, false
35
+
36
+ expect(last_command_started.output).to match('0 failures') if options[:assert_all_passed]
37
+ end
38
+
39
+ def cmd_with_format(format)
40
+ "rspec #{"--format #{format} " if format}#{expand_path('spec/test_failure.rb')}"
41
+ end
42
+
43
+ it 'saves a screenshot on failure' do
44
+ run_failing_case <<-RUBY, %q{Unable to find link or button "you'll never find me"}
45
+ feature 'screenshot with failure' do
46
+ scenario 'click on a missing link' do
47
+ visit '/'
48
+ expect(page.body).to include('This is the root page')
49
+ click_on "you'll never find me"
50
+ end
51
+ end
52
+ RUBY
53
+ expect(expand_path('tmp/screenshot.html')).to_not have_file_content('This is the root page')
54
+ end
55
+
56
+ formatters = {
57
+ progress: 'HTML screenshot:',
58
+ documentation: 'HTML screenshot:',
59
+ html: %r{<a href="file://\./tmp/screenshot\.html"[^>]*>HTML page</a>},
60
+ json: '"screenshot":{"'
61
+ }
62
+
63
+ # Textmate formatter is only included in RSpec 2
64
+ if RSpec::Core::Version::STRING.to_i == 2
65
+ formatters[:textmate] = %r{TextMate\.system\(.*open file://\./tmp/screenshot.html}
66
+ end
67
+
68
+ formatters.each do |formatter, error_message|
69
+ it "uses the associated #{formatter} formatter" do
70
+ run_failing_case <<-RUBY, error_message, formatter
71
+ feature 'screenshot with failure' do
72
+ scenario 'click on a missing link' do
73
+ visit '/'
74
+ click_on "you'll never find me"
75
+ end
76
+ end
77
+ RUBY
78
+ expect('tmp/screenshot.html').to have_file_content('This is the root page')
79
+ end
80
+ end
81
+
82
+ it "does not save a screenshot for tests that don't use Capybara" do
83
+ run_failing_case <<-RUBY, %q{expected: false}
84
+ describe 'failing test' do
85
+ it 'fails intentionally' do
86
+ expect(true).to eql(false)
87
+ end
88
+ end
89
+ RUBY
90
+ expect('tmp/screenshot.html').to_not be_an_existing_file
91
+ end
92
+
93
+ it 'saves a screenshot for the correct session for failures using_session' do
94
+ run_failing_case <<-RUBY, %q{Unable to find link or button "you'll never find me"}
95
+ feature 'screenshot with failure' do
96
+ scenario 'click on a missing link' do
97
+ visit '/'
98
+ expect(page.body).to include('This is the root page')
99
+ using_session :different_session do
100
+ visit '/different_page'
101
+ expect(page.body).to include('This is a different page')
102
+ click_on "you'll never find me"
103
+ end
104
+ end
105
+ end
106
+ RUBY
107
+ expect('tmp/screenshot.html').to have_file_content(/is/)
108
+ end
109
+
110
+ context 'pruning' do
111
+ before do
112
+ create_screenshot_for_pruning
113
+ configure_prune_strategy :last_run
114
+ end
115
+
116
+ it 'on failure it prunes previous screenshots when strategy is set' do
117
+ run_failing_case <<-RUBY, 'HTML screenshot:', :progress
118
+ feature 'screenshot with failure' do
119
+ scenario 'click on a missing link' do
120
+ visit '/'
121
+ click_on "you'll never find me"
122
+ end
123
+ end
124
+ RUBY
125
+ assert_screenshot_pruned
126
+ end
127
+
128
+ it 'on success it never prunes' do
129
+ run_case <<-CUCUMBER, assert_all_passed: true
130
+ feature 'screenshot without failure' do
131
+ scenario 'click on a link' do
132
+ visit '/'
133
+ end
134
+ end
135
+ CUCUMBER
136
+ assert_screenshot_not_pruned
137
+ end
138
+ end
139
+
140
+ context 'no pruning by default' do
141
+ before do
142
+ create_screenshot_for_pruning
143
+ end
144
+
145
+ it 'on failure it leaves existing screenshots' do
146
+ run_failing_case <<-RUBY, 'HTML screenshot:', :progress
147
+ feature 'screenshot with failure' do
148
+ scenario 'click on a missing link' do
149
+ visit '/'
150
+ click_on "you'll never find me"
151
+ end
152
+ end
153
+ RUBY
154
+ assert_screenshot_not_pruned
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,34 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper.rb"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ $: << '../lib'
9
+ require 'rspec'
10
+ require 'capybara-screenshot'
11
+ require 'capybara-screenshot/rspec'
12
+ require 'timecop'
13
+
14
+ RSpec.configure do |config|
15
+ if RSpec::Core::Version::STRING.to_i == 2
16
+ config.treat_symbols_as_metadata_keys_with_true_values = true
17
+ end
18
+ config.run_all_when_everything_filtered = true
19
+ config.filter_run :focus
20
+ config.before do
21
+ @aruba_timeout_seconds = 60
22
+ end if RUBY_PLATFORM == 'java'
23
+ end
24
+
25
+ Capybara.app = lambda { |env| [200, {}, ["OK"]] }
26
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
27
+
28
+ if RUBY_VERSION < '1.9.3'
29
+ ::Dir.glob(::File.expand_path('../support/*.rb', __FILE__)).each { |f| require File.join(File.dirname(f), File.basename(f, '.rb')) }
30
+ ::Dir.glob(::File.expand_path('../support/**/*.rb', __FILE__)).each { |f| require File.join(File.dirname(f), File.basename(f, '.rb')) }
31
+ else
32
+ ::Dir.glob(::File.expand_path('../support/*.rb', __FILE__)).each { |f| require_relative f }
33
+ ::Dir.glob(::File.expand_path('../support/**/*.rb', __FILE__)).each { |f| require_relative f }
34
+ end
@@ -0,0 +1,60 @@
1
+ require "spec_helper"
2
+
3
+ describe "Using Capybara::Screenshot with Spinach" do
4
+ include CommonSetup
5
+
6
+ def run_failing_case(failure_message, code)
7
+ write_file('steps/failure.rb', <<-RUBY)
8
+ #{ensure_load_paths_valid}
9
+ require 'spinach/support/spinach_failure.rb'
10
+ #{setup_test_app}
11
+ RUBY
12
+
13
+ write_file('spinach.feature', code)
14
+ cmd = 'bundle exec spinach -f .'
15
+ run_simple_with_retry cmd, false
16
+ expect(last_command_started.output).to match(failure_message)
17
+ end
18
+
19
+ it "saves a screenshot on failure" do
20
+ run_failing_case(%q{Unable to find link or button "you'll never find me"}, <<-GHERKIN)
21
+ Feature: Failure
22
+ Scenario: Failure
23
+ Given I visit "/"
24
+ And I click on a missing link
25
+ GHERKIN
26
+ expect('tmp/my_screenshot.html').to have_file_content('This is the root page')
27
+ end
28
+
29
+ it "saves a screenshot on an error" do
30
+ run_failing_case(%q{you can't handle me}, <<-GHERKIN)
31
+ Feature: Failure
32
+ Scenario: Failure
33
+ Given I visit "/"
34
+ And I trigger an unhandled exception
35
+ GHERKIN
36
+ expect('tmp/my_screenshot.html').to have_file_content('This is the root page')
37
+ end
38
+
39
+ it "saves a screenshot for the correct session for failures using_session" do
40
+ run_failing_case(%q{Unable to find link or button "you'll never find me"}, <<-GHERKIN)
41
+ Feature: Failure
42
+ Scenario: Failure in different session
43
+ Given I visit "/"
44
+ And I click on a missing link on a different page in a different session
45
+ GHERKIN
46
+ expect('tmp/my_screenshot.html').to have_file_content('This is a different page')
47
+ end
48
+
49
+ it 'on failure it prunes previous screenshots when strategy is set' do
50
+ create_screenshot_for_pruning
51
+ configure_prune_strategy :last_run
52
+ run_failing_case(%q{Unable to find link or button "you'll never find me"}, <<-GHERKIN)
53
+ Feature: Failure
54
+ Scenario: Failure
55
+ Given I visit "/"
56
+ And I click on a missing link
57
+ GHERKIN
58
+ assert_screenshot_pruned
59
+ end
60
+ end
@@ -0,0 +1,41 @@
1
+ require 'capybara'
2
+ require 'capybara/rspec'
3
+ require 'capybara-screenshot'
4
+ require 'capybara-screenshot/spinach'
5
+ require 'spinach/capybara'
6
+ require 'support/test_app'
7
+
8
+ Spinach.config.failure_exceptions = [Capybara::ElementNotFound]
9
+
10
+ class Spinach::Features::Failure < Spinach::FeatureSteps
11
+ include ::Capybara::DSL
12
+
13
+ before do
14
+ ::Capybara::Screenshot.register_filename_prefix_formatter(:spinach) do |failed_step|
15
+ raise 'expected failing step' if !@expected_failed_step.nil? && !failed_step.name.include?(@expected_failed_step)
16
+ 'my_screenshot'
17
+ end
18
+ end
19
+
20
+ step 'I visit "/"' do
21
+ visit '/'
22
+ end
23
+
24
+ step 'I click on a missing link' do
25
+ @expected_failed_step = 'I click on a missing link'
26
+ click_on "you'll never find me"
27
+ end
28
+
29
+ step 'I trigger an unhandled exception' do
30
+ @expected_failed_step = "I trigger an unhandled exception"
31
+ raise "you can't handle me"
32
+ end
33
+
34
+ step 'I click on a missing link on a different page in a different session' do
35
+ using_session :different_session do
36
+ visit '/different_page'
37
+ @expected_failed_step = 'I click on a missing link on a different page in a different session'
38
+ click_on "you'll never find me"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,2 @@
1
+ require 'aruba/rspec'
2
+ require 'aruba/config/jruby'
@@ -0,0 +1,67 @@
1
+ module CommonSetup
2
+ def self.included(target)
3
+ target.class_eval do
4
+ include Aruba::Api
5
+ end
6
+
7
+ target.let(:gem_root) { File.expand_path('../..', File.dirname(__FILE__)) }
8
+
9
+ target.let(:ensure_load_paths_valid) do
10
+ <<-RUBY
11
+ %w(lib spec).each do |include_folder|
12
+ $LOAD_PATH.unshift(File.join('#{gem_root}', include_folder))
13
+ end
14
+ RUBY
15
+ end
16
+
17
+ target.let(:screenshot_path) { 'tmp' }
18
+ target.let(:screenshot_for_pruning_path) { "#{screenshot_path}/old_screenshot.html" }
19
+
20
+ target.let(:setup_test_app) do
21
+ <<-RUBY
22
+ require 'support/test_app'
23
+ Capybara::Screenshot.capybara_tmp_path = '#{screenshot_path}'
24
+ Capybara.app = TestApp
25
+ Capybara::Screenshot.append_timestamp = false
26
+ #{@additional_setup_steps}
27
+ RUBY
28
+ end
29
+
30
+ target.before do
31
+ if ENV['BUNDLE_GEMFILE'] && ENV['BUNDLE_GEMFILE'].match(/^\.|^[^\/\.]/)
32
+ ENV['BUNDLE_GEMFILE'] = File.join(gem_root, ENV['BUNDLE_GEMFILE'])
33
+ end
34
+ end
35
+
36
+ target.after(:each) do |example|
37
+ if example.exception
38
+ puts "Output from failed Aruba test:"
39
+ puts all_output.split(/\n/).map { |line| " #{line}"}
40
+ puts ""
41
+ end
42
+ end
43
+
44
+ def run_simple_with_retry(*args)
45
+ run_simple(*args)
46
+ rescue ChildProcess::TimeoutError => e
47
+ puts "run_simple(#{args.join(', ')}) failed. Will retry once. `#{e.message}`"
48
+ run_simple(*args)
49
+ end
50
+
51
+ def configure_prune_strategy(strategy)
52
+ @additional_setup_steps = "Capybara::Screenshot.prune_strategy = :keep_last_run"
53
+ end
54
+
55
+ def create_screenshot_for_pruning
56
+ write_file screenshot_for_pruning_path, '<html></html>'
57
+ end
58
+
59
+ def assert_screenshot_pruned
60
+ expect(screenshot_for_pruning_path).to_not be_an_existing_file
61
+ end
62
+
63
+ def assert_screenshot_not_pruned
64
+ expect(screenshot_for_pruning_path).to be_an_existing_file
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,28 @@
1
+ shared_context 'html reporter' do
2
+ def set_example(example)
3
+ @reporter.instance_variable_set :@failed_examples, [example]
4
+ end
5
+
6
+ before do
7
+ # Mocking `RSpec::Core::Formatters::HtmlFormatter`, but only implementing the things that
8
+ # are actually used in `HtmlLinkReporter#extra_failure_content_with_screenshot`.
9
+ @reporter_class = Class.new do
10
+ def extra_failure_content(exception)
11
+ "original content"
12
+ end
13
+ end
14
+
15
+ @reporter = @reporter_class.new
16
+ @reporter.singleton_class.send :include, described_class
17
+ end
18
+
19
+ context 'when there is no screenshot' do
20
+ before do
21
+ set_example double("example", metadata: {})
22
+ end
23
+
24
+ it 'doesnt change the original content of the reporter' do
25
+ expect(@reporter.extra_failure_content(nil)).to eql("original content")
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ require 'sinatra/base'
2
+
3
+ Sinatra::Application.root = '.'
4
+
5
+ class TestApp < Sinatra::Base
6
+ get '/' do
7
+ 'This is the root page'
8
+ end
9
+
10
+ get '/different_page' do
11
+ 'This is a different page'
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Capybara::Screenshot::RSpec::BaseReporter do
4
+ describe '#enhance_with_screenshot' do
5
+ it 'makes the original method available under an alias and replaces it with the enhanced method' do
6
+ reporter_module = Module.new do
7
+ extend Capybara::Screenshot::RSpec::BaseReporter
8
+ enhance_with_screenshot :foo
9
+ def foo_with_screenshot
10
+ [foo_without_screenshot, :enhanced]
11
+ end
12
+ end
13
+
14
+ klass = Class.new do
15
+ def foo
16
+ :original
17
+ end
18
+ end
19
+
20
+ expect(klass.new.foo).to eql(:original)
21
+ klass.send :include, reporter_module
22
+ expect(klass.new.foo).to eql([:original, :enhanced])
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe Capybara::Screenshot::RSpec do
4
+ describe '.after_failed_example' do
5
+ context 'for a failed example in a feature that can be snapshotted' do
6
+ before do
7
+ allow(Capybara.page).to receive(:current_url).and_return("http://test.local")
8
+ allow(Capybara::Screenshot::Saver).to receive(:new).and_return(mock_saver)
9
+ end
10
+ let(:example_group) { Module.new.send(:include, Capybara::DSL) }
11
+ let(:example) { double("example", exception: Exception.new, example_group: example_group, metadata: {}) }
12
+ let(:mock_saver) do
13
+ Capybara::Screenshot::Saver.new(Capybara, Capybara.page).tap do |saver|
14
+ allow(saver).to receive(:save)
15
+ end
16
+ end
17
+
18
+ it 'instantiates a saver and calls `save` on it' do
19
+ expect(mock_saver).to receive(:save)
20
+ described_class.after_failed_example(example)
21
+ end
22
+
23
+ it 'extends the metadata with an empty hash for screenshot metadata' do
24
+ described_class.after_failed_example(example)
25
+ expect(example.metadata).to have_key(:screenshot)
26
+ expect(example.metadata[:screenshot]).to eql({})
27
+ end
28
+
29
+ context 'when a html file gets saved' do
30
+ before { allow(mock_saver).to receive(:html_saved?).and_return(true) }
31
+
32
+ it 'adds the html file path to the screenshot metadata' do
33
+ described_class.after_failed_example(example)
34
+ expect(example.metadata[:screenshot][:html]).to match("./screenshot")
35
+ end
36
+ end
37
+
38
+ context 'when an image gets saved' do
39
+ before { allow(mock_saver).to receive(:screenshot_saved?).and_return(true) }
40
+
41
+ it 'adds the image path to the screenshot metadata' do
42
+ described_class.after_failed_example(example)
43
+ expect(example.metadata[:screenshot][:image]).to match("./screenshot")
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end