leifcr-capybara-screenshot 1.0.14

Sign up to get free protection for your applications and to get access to all the features.
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,19 @@
1
+ require 'capybara-screenshot/rspec/base_reporter'
2
+
3
+ module Capybara
4
+ module Screenshot
5
+ module RSpec
6
+ module JsonReporter
7
+ extend BaseReporter
8
+
9
+ enhance_with_screenshot :format_example
10
+
11
+ def format_example_with_screenshot(example)
12
+ format_example_without_screenshot(example).merge({
13
+ screenshot: example.metadata[:screenshot]
14
+ })
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ require 'capybara-screenshot/rspec/base_reporter'
2
+ require 'capybara-screenshot/helpers'
3
+
4
+ module Capybara
5
+ module Screenshot
6
+ module RSpec
7
+ module TextReporter
8
+ extend BaseReporter
9
+
10
+ if ::RSpec::Core::Version::STRING.to_i <= 2
11
+ enhance_with_screenshot :dump_failure_info
12
+ else
13
+ enhance_with_screenshot :example_failed
14
+ end
15
+
16
+ def dump_failure_info_with_screenshot(example)
17
+ dump_failure_info_without_screenshot example
18
+ output_screenshot_info(example)
19
+ end
20
+
21
+ def example_failed_with_screenshot(notification)
22
+ example_failed_without_screenshot notification
23
+ output_screenshot_info(notification.example)
24
+ end
25
+
26
+ private
27
+ def output_screenshot_info(example)
28
+ return unless (screenshot = example.metadata[:screenshot])
29
+ output.puts(long_padding + CapybaraScreenshot::Helpers.yellow("HTML screenshot: file://#{screenshot[:html]}")) if screenshot[:html]
30
+ output.puts(long_padding + CapybaraScreenshot::Helpers.yellow("Image screenshot: file://#{screenshot[:image]}")) if screenshot[:image]
31
+ end
32
+
33
+ def long_padding
34
+ " "
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,19 @@
1
+ require 'capybara-screenshot/rspec/base_reporter'
2
+ require 'capybara-screenshot/rspec/html_link_reporter'
3
+ require 'shellwords'
4
+
5
+ module Capybara
6
+ module Screenshot
7
+ module RSpec
8
+ module TextMateLinkReporter
9
+ extend BaseReporter
10
+ include HtmlLinkReporter
11
+ enhance_with_screenshot :extra_failure_content
12
+
13
+ def attributes_for_screenshot_link(url)
14
+ super.merge("onclick" => "TextMate.system('open #{Shellwords.escape(url)}'); return false;")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,95 @@
1
+ require "capybara-screenshot"
2
+
3
+ require "capybara-screenshot/rspec/text_reporter"
4
+ require "capybara-screenshot/rspec/html_link_reporter"
5
+ require "capybara-screenshot/rspec/html_embed_reporter"
6
+ require "capybara-screenshot/rspec/json_reporter"
7
+ require "capybara-screenshot/rspec/textmate_link_reporter"
8
+
9
+ module Capybara
10
+ module Screenshot
11
+ module RSpec
12
+
13
+ # Reporters extend RSpec formatters to display information about screenshots for failed
14
+ # examples.
15
+ #
16
+ # Technically, a reporter is a module that gets injected into a RSpec formatter class.
17
+ # It uses method aliasing to extend some (usually just one) of the formatter's methods.
18
+ #
19
+ # Implementing a custom reporter is as simple as creating a module and setting up the
20
+ # appropriate aliases. Use `BaseReporter.enhance_with_screenshot` if you don't want
21
+ # to set up the aliases manually:
22
+ #
23
+ # module MyReporter
24
+ # extend Capybara::Screenshot::RSpec::BaseReporter
25
+ #
26
+ # # Will replace the formatter's original `dump_failure_info` method with
27
+ # # `dump_failure_info_with_screenshot` from this module:
28
+ # enhance_with_screenshot :dump_failure_info
29
+ #
30
+ # def dump_failure_info_with_screenshot(example)
31
+ # dump_failure_info_without_screenshot(example) # call original implementation
32
+ # ... # your additions here
33
+ # end
34
+ # end
35
+ #
36
+ # Finally customize `Capybara::Screenshot::RSpec::FORMATTERS` to make sure your reporter
37
+ # gets injected into the appropriate formatter.
38
+
39
+ REPORTERS = {
40
+ "RSpec::Core::Formatters::ProgressFormatter" => Capybara::Screenshot::RSpec::TextReporter,
41
+ "RSpec::Core::Formatters::DocumentationFormatter" => Capybara::Screenshot::RSpec::TextReporter,
42
+ "RSpec::Core::Formatters::HtmlFormatter" => Capybara::Screenshot::RSpec::HtmlLinkReporter,
43
+ "RSpec::Core::Formatters::JsonFormatter" => Capybara::Screenshot::RSpec::JsonReporter,
44
+ "RSpec::Core::Formatters::TextMateFormatter" => Capybara::Screenshot::RSpec::TextMateLinkReporter, # RSpec 2
45
+ "RSpec::Mate::Formatters::TextMateFormatter" => Capybara::Screenshot::RSpec::TextMateLinkReporter, # RSpec 3
46
+ "Fuubar" => Capybara::Screenshot::RSpec::TextReporter
47
+ }
48
+
49
+ class << self
50
+ attr_accessor :add_link_to_screenshot_for_failed_examples
51
+
52
+ def after_failed_example(example)
53
+ if example.example_group.include?(Capybara::DSL) # Capybara DSL method has been included for a feature we can snapshot
54
+ Capybara.using_session(Capybara::Screenshot.final_session_name) do
55
+ if Capybara.page.current_url != '' && Capybara::Screenshot.autosave_on_failure && example.exception
56
+ filename_prefix = Capybara::Screenshot.filename_prefix_for(:rspec, example)
57
+
58
+ saver = Capybara::Screenshot.new_saver(Capybara, Capybara.page, true, filename_prefix)
59
+ saver.save
60
+
61
+ example.metadata[:screenshot] = {}
62
+ example.metadata[:screenshot][:html] = saver.html_path if saver.html_saved?
63
+ example.metadata[:screenshot][:image] = saver.screenshot_path if saver.screenshot_saved?
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ self.add_link_to_screenshot_for_failed_examples = true
71
+ end
72
+ end
73
+ end
74
+
75
+ RSpec.configure do |config|
76
+ config.before do
77
+ Capybara::Screenshot.final_session_name = nil
78
+ end
79
+
80
+ config.after do |example_from_block_arg|
81
+ # RSpec 3 no longer defines `example`, but passes the example as block argument instead
82
+ example = config.respond_to?(:expose_current_running_example_as) ? example_from_block_arg : self.example
83
+
84
+ Capybara::Screenshot::RSpec.after_failed_example(example)
85
+ end
86
+
87
+ config.before(:suite) do
88
+ if Capybara::Screenshot::RSpec.add_link_to_screenshot_for_failed_examples
89
+ RSpec.configuration.formatters.each do |formatter|
90
+ next unless (reporter_module = Capybara::Screenshot::RSpec::REPORTERS[formatter.class.to_s])
91
+ formatter.singleton_class.send :include, reporter_module
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,64 @@
1
+ require 'aws-sdk'
2
+
3
+ module Capybara
4
+ module Screenshot
5
+ class S3Saver
6
+ DEFAULT_REGION = 'us-east-1'
7
+
8
+ def initialize(saver, s3_client, bucket_name)
9
+ @saver = saver
10
+ @s3_client = s3_client
11
+ @bucket_name = bucket_name
12
+ end
13
+
14
+ def self.new_with_configuration(saver, configuration)
15
+ default_s3_client_credentials = {
16
+ region: DEFAULT_REGION
17
+ }
18
+
19
+ s3_client_credentials = default_s3_client_credentials.merge(
20
+ configuration.fetch(:s3_client_credentials)
21
+ )
22
+
23
+ s3_client = Aws::S3::Client.new(s3_client_credentials)
24
+ bucket_name = configuration.fetch(:bucket_name)
25
+
26
+ new(saver, s3_client, bucket_name)
27
+ rescue KeyError
28
+ raise "Invalid S3 Configuration #{configuration}. Please refer to the documentation for the necessary configurations."
29
+ end
30
+
31
+ def save_and_upload_screenshot
32
+ save_and do |local_file_path|
33
+ File.open(local_file_path) do |file|
34
+ s3_client.put_object(
35
+ bucket: bucket_name,
36
+ key: File.basename(local_file_path),
37
+ body: file
38
+ )
39
+ end
40
+ end
41
+ end
42
+ alias_method :save, :save_and_upload_screenshot
43
+
44
+ def method_missing(method, *args)
45
+ # Need to use @saver instead of S3Saver#saver attr_reader method because
46
+ # using the method goes into infinite loop. Maybe attr_reader implements
47
+ # its methods via method_missing?
48
+ @saver.send(method, *args)
49
+ end
50
+
51
+ private
52
+ attr_reader :saver,
53
+ :s3_client,
54
+ :bucket_name
55
+
56
+ def save_and
57
+ saver.save
58
+
59
+ yield(saver.html_path) if block_given? && saver.html_saved?
60
+ yield(saver.screenshot_path) if block_given? && saver.screenshot_saved?
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,131 @@
1
+ require 'capybara-screenshot/helpers'
2
+ require 'capybara-screenshot/callbacks'
3
+
4
+ module Capybara
5
+ module Screenshot
6
+ class Saver
7
+ include Capybara::Screenshot::Callbacks
8
+
9
+ define_callback :after_save_html
10
+ define_callback :after_save_screenshot
11
+
12
+ attr_reader :capybara, :page, :file_base_name
13
+
14
+ def initialize(capybara, page, html_save=true, filename_prefix='screenshot')
15
+ @capybara, @page, @html_save = capybara, page, html_save
16
+ time_now = Time.now
17
+ timestamp = "#{time_now.strftime('%Y-%m-%d-%H-%M-%S.')}#{'%03d' % (time_now.usec/1000).to_i}"
18
+
19
+ filename = [filename_prefix]
20
+ filename << timestamp if Capybara::Screenshot.append_timestamp
21
+ filename << SecureRandom.hex if Capybara::Screenshot.append_random
22
+
23
+ @file_base_name = filename.join('_')
24
+
25
+ Capybara::Screenshot.prune
26
+ end
27
+
28
+ def save
29
+ # if current_path empty then nothing to screen shot as browser has not loaded any URL
30
+ return if page.current_path.to_s.empty?
31
+
32
+ save_html if @html_save
33
+ save_screenshot
34
+ end
35
+
36
+ def save_html
37
+ path = html_path
38
+ clear_save_path do
39
+ if Capybara::VERSION.match(/^\d+/)[0] == '1'
40
+ capybara.save_page(page.body, "#{path}")
41
+ else
42
+ capybara.save_page("#{path}")
43
+ end
44
+ end
45
+ @html_saved = true
46
+ run_callbacks :after_save_html, html_path if html_saved?
47
+ end
48
+
49
+ def save_screenshot
50
+ path = screenshot_path
51
+ clear_save_path do
52
+ result = Capybara::Screenshot.registered_drivers.fetch(capybara.current_driver) { |driver_name|
53
+ warn "capybara-screenshot could not detect a screenshot driver for '#{capybara.current_driver}'. Saving with default with unknown results."
54
+ Capybara::Screenshot.registered_drivers[:default]
55
+ }.call(page.driver, path)
56
+ @screenshot_saved = result != :not_supported
57
+ end
58
+ run_callbacks :after_save_screenshot, screenshot_path if screenshot_saved?
59
+ end
60
+
61
+ def html_path
62
+ File.join(Capybara::Screenshot.capybara_root, "#{file_base_name}.html")
63
+ end
64
+
65
+ def screenshot_path
66
+ File.join(Capybara::Screenshot.capybara_root, "#{file_base_name}.png")
67
+ end
68
+
69
+ def html_path_alt_root
70
+ File.join(Capybara::Screenshot.capybara_alt_root, "#{file_base_name}.html")
71
+ end
72
+
73
+ def screenshot_path_alt_root
74
+ File.join(Capybara::Screenshot.capybara_alt_root, "#{file_base_name}.png")
75
+ end
76
+
77
+ def html_saved?
78
+ @html_saved
79
+ end
80
+
81
+ def screenshot_saved?
82
+ @screenshot_saved
83
+ end
84
+
85
+ # If Capybara::Screenshot.capybara_tmp_path is set then
86
+ # the html_path or screenshot_path can be appended to this path in
87
+ # some versions of Capybara instead of using it as an absolute path
88
+ def clear_save_path
89
+ old_path = Capybara::Screenshot.capybara_tmp_path
90
+ Capybara::Screenshot.capybara_tmp_path = nil
91
+ yield
92
+ ensure
93
+ Capybara::Screenshot.capybara_tmp_path = old_path
94
+ end
95
+
96
+ def output_screenshot_path
97
+ output "HTML screenshot: #{html_path_alt_root}" if html_saved?
98
+ output "Image screenshot: #{screenshot_path_alt_root}" if screenshot_saved?
99
+ end
100
+
101
+ # Print image to screen, if imgcat is available
102
+ def display_image
103
+ system("#{imgcat} #{screenshot_path}") unless imgcat.nil?
104
+ end
105
+
106
+ private
107
+
108
+ def output(message)
109
+ puts " #{CapybaraScreenshot::Helpers.yellow(message)}"
110
+ end
111
+
112
+ def imgcat
113
+ @imgcat ||= which('imgcat')
114
+ end
115
+
116
+ # Cross-platform way of finding an executable in the $PATH.
117
+ #
118
+ # which('ruby') #=> /usr/bin/ruby
119
+ def which(cmd)
120
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
121
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
122
+ exts.each { |ext|
123
+ exe = File.join(path, "#{cmd}#{ext}")
124
+ return exe if File.executable?(exe) && !File.directory?(exe)
125
+ }
126
+ end
127
+ return nil
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,26 @@
1
+ require "capybara-screenshot"
2
+
3
+ Spinach.hooks.before_scenario do |scenario|
4
+ Capybara::Screenshot.final_session_name = nil
5
+ end
6
+
7
+ module Capybara::Screenshot::Spinach
8
+ def self.fail_with_screenshot(step_data, exception, location, step_definitions)
9
+ if Capybara::Screenshot.autosave_on_failure
10
+ Capybara.using_session(Capybara::Screenshot.final_session_name) do
11
+ filename_prefix = Capybara::Screenshot.filename_prefix_for(:spinach, step_data)
12
+ saver = Capybara::Screenshot.new_saver(Capybara, Capybara.page, true, filename_prefix)
13
+ saver.save
14
+ saver.output_screenshot_path
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ Spinach.hooks.on_failed_step do |*args|
21
+ Capybara::Screenshot::Spinach.fail_with_screenshot(*args)
22
+ end
23
+
24
+ Spinach.hooks.on_error_step do |*args|
25
+ Capybara::Screenshot::Spinach.fail_with_screenshot(*args)
26
+ end
@@ -0,0 +1,39 @@
1
+ require 'test/unit/testresult'
2
+
3
+ module Capybara::Screenshot
4
+ class << self
5
+ attr_accessor :testunit_paths
6
+ end
7
+
8
+ self.testunit_paths = [%r{test/integration}]
9
+ end
10
+
11
+ Test::Unit::TestCase.class_eval do
12
+ setup do
13
+ Capybara::Screenshot.final_session_name = nil
14
+ end
15
+ end
16
+
17
+ Test::Unit::TestResult.class_eval do
18
+ private
19
+
20
+ def notify_fault_with_screenshot(fault, *args)
21
+ notify_fault_without_screenshot fault, *args
22
+ is_integration_test = fault.location.any? do |location|
23
+ Capybara::Screenshot.testunit_paths.any? { |path| location.match(path) }
24
+ end
25
+ if is_integration_test
26
+ if Capybara::Screenshot.autosave_on_failure
27
+ Capybara.using_session(Capybara::Screenshot.final_session_name) do
28
+ filename_prefix = Capybara::Screenshot.filename_prefix_for(:testunit, fault)
29
+
30
+ saver = Capybara::Screenshot.new_saver(Capybara, Capybara.page, true, filename_prefix)
31
+ saver.save
32
+ saver.output_screenshot_path
33
+ end
34
+ end
35
+ end
36
+ end
37
+ alias notify_fault_without_screenshot notify_fault
38
+ alias notify_fault notify_fault_with_screenshot
39
+ end
@@ -0,0 +1,5 @@
1
+ module Capybara
2
+ module Screenshot
3
+ VERSION = '1.0.14'
4
+ end
5
+ end