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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +1 -1
- data/CHANGELOG.md +7 -0
- data/Guardfile +2 -2
- data/README.md +11 -20
- data/Rakefile +11 -1
- data/bin/janus +1 -1
- data/janus.gemspec +3 -1
- data/lib/janus.rb +0 -1
- data/lib/janus/browser.rb +19 -0
- data/lib/janus/command/record.rb +35 -4
- data/lib/janus/command/validate.rb +39 -5
- data/lib/janus/configuration.rb +21 -2
- data/lib/janus/core/engine.rb +26 -0
- data/lib/janus/core/error.rb +6 -0
- data/lib/janus/core/rule.rb +46 -0
- data/lib/janus/io/directory.rb +40 -0
- data/lib/janus/io/selenium.rb +43 -0
- data/lib/janus/screenshot.rb +7 -27
- data/lib/janus/version.rb +1 -1
- data/spec/integration/engine_spec.rb +50 -0
- data/spec/support/square-base.png +0 -0
- data/spec/support/square-big.png +0 -0
- data/spec/support/square-ten.png +0 -0
- data/spec/support/square-thirty.png +0 -0
- data/spec/support/square-twenty.png +0 -0
- data/spec/unit/janus/browser_spec.rb +57 -0
- data/spec/{janus → unit/janus}/command/initialize_spec.rb +1 -1
- data/spec/unit/janus/command/record_spec.rb +93 -0
- data/spec/unit/janus/command/validate_spec.rb +105 -0
- data/spec/{janus → unit/janus}/configuration_spec.rb +42 -0
- data/spec/unit/janus/core/engine_spec.rb +36 -0
- data/spec/unit/janus/core/error_spec.rb +4 -0
- data/spec/unit/janus/core/rule_spec.rb +65 -0
- data/spec/unit/janus/io/directory_spec.rb +83 -0
- data/spec/unit/janus/io/selenium_spec.rb +78 -0
- data/spec/unit/janus/screenshot_spec.rb +26 -0
- data/spec/{janus → unit/janus}/test_spec.rb +0 -0
- data/spec/{spec_helper.rb → unit/spec_helper.rb} +0 -0
- metadata +78 -19
- data/spec/janus/command/record_spec.rb +0 -36
- data/spec/janus/command/validate_spec.rb +0 -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
|
data/lib/janus/screenshot.rb
CHANGED
@@ -1,37 +1,17 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require 'selenium/webdriver'
|
3
|
-
|
4
1
|
module Janus
|
5
2
|
class Screenshot
|
6
|
-
|
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
|
-
|
5
|
+
def initialize(image)
|
6
|
+
@image = image
|
23
7
|
end
|
24
8
|
|
25
|
-
def
|
26
|
-
@
|
27
|
-
@image = parameters[:image]
|
9
|
+
def dimensions
|
10
|
+
{ width: @image.width, height: @image.height }
|
28
11
|
end
|
29
12
|
|
30
|
-
def
|
31
|
-
|
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
@@ -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('
|
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 = []
|