screenpress 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 60b8533d92e4bd76d766d8edf7c19c1d632daade
4
+ data.tar.gz: 9714f31a961652e8721eaad4db9a7fb94de3f66c
5
+ SHA512:
6
+ metadata.gz: 0bde0c099aae02852676f5e45c342b4f74323cc20635e5bbadc3a9c7c97c08a251566d0a3c5908f1d44680499ba2a849f2632cda383306e4b6405d2f81b0286c
7
+ data.tar.gz: cae85ae2c530f8be666521424907c6e5bb8baaed8a6d1b5300ca6815a15f608960395f3bbdbd7ebe17e7dbae68aef80c31d5ab0dce02c09b681a762bfbeb826a
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --order rand
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in screenpress.gemspec
4
+ gemspec
5
+
6
+ gem "capybara", "2.2.0"
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Screenpress
2
+
3
+ It happens. Your button is there but it's white on white on white and no one can see it. Especially your rspec tests.
4
+
5
+ Screenpress integrates with your Capybara tests to implement a visual regression prevention workflow.
6
+
7
+ ## Setup
8
+
9
+ ```ruby
10
+
11
+ # acceptance_helper.rb
12
+
13
+ require 'screenpress'
14
+
15
+ RSpec.configure do |config|
16
+ config.include ::Screenpress::DSL
17
+ end
18
+
19
+ ```
20
+
21
+ ```ruby
22
+
23
+ # your_spec.rb
24
+
25
+ visit '/tasks/new'
26
+
27
+ screenpress('tasks/form')
28
+
29
+ ```
30
+
31
+ This will take a picture of the page and put it at `/screenpress/tasks/form.png` to review.
32
+
33
+ ## Workflow
34
+
35
+ So it just takes a screenshot and puts in in a folder. So what?
36
+
37
+ The thing is that it's now in git. If it's different, it's now on your diff and everyone can see what has changed.
38
+
39
+ You've just added a visual design review to your development process and that's cool. Now we can go back in time and see when that header changed or not accept the pull request in the first place if the button is missing.
40
+
41
+ ### Options
42
+
43
+ There are a few config options...
44
+
45
+ ```ruby
46
+ # acceptance_helper.rb
47
+
48
+ require 'screenpress'
49
+
50
+ # Maybe you want to turn it off in some cases (like on your continuous integration server)
51
+ Screenpress.config.enabled = false if ENV['JENKINS']
52
+
53
+ # You can change where files are saved relative to project root (default if /screenpress)
54
+ Screenpress.config.path = "/spec/screenpress"
55
+
56
+ # Or provide the full path
57
+ Screenpress.config.full_path = Rails.root.join("spec", "pictures")
58
+
59
+ RSpec.configure do |config|
60
+ config.include ::Screenpress::DSL
61
+ end
62
+ ```
63
+
64
+ ### TODO
65
+
66
+ * Allow a proc to be set for enablement
67
+ * Maybe be more deliberate like Huxley and set modes (ENV variables?) for recording
68
+ * Enable mode that fails test if image changes
69
+ * Enable tools to easily compare without Github (locally)
70
+
71
+
72
+ ### Inspiration
73
+
74
+ * [Huxley](https://github.com/facebook/huxley)
75
+ * [Wraith](https://github.com/BBC-News/wraith)
76
+ * [Capybara Screenshot](https://github.com/mattheworiordan/capybara-screenshot)
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,47 @@
1
+ module Screenpress
2
+ class Config
3
+ def path=val
4
+ self.full_path = root.join(val)
5
+ end
6
+
7
+ def full_path=val
8
+ @full_path = Pathname.new(val).expand_path
9
+ end
10
+
11
+ def full_path
12
+ self.path = "screenpress" unless @full_path
13
+ @full_path
14
+ end
15
+
16
+ def enabled=val
17
+ @enabled = val
18
+ end
19
+
20
+ def enabled?
21
+ return !!@enabled if defined?(@enabled)
22
+ @enabled = calc_enabled
23
+ end
24
+
25
+ protected
26
+
27
+ def root
28
+ @root ||= Pathname.new(calc_root_string).expand_path
29
+ end
30
+
31
+ def calc_enabled
32
+ # TODO env variables or something?
33
+ true
34
+ end
35
+
36
+ def calc_root_string
37
+ return Rails.root.to_s if defined?(Rails)
38
+ return Padrino.root.to_s if defined?(Padrino)
39
+ return Sinatra::Application.root.to_s if defined?(Sinatra)
40
+ return RAILS_ROOT if defined?(RAILS_ROOT)
41
+ return RACK_ROOT if defined?(RACK_ROOT)
42
+ return ENV['RAILS_ROOT'] if ENV['RAILS_ROOT']
43
+ return ENV['RACK_ROOT'] if ENV['RACK_ROOT']
44
+ return Dir.pwd
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,15 @@
1
+ module Screenpress
2
+ module DSL
3
+ def screenpress(relative_filename)
4
+ return true unless Screenpress.config.enabled?
5
+
6
+ filename = Screenpress.config.full_path.join(relative_filename)
7
+
8
+ # TODO: see if have extension
9
+ filename << ".png"
10
+
11
+ saver = Screenpress::Saver.new(filename.to_s, Capybara, Capybara.page)
12
+ saver.save
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,112 @@
1
+ require 'fileutils'
2
+
3
+ module Screenpress
4
+ class Saver
5
+ attr_reader :capybara, :page, :filename
6
+
7
+ def initialize(filename, capybara = nil, page = nil)
8
+ @capybara = capybara || Capybara
9
+ @page = page || @capybara.page
10
+ @filename = filename
11
+ end
12
+
13
+ def save
14
+ # if current_path empty then nothing to screen shot as browser has not loaded any URL
15
+ return false if capybara.current_path.to_s.empty?
16
+ save_screenshot
17
+ end
18
+
19
+ def save_screenshot
20
+ # settings to nil because of issues in some version of capybara
21
+ old_path = Capybara.save_and_open_page_path
22
+ Capybara.save_and_open_page_path = nil
23
+
24
+ ensure_directory
25
+
26
+ Screenpress::Saver::Proxy.save!(capybara.current_driver, page.driver, filename)
27
+ end
28
+
29
+ def ensure_directory
30
+ folder = File.dirname(filename)
31
+ return if File.directory?(folder)
32
+ FileUtils.mkdir_p(folder)
33
+ end
34
+
35
+ class Proxy
36
+ class << self
37
+ def save!(name, driver, filename)
38
+ return send(name, driver, filename) if self.respond_to?(name)
39
+
40
+ klass = driver.class.name
41
+ if klass =~ /Selenium/
42
+ return send(:selenium, driver, filename)
43
+ elsif klass =~ /Mechanize/
44
+ return send(:mechanize, driver, filename)
45
+ elsif klass =~ /RackTest/
46
+ return send(:rack_test, driver, filename)
47
+ elsif klass =~ /Poltergeist/
48
+ return send(:poltergeist, driver, filename)
49
+ elsif klass =~ /Webkit/
50
+ return send(:webkit, driver, filename)
51
+ else
52
+ warn "Screenpress could not detect a screenshot driver for '#{name}'. Saving with default with unknown results."
53
+ return send(:default, driver, filename)
54
+ end
55
+ end
56
+
57
+ def default(driver, path)
58
+ if driver.respond_to?(:save_screenshot)
59
+ driver.save_screenshot(path)
60
+ else
61
+ driver.render(path)
62
+ end
63
+ true
64
+ end
65
+
66
+ def rack_test(driver, path)
67
+ warn "Rack::Test capybara driver has no ability to output screen shots. Skipping."
68
+ false
69
+ end
70
+
71
+ def mechanize(driver, path)
72
+ warn "Mechanize capybara driver has no ability to output screen shots. Skipping."
73
+ false
74
+ end
75
+
76
+ def selenium(driver, path)
77
+ driver.browser.save_screenshot(path)
78
+ true
79
+ end
80
+
81
+ def poltergeist(driver, path)
82
+ driver.render(path, :full => true)
83
+ true
84
+ end
85
+
86
+ def webkit(driver, path)
87
+ if driver.respond_to?(:save_screenshot)
88
+ driver.save_screenshot(path)
89
+ else
90
+ driver.render(path)
91
+ end
92
+ true
93
+ end
94
+
95
+ def webkit_debug(driver, path)
96
+ driver.render(path)
97
+ true
98
+ end
99
+
100
+ def terminus(driver, path)
101
+ if driver.respond_to?(:save_screenshot)
102
+ driver.save_screenshot(path)
103
+ true
104
+ else
105
+ warn "Terminus capybara driver has no ability to output screen shots. Skipping."
106
+ false
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,3 @@
1
+ module Screenpress
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,21 @@
1
+ require "screenpress/version"
2
+ require "capybara"
3
+
4
+ module Screenpress
5
+ autoload :Config, 'screenpress/config'
6
+ autoload :DSL, 'screenpress/dsl'
7
+ autoload :Saver, 'screenpress/saver'
8
+
9
+ class << self
10
+ def config
11
+ @config ||= Screenpress::Config.new
12
+ end
13
+
14
+ protected
15
+
16
+ def reset
17
+ # mostly for tests, resets eveything
18
+ @config = nil
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'screenpress/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "screenpress"
8
+ spec.version = Screenpress::VERSION
9
+ spec.authors = ["Brian Leonard"]
10
+ spec.email = ["brian@bleonard.com"]
11
+ spec.description = %q{Workflow and Capybara extension that takes screenshots of your tests to prevent visual regressions}
12
+ spec.summary = %q{Prevent visual regressions}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "capybara"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+
26
+ spec.add_development_dependency("rspec")
27
+ spec.add_development_dependency("debugger")
28
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Screenpress::Config do
4
+ it "should be returned from the module" do
5
+ Screenpress.config.class.name.should == "Screenpress::Config"
6
+ end
7
+
8
+ describe ".path" do
9
+ it "should default to /screenpress" do
10
+ Screenpress.config.full_path.to_s.should == "#{Dir.pwd}/screenpress"
11
+ end
12
+
13
+ it "should use the rails root if it was there" do
14
+ rails = Object.new
15
+ rails.should_receive(:root).and_return("/my/rails/")
16
+ stub_const("Rails", rails)
17
+ Screenpress.config.full_path.to_s.should == "/my/rails/screenpress"
18
+ end
19
+ end
20
+
21
+ end
data/spec/dsl_spec.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ class MyDslTest
4
+ include Screenpress::DSL
5
+ end
6
+
7
+ describe "Screenpress::DSL" do
8
+ it "should provide screenpress method" do
9
+ obj = MyDslTest.new
10
+ obj.should respond_to(:screenpress)
11
+ end
12
+
13
+ it "should be in rspec because it's included in my spec helper" do
14
+ Screenpress::Config.any_instance.stub(:enabled?).and_return(false)
15
+ lambda {
16
+ screenpress("here")
17
+ }.should_not raise_error
18
+ end
19
+
20
+ end
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ describe Screenpress::Saver do
4
+ before do
5
+ Screenpress.config.path = image_dir
6
+ end
7
+
8
+ let(:image_dir) { '/tmp' }
9
+ let(:file_basename) { "my_screenshot" }
10
+ let(:screenshot_path) { "#{Dir.pwd}#{image_dir}/#{file_basename}.png" }
11
+
12
+ let(:driver_mock) { double('Capybara driver') }
13
+ let(:page_mock) { double('Capybara session page', :body => 'body', :driver => driver_mock) }
14
+ let(:capybara_mock) {
15
+ double(Capybara).as_null_object.tap do |m|
16
+ m.stub(:current_driver).and_return(:default)
17
+ m.stub(:current_path).and_return('/')
18
+ end
19
+ }
20
+
21
+ let(:saver) { Screenpress::Saver.new(screenshot_path, capybara_mock, page_mock) }
22
+
23
+ context "default" do
24
+ it 'should be in capybara root output' do
25
+ driver_mock.should_receive(:render).with(screenshot_path)
26
+ saver.save
27
+ end
28
+
29
+
30
+ it 'should save if current_path is empty' do
31
+ capybara_mock.stub(:current_path).and_return(nil)
32
+ capybara_mock.should_not_receive(:save_page)
33
+ driver_mock.should_not_receive(:render)
34
+
35
+ saver.save
36
+ end
37
+ end
38
+
39
+ context "selenium" do
40
+ before do
41
+ capybara_mock.stub(:current_driver).and_return(:selenium)
42
+ end
43
+ it 'should save via browser' do
44
+ browser_mock = double('browser')
45
+ driver_mock.should_receive(:browser).and_return(browser_mock)
46
+ browser_mock.should_receive(:save_screenshot).with(screenshot_path)
47
+
48
+ saver.save
49
+ end
50
+ end
51
+
52
+ context "poltergeist" do
53
+ before do
54
+ capybara_mock.stub(:current_driver).and_return(:poltergeist)
55
+ end
56
+ it 'should save driver render with :full => true' do
57
+ driver_mock.should_receive(:render).with(screenshot_path, {:full => true})
58
+
59
+ saver.save
60
+ end
61
+ end
62
+
63
+ describe "webkit" do
64
+ before do
65
+ capybara_mock.stub(:current_driver).and_return(:webkit)
66
+ end
67
+
68
+ context 'has render method' do
69
+ before do
70
+ driver_mock.stub(:respond_to?).with(:'save_screenshot').and_return(false)
71
+ end
72
+
73
+ it 'should save driver render' do
74
+ driver_mock.should_receive(:render).with(screenshot_path)
75
+
76
+ saver.save
77
+ end
78
+ end
79
+
80
+ context 'has save_screenshot method' do
81
+ before do
82
+ driver_mock.stub(:respond_to?).with(:'save_screenshot').and_return(true)
83
+ end
84
+
85
+ it 'should save driver render' do
86
+ driver_mock.should_receive(:save_screenshot).with(screenshot_path)
87
+
88
+ saver.save
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "webkit debug" do
94
+ before do
95
+ capybara_mock.stub(:current_driver).and_return(:webkit_debug)
96
+ end
97
+
98
+ it 'should save driver render' do
99
+ driver_mock.should_receive(:render).with(screenshot_path)
100
+
101
+ saver.save
102
+ end
103
+ end
104
+
105
+ describe "with unknown driver" do
106
+ before do
107
+ capybara_mock.stub(:current_driver).and_return(:unknown)
108
+ Screenpress::Saver::Proxy.stub(:warn).and_return(nil)
109
+ end
110
+
111
+ it 'should save driver render' do
112
+ driver_mock.should_receive(:render).with(screenshot_path)
113
+
114
+ saver.save
115
+ end
116
+
117
+ it 'should output warning about unknown results' do
118
+ # Not pure mock testing
119
+ Screenpress::Saver::Proxy.should_receive(:warn).with(/screenshot driver for 'unknown'.*unknown results/).and_return(nil)
120
+ driver_mock.should_receive(:render)
121
+ saver.save
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,12 @@
1
+ require 'screenpress'
2
+
3
+ RSpec.configure do |config|
4
+ config.mock_framework = :rspec
5
+
6
+ config.include Screenpress::DSL
7
+
8
+ config.after(:each) do
9
+ Screenpress.send(:reset)
10
+ end
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: screenpress
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Brian Leonard
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capybara
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: debugger
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Workflow and Capybara extension that takes screenshots of your tests
84
+ to prevent visual regressions
85
+ email:
86
+ - brian@bleonard.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - .rspec
93
+ - Gemfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - lib/screenpress.rb
98
+ - lib/screenpress/config.rb
99
+ - lib/screenpress/dsl.rb
100
+ - lib/screenpress/saver.rb
101
+ - lib/screenpress/version.rb
102
+ - screenpress.gemspec
103
+ - spec/config_spec.rb
104
+ - spec/dsl_spec.rb
105
+ - spec/saver_spec.rb
106
+ - spec/spec_helper.rb
107
+ homepage: ''
108
+ licenses:
109
+ - MIT
110
+ metadata: {}
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubyforge_project:
127
+ rubygems_version: 2.0.3
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: Prevent visual regressions
131
+ test_files:
132
+ - spec/config_spec.rb
133
+ - spec/dsl_spec.rb
134
+ - spec/saver_spec.rb
135
+ - spec/spec_helper.rb