zucchini-ios 0.5.7 → 0.5.8
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.md +8 -0
- data/README.md +2 -1
- data/bin/zucchini +3 -0
- data/lib/approver.rb +14 -0
- data/lib/detector.rb +61 -0
- data/lib/feature.rb +15 -3
- data/lib/runner.rb +3 -59
- data/lib/version.rb +1 -1
- data/spec/lib/{runner_spec.rb → detector_spec.rb} +11 -11
- data/spec/lib/feature_spec.rb +37 -0
- data/spec/sample_setup/feature_three/feature.zucchini +1 -0
- data/spec/spec_helper.rb +2 -0
- data/zucchini-ios.gemspec +1 -0
- metadata +12 -6
data/LICENSE.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Copyright (c) Vasily Mikhaylichenko and PlayUp USA, LLC.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
4
|
+
|
5
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
6
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
7
|
+
|
8
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
CHANGED
data/bin/zucchini
CHANGED
@@ -8,12 +8,15 @@ require 'lib/config'
|
|
8
8
|
require 'lib/screenshot'
|
9
9
|
require 'lib/report'
|
10
10
|
require 'lib/feature'
|
11
|
+
require 'lib/detector'
|
11
12
|
require 'lib/runner'
|
12
13
|
require 'lib/generator'
|
14
|
+
require 'lib/approver'
|
13
15
|
|
14
16
|
class Zucchini::App < Clamp::Command
|
15
17
|
subcommand "generate", "Generate a project scaffold", Zucchini::Generator
|
16
18
|
subcommand "run", "Run zucchini", Zucchini::Runner
|
19
|
+
subcommand "approve", "Update reference screenshots", Zucchini::Approver
|
17
20
|
end
|
18
21
|
|
19
22
|
Zucchini::App.run
|
data/lib/approver.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class Zucchini::Approver < Zucchini::Detector
|
2
|
+
parameter "PATH", "a path to feature or a directory"
|
3
|
+
|
4
|
+
option %W(-p --pending), :flag, "update pending screenshots instead"
|
5
|
+
|
6
|
+
def run_command
|
7
|
+
reference_type = pending? ? "pending" : "reference"
|
8
|
+
features.each do |f|
|
9
|
+
f.device = @device
|
10
|
+
f.approve reference_type
|
11
|
+
end
|
12
|
+
features.inject(true){ |result, feature| result &= feature.succeeded }
|
13
|
+
end
|
14
|
+
end
|
data/lib/detector.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
class Zucchini::Detector < Clamp::Command
|
2
|
+
attr_reader :features
|
3
|
+
|
4
|
+
parameter "PATH", "a path to feature or a directory"
|
5
|
+
|
6
|
+
def execute
|
7
|
+
raise "Directory #{path} does not exist" unless File.exists?(path)
|
8
|
+
|
9
|
+
@path = File.expand_path(path)
|
10
|
+
Zucchini::Config.base_path = File.exists?("#{path}/feature.zucchini") ? File.dirname(path) : path
|
11
|
+
|
12
|
+
raise "ZUCCHINI_DEVICE environment variable not set" unless ENV['ZUCCHINI_DEVICE']
|
13
|
+
@device = Zucchini::Config.device(ENV['ZUCCHINI_DEVICE'])
|
14
|
+
|
15
|
+
@template = detect_template
|
16
|
+
|
17
|
+
exit run_command
|
18
|
+
end
|
19
|
+
|
20
|
+
def run_command; end
|
21
|
+
|
22
|
+
def features
|
23
|
+
@features ||= detect_features(@path)
|
24
|
+
end
|
25
|
+
|
26
|
+
def detect_features(path)
|
27
|
+
features = []
|
28
|
+
if File.exists?("#{path}/feature.zucchini")
|
29
|
+
features << Zucchini::Feature.new(path)
|
30
|
+
else
|
31
|
+
raise detection_error(path) if Dir["#{path}/*"].empty?
|
32
|
+
|
33
|
+
Dir.glob("#{path}/*").each do |dir|
|
34
|
+
unless dir.match /support/
|
35
|
+
if File.exists?("#{dir}/feature.zucchini")
|
36
|
+
features << Zucchini::Feature.new(dir)
|
37
|
+
else
|
38
|
+
raise detection_error(dir)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
features
|
44
|
+
end
|
45
|
+
|
46
|
+
def detection_error(path)
|
47
|
+
"#{path} is not a feature directory"
|
48
|
+
end
|
49
|
+
|
50
|
+
def detect_template
|
51
|
+
locations = [
|
52
|
+
`xcode-select -print-path`.gsub(/\n/, '') + "/Platforms/iPhoneOS.platform/Developer/Library/Instruments",
|
53
|
+
"/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents" # Xcode 4.5
|
54
|
+
].map do |start_path|
|
55
|
+
"#{start_path}/PlugIns/AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate"
|
56
|
+
end
|
57
|
+
|
58
|
+
locations.each { |path| return path if File.exists?(path) }
|
59
|
+
raise "Can't find Instruments template (tried #{locations.join(', ')})"
|
60
|
+
end
|
61
|
+
end
|
data/lib/feature.rb
CHANGED
@@ -27,11 +27,13 @@ class Zucchini::Feature
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
def screenshots
|
30
|
+
def screenshots(process = true)
|
31
31
|
@screenshots ||= Dir.glob("#{run_data_path}/Run\ 1/*.png").map do |file|
|
32
32
|
screenshot = Zucchini::Screenshot.new(file, @device)
|
33
|
-
|
34
|
-
|
33
|
+
if process
|
34
|
+
screenshot.mask
|
35
|
+
screenshot.compare
|
36
|
+
end
|
35
37
|
screenshot
|
36
38
|
end + unmatched_pending_screenshots
|
37
39
|
end
|
@@ -92,4 +94,14 @@ class Zucchini::Feature
|
|
92
94
|
yield
|
93
95
|
end
|
94
96
|
end
|
97
|
+
|
98
|
+
def approve(reference_type)
|
99
|
+
raise "Directory #{path} doesn't contain previous run data" unless File.exists?("#{run_data_path}/Run\ 1")
|
100
|
+
|
101
|
+
screenshots(false).each do |s|
|
102
|
+
reference_file_path = "#{File.dirname(s.file_path)}/../../#{reference_type}/#{device[:screen]}/#{s.file_name}"
|
103
|
+
FileUtils.mkdir_p File.dirname(reference_file_path)
|
104
|
+
@succeeded = FileUtils.copy_file(s.file_path, reference_file_path)
|
105
|
+
end
|
106
|
+
end
|
95
107
|
end
|
data/lib/runner.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
|
-
class Zucchini::Runner <
|
2
|
-
|
3
|
-
|
4
|
-
parameter "PATH", "a path to feature or a directory to run"
|
1
|
+
class Zucchini::Runner < Zucchini::Detector
|
2
|
+
parameter "PATH", "a path to feature or a directory"
|
5
3
|
|
6
4
|
option %W(-c --collect), :flag, "only collect the screenshots from the device"
|
7
5
|
option %W(-p --compare), :flag, "perform screenshots comparison based on the last collection"
|
@@ -9,21 +7,7 @@ class Zucchini::Runner < Clamp::Command
|
|
9
7
|
|
10
8
|
option "--ci", :flag, "produce a CI version of the report after comparison"
|
11
9
|
|
12
|
-
def
|
13
|
-
raise "Directory #{path} does not exist" unless File.exists?(path)
|
14
|
-
|
15
|
-
@path = File.expand_path(path)
|
16
|
-
Zucchini::Config.base_path = File.exists?("#{path}/feature.zucchini") ? File.dirname(path) : path
|
17
|
-
|
18
|
-
raise "ZUCCHINI_DEVICE environment variable not set" unless ENV['ZUCCHINI_DEVICE']
|
19
|
-
@device = Zucchini::Config.device(ENV['ZUCCHINI_DEVICE'])
|
20
|
-
|
21
|
-
@template = detect_template
|
22
|
-
|
23
|
-
exit run_features
|
24
|
-
end
|
25
|
-
|
26
|
-
def run_features
|
10
|
+
def run_command
|
27
11
|
compare_threads = {}
|
28
12
|
|
29
13
|
features.each do |f|
|
@@ -45,44 +29,4 @@ class Zucchini::Runner < Clamp::Command
|
|
45
29
|
|
46
30
|
features.inject(true){ |result, feature| result &= feature.succeeded }
|
47
31
|
end
|
48
|
-
|
49
|
-
def features
|
50
|
-
@features ||= detect_features(@path)
|
51
|
-
end
|
52
|
-
|
53
|
-
def detect_features(path)
|
54
|
-
features = []
|
55
|
-
if File.exists?("#{path}/feature.zucchini")
|
56
|
-
features << Zucchini::Feature.new(path)
|
57
|
-
else
|
58
|
-
raise detection_error(path) if Dir["#{path}/*"].empty?
|
59
|
-
|
60
|
-
Dir.glob("#{path}/*").each do |dir|
|
61
|
-
unless dir.match /support/
|
62
|
-
if File.exists?("#{dir}/feature.zucchini")
|
63
|
-
features << Zucchini::Feature.new(dir)
|
64
|
-
else
|
65
|
-
raise detection_error(dir)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
features
|
71
|
-
end
|
72
|
-
|
73
|
-
def detection_error(path)
|
74
|
-
"#{path} is not a feature directory"
|
75
|
-
end
|
76
|
-
|
77
|
-
def detect_template
|
78
|
-
locations = [
|
79
|
-
`xcode-select -print-path`.gsub(/\n/, '') + "/Platforms/iPhoneOS.platform/Developer/Library/Instruments",
|
80
|
-
"/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents" # Xcode 4.5
|
81
|
-
].map do |start_path|
|
82
|
-
"#{start_path}/PlugIns/AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate"
|
83
|
-
end
|
84
|
-
|
85
|
-
locations.each { |path| return path if File.exists?(path) }
|
86
|
-
raise "Can't find Instruments template (tried #{locations.join(', ')})"
|
87
|
-
end
|
88
32
|
end
|
data/lib/version.rb
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Zucchini::
|
4
|
-
before
|
5
|
-
|
3
|
+
describe Zucchini::Detector do
|
4
|
+
before do
|
5
|
+
detector.path = "spec/sample_setup/feature_one"
|
6
6
|
ENV['ZUCCHINI_DEVICE'] = 'My iDevice'
|
7
7
|
end
|
8
8
|
|
9
|
-
let (:
|
10
|
-
|
9
|
+
let (:detector) { Zucchini::Detector.new(nil) }
|
10
|
+
|
11
11
|
describe "execute" do
|
12
|
-
subject { lambda {
|
12
|
+
subject { lambda { detector.execute } }
|
13
13
|
|
14
14
|
context "feature directory doesn't exist" do
|
15
|
-
before {
|
15
|
+
before { detector.path = "spec/sample_setup/erroneous_feature" }
|
16
16
|
it { should raise_error "Directory spec/sample_setup/erroneous_feature does not exist" }
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
context "device hasn't been found" do
|
20
20
|
before { ENV['ZUCCHINI_DEVICE'] = 'My Android Phone' }
|
21
21
|
it { should raise_error "Device not listed in config.yml" }
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
describe "detect features" do
|
26
|
-
subject { lambda {
|
26
|
+
subject { lambda { detector.detect_features(@path) } }
|
27
27
|
|
28
28
|
context "path to a single feature" do
|
29
29
|
before { @path = "spec/sample_setup/feature_one" }
|
@@ -35,7 +35,7 @@ describe Zucchini::Runner do
|
|
35
35
|
context "path to a directory with features" do
|
36
36
|
before { @path = File.expand_path("spec/sample_setup") }
|
37
37
|
it "should detect all features in it" do
|
38
|
-
subject.call.length.should eq
|
38
|
+
subject.call.length.should eq 3
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
data/spec/lib/feature_spec.rb
CHANGED
@@ -29,4 +29,41 @@ describe Zucchini::Feature do
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
32
|
+
|
33
|
+
describe "approve" do
|
34
|
+
subject { lambda { feature.approve "reference" } }
|
35
|
+
|
36
|
+
context "no previous run data" do
|
37
|
+
before { feature.path = './spec/sample_setup/feature_three' }
|
38
|
+
it { should raise_error "Directory ./spec/sample_setup/feature_three doesn't contain previous run data" }
|
39
|
+
end
|
40
|
+
|
41
|
+
context "copies screenshots to reference directory" do
|
42
|
+
before do
|
43
|
+
feature.path = './spec/sample_setup/feature_three'
|
44
|
+
feature.device = {screen: 'retina_ios5'}
|
45
|
+
|
46
|
+
# Copying some random image to run screenshots.
|
47
|
+
@screenshot_path = "#{feature.path}/run_data/Run\ 1/screenshot.png"
|
48
|
+
FileUtils.mkdir_p(File.dirname(@screenshot_path))
|
49
|
+
FileUtils.copy_file("./spec/sample_setup/feature_one/reference/retina_ios5/06_sign up_spinner.png", @screenshot_path)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should copy screenshot to reference directory" do
|
53
|
+
feature.approve "reference"
|
54
|
+
(File.exists? "#{feature.path}/reference/retina_ios5/screenshot.png").should eq true
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should copy screenshot to pending directory" do
|
58
|
+
feature.approve "pending"
|
59
|
+
(File.exists? "#{feature.path}/pending/retina_ios5/screenshot.png").should eq true
|
60
|
+
end
|
61
|
+
|
62
|
+
after do
|
63
|
+
FileUtils.rm_rf("#{feature.path}/run_data")
|
64
|
+
FileUtils.rm_rf("#{feature.path}/reference")
|
65
|
+
FileUtils.rm_rf("#{feature.path}/pending")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
32
69
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# Start on the "Menu" screen
|
data/spec/spec_helper.rb
CHANGED
@@ -6,8 +6,10 @@ require 'lib/config'
|
|
6
6
|
require 'lib/screenshot'
|
7
7
|
require 'lib/report'
|
8
8
|
require 'lib/feature'
|
9
|
+
require 'lib/detector'
|
9
10
|
require 'lib/runner'
|
10
11
|
require 'lib/generator'
|
12
|
+
require 'lib/approver'
|
11
13
|
|
12
14
|
RSpec.configure do |config|
|
13
15
|
config.color_enabled = true
|
data/zucchini-ios.gemspec
CHANGED
@@ -8,6 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.date = Date.today.to_s
|
9
9
|
s.platform = Gem::Platform::RUBY
|
10
10
|
s.authors = ["Vasily Mikhaylichenko", "Rajesh Kumar", "Kevin O'Neill"]
|
11
|
+
s.license = "BSD"
|
11
12
|
s.email = ["vaskas@zucchiniframework.org"]
|
12
13
|
s.homepage = "http://www.zucchiniframework.org"
|
13
14
|
s.summary = %q{Functional testing framework for iOS-powered devices}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zucchini-ios
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2013-02-03 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: clamp
|
@@ -74,10 +74,13 @@ files:
|
|
74
74
|
- .travis.yml
|
75
75
|
- Gemfile
|
76
76
|
- Gemfile.lock
|
77
|
+
- LICENSE.md
|
77
78
|
- README.md
|
78
79
|
- Rakefile
|
79
80
|
- bin/zucchini
|
81
|
+
- lib/approver.rb
|
80
82
|
- lib/config.rb
|
83
|
+
- lib/detector.rb
|
81
84
|
- lib/feature.rb
|
82
85
|
- lib/generator.rb
|
83
86
|
- lib/report.rb
|
@@ -94,16 +97,17 @@ files:
|
|
94
97
|
- lib/uia/screen.coffee
|
95
98
|
- lib/version.rb
|
96
99
|
- spec/lib/config_spec.rb
|
100
|
+
- spec/lib/detector_spec.rb
|
97
101
|
- spec/lib/feature_spec.rb
|
98
102
|
- spec/lib/generator_spec.rb
|
99
103
|
- spec/lib/report_spec.rb
|
100
|
-
- spec/lib/runner_spec.rb
|
101
104
|
- spec/lib/screenshot_spec.rb
|
102
105
|
- spec/sample_setup/feature_one/feature.zucchini
|
103
106
|
- spec/sample_setup/feature_one/masks/retina_ios5/06_sign up_spinner.png
|
104
107
|
- spec/sample_setup/feature_one/reference/retina_ios5/06_sign up_spinner.png
|
105
108
|
- spec/sample_setup/feature_one/reference/retina_ios5/06_sign up_spinner_error.png
|
106
109
|
- spec/sample_setup/feature_one/run_data/Run 1/06_sign up_spinner.png
|
110
|
+
- spec/sample_setup/feature_three/feature.zucchini
|
107
111
|
- spec/sample_setup/feature_two/feature.zucchini
|
108
112
|
- spec/sample_setup/feature_two/masks/retina_ios5/06_sign up_spinner.png
|
109
113
|
- spec/sample_setup/feature_two/reference/retina_ios5/06_sign up_spinner.png
|
@@ -128,7 +132,8 @@ files:
|
|
128
132
|
- templates/project/features/support/screens/welcome.coffee
|
129
133
|
- zucchini-ios.gemspec
|
130
134
|
homepage: http://www.zucchiniframework.org
|
131
|
-
licenses:
|
135
|
+
licenses:
|
136
|
+
- BSD
|
132
137
|
post_install_message:
|
133
138
|
rdoc_options: []
|
134
139
|
require_paths:
|
@@ -147,22 +152,23 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
152
|
version: '0'
|
148
153
|
requirements: []
|
149
154
|
rubyforge_project:
|
150
|
-
rubygems_version: 1.8.
|
155
|
+
rubygems_version: 1.8.23
|
151
156
|
signing_key:
|
152
157
|
specification_version: 3
|
153
158
|
summary: Functional testing framework for iOS-powered devices
|
154
159
|
test_files:
|
155
160
|
- spec/lib/config_spec.rb
|
161
|
+
- spec/lib/detector_spec.rb
|
156
162
|
- spec/lib/feature_spec.rb
|
157
163
|
- spec/lib/generator_spec.rb
|
158
164
|
- spec/lib/report_spec.rb
|
159
|
-
- spec/lib/runner_spec.rb
|
160
165
|
- spec/lib/screenshot_spec.rb
|
161
166
|
- spec/sample_setup/feature_one/feature.zucchini
|
162
167
|
- spec/sample_setup/feature_one/masks/retina_ios5/06_sign up_spinner.png
|
163
168
|
- spec/sample_setup/feature_one/reference/retina_ios5/06_sign up_spinner.png
|
164
169
|
- spec/sample_setup/feature_one/reference/retina_ios5/06_sign up_spinner_error.png
|
165
170
|
- spec/sample_setup/feature_one/run_data/Run 1/06_sign up_spinner.png
|
171
|
+
- spec/sample_setup/feature_three/feature.zucchini
|
166
172
|
- spec/sample_setup/feature_two/feature.zucchini
|
167
173
|
- spec/sample_setup/feature_two/masks/retina_ios5/06_sign up_spinner.png
|
168
174
|
- spec/sample_setup/feature_two/reference/retina_ios5/06_sign up_spinner.png
|