janus-cli 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -1
  4. data/CHANGELOG.md +7 -0
  5. data/Guardfile +2 -2
  6. data/README.md +11 -20
  7. data/Rakefile +11 -1
  8. data/bin/janus +1 -1
  9. data/janus.gemspec +3 -1
  10. data/lib/janus.rb +0 -1
  11. data/lib/janus/browser.rb +19 -0
  12. data/lib/janus/command/record.rb +35 -4
  13. data/lib/janus/command/validate.rb +39 -5
  14. data/lib/janus/configuration.rb +21 -2
  15. data/lib/janus/core/engine.rb +26 -0
  16. data/lib/janus/core/error.rb +6 -0
  17. data/lib/janus/core/rule.rb +46 -0
  18. data/lib/janus/io/directory.rb +40 -0
  19. data/lib/janus/io/selenium.rb +43 -0
  20. data/lib/janus/screenshot.rb +7 -27
  21. data/lib/janus/version.rb +1 -1
  22. data/spec/integration/engine_spec.rb +50 -0
  23. data/spec/support/square-base.png +0 -0
  24. data/spec/support/square-big.png +0 -0
  25. data/spec/support/square-ten.png +0 -0
  26. data/spec/support/square-thirty.png +0 -0
  27. data/spec/support/square-twenty.png +0 -0
  28. data/spec/unit/janus/browser_spec.rb +57 -0
  29. data/spec/{janus → unit/janus}/command/initialize_spec.rb +1 -1
  30. data/spec/unit/janus/command/record_spec.rb +93 -0
  31. data/spec/unit/janus/command/validate_spec.rb +105 -0
  32. data/spec/{janus → unit/janus}/configuration_spec.rb +42 -0
  33. data/spec/unit/janus/core/engine_spec.rb +36 -0
  34. data/spec/unit/janus/core/error_spec.rb +4 -0
  35. data/spec/unit/janus/core/rule_spec.rb +65 -0
  36. data/spec/unit/janus/io/directory_spec.rb +83 -0
  37. data/spec/unit/janus/io/selenium_spec.rb +78 -0
  38. data/spec/unit/janus/screenshot_spec.rb +26 -0
  39. data/spec/{janus → unit/janus}/test_spec.rb +0 -0
  40. data/spec/{spec_helper.rb → unit/spec_helper.rb} +0 -0
  41. metadata +78 -19
  42. data/spec/janus/command/record_spec.rb +0 -36
  43. data/spec/janus/command/validate_spec.rb +0 -44
  44. data/spec/janus/screenshot_spec.rb +0 -79
@@ -0,0 +1,43 @@
1
+ require 'oily_png'
2
+ require 'selenium/webdriver'
3
+ require 'janus/screenshot'
4
+
5
+ module Janus
6
+ module IO
7
+ class Selenium
8
+ @@driver_pool = {}
9
+
10
+ def initialize(username, access_key, browser)
11
+ @username = username
12
+ @access_key = access_key
13
+ @browser = browser
14
+
15
+ @driver = @@driver_pool[browser] || build_driver
16
+ end
17
+
18
+ def read(test)
19
+ @driver.get(test.url)
20
+
21
+ png = @driver.screenshot_as(:png)
22
+ image = ChunkyPNG::Image.from_blob(png)
23
+ Janus::Screenshot.new(image)
24
+ end
25
+
26
+ private
27
+
28
+ def build_driver
29
+ capabilities = ::Selenium::WebDriver::Remote::Capabilities.new(
30
+ platform: @browser.platform,
31
+ browser_name: @browser.name,
32
+ version: @browser.version
33
+ )
34
+
35
+ driver = ::Selenium::WebDriver.for(:remote, {
36
+ url: "http://#{@username}:#{@access_key}@ondemand.saucelabs.com/wd/hub",
37
+ desired_capabilities: capabilities
38
+ })
39
+ @@driver_pool[@browser] = driver
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,37 +1,17 @@
1
- require 'fileutils'
2
- require 'selenium/webdriver'
3
-
4
1
  module Janus
5
2
  class Screenshot
6
- attr_accessor :test, :image
7
-
8
- def self.capture(test, options = {})
9
- driver = Selenium::WebDriver.for(:remote, {
10
- url: "http://#{options[:username]}:#{options[:access_key]}@ondemand.saucelabs.com/wd/hub",
11
- desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome
12
- })
13
- driver.get(test.url)
14
-
15
- Screenshot.new(test: test, image: driver.screenshot_as(:png))
16
- end
17
-
18
- def self.load(test, options = {})
19
- path = File.join(options[:path], "#{test.name}.janus", 'screenshot.png')
20
- image = IO.read(path, mode: 'rb')
3
+ attr_reader :image
21
4
 
22
- Screenshot.new(test: test, image: image)
5
+ def initialize(image)
6
+ @image = image
23
7
  end
24
8
 
25
- def initialize(parameters = {})
26
- @test = parameters[:test]
27
- @image = parameters[:image]
9
+ def dimensions
10
+ { width: @image.width, height: @image.height }
28
11
  end
29
12
 
30
- def save(path)
31
- directory = File.join(path, "#{test.name}.janus")
32
-
33
- FileUtils.mkpath(directory) unless Dir.exists?(directory)
34
- IO.write(File.join(directory, 'screenshot.png'), @image, mode: 'wb')
13
+ def pixels
14
+ @image.pixels
35
15
  end
36
16
  end
37
17
  end
data/lib/janus/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Janus
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -0,0 +1,50 @@
1
+ require 'oily_png'
2
+ require 'janus/configuration'
3
+ require 'janus/core/engine'
4
+ require 'janus/core/error'
5
+ require 'janus/screenshot'
6
+
7
+ describe 'Engine Integration Test' do
8
+ let(:config) { Janus::Configuration.new('threshold' => 0.2) }
9
+ let(:engine) { Janus::Core::Engine.create(config) }
10
+ let(:square_base) { ChunkyPNG::Image::from_file('spec/support/square-base.png') }
11
+ let(:square_big) { ChunkyPNG::Image::from_file('spec/support/square-big.png') }
12
+ let(:square_ten) { ChunkyPNG::Image::from_file('spec/support/square-ten.png') }
13
+ let(:square_twenty) { ChunkyPNG::Image::from_file('spec/support/square-twenty.png') }
14
+ let(:square_thirty) { ChunkyPNG::Image::from_file('spec/support/square-thirty.png') }
15
+
16
+ it 'succeeds for matching image' do
17
+ original = Janus::Screenshot.new(square_base)
18
+ fresh = Janus::Screenshot.new(square_base)
19
+
20
+ expect { engine.execute(original, fresh) }.not_to raise_error
21
+ end
22
+
23
+ it 'succeeds for image below threshold' do
24
+ original = Janus::Screenshot.new(square_base)
25
+ fresh = Janus::Screenshot.new(square_ten)
26
+
27
+ expect { engine.execute(original, fresh) }.not_to raise_error
28
+ end
29
+
30
+ it 'succeeds for image matching threshold' do
31
+ original = Janus::Screenshot.new(square_base)
32
+ fresh = Janus::Screenshot.new(square_twenty)
33
+
34
+ expect { engine.execute(original, fresh) }.not_to raise_error
35
+ end
36
+
37
+ it 'fails for image exceeding threshold' do
38
+ original = Janus::Screenshot.new(square_base)
39
+ fresh = Janus::Screenshot.new(square_thirty)
40
+
41
+ expect { engine.execute(original, fresh) }.to raise_error
42
+ end
43
+
44
+ it 'fails for different sized image' do
45
+ original = Janus::Screenshot.new(square_base)
46
+ fresh = Janus::Screenshot.new(square_big)
47
+
48
+ expect { engine.execute(original, fresh) }.to raise_error
49
+ end
50
+ end
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,57 @@
1
+ require 'janus/browser'
2
+
3
+ describe Janus::Browser do
4
+ it 'sets platform' do
5
+ browser = Janus::Browser.new('platform' => 'platform')
6
+ browser.platform.should == 'platform'
7
+ end
8
+
9
+ it 'sets name' do
10
+ browser = Janus::Browser.new('name' => 'name')
11
+ browser.name.should == 'name'
12
+ end
13
+
14
+ it 'sets version' do
15
+ browser = Janus::Browser.new('version' => '7')
16
+ browser.version.should == '7'
17
+ end
18
+
19
+ describe '#eql' do
20
+ let(:platform) { 'platform' }
21
+ let(:name) { 'name' }
22
+ let(:version) { 'version' }
23
+ let(:a) { Janus::Browser.new('platform' => platform, 'name' => name, 'version' => version) }
24
+
25
+ it 'is false when platform is different' do
26
+ b = Janus::Browser.new('platform' => 'different', 'name' => name, 'version' => version)
27
+ b.should_not eql(a)
28
+ end
29
+
30
+ it 'is false when name is different' do
31
+ b = Janus::Browser.new('platform' => platform, 'name' => 'different', 'version' => version)
32
+ b.should_not eql(a)
33
+ end
34
+
35
+ it 'is false when version is different' do
36
+ b = Janus::Browser.new('platform' => platform, 'name' => name, 'version' => 'different')
37
+ b.should_not eql(a)
38
+ end
39
+
40
+ it 'is true when browser, name, and version are the same' do
41
+ b = Janus::Browser.new('platform' => platform, 'name' => name, 'version' => version)
42
+ b.should eql(a)
43
+ end
44
+ end
45
+
46
+ describe '#to_s' do
47
+ it 'converts to string for browser with version' do
48
+ browser = Janus::Browser.new('platform' => 'platform', 'name' => 'name', 'version' => 0.7)
49
+ browser.to_s.should == 'platform, name 0.7'
50
+ end
51
+
52
+ it 'converts to string for browser without version' do
53
+ browser = Janus::Browser.new('platform' => 'platform', 'name' => 'name')
54
+ browser.to_s.should == 'platform, name'
55
+ end
56
+ end
57
+ end
@@ -8,7 +8,7 @@ describe Janus::Command::Initialize do
8
8
  it 'writes samples configuration if file does not exist' do
9
9
  File.stub(:exists?) { false }
10
10
 
11
- source = File.expand_path('../../../../lib/janus/template/Janusfile', __FILE__)
11
+ source = File.expand_path('../../../../../lib/janus/template/Janusfile', __FILE__)
12
12
  destination = 'Janusfile'
13
13
  FileUtils.should_receive(:copy).with(source, destination)
14
14
 
@@ -0,0 +1,93 @@
1
+ require 'sauce/connect'
2
+ require 'janus/command/record'
3
+ require 'janus/configuration'
4
+
5
+ describe Janus::Command::Record do
6
+ let(:config) { Janus::Configuration.new('username' => 'username', 'access_key' => 'key', 'directory' => 'base') }
7
+ let(:record) { Janus::Command::Record.new(config) }
8
+
9
+ before :each do
10
+ record.stub(:puts)
11
+ record.stub(:print)
12
+
13
+ Sauce::Connect.stub(:connect!)
14
+ end
15
+
16
+ describe '#execute' do
17
+ before :each do
18
+ config.stub(:browsers) { ['red', 'blue'] }
19
+ config.stub(:tests) { ['one', 'two'] }
20
+ end
21
+
22
+ it 'starts tunnel when tunnel is true' do
23
+ config.stub(:tunnel?) { true }
24
+ record.stub(:record_screenshot)
25
+
26
+ Sauce::Connect.should_receive(:connect!)
27
+
28
+ record.execute
29
+ end
30
+
31
+ it 'does not start tunnel when tunnel is false' do
32
+ config.stub(:tunnel?) { false }
33
+ record.stub(:record_screenshot)
34
+
35
+ Sauce::Connect.should_not_receive(:connect!)
36
+
37
+ record.execute
38
+ end
39
+
40
+ it 'records screenshot for each configured test and browser combination' do
41
+ record.should_receive(:record_screenshot).with('red', 'one')
42
+ record.should_receive(:record_screenshot).with('red', 'two')
43
+ record.should_receive(:record_screenshot).with('blue', 'one')
44
+ record.should_receive(:record_screenshot).with('blue', 'two')
45
+
46
+ record.execute
47
+ end
48
+ end
49
+
50
+ describe '#record_screenshot' do
51
+ let(:screenshot) { double }
52
+ let(:browser) { double }
53
+
54
+ let(:test) do
55
+ test = double
56
+ test.stub(:name)
57
+ test
58
+ end
59
+
60
+ # TODO: Builder
61
+ let(:directory) do
62
+ directory = double
63
+ directory.stub(:write)
64
+ directory
65
+ end
66
+
67
+ # TODO: Builder
68
+ let(:selenium) do
69
+ selenium = double
70
+ selenium.stub(:read) { screenshot }
71
+ selenium
72
+ end
73
+
74
+ before :each do
75
+ Janus::IO::Directory.stub(:new) { directory }
76
+ Janus::IO::Selenium.stub(:new) { selenium }
77
+ end
78
+
79
+ it 'reads screenshot from Selenium' do
80
+ Janus::IO::Selenium.should_receive(:new).with('username', 'key', browser) { selenium }
81
+ selenium.should_receive(:read).with(test) { screenshot }
82
+
83
+ record.record_screenshot(browser, test)
84
+ end
85
+
86
+ it 'writes screenshot to Janus directory' do
87
+ Janus::IO::Directory.should_receive(:new).with('base', browser) { directory}
88
+ directory.should_receive(:write).with(test, screenshot)
89
+
90
+ record.record_screenshot(browser, test)
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,105 @@
1
+ require 'janus/command/validate'
2
+ require 'janus/configuration'
3
+
4
+ describe Janus::Command::Validate do
5
+ let(:config) { Janus::Configuration.new('username' => 'username', 'access_key' => 'key', 'directory' => 'base') }
6
+ let(:validate) { Janus::Command::Validate.new(config) }
7
+
8
+ before :each do
9
+ validate.stub(:puts)
10
+ validate.stub(:print)
11
+ end
12
+
13
+ describe '#execute' do
14
+ before :each do
15
+ config.stub(:browsers) { %w(red blue) }
16
+ config.stub(:tests) { %w(one two) }
17
+ end
18
+
19
+ it 'starts tunnel when tunnel is true' do
20
+ config.stub(:tunnel?) { true }
21
+ validate.stub(:validate_screenshot)
22
+
23
+ Sauce::Connect.should_receive(:connect!)
24
+
25
+ validate.execute
26
+ end
27
+
28
+ it 'does not start tunnel when tunnel is false' do
29
+ config.stub(:tunnel?) { false }
30
+ validate.stub(:validate_screenshot)
31
+
32
+ Sauce::Connect.should_not_receive(:connect!)
33
+
34
+ validate.execute
35
+ end
36
+
37
+ it 'validates screenshots for each configured test' do
38
+ validate.should_receive(:validate_screenshot).with('red', 'one')
39
+ validate.should_receive(:validate_screenshot).with('red', 'two')
40
+ validate.should_receive(:validate_screenshot).with('blue', 'one')
41
+ validate.should_receive(:validate_screenshot).with('blue', 'two')
42
+
43
+ validate.execute
44
+ end
45
+ end
46
+
47
+ describe '#validate_screenshot' do
48
+ let(:test) do
49
+ test = double
50
+ test.stub(:name)
51
+ test
52
+ end
53
+
54
+ let(:fresh) { double }
55
+ let(:original) { double }
56
+ let(:browser) { double }
57
+
58
+ # TODO: Builder
59
+ let(:engine) do
60
+ engine = double
61
+ engine.stub(:execute)
62
+ engine
63
+ end
64
+
65
+ # TODO: Builder
66
+ let(:directory) do
67
+ directory = double
68
+ directory.stub(:read) { original }
69
+ directory
70
+ end
71
+
72
+ # TODO: Builder
73
+ let(:selenium) do
74
+ selenium = double
75
+ selenium.stub(:read) { fresh }
76
+ selenium
77
+ end
78
+
79
+ before :each do
80
+ Janus::IO::Directory.stub(:new) { directory }
81
+ Janus::IO::Selenium.stub(:new) { selenium }
82
+ Janus::Core::Engine.stub(:create) { engine }
83
+ end
84
+
85
+ it 'reads screenshot from Selenium' do
86
+ Janus::IO::Selenium.should_receive(:new).with('username', 'key', browser) { selenium }
87
+ selenium.should_receive(:read).with(test) { fresh }
88
+
89
+ validate.validate_screenshot(browser, test)
90
+ end
91
+
92
+ it 'reads screenshot from directory' do
93
+ Janus::IO::Directory.should_receive(:new).with('base', browser) { directory }
94
+ selenium.should_receive(:read).with(test) { original }
95
+
96
+ validate.validate_screenshot(browser, test)
97
+ end
98
+
99
+ it 'executes engine' do
100
+ engine.should_receive(:execute).with(original, fresh)
101
+
102
+ validate.validate_screenshot(browser, test)
103
+ end
104
+ end
105
+ end
@@ -40,6 +40,48 @@ describe Janus::Configuration do
40
40
  end
41
41
  end
42
42
 
43
+ describe '#tunnel' do
44
+ it 'returns tunnel setting' do
45
+ configuration = Janus::Configuration.new('tunnel' => true)
46
+ configuration.tunnel?.should == true
47
+ end
48
+ end
49
+
50
+ describe '#directory' do
51
+ it 'returns directory' do
52
+ configuration = Janus::Configuration.new('directory' => 'directory')
53
+ configuration.directory.should == 'directory'
54
+ end
55
+ end
56
+
57
+ describe '#threshold' do
58
+ it 'returns threshold' do
59
+ configuration = Janus::Configuration.new('threshold' => 0.1)
60
+ configuration.threshold.should == 0.1
61
+ end
62
+
63
+ it 'defaults threshold to zero' do
64
+ configuration = Janus::Configuration.new
65
+ configuration.threshold.should == 0
66
+ end
67
+ end
68
+
69
+ describe '#browsers' do
70
+ it 'creates browser for each entry in configuration file' do
71
+ browser_configuration = []
72
+ browser_configuration << { 'platform' => 'a', 'name' => 'a', 'version' => 'a' }
73
+ browser_configuration << { 'platform' => 'b', 'name' => 'b', 'version' => 'b' }
74
+
75
+ configuration = Janus::Configuration.new({ 'browsers' => browser_configuration })
76
+
77
+ configuration.browsers.each_with_index do |browser, i|
78
+ browser.platform.should == browser_configuration[i]['platform']
79
+ browser.name.should == browser_configuration[i]['name']
80
+ browser.version.should == browser_configuration[i]['version']
81
+ end
82
+ end
83
+ end
84
+
43
85
  describe '#tests' do
44
86
  it 'creates test for each entry in configuration file' do
45
87
  test_configuration = []