zucchini-ios 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/.gitignore +17 -1
  2. data/CHANGELOG.md +28 -15
  3. data/README.md +23 -19
  4. data/Rakefile +1 -0
  5. data/bin/zucchini +4 -11
  6. data/lib/zucchini.rb +12 -0
  7. data/lib/{approver.rb → zucchini/approver.rb} +0 -0
  8. data/lib/{config.rb → zucchini/config.rb} +0 -0
  9. data/lib/{detector.rb → zucchini/detector.rb} +0 -0
  10. data/lib/{feature.rb → zucchini/feature.rb} +25 -22
  11. data/lib/{generator.rb → zucchini/generator.rb} +5 -5
  12. data/lib/{report.rb → zucchini/report.rb} +3 -4
  13. data/lib/zucchini/report/css/zucchini.report.css +241 -0
  14. data/lib/{report → zucchini/report}/js/jquery.effects.core.js +0 -0
  15. data/lib/{report → zucchini/report}/js/jquery.js +0 -0
  16. data/lib/{report → zucchini/report}/js/jquery.ui.core.js +0 -0
  17. data/lib/zucchini/report/js/zucchini.report.js +59 -0
  18. data/lib/zucchini/report/template.erb.html +47 -0
  19. data/lib/{report → zucchini/report}/view.rb +0 -0
  20. data/lib/{runner.rb → zucchini/runner.rb} +0 -0
  21. data/lib/{screenshot.rb → zucchini/screenshot.rb} +77 -30
  22. data/lib/{uia → zucchini/uia}/base.coffee +0 -1
  23. data/lib/{uia → zucchini/uia}/screen.coffee +5 -4
  24. data/lib/{version.rb → zucchini/version.rb} +1 -1
  25. data/spec/lib/{config_spec.rb → zucchini/config_spec.rb} +0 -0
  26. data/spec/lib/{detector_spec.rb → zucchini/detector_spec.rb} +0 -0
  27. data/spec/lib/{feature_spec.rb → zucchini/feature_spec.rb} +0 -0
  28. data/spec/lib/{generator_spec.rb → zucchini/generator_spec.rb} +0 -0
  29. data/spec/lib/{report_spec.rb → zucchini/report_spec.rb} +0 -0
  30. data/spec/lib/zucchini/screenshot_spec.rb +164 -0
  31. data/spec/sample_setup/feature_one/run_data/Run 1/06_sign up_spinner.png b/data/spec/sample_setup/feature_one/run_data/Run 1/06_splash-screen_sign → up_spinner.png +0 -0
  32. data/spec/sample_setup/support/masks/splash.png +0 -0
  33. data/spec/spec_helper.rb +14 -10
  34. data/zucchini-ios.gemspec +8 -9
  35. metadata +58 -36
  36. data/lib/report/css/zucchini.report.css +0 -239
  37. data/lib/report/js/zucchini.report.js +0 -59
  38. data/lib/report/template.erb +0 -47
  39. data/spec/lib/screenshot_spec.rb +0 -109
data/.gitignore CHANGED
@@ -1,3 +1,19 @@
1
- .rvmrc
2
1
  .DS_Store
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ .ruby-version
3
8
  Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
@@ -1,13 +1,20 @@
1
+ ## 0.6.2 / 2013-08-07
2
+ * Implement screen specific masks - [@phatmann][], [#24][]
3
+ * Rearrange source files in a more conventional gem way - [@vaskas][], [#25][]
4
+ * Fix report UI in Firefox - [@vaskas][], [#26][]
5
+ * Do not squash landscape screenshots in the report - [@phatmann][]
6
+ * Remove 1 second delay after screen is loaded - [@phatmann][], [#23][]
7
+
1
8
  ## 0.6.1 / 2013-07-28
2
- * Add Rotate device screen action - [@phatmann][], [#19][]
9
+ * Add `Rotate device` screen action - [@phatmann][], [#19][]
3
10
  * Fix screenshot code to work with the latest version of ImageMagick - [@phatmann][], [#17][]
4
11
  * Raise error if screen anchor is not found - [@phatmann][], [#16][]
5
12
 
6
13
  ## 0.6.0 / 2013-03-30
7
14
  * Add a mask for retina iPad - [@phatmann][], [#8][]
8
- * Fix alert Confirm / Cancel actions so that they match to end of line - [@phatmann][], [#9][]
15
+ * Fix alert `Confirm` / `Cancel` actions so that they match to end of line - [@phatmann][], [#9][]
9
16
  * Allow app path to be set via an environment variable - [@phatmann][], [#10][]
10
- * Screenshot orientation matching device orientation - [@Jaco][]-Pretorius, [#13][]
17
+ * Screenshot orientation matching device orientation - [@Jaco-Pretorius][], [#13][]
11
18
 
12
19
  ## 0.5.9 / 2013-02-04
13
20
  * Add default device flag - [@insanehunter][], [#6][]
@@ -29,22 +36,28 @@
29
36
  * Fix Instruments template detection for Xcode 4.5 - [@vaskas][]
30
37
  * Fixed config to take relative paths to the app - [@coomans][]
31
38
  * Quote path params in call to instruments - [@kconnor][]
39
+
32
40
  <!--- The following link definition list is generated by PimpMyChangelog --->
33
- [#1]: https://github.com/src/zucchini/issues/1
34
- [#3]: https://github.com/src/zucchini/issues/3
35
- [#5]: https://github.com/src/zucchini/issues/5
36
- [#6]: https://github.com/src/zucchini/issues/6
37
- [#8]: https://github.com/src/zucchini/issues/8
38
- [#9]: https://github.com/src/zucchini/issues/9
39
- [#10]: https://github.com/src/zucchini/issues/10
40
- [#13]: https://github.com/src/zucchini/issues/13
41
- [#16]: https://github.com/src/zucchini/issues/16
42
- [#17]: https://github.com/src/zucchini/issues/17
43
- [#19]: https://github.com/src/zucchini/issues/19
41
+ [#1]: https://github.com/zucchini-src/zucchini/issues/1
42
+ [#3]: https://github.com/zucchini-src/zucchini/issues/3
43
+ [#5]: https://github.com/zucchini-src/zucchini/issues/5
44
+ [#6]: https://github.com/zucchini-src/zucchini/issues/6
45
+ [#8]: https://github.com/zucchini-src/zucchini/issues/8
46
+ [#9]: https://github.com/zucchini-src/zucchini/issues/9
47
+ [#10]: https://github.com/zucchini-src/zucchini/issues/10
48
+ [#13]: https://github.com/zucchini-src/zucchini/issues/13
49
+ [#16]: https://github.com/zucchini-src/zucchini/issues/16
50
+ [#17]: https://github.com/zucchini-src/zucchini/issues/17
51
+ [#19]: https://github.com/zucchini-src/zucchini/issues/19
52
+ [#23]: https://github.com/zucchini-src/zucchini/issues/23
53
+ [#24]: https://github.com/zucchini-src/zucchini/issues/24
54
+ [#25]: https://github.com/zucchini-src/zucchini/issues/25
55
+ [#26]: https://github.com/zucchini-src/zucchini/issues/26
56
+
44
57
  [@Jaco-Pretorius]: https://github.com/Jaco-Pretorius
45
58
  [@NathanSudell]: https://github.com/NathanSudell
46
59
  [@coomans]: https://github.com/coomans
47
60
  [@insanehunter]: https://github.com/insanehunter
48
61
  [@kconnor]: https://github.com/kconnor
49
62
  [@phatmann]: https://github.com/phatmann
50
- [@vaskas]: https://github.com/vaskas
63
+ [@vaskas]: https://github.com/vaskas
data/README.md CHANGED
@@ -1,19 +1,23 @@
1
+ # Zucchini
2
+
1
3
  [![Build Status](https://api.travis-ci.org/zucchini-src/zucchini.png)](http://travis-ci.org/zucchini-src/zucchini)
4
+ [![Coverage Status](https://coveralls.io/repos/zucchini-src/zucchini/badge.png)](https://coveralls.io/r/zucchini-src/zucchini)
5
+ [![Gem Version](https://badge.fury.io/rb/zucchini-ios.png)](http://badge.fury.io/rb/zucchini-ios)
6
+
7
+ ## Requirements
2
8
 
3
- Pre-requisites
4
- --------------
5
- 1. Mac OS X >= 10.6
6
- 2. XCode >= 4.2
7
- 3. Ruby >= 1.9.2
8
- 4. A few command line tools:
9
+ 1. Mac OS X 10.6 or newer
10
+ 2. XCode 4.2 or newer
11
+ 3. Ruby 1.9.3 or newer
12
+ 4. A few command line tools which can be installed with [homebrew](http://brew.sh/):
9
13
 
10
14
  ```
11
15
  brew update && brew install imagemagick node
12
16
  npm install -g coffee-script
13
17
  ```
14
18
 
15
- Start using Zucchini
16
- ----------------------
19
+ ## Start using Zucchini
20
+
17
21
  ```
18
22
  gem install zucchini-ios
19
23
  ```
@@ -33,13 +37,13 @@ Create a feature scaffold for your first feature:
33
37
  zucchini generate --feature /path/to/my_project/features/my_feature
34
38
  ```
35
39
 
36
- Start hacking by modifying features/my_feature/feature.zucchini and features/support/screens/welcome.coffee.
40
+ Start hacking by modifying `features/my_feature/feature.zucchini` and `features/support/screens/welcome.coffee`.
37
41
 
38
42
  Alternatively, check out the [zucchini-demo](https://github.com/zucchini-src/zucchini-demo) project featuring an easy to explore Zucchini setup around Apple's CoreDataBooks sample.
39
43
 
40
- Running on the device
41
- --------------------------------
42
- Add your device to features/support/config.yml.
44
+ ## Running on the device
45
+
46
+ Add your device to `features/support/config.yml`.
43
47
 
44
48
  The [udidetect](https://github.com/vaskas/udidetect) utility comes in handy if you plan to add devices from time to time: `udidetect -z`.
45
49
 
@@ -47,17 +51,17 @@ The [udidetect](https://github.com/vaskas/udidetect) utility comes in handy if y
47
51
  ZUCCHINI_DEVICE="My Device" zucchini run /path/to/my_feature
48
52
  ```
49
53
 
50
- Running on the iOS Simulator
51
- -------------------------------
52
- We strongly encourage you to run your Zucchini features on real hardware. However, you can run them on the iOS Simulator if you must.
54
+ ## Running on the iOS Simulator
55
+
56
+ We encourage you to run your Zucchini features on real hardware. However you can also run them on the iOS Simulator.
53
57
 
54
- First off, modify your features/support/config.yml to include the path to your compiled app, e.g.
58
+ First off, modify your `features/support/config.yml` to include the path to your compiled app, e.g.
55
59
 
56
60
  ```
57
61
  app: ./Build/Products/Debug-iphonesimulator/CoreDataBooks.app
58
62
  ```
59
63
 
60
- Secondly, add an 'iOS Simulator' entry to the devices section (no UDID needed) and make sure you provide the actual value for 'screen' based on your iOS Simulator settings:
64
+ Secondly, add an `iOS Simulator` entry to the devices section (no UDID needed) and make sure you provide the actual value for 'screen' based on your iOS Simulator settings:
61
65
 
62
66
  ```
63
67
  devices:
@@ -89,8 +93,8 @@ Run Zucchini and watch the simulator go!
89
93
  ZUCCHINI_DEVICE="iOS Simulator" zucchini run /path/to/my_feature
90
94
  ```
91
95
 
92
- See also
93
- ---------
96
+ ## See also
97
+
94
98
  ```
95
99
  zucchini --help
96
100
  zucchini run --help
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ require 'bundler/gem_tasks'
1
2
  require 'rspec/core/rake_task'
2
3
 
3
4
  desc "Run all RSpec tests"
@@ -3,20 +3,13 @@
3
3
  require 'clamp'
4
4
  require 'fileutils'
5
5
 
6
- $LOAD_PATH << File.expand_path("#{File.dirname(__FILE__)}/..")
7
- require 'lib/config'
8
- require 'lib/screenshot'
9
- require 'lib/report'
10
- require 'lib/feature'
11
- require 'lib/detector'
12
- require 'lib/runner'
13
- require 'lib/generator'
14
- require 'lib/approver'
15
-
6
+ $LOAD_PATH << File.expand_path("../..", __FILE__)
7
+ require 'lib/zucchini'
8
+
16
9
  class Zucchini::App < Clamp::Command
17
10
  subcommand "generate", "Generate a project scaffold", Zucchini::Generator
18
11
  subcommand "run", "Run zucchini", Zucchini::Runner
19
12
  subcommand "approve", "Update reference screenshots", Zucchini::Approver
20
13
  end
21
14
 
22
- Zucchini::App.run
15
+ Zucchini::App.run
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__))
2
+
3
+ module Zucchini
4
+ require 'zucchini/config'
5
+ require 'zucchini/screenshot'
6
+ require 'zucchini/report'
7
+ require 'zucchini/feature'
8
+ require 'zucchini/detector'
9
+ require 'zucchini/runner'
10
+ require 'zucchini/generator'
11
+ require 'zucchini/approver'
12
+ end
File without changes
@@ -3,20 +3,20 @@ class Zucchini::Feature
3
3
  attr_accessor :device
4
4
  attr_accessor :template
5
5
  attr_accessor :stats
6
-
6
+
7
7
  attr_reader :succeeded
8
- attr_reader :name
9
-
8
+ attr_reader :name
9
+
10
10
  def initialize(path)
11
11
  @path = path
12
12
  @device = nil
13
13
  @succeeded = false
14
14
  @name = File.basename(path)
15
15
  end
16
-
16
+
17
17
  def run_data_path
18
- "#{@path}/run_data"
19
- end
18
+ "#{@path}/run_data"
19
+ end
20
20
 
21
21
  def unmatched_pending_screenshots
22
22
  Dir.glob("#{@path}/pending/#{@device[:screen]}/[^0-9]*.png").map do |file|
@@ -26,53 +26,56 @@ class Zucchini::Feature
26
26
  screenshot
27
27
  end
28
28
  end
29
-
29
+
30
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
33
  if process
34
- screenshot.rotate
35
34
  screenshot.mask
36
35
  screenshot.compare
37
36
  end
38
37
  screenshot
39
38
  end + unmatched_pending_screenshots
40
39
  end
41
-
40
+
42
41
  def stats
43
42
  @stats ||= screenshots.inject({:passed => [], :failed => [], :pending => []}) do |stats, s|
44
43
  stats[s.diff[0]] << s
45
44
  stats
46
45
  end
47
- end
48
-
46
+ end
47
+
49
48
  def compile_js
50
- zucchini_base_path = File.expand_path("#{File.dirname(__FILE__)}/..")
51
-
49
+ zucchini_base_path = File.expand_path(File.dirname(__FILE__))
50
+
52
51
  feature_text = File.open("#{@path}/feature.zucchini").read.gsub(/\#.+[\z\n]?/,"").gsub(/\n/, "\\n")
53
52
  File.open("#{run_data_path}/feature.coffee", "w+") { |f| f.write("Zucchini.run('#{feature_text}')") }
54
53
 
55
- cs_paths = "#{zucchini_base_path}/lib/uia #{@path}/../support/screens"
54
+ cs_paths = "#{zucchini_base_path}/uia #{@path}/../support/screens"
56
55
  cs_paths += " #{@path}/../support/lib" if File.exists?("#{@path}/../support/lib")
57
56
  cs_paths += " #{run_data_path}/feature.coffee"
58
-
59
- `coffee -o #{run_data_path} -j #{run_data_path}/feature.js -c #{cs_paths}`
57
+
58
+ compile_cmd = "coffee -o #{run_data_path} -j #{run_data_path}/feature.js -c #{cs_paths}"
59
+ system compile_cmd
60
+ unless $?.exitstatus == 0
61
+ raise "Error compiling a feature file: #{compile_cmd}"
62
+ end
60
63
  end
61
64
 
62
65
  def collect
63
- with_setup do
66
+ with_setup do
64
67
  `rm -rf #{run_data_path}/*`
65
68
  compile_js
66
-
69
+
67
70
  device_params = (@device[:name] == "iOS Simulator") ? "" : "-w #{@device[:udid]}"
68
-
71
+
69
72
  begin
70
73
  out = `instruments #{device_params} -t "#{@template}" "#{Zucchini::Config.app}" -e UIASCRIPT "#{run_data_path}/feature.js" -e UIARESULTSPATH "#{run_data_path}" 2>&1`
71
74
  puts out
72
75
  # Hack. Instruments don't issue error return codes when JS exceptions occur
73
76
  raise "Instruments run error" if (out.match /JavaScript error/) || (out.match /Instruments\ .{0,5}\ Error\ :/ )
74
77
  ensure
75
- `rm -rf instrumentscli*.trace`
78
+ `rm -rf instrumentscli*.trace`
76
79
  end
77
80
  end
78
81
  end
@@ -84,8 +87,8 @@ class Zucchini::Feature
84
87
 
85
88
  def with_setup
86
89
  setup = "#{@path}/setup.rb"
87
- if File.exists?(setup)
88
- require setup
90
+ if File.exists?(setup)
91
+ require setup
89
92
  begin
90
93
  Setup.before { yield }
91
94
  ensure
@@ -1,13 +1,13 @@
1
1
  class Zucchini::Generator < Clamp::Command
2
2
  option %W(-p --project), :flag, "Generate a project"
3
3
  option %W(-f --feature), :flag, "Generate a feature"
4
-
4
+
5
5
  parameter "PATH", "Path"
6
-
6
+
7
7
  def templates_path
8
- File.expand_path("#{File.dirname(__FILE__)}/../templates")
8
+ File.expand_path("#{File.dirname(__FILE__)}/../../templates")
9
9
  end
10
-
10
+
11
11
  def execute
12
12
  if project?
13
13
  FileUtils.mkdir_p(path)
@@ -15,4 +15,4 @@ class Zucchini::Generator < Clamp::Command
15
15
  elsif feature? then FileUtils.cp_r("#{templates_path}/feature", path)
16
16
  end
17
17
  end
18
- end
18
+ end
@@ -1,5 +1,5 @@
1
1
  require 'erb'
2
- require 'lib/report/view'
2
+ require 'zucchini/report/view'
3
3
 
4
4
  class Zucchini::Report
5
5
 
@@ -11,7 +11,7 @@ class Zucchini::Report
11
11
  def text
12
12
  @features.map do |f|
13
13
  failed_list = f.stats[:failed].empty? ? "" : "\n\nFailed:\n" + f.stats[:failed].map { |s| " #{s.file_name}: #{s.diff[1]}" }.join
14
- summary = f.stats.map { |key, set| "#{set.length.to_s} #{key}" }.join(", ")
14
+ summary = f.stats.map { |key, set| "#{set.length.to_s} #{key}" }.join(", ")
15
15
 
16
16
  "#{f.name}:\n#{summary}#{failed_list}"
17
17
  end.join("\n\n")
@@ -19,7 +19,7 @@ class Zucchini::Report
19
19
 
20
20
  def html
21
21
  @html ||= begin
22
- template_path = File.expand_path("#{File.dirname(__FILE__)}/report/template.erb")
22
+ template_path = File.expand_path("#{File.dirname(__FILE__)}/report/template.erb.html")
23
23
 
24
24
  view = Zucchini::ReportView.new(@features, @ci)
25
25
  compiled = (ERB.new(File.open(template_path).read)).result(view.get_binding)
@@ -37,5 +37,4 @@ class Zucchini::Report
37
37
  def open; system "open #{@html_path}"; end
38
38
 
39
39
  def log(buf); puts buf; end
40
-
41
40
  end
@@ -0,0 +1,241 @@
1
+ html {
2
+ font-family: Myriad Pro, sans-serif;
3
+ }
4
+ body {
5
+ margin: 0;
6
+ }
7
+ tr {
8
+ text-align: center;
9
+ }
10
+ td {
11
+ padding: 2px;
12
+ }
13
+ dl {
14
+ -webkit-margin-before: 0;
15
+ }
16
+ dd {
17
+ -webkit-margin-start: 0;
18
+ }
19
+ h1 {
20
+ margin: 16px;
21
+ font-weight: normal;
22
+ font-size: 24px;
23
+ }
24
+ h1 .time {
25
+ margin-left: 10px;
26
+ opacity: 0.5;
27
+ }
28
+ h3 {
29
+ margin: 0 0 6px 4px;
30
+ font-size: 24px;
31
+ width: 763px;
32
+ padding: 0;
33
+ float: left;
34
+ text-shadow: 1px 1px 1px white;
35
+ }
36
+ .indicators {
37
+ font-size: 12px;
38
+ width: 92px;
39
+ float: left;
40
+ margin: 5px 28px 5px 0;
41
+ -webkit-transition: all 0.1s ease-in-out;
42
+ }
43
+ .indicators div {
44
+ border-radius: 8px;
45
+ padding: 3px 8px;
46
+ margin-right: 5px;
47
+ float: right;
48
+ color: #FFF;
49
+ opacity: 0.8;
50
+ height: 11px;
51
+ line-height: 11px;
52
+ font-weight: bold;
53
+ }
54
+ .indicators div:hover {
55
+ -webkit-transition:opacity 0.3s ease-in-out;
56
+ }
57
+ .indicators .passed {
58
+ background: #65C400;
59
+ }
60
+ .indicators .failed {
61
+ background: #C20000;
62
+ }
63
+ .indicators .pending {
64
+ background: #F9E934;
65
+ color: #000;
66
+ }
67
+ .feature {
68
+ padding: 10px 9px 4px 9px;
69
+ border-radius: 5px;
70
+ width: 1012px;
71
+ margin: 15px 15px 24px 15px;
72
+ box-shadow: 0 0 4px rgba(0,0,0,0.2);
73
+ }
74
+ .ci .feature {
75
+ display: none;
76
+ }
77
+ .ci .first.feature {
78
+ display: block;
79
+ }
80
+ .buttons {
81
+ float: left;
82
+ width: 125px;
83
+ display: block;
84
+ }
85
+ .ci .buttons {
86
+ display: none;
87
+ }
88
+ .buttons a {
89
+ text-align: center;
90
+ width: 70px;
91
+ color: #484848;
92
+ text-decoration: none;
93
+ text-shadow: 0 1px 0 white;
94
+ font: bold 12px Helvetica, Arial, sans-serif;
95
+ margin-bottom: 6px;
96
+ line-height: 26px;
97
+ height: 25px;
98
+ display: block;
99
+ float: left;
100
+ padding: 0 5px;
101
+ background: -webkit-linear-gradient(top, #F4F4F4, #ECECEC);
102
+ border: solid 1px #D4D4D4;
103
+ border-radius: 5px;
104
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
105
+ -webkit-transition: border-color .218s;
106
+ cursor: pointer;
107
+ }
108
+ .buttons a.left {
109
+ border-radius: 5px 0 0 5px;
110
+ width: 50px;
111
+ float: left;
112
+ margin: 0;
113
+ }
114
+ .buttons a.right {
115
+ border-radius: 0 5px 5px 0;
116
+ width: 50px;
117
+ float: left;
118
+ position: relative;
119
+ left: -1px;
120
+ margin: 0;
121
+ }
122
+ .buttons a:hover {
123
+ border: solid 1px #7f7f7f;
124
+ color: #282828;
125
+ background: -webkit-linear-gradient(top, #ffffff, #dfdfdf);
126
+ }
127
+ .buttons a:active {
128
+ border: solid 1px #7f7f7f;
129
+ background: #d0d0d0;
130
+ background: -webkit-gradient(linear, left top, left bottom, from(#a8a8a8), color-stop(0.15, #c6c6c6), to(#d8d8d8));
131
+ background: -webkit-linear-gradient(top, #a8a8a8, #c6c6c6 15%, #d8d8d8);
132
+ }
133
+
134
+ .screen {
135
+ -webkit-transition:all 0.2s ease-in-out;
136
+ width: 990px;
137
+ height: 15px;
138
+ padding: 5px 0 5px 9px;
139
+ margin-bottom: 6px;
140
+ border-radius: 5px;
141
+ cursor: pointer;
142
+ overflow: hidden;
143
+ }
144
+ .screen.passed {
145
+ color: #65C400;
146
+ background-color: #DBFFB4;
147
+ border: 1px #65C400 solid;
148
+ border-left: 10px #65C400 solid;
149
+ }
150
+ .screen.passed img {
151
+ box-shadow: 0px 0px 4px #65C400;
152
+ }
153
+ .screen.failed {
154
+ color: #C20000;
155
+ background-color: #FFD6D6;
156
+ border: 1px #C20000 solid;
157
+ border-left: 10px #C20000 solid;
158
+ }
159
+ .screen.failed img {
160
+ box-shadow: 0px 0px 4px #C20000;
161
+ }
162
+ .screen.pending {
163
+ color: #F2CF32;
164
+ background-color: #FFFDBC;
165
+ border: 1px solid #F9E934;
166
+ border-left: 10px solid #F9E934;
167
+ }
168
+ .screen.pending img {
169
+ box-shadow: 0px 0px 4px #F9E934;
170
+ }
171
+ .screen dt {
172
+ color: #000;
173
+ font-size: 13px;
174
+ line-height: 17px;
175
+ margin: 0;
176
+ font-weight: normal;
177
+ }
178
+ .ci .screen dt {
179
+ position: relative;
180
+ z-index: 2;
181
+ }
182
+ .screen dd {
183
+ float: left;
184
+ margin: 0 10px 0 0;
185
+ -webkit-transition:all 0.3s ease-in-out;
186
+ opacity: 0;
187
+ position: relative;
188
+ top: -30px;
189
+ }
190
+ .screen dd.hidden {
191
+ visibility: hidden;
192
+ }
193
+ .screen.expanded, .ci .screen {
194
+ -webkit-transition:all 0.2s ease-in-out;
195
+ height: 510px;
196
+ }
197
+ .screen.expanded dd, .ci .screen dd {
198
+ opacity: 1.0;
199
+ -webkit-transition:all 0.3s ease-in-out;
200
+ }
201
+ .screen p {
202
+ margin-bottom: -3px;
203
+ padding: 5px;
204
+ font-size: 13px;
205
+ text-align: center;
206
+ font-weight: bold;
207
+ background-color: rgba(255, 255, 255, 0.5);;
208
+ border-radius: 5px;
209
+ opacity: 0.0;
210
+ position: relative;
211
+ z-index: 0;
212
+ }
213
+ .screen dd:hover p {
214
+ opacity: 1.0;
215
+ }
216
+ .ci .screen dd p {
217
+ opacity: 1.0;
218
+ background: transparent;
219
+ }
220
+ .screen img {
221
+ width: 320px;
222
+ position: relative;
223
+ }
224
+ .viewport {
225
+ clear: both;
226
+ }
227
+ .ci .viewport {
228
+ width: 1018px;
229
+ height: 530px;
230
+ overflow: scroll;
231
+ }
232
+ .ci .surface {
233
+ height: 530px;
234
+ width: 100000px;
235
+ position: relative;
236
+ }
237
+ .ci .surface .screen {
238
+ float: left;
239
+ margin-right: 10px;
240
+ position: relative;
241
+ }