janus-cli 0.1.0 → 0.2.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.
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 = []