teaspoon 0.7.9 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +382 -260
  3. data/app/assets/javascripts/teaspoon-angular.js +108 -26241
  4. data/app/assets/javascripts/teaspoon-jasmine.js +103 -2642
  5. data/app/assets/javascripts/teaspoon-mocha.js +109 -5416
  6. data/app/assets/javascripts/teaspoon-qunit.js +107 -2255
  7. data/app/assets/javascripts/teaspoon-teaspoon.js +0 -1
  8. data/app/assets/javascripts/teaspoon/angular.coffee +3 -1
  9. data/app/assets/javascripts/teaspoon/base/hook.coffee +21 -0
  10. data/app/assets/javascripts/teaspoon/base/reporters/html.coffee +26 -14
  11. data/app/assets/javascripts/teaspoon/base/reporters/html/progress_view.coffee +1 -1
  12. data/app/assets/javascripts/teaspoon/base/reporters/html/template.coffee +3 -3
  13. data/app/assets/javascripts/teaspoon/base/teaspoon.coffee +10 -1
  14. data/app/assets/javascripts/teaspoon/jasmine.coffee +3 -1
  15. data/app/assets/javascripts/teaspoon/mocha.coffee +3 -1
  16. data/app/assets/javascripts/teaspoon/mocha/reporters/html.coffee +1 -1
  17. data/app/assets/javascripts/teaspoon/qunit.coffee +3 -1
  18. data/app/assets/javascripts/teaspoon/qunit/reporters/html.coffee +1 -1
  19. data/app/assets/javascripts/teaspoon/teaspoon.coffee +0 -1
  20. data/app/assets/stylesheets/teaspoon.css +12 -8
  21. data/app/controllers/teaspoon/suite_controller.rb +32 -0
  22. data/app/views/teaspoon/suite/_body.html.erb +0 -0
  23. data/app/views/teaspoon/suite/_boot.html.erb +4 -0
  24. data/app/views/teaspoon/suite/_boot_require_js.html.erb +19 -0
  25. data/app/views/teaspoon/{spec/suites.html.erb → suite/index.html.erb} +6 -7
  26. data/app/views/teaspoon/suite/show.html.erb +19 -0
  27. data/bin/teaspoon +1 -1
  28. data/config/routes.rb +14 -4
  29. data/lib/generators/teaspoon/install/POST_INSTALL +2 -2
  30. data/lib/generators/teaspoon/install/install_generator.rb +22 -11
  31. data/lib/generators/teaspoon/install/templates/_body.html.erb +0 -0
  32. data/lib/generators/teaspoon/install/templates/_boot.html.erb +4 -0
  33. data/lib/generators/teaspoon/install/templates/jasmine/env.rb +11 -0
  34. data/lib/generators/teaspoon/install/templates/jasmine/env_comments.rb +182 -0
  35. data/lib/generators/teaspoon/install/templates/jasmine/spec_helper.coffee +8 -6
  36. data/lib/generators/teaspoon/install/templates/jasmine/spec_helper.js +8 -7
  37. data/lib/generators/teaspoon/install/templates/mocha/env.rb +11 -0
  38. data/lib/generators/teaspoon/install/templates/mocha/env_comments.rb +182 -0
  39. data/lib/generators/teaspoon/install/templates/mocha/spec_helper.coffee +13 -13
  40. data/lib/generators/teaspoon/install/templates/mocha/spec_helper.js +13 -13
  41. data/lib/generators/teaspoon/install/templates/qunit/env.rb +11 -0
  42. data/lib/generators/teaspoon/install/templates/qunit/env_comments.rb +182 -0
  43. data/lib/generators/teaspoon/install/templates/qunit/test_helper.coffee +6 -5
  44. data/lib/generators/teaspoon/install/templates/qunit/test_helper.js +6 -5
  45. data/lib/tasks/teaspoon.rake +9 -2
  46. data/lib/teaspoon.rb +4 -6
  47. data/lib/teaspoon/command_line.rb +116 -134
  48. data/lib/teaspoon/configuration.rb +144 -66
  49. data/lib/teaspoon/console.rb +70 -37
  50. data/lib/teaspoon/coverage.rb +42 -15
  51. data/lib/teaspoon/deprecated.rb +65 -0
  52. data/lib/teaspoon/drivers/base.rb +10 -0
  53. data/lib/teaspoon/drivers/phantomjs/runner.js +9 -11
  54. data/lib/teaspoon/drivers/phantomjs_driver.rb +21 -21
  55. data/lib/teaspoon/drivers/selenium_driver.rb +32 -13
  56. data/lib/teaspoon/engine.rb +32 -12
  57. data/lib/teaspoon/environment.rb +16 -12
  58. data/lib/teaspoon/exceptions.rb +41 -5
  59. data/lib/teaspoon/exporter.rb +52 -0
  60. data/lib/teaspoon/formatters/base.rb +171 -0
  61. data/lib/teaspoon/formatters/clean_formatter.rb +2 -4
  62. data/lib/teaspoon/formatters/documentation_formatter.rb +60 -0
  63. data/lib/teaspoon/formatters/dot_formatter.rb +12 -90
  64. data/lib/teaspoon/formatters/json_formatter.rb +36 -0
  65. data/lib/teaspoon/formatters/junit_formatter.rb +51 -32
  66. data/lib/teaspoon/formatters/modules/report_module.rb +76 -0
  67. data/lib/teaspoon/formatters/pride_formatter.rb +23 -27
  68. data/lib/teaspoon/formatters/snowday_formatter.rb +7 -11
  69. data/lib/teaspoon/formatters/swayze_or_oprah_formatter.rb +88 -64
  70. data/lib/teaspoon/formatters/tap_formatter.rb +18 -27
  71. data/lib/teaspoon/formatters/tap_y_formatter.rb +35 -45
  72. data/lib/teaspoon/formatters/teamcity_formatter.rb +69 -31
  73. data/lib/teaspoon/instrumentation.rb +33 -33
  74. data/lib/teaspoon/result.rb +2 -1
  75. data/lib/teaspoon/runner.rb +40 -28
  76. data/lib/teaspoon/server.rb +23 -25
  77. data/lib/teaspoon/suite.rb +52 -72
  78. data/lib/teaspoon/utility.rb +3 -14
  79. data/lib/teaspoon/version.rb +1 -1
  80. data/spec/dummy/app/assets/javascripts/integration/integration_spec.coffee +3 -0
  81. data/spec/dummy/app/assets/javascripts/integration/spec_helper.coffee +2 -0
  82. data/spec/dummy/config/application.rb +3 -0
  83. data/spec/features/console_reporter_spec.rb +48 -18
  84. data/spec/features/hooks_spec.rb +23 -41
  85. data/spec/features/html_reporter_spec.rb +38 -21
  86. data/spec/features/install_generator_spec.rb +34 -20
  87. data/spec/features/instrumentation_spec.rb +3 -2
  88. data/spec/fixtures/coverage.json +243 -0
  89. data/spec/javascripts/fixtures/_body.html.erb +1 -0
  90. data/spec/javascripts/jasmine_helper.coffee +1 -1
  91. data/spec/javascripts/teaspoon/base/fixture_spec.coffee +4 -4
  92. data/spec/javascripts/teaspoon/base/reporters/html_spec.coffee +9 -10
  93. data/spec/javascripts/teaspoon/mocha/reporters/html_mspec.coffee +0 -6
  94. data/spec/javascripts/teaspoon/phantomjs/runner_spec.coffee +5 -6
  95. data/spec/javascripts/turbolinks_helper.coffee +1 -1
  96. data/spec/spec_helper.rb +3 -4
  97. data/spec/teaspoon/command_line_spec.rb +139 -23
  98. data/spec/teaspoon/configuration_spec.rb +164 -46
  99. data/spec/teaspoon/console_spec.rb +142 -47
  100. data/spec/teaspoon/coverage_spec.rb +98 -28
  101. data/spec/teaspoon/drivers/base_spec.rb +5 -0
  102. data/spec/teaspoon/drivers/phantomjs_driver_spec.rb +32 -14
  103. data/spec/teaspoon/drivers/selenium_driver_spec.rb +32 -24
  104. data/spec/teaspoon/engine_spec.rb +8 -5
  105. data/spec/teaspoon/environment_spec.rb +56 -33
  106. data/spec/teaspoon/exceptions_spec.rb +57 -0
  107. data/spec/teaspoon/exporter_spec.rb +96 -0
  108. data/spec/teaspoon/formatters/base_spec.rb +259 -0
  109. data/spec/teaspoon/formatters/clean_formatter_spec.rb +37 -0
  110. data/spec/teaspoon/formatters/documentation_formatter_spec.rb +127 -0
  111. data/spec/teaspoon/formatters/dot_formatter_spec.rb +52 -56
  112. data/spec/teaspoon/formatters/json_formatter_spec.rb +77 -0
  113. data/spec/teaspoon/formatters/junit_formatter_spec.rb +72 -35
  114. data/spec/teaspoon/formatters/pride_formatter_spec.rb +37 -0
  115. data/spec/teaspoon/formatters/snowday_formatter_spec.rb +35 -0
  116. data/spec/teaspoon/formatters/tap_formatter_spec.rb +29 -81
  117. data/spec/teaspoon/formatters/tap_y_formatter_spec.rb +31 -141
  118. data/spec/teaspoon/formatters/teamcity_formatter_spec.rb +99 -42
  119. data/spec/teaspoon/instrumentation_spec.rb +44 -44
  120. data/spec/teaspoon/result_spec.rb +37 -0
  121. data/spec/teaspoon/runner_spec.rb +70 -59
  122. data/spec/teaspoon/server_spec.rb +34 -52
  123. data/spec/teaspoon/suite_spec.rb +42 -188
  124. data/spec/teaspoon_env.rb +39 -28
  125. data/vendor/assets/javascripts/{angular-scenario-1.0.5.js → angular/1.0.5.js} +0 -0
  126. data/vendor/assets/javascripts/{angular-scenario-1.0.5.MIT-LICENSE → angular/MIT-LICENSE} +0 -0
  127. data/vendor/assets/javascripts/{jasmine-1.3.1.js → jasmine/1.3.1.js} +0 -0
  128. data/vendor/assets/javascripts/jasmine/2.0.0.js +2412 -0
  129. data/vendor/assets/javascripts/{jasmine-1.3.1.MIT.LICENSE → jasmine/MIT.LICENSE} +0 -0
  130. data/vendor/assets/javascripts/{mocha-1.10.0.js → mocha/1.10.0.js} +1 -0
  131. data/vendor/assets/javascripts/mocha/1.17.1.js +5813 -0
  132. data/vendor/assets/javascripts/{mocha-1.10.1.MIT.LICENSE → mocha/MIT.LICENSE} +0 -0
  133. data/vendor/assets/javascripts/{qunit-1.12.0.js → qunit/1.12.0.js} +1 -1
  134. data/vendor/assets/javascripts/qunit/1.14.0.js +2288 -0
  135. data/vendor/assets/javascripts/{qunit-1.12.0.MIT.LICENSE → qunit/MIT.LICENSE} +0 -0
  136. data/vendor/assets/javascripts/support/chai.js +827 -385
  137. data/vendor/assets/javascripts/support/jasmine-jquery-1.7.0.js +720 -0
  138. data/vendor/assets/javascripts/support/jasmine-jquery-2.0.0.js +812 -0
  139. data/vendor/assets/javascripts/support/sinon-chai.js +17 -0
  140. data/vendor/assets/javascripts/support/sinon.js +1138 -643
  141. metadata +57 -36
  142. data/app/controllers/teaspoon/spec_controller.rb +0 -38
  143. data/app/helpers/teaspoon/spec_helper.rb +0 -36
  144. data/app/views/teaspoon/spec/_require_js.html.erb +0 -21
  145. data/app/views/teaspoon/spec/_standard.html.erb +0 -4
  146. data/app/views/teaspoon/spec/runner.html.erb +0 -19
  147. data/lib/generators/teaspoon/install/templates/env.rb +0 -38
  148. data/lib/generators/teaspoon/install/templates/jasmine/initializer.rb +0 -64
  149. data/lib/generators/teaspoon/install/templates/mocha/initializer.rb +0 -64
  150. data/lib/generators/teaspoon/install/templates/qunit/initializer.rb +0 -64
  151. data/lib/teaspoon/check_coverage.rb +0 -33
  152. data/lib/teaspoon/drivers/base_driver.rb +0 -10
  153. data/lib/teaspoon/exception_handling.rb +0 -18
  154. data/lib/teaspoon/formatters/base_formatter.rb +0 -63
  155. data/spec/dummy/config/initializers/teaspoon.rb +0 -41
  156. data/spec/teaspoon/check_coverage_spec.rb +0 -50
  157. data/spec/teaspoon/formatters/base_formatter_spec.rb +0 -45
  158. data/vendor/assets/javascripts/support/chai.MIT.LICENSE +0 -22
  159. data/vendor/assets/javascripts/support/expect.MIT.LICENSE +0 -22
  160. data/vendor/assets/javascripts/support/jasmine-jquery.MIT.LICENSE +0 -20
  161. data/vendor/assets/javascripts/support/jasmine-jquery.js +0 -659
  162. data/vendor/assets/javascripts/support/sinon-chai.MIT-ISH.LICENSE +0 -13
  163. data/vendor/assets/javascripts/support/sinon.BSD.LICENSE +0 -27
@@ -1,77 +1,152 @@
1
1
  require "singleton"
2
2
 
3
3
  module Teaspoon
4
+
5
+ autoload :Formatters, "teaspoon/formatters/base"
6
+ autoload :Drivers, "teaspoon/drivers/base"
7
+
4
8
  class Configuration
5
9
  include Singleton
6
10
 
7
- cattr_accessor :mount_at, :context, :root, :asset_paths, :fixture_path, :suites, :driver_cli_options
8
- @@mount_at = "/teaspoon"
9
- @@context = nil # will default to Rails #relative_url_root
10
- @@root = nil # will default to Rails.root
11
- @@asset_paths = ["spec/javascripts", "spec/javascripts/stylesheets", "test/javascripts", "test/javascripts/stylesheets"]
12
- @@fixture_path = "spec/javascripts/fixtures"
13
- @@suites = {"default" => proc{}}
14
- @@driver_cli_options = nil
11
+ # CONTRIBUTORS:
12
+ # If you add a configuration option you should do the following before it will be considered for merging.
13
+ # - think about if it should be a suite, coverage, or global configuration
14
+ # - write specs for it, and add it to existing specs in spec/teaspoon/configuration_spec.rb
15
+ # - add it to the readme so it's documented
16
+ # - add it to the command_line.rb if appropriate (_only_ if it's appropriate)
17
+ # - add it to ENV_OVERRIDES if it can be overridden from ENV
18
+ # - add it to the initializers in /lib/generators/install/templates so it's documented there as well
19
+
20
+ cattr_accessor :mount_at, :root, :asset_paths, :fixture_paths
21
+ @@mount_at = "/teaspoon"
22
+ @@root = nil # will default to Rails.root
23
+ @@asset_paths = ["spec/javascripts", "spec/javascripts/stylesheets", "test/javascripts", "test/javascripts/stylesheets"]
24
+ @@fixture_paths = ["spec/javascripts/fixtures", "test/javascripts/fixtures"]
15
25
 
16
26
  # console runner specific
17
- cattr_accessor :driver, :server_timeout, :server_port, :fail_fast, :formatters, :suppress_log, :color, :coverage, :coverage_reports, :coverage_output_dir, :server, :statements_coverage_threshold, :functions_coverage_threshold, :branches_coverage_threshold, :lines_coverage_threshold
18
- @@driver = "phantomjs"
19
- @@server = nil
20
- @@server_port = nil
21
- @@server_timeout = 20
22
- @@fail_fast = true
23
- @@formatters = "dot"
24
- @@suppress_log = false
25
- @@color = true
26
- @@coverage = false
27
- @@coverage_reports = nil
28
- @@coverage_output_dir = "coverage"
29
- @@statements_coverage_threshold = nil
30
- @@functions_coverage_threshold = nil
31
- @@branches_coverage_threshold = nil
32
- @@lines_coverage_threshold = nil
27
+
28
+ cattr_accessor :driver, :driver_options, :driver_timeout, :server, :server_port, :server_timeout, :fail_fast,
29
+ :formatters, :color, :suppress_log,
30
+ :use_coverage
31
+ @@driver = "phantomjs"
32
+ @@driver_options = nil
33
+ @@driver_timeout = 180
34
+ @@server = nil
35
+ @@server_port = nil
36
+ @@server_timeout = 20
37
+ @@fail_fast = true
38
+
39
+ @@formatters = ["dot"]
40
+ @@color = true
41
+ @@suppress_log = false
42
+
43
+ @@use_coverage = nil
44
+
45
+ # options that can be specified in the ENV
46
+
47
+ ENV_OVERRIDES = {
48
+ boolean: %w(FAIL_FAST SUPPRESS_LOG COLOR),
49
+ integer: %w(DRIVER_TIMEOUT SERVER_TIMEOUT),
50
+ string: %w(DRIVER DRIVER_OPTIONS SERVER SERVER_PORT FORMATTERS USE_COVERAGE)
51
+ }
52
+
53
+ # suite configurations
54
+
55
+ cattr_accessor :suite_configs
56
+ @@suite_configs = {"default" => {block: proc{}}}
57
+
58
+ def self.suite(name = :default, &block)
59
+ @@suite_configs[name.to_s] = {block: block, instance: Suite.new(&block)}
60
+ end
33
61
 
34
62
  class Suite
35
- attr_accessor :matcher, :helper, :stylesheets, :javascripts, :no_coverage, :boot_partial, :js_config, :hooks
63
+
64
+ FRAMEWORKS = {
65
+ jasmine: ["1.3.1", "2.0.0"],
66
+ mocha: ["1.10.0", "1.17.1"],
67
+ qunit: ["1.12.0", "1.14.0"],
68
+ angular: ["1.0.5"],
69
+ }
70
+
71
+ attr_accessor :matcher, :helper, :javascripts, :stylesheets,
72
+ :boot_partial, :body_partial,
73
+ :no_coverage,
74
+ :hooks
36
75
 
37
76
  def initialize
38
- @matcher = "{spec/javascripts,app/assets}/**/*_spec.{js,js.coffee,coffee}"
39
- @helper = "spec_helper"
40
- @javascripts = ["teaspoon-jasmine"]
41
- @stylesheets = ["teaspoon"]
42
- @no_coverage = [%r{/lib/ruby/gems/}, %r{/vendor/assets/}, %r{/support/}, %r{/(.+)_helper.}]
43
- @boot_partial = nil
44
- @js_config = {}
45
-
46
- @hooks = Hash.new {|h, k| h[k] = [] }
47
-
48
- default = Teaspoon.configuration.suites["default"]
49
- self.instance_eval(&default) if default
77
+ @matcher = "{spec/javascripts,app/assets}/**/*_spec.{js,js.coffee,coffee}"
78
+ @helper = "spec_helper"
79
+ @javascripts = ["jasmine/1.3.1", "teaspoon-jasmine"]
80
+ @stylesheets = ["teaspoon"]
81
+
82
+ @boot_partial = "boot"
83
+ @body_partial = "body"
84
+
85
+ @no_coverage = [%r{/lib/ruby/gems/}, %r{/vendor/assets/}, %r{/support/}, %r{/(.+)_helper.}]
86
+
87
+ @hooks = Hash.new{ |h, k| h[k] = [] }
88
+
89
+ default = Teaspoon.configuration.suite_configs["default"]
90
+ self.instance_eval(&default[:block]) if default
50
91
  yield self if block_given?
51
92
  end
52
93
 
53
- def use_require=(val) # todo: deprecated in version 0.7.4
54
- puts "Deprecation Notice: use_require will be removed, set config.boot_partial to 'require_js' instead."
55
- self.boot_partial = 'require_js' if val
94
+ def use_framework(name, version = nil)
95
+ name = name.to_sym
96
+ version ||= FRAMEWORKS[name].last if FRAMEWORKS[name]
97
+ unless FRAMEWORKS[name] && FRAMEWORKS[name].include?(version)
98
+ message = "Unknown framework \"#{name}\""
99
+ message += " with version #{version} -- available versions #{FRAMEWORKS[name].join(", ")}" if FRAMEWORKS[name] && version
100
+ raise Teaspoon::UnknownFramework, message
101
+ end
102
+
103
+ @javascripts = [[name, version].join("/"), "teaspoon-#{name}"]
104
+ case name.to_sym
105
+ when :qunit
106
+ @matcher = "{test/javascripts,app/assets}/**/*_test.{js,js.coffee,coffee}"
107
+ @helper = "test_helper"
108
+ else
109
+ end
56
110
  end
111
+ alias_method :use_framework=, :use_framework
57
112
 
58
113
  def hook(group = :default, &block)
59
114
  @hooks[group.to_s] << block
60
115
  end
61
116
  end
62
117
 
63
- def self.root=(path)
64
- @@root = Pathname.new(path.to_s) if path.present?
118
+ # coverage configurations
119
+
120
+ cattr_accessor :coverage_configs
121
+ @@coverage_configs = {"default" => {block: proc{}}}
122
+
123
+ def self.coverage(name = :default, &block)
124
+ @@coverage_configs[name.to_s] = {block: block, instance: Coverage.new(&block)}
65
125
  end
66
126
 
67
- def self.suite(name = :default, &block)
68
- @@suites[name.to_s] = block
127
+ class Coverage
128
+ attr_accessor :reports, :output_path,
129
+ :statements, :functions, :branches, :lines
130
+
131
+ def initialize
132
+ @reports = ["text-summary"]
133
+ @output_path = "coverage"
134
+
135
+ @statements = nil
136
+ @functions = nil
137
+ @branches = nil
138
+ @lines = nil
139
+
140
+ default = Teaspoon.configuration.coverage_configs["default"]
141
+ self.instance_eval(&default[:block]) if default
142
+ yield self if block_given?
143
+ end
69
144
  end
70
145
 
71
- def self.coverage_reports
72
- return ["text-summary"] if @@coverage_reports.blank?
73
- return @@coverage_reports if @@coverage_reports.is_a?(Array)
74
- @@coverage_reports.to_s.split(/,\s?/)
146
+ # custom getters / setters
147
+
148
+ def self.root=(path)
149
+ @@root = Pathname.new(path.to_s) if path.present?
75
150
  end
76
151
 
77
152
  def self.formatters
@@ -79,29 +154,32 @@ module Teaspoon
79
154
  return @@formatters if @@formatters.is_a?(Array)
80
155
  @@formatters.to_s.split(/,\s?/)
81
156
  end
82
- end
83
157
 
84
- autoload :Formatters, "teaspoon/formatters/base_formatter"
85
- autoload :Drivers, "teaspoon/drivers/base_driver"
158
+ # override from env or options
86
159
 
87
- mattr_accessor :configuration
88
- @@configuration = Configuration
160
+ def self.override_from_options(options)
161
+ options.each { |k, v| override(k, v) }
162
+ end
89
163
 
90
- def self.setup
91
- yield @@configuration
92
- override_from_env
164
+ def self.override_from_env(env)
165
+ ENV_OVERRIDES[:boolean].each { |o| override(o, env[o] == "true") if env[o].present? }
166
+ ENV_OVERRIDES[:integer].each { |o| override(o, env[o].to_i) if env[o].present? }
167
+ ENV_OVERRIDES[:string].each { |o| override(o, env[o]) if env[o].present? }
168
+ end
169
+
170
+ def self.override(config, value)
171
+ setter = "#{config.to_s.downcase}="
172
+ send(setter, value) if respond_to?(setter)
173
+ end
93
174
  end
94
175
 
95
- private
176
+ mattr_accessor :configured, :configuration
177
+ @@configured = false
178
+ @@configuration = Configuration
96
179
 
97
- def self.override_from_env
98
- %w(FAIL_FAST SUPPRESS_LOG COLOR COVERAGE).each do |directive|
99
- next unless ENV[directive].present?
100
- @@configuration.send("#{directive.downcase}=", ENV[directive] == "true")
101
- end
102
- %w(DRIVER DRIVER_CLI_OPTIONS SERVER SERVER_TIMEOUT SERVER_PORT FORMATTERS COVERAGE_REPORTS COVERAGE_OUTPUT_DIR).each do |directive|
103
- next unless ENV[directive].present?
104
- @@configuration.send("#{directive.downcase}=", ENV[directive])
105
- end
180
+ def self.configure
181
+ yield @@configuration
182
+ @@configured = true
183
+ @@configuration.override_from_env(ENV)
106
184
  end
107
185
  end
@@ -1,49 +1,62 @@
1
- require 'open-uri'
2
- require 'teaspoon/environment'
1
+ require "teaspoon/environment"
3
2
 
4
3
  module Teaspoon
5
4
  class Console
6
5
 
7
- def initialize(options = nil, files = [])
8
- @options = options || {}
6
+ def initialize(options = {})
7
+ @options = options
9
8
  @suites = {}
10
- @files = []
11
-
12
9
  Teaspoon::Environment.load(@options)
13
10
 
14
- start_server
15
- resolve(files)
11
+ @server = start_server
12
+ rescue Teaspoon::ServerException => e
13
+ abort(e.message)
16
14
  end
17
15
 
18
- def execute(options = {}, files = [])
19
- @options = @options.merge(options) if options.present?
20
- resolve(files)
16
+ def failures?
17
+ !execute
18
+ end
21
19
 
22
- failure_count = 0
23
- suites.each do |suite|
24
- STDOUT.print "Teaspoon running #{suite} suite at #{url(suite)}\n" unless Teaspoon.configuration.suppress_log
25
- failure_count += run_specs(suite, @options[:driver_cli_options] || Teaspoon.configuration.driver_cli_options)
26
- end
27
- failure_count > 0
20
+ def execute(options = {})
21
+ execute_without_handling(options)
28
22
  rescue Teaspoon::Failure
29
- true
30
- rescue Teaspoon::RunnerException
31
- true
23
+ false
24
+ rescue Teaspoon::Error => e
25
+ abort(e.message)
32
26
  end
33
27
 
34
- def run_specs(suite, driver_cli_options = nil)
35
- url = url(suite)
36
- url += url.include?("?") ? "&" : "?"
37
- url += "reporter=Console"
38
- driver.run_specs(suite, url, driver_cli_options)
28
+ def execute_without_handling(options = {})
29
+ @options.merge!(options)
30
+ @suites = {}
31
+ resolve(@options[:files])
32
+
33
+ 0 == suites.inject(0) do |failures, suite|
34
+ export(suite) if @options.include?(:export)
35
+ failures += run_specs(suite)
36
+ log("") # empty line for space
37
+ failures
38
+ end
39
+ end
40
+
41
+ def run_specs(suite)
42
+ raise Teaspoon::UnknownSuite, "Unknown suite: \"#{suite}\"" unless Teaspoon.configuration.suite_configs[suite.to_s]
43
+ log("Teaspoon running #{suite} suite at #{base_url_for(suite)}")
44
+ runner = Teaspoon::Runner.new(suite)
45
+ driver.run_specs(runner, url_for(suite))
46
+ raise Teaspoon::Failure if Teaspoon.configuration.fail_fast && runner.failure_count > 0
47
+ runner.failure_count
48
+ end
49
+
50
+ def export(suite)
51
+ raise Teaspoon::UnknownSuite, "Unknown suite: \"#{suite}\"" unless Teaspoon.configuration.suite_configs[suite.to_s]
52
+ log("Teaspoon exporting #{suite} suite at #{base_url_for(suite)}")
53
+ Teaspoon::Exporter.new(suite, url_for(suite, false), @options[:export]).export
39
54
  end
40
55
 
41
56
  protected
42
57
 
43
- def resolve(files)
44
- return if files.length == 0
45
- @suites = {}
46
- @files = files
58
+ def resolve(files = [])
59
+ return if files.blank?
47
60
  files.uniq.each do |path|
48
61
  if result = Teaspoon::Suite.resolve_spec_for(path)
49
62
  suite = @suites[result[:suite]] ||= []
@@ -53,30 +66,50 @@ module Teaspoon
53
66
  end
54
67
 
55
68
  def start_server
56
- @server = Teaspoon::Server.new
57
- @server.start
69
+ log("Starting the Teaspoon server...")
70
+ server = Teaspoon::Server.new
71
+ server.start
72
+ server
58
73
  end
59
74
 
60
75
  def suites
61
76
  return [@options[:suite]] if @options[:suite].present?
62
77
  return @suites.keys if @suites.present?
63
- Teaspoon.configuration.suites.keys
78
+ Teaspoon.configuration.suite_configs.keys
64
79
  end
65
80
 
66
81
  def driver
67
- @driver ||= Teaspoon::Drivers.const_get("#{Teaspoon.configuration.driver.to_s.camelize}Driver").new
82
+ return @driver if @driver
83
+ klass = "#{Teaspoon.configuration.driver.to_s.camelize}Driver"
84
+ @driver = Teaspoon::Drivers.const_get(klass).new(Teaspoon.configuration.driver_options)
85
+ rescue NameError
86
+ raise Teaspoon::UnknownDriver, "Unknown driver: \"#{Teaspoon.configuration.driver}\""
87
+ end
88
+
89
+ def base_url_for(suite)
90
+ ["#{@server.url}#{Teaspoon.configuration.mount_at}", suite].join('/')
91
+ end
92
+
93
+ def url_for(suite, console = true)
94
+ url = [base_url_for(suite), filter(suite)].compact.join('?')
95
+ url += "#{(url.include?("?") ? "&" : "?")}reporter=Console" if console
96
+ url
68
97
  end
69
98
 
70
99
  def filter(suite)
71
100
  parts = []
72
101
  parts << "grep=#{URI::encode(@options[:filter])}" if @options[:filter].present?
73
- (@suites[suite] || @files).flatten.each { |file| parts << "file[]=#{URI::encode(file)}" }
102
+ (@suites[suite] || @options[:files] || []).flatten.each { |file| parts << "file[]=#{URI::encode(file)}" }
74
103
  "#{parts.join('&')}" if parts.present?
75
104
  end
76
105
 
77
- def url(suite)
78
- base_url = ["#{@server.url}#{Teaspoon.configuration.mount_at}", suite].join('/')
79
- [base_url, filter(suite)].compact.join('?')
106
+ def log(str, force = false)
107
+ STDOUT.print("#{str}\n") if force || !Teaspoon.configuration.suppress_log
108
+ end
109
+
110
+ def abort(message = nil)
111
+ log(message, true) if message
112
+ exit(1)
80
113
  end
81
114
  end
82
115
  end
@@ -1,36 +1,63 @@
1
1
  module Teaspoon
2
2
  class Coverage
3
- include Teaspoon::Utility
4
3
 
5
- def initialize(data, suite_name)
6
- @data = data
4
+ def initialize(suite_name, config_name, data)
7
5
  @suite_name = suite_name
6
+ @data = data
7
+ @executable = Teaspoon::Instrumentation.executable
8
+ @config = coverage_configuration(config_name.to_s)
8
9
  end
9
10
 
10
- def reports
11
- Dir.mktmpdir do |path|
12
- input = File.join(path, 'coverage.json')
13
- File.open(input, 'w') { |file| file.write(@data.to_json) }
11
+ def generate_reports(&block)
12
+ input_path do |input|
14
13
  results = []
15
- for format in Teaspoon.configuration.coverage_reports
14
+ for format in @config.reports
16
15
  result = generate_report(input, format)
17
16
  results << result if ["text", "text-summary"].include?(format.to_s)
18
17
  end
19
- Teaspoon::CheckCoverage.new(input).check_coverage
20
- "\n#{results.join("\n\n")}\n"
18
+ block.call(results.join("\n\n")) unless results.blank?
19
+ end
20
+ end
21
+
22
+ def check_thresholds(&block)
23
+ args = threshold_args
24
+ return if args.blank?
25
+ input_path do |input|
26
+ result = %x{#{@executable} check-coverage #{args.join(" ")} #{input.shellescape} 2>&1}
27
+ return if $?.exitstatus == 0
28
+ result = result.scan(/ERROR: .*$/).join("\n").gsub("ERROR: ", "")
29
+ block.call(result) unless result.blank?
21
30
  end
22
31
  end
23
32
 
24
33
  private
25
34
 
35
+ def coverage_configuration(name)
36
+ config = Teaspoon.configuration.coverage_configs[name]
37
+ raise Teaspoon::UnknownCoverage, "Unknown coverage configuration \"#{name}\"" unless config.present?
38
+ config[:instance] ||= Teaspoon::Configuration::Coverage.new(&config[:block])
39
+ end
40
+
41
+ def input_path(&block)
42
+ Dir.mktmpdir do |temp_path|
43
+ input_path = File.join(temp_path, "coverage.json")
44
+ File.open(input_path, "w") { |f| f.write(@data.to_json) }
45
+ block.call(input_path)
46
+ end
47
+ end
48
+
26
49
  def generate_report(input, format)
27
- result = %x{#{executable} report #{format} #{input.shellescape} --dir #{File.join(Teaspoon.configuration.coverage_output_dir, @suite_name)}}
28
- raise "Could not generate coverage report for #{format}" unless $?.exitstatus == 0
29
- result.gsub("Done", "").gsub("Using reporter [#{format}]", "").strip
50
+ output_path = File.join(@config.output_path, @suite_name)
51
+ result = %x{#{@executable} report #{format} #{input.shellescape} --dir #{output_path} 2>&1}
52
+ return result.gsub("Done", "").gsub("Using reporter [#{format}]", "").strip if $?.exitstatus == 0
53
+ raise Teaspoon::DependencyFailure, "Could not generate coverage report for #{format}"
30
54
  end
31
55
 
32
- def executable
33
- @executable ||= istanbul()
56
+ def threshold_args
57
+ %w{statements functions branches lines}.map do |assert|
58
+ threshold = @config.send(:"#{assert}")
59
+ "--#{assert}=#{threshold}" if threshold
60
+ end.compact
34
61
  end
35
62
  end
36
63
  end