teaspoon 0.7.9 → 0.8.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 (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
@@ -0,0 +1,65 @@
1
+ module Teaspoon
2
+
3
+ def self.setup(&block)
4
+ Teaspoon.dep("Teaspoon.setup is deprecated, use Teaspoon.configure instead. The /initializer/teaspoon.rb file should be removed, and a new teaspoon_env.rb file should be created by running the install generator.")
5
+ configure(&block)
6
+ end
7
+
8
+ @dep_notified = {}
9
+ def self.dep(message, category = nil)
10
+ return if Teaspoon.configured
11
+ if category
12
+ return if @dep_notified[category]
13
+ @dep_notified[category] = true if category
14
+ end
15
+ puts "WARNING: Deprecated - #{message}"
16
+ end
17
+
18
+ class Configuration
19
+
20
+ def self.context=(*args)
21
+ Teaspoon.dep("the teaspoon context directive is no longer used, remove it from your configuration.")
22
+ end
23
+
24
+ def self.fixture_path=(*args)
25
+ Teaspoon.dep("the teaspoon fixture_path directive has been changed to fixture_paths, which expects an array, please update your configuration.")
26
+ self.fixture_paths = args
27
+ end
28
+
29
+ def self.driver_cli_options=(val)
30
+ Teaspoon.dep("the teaspoon driver_cli_options directive is no longer used, use driver_options instead.")
31
+ self.driver_options = val
32
+ end
33
+
34
+ @coverage_dep_message = <<-MESSAGE
35
+ teaspoon coverage directive has changed and is now more flexible, define coverage using a block instead:
36
+ config.coverage :CI do |coverage|
37
+ coverage.reports = ["html", "text-summary"]
38
+ coverage.output_path = "coverage"
39
+ coverage.statements = 50 # statement threshold required
40
+ coverage.functions = 50 # function threshold required
41
+ coverage.branches = 50 # branch threshold required
42
+ coverage.lines = nil # no line threshold
43
+ end
44
+ > run: teaspoon --coverage=CI --suite=default
45
+ > set: config.use_coverage = "CI"
46
+ MESSAGE
47
+
48
+ for method in %w{coverage coverage_reports coverage_output_dir statements_coverage_threshold functions_coverage_threshold branches_coverage_threshold lines_coverage_threshold}
49
+ define_singleton_method("#{method}=") do |val|
50
+ Teaspoon.dep(@coverage_dep_message, :coverage)
51
+ end
52
+ end
53
+
54
+ class Suite
55
+
56
+ def js_config=(*args)
57
+ Teaspoon.dep("the teaspoon suite js_config directive is no longer used, use the install generator to install the boot partial and customize it instead.", :js_config)
58
+ end
59
+
60
+ def normalize_asset_path=(*args)
61
+ Teaspoon.dep("the teaspoon suite normalize_asset_path directive is no longer used, reopen Teaspoon::Suite and define a normalize_js_extension method instead.", :normalize_asset_path)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,10 @@
1
+ module Teaspoon
2
+ module Drivers
3
+
4
+ autoload :PhantomjsDriver, "teaspoon/drivers/phantomjs_driver"
5
+ autoload :SeleniumDriver, "teaspoon/drivers/selenium_driver"
6
+
7
+ class Base
8
+ end
9
+ end
10
+ end
@@ -26,15 +26,11 @@
26
26
  };
27
27
 
28
28
  Runner.prototype.loadPage = function() {
29
- var method, name, _ref, _results;
30
29
  this.page.open(this.url);
31
- _ref = this.pageCallbacks();
32
- _results = [];
33
- for (name in _ref) {
34
- method = _ref[name];
35
- _results.push(this.page[name] = method);
30
+ var callbacks = this.pageCallbacks();
31
+ for (var name in callbacks) {
32
+ this.page[name] = callbacks[name];
36
33
  }
37
- return _results;
38
34
  };
39
35
 
40
36
  Runner.prototype.waitForResults = function() {
@@ -46,17 +42,16 @@
46
42
  Runner.prototype.fail = function(msg, errno) {
47
43
  if (msg == null) msg = null;
48
44
  if (errno == null) errno = 1;
49
- if (msg) console.log("Error: " + msg);
50
45
 
51
46
  console.log(JSON.stringify({
52
47
  _teaspoon: true,
53
- type: "exception"
48
+ type: "exception",
49
+ message: msg
54
50
  }));
55
51
  phantom.exit(errno);
56
52
  };
57
53
 
58
54
  Runner.prototype.finish = function() {
59
- console.log(" ");
60
55
  phantom.exit(0);
61
56
  };
62
57
 
@@ -71,6 +66,9 @@
71
66
  trace: trace
72
67
  }));
73
68
  _this.errored = true;
69
+ if (/^TeaspoonError: /.test(message || "")) {
70
+ _this.fail("Execution halted.");
71
+ }
74
72
  },
75
73
 
76
74
  onConsoleMessage: function(msg) {
@@ -78,7 +76,7 @@
78
76
  if (_this.errorTimeout) clearTimeout(_this.errorTimeout);
79
77
  if (_this.errored) {
80
78
  _this.errorTimeout = setTimeout((function() {
81
- return _this.fail('Javascript error has cause a timeout.');
79
+ return _this.fail("Javascript error has cause a timeout.");
82
80
  }), 1000);
83
81
  return _this.errored = false;
84
82
  }
@@ -1,46 +1,46 @@
1
- require "teaspoon/runner"
2
- require 'teaspoon/utility'
3
-
4
1
  begin
5
2
  require "phantomjs"
6
3
  rescue LoadError
4
+ # if we can't load phantomjs, assume the cli is installed and in the path
7
5
  end
8
6
 
9
7
  module Teaspoon
10
8
  module Drivers
11
- class PhantomjsDriver < BaseDriver
9
+ class PhantomjsDriver < Base
12
10
  include Teaspoon::Utility
13
11
 
14
- def run_specs(suite, url, cli_options = nil)
15
- runner = Teaspoon::Runner.new(suite)
12
+ def initialize(options = nil)
13
+ options ||= []
14
+ case options
15
+ when Array then @options = options
16
+ when String then @options = options.split(" ")
17
+ when Hash then @options = options.map { |k, v| "--#{k}=#{v}" }
18
+ else raise Teaspoon::UnknownDriverOptions, "Unknown driver options -- supply a string, array or hash"
19
+ end
20
+ end
16
21
 
17
- run(*cli_arguments(url, cli_options)) do |line|
22
+ def run_specs(runner, url)
23
+ run(*driver_options(url)) do |line|
18
24
  runner.process(line) if line && line.strip != ""
19
25
  end
20
-
21
- runner.failure_count
22
26
  end
23
27
 
24
28
  protected
25
29
 
26
30
  def run(*args, &block)
27
- IO.popen([executable, *args]) { |io|
28
- io.each(&block)
29
- }
31
+ IO.popen([executable, *args].join(' ')) { |io| io.each(&block) }
30
32
  end
31
33
 
32
- def cli_arguments(url, cli_options)
33
- [cli_options.to_s.split(" "), script, url].flatten.compact
34
+ def driver_options(url)
35
+ [@options, script, url.shellescape, Teaspoon.configuration.driver_timeout].flatten.compact
34
36
  end
35
37
 
36
38
  def executable
37
- executable ||= which('phantomjs')
38
- executable = Phantomjs.path if executable.blank? && defined?(::Phantomjs)
39
- if executable.blank?
40
- STDOUT.print("Could not find PhantomJS. Install phantomjs or try the phantomjs gem.")
41
- exit(1)
42
- end
43
- executable
39
+ return @executable if @executable
40
+ @executable = which("phantomjs")
41
+ @executable = Phantomjs.path if @executable.blank? && defined?(::Phantomjs)
42
+ return @executable unless @executable.blank?
43
+ raise Teaspoon::MissingDependency, "Could not find PhantomJS. Install phantomjs or try the phantomjs gem."
44
44
  end
45
45
 
46
46
  def script
@@ -1,32 +1,51 @@
1
- require "selenium-webdriver"
2
- require "teaspoon/runner"
1
+ begin
2
+ require "selenium-webdriver"
3
+ rescue LoadError
4
+ STDOUT.print("Could not find Selenium Webdriver. Install the selenium-webdriver gem.\n")
5
+ exit(1)
6
+ end
3
7
 
4
8
  module Teaspoon
5
9
  module Drivers
6
- class SeleniumDriver < BaseDriver
10
+ class SeleniumDriver < Base
11
+
12
+ def initialize(options = nil)
13
+ options ||= {}
14
+ case options
15
+ when Hash then @options = options
16
+ when String then @options = JSON.parse(options)
17
+ else raise Teaspoon::UnknownDriverOptions, "Unknown driver options -- supply a hash or json string"
18
+ end
7
19
 
8
- # note: driver_cli_options which is meant to be used for CLI options to pass into the driver is
9
- # currently ignored. We use the Selenium Ruby binding, so the Selenium command-line options
10
- # aren't used. There are a variety of Selenium options and browser-specific options
11
- # supported by the binding that will take more thought and design to configure cleanly.
12
- def run_specs(suite, url, driver_cli_options = nil)
13
- runner = Teaspoon::Runner.new(suite)
20
+ rescue JSON::ParserError
21
+ raise Teaspoon::UnknownDriverOptions, "Malformed driver options -- supply a hash or json string"
22
+ end
14
23
 
15
- driver = Selenium::WebDriver.for(:firefox)
24
+ def run_specs(runner, url)
25
+ driver = Selenium::WebDriver.for(driver_options[:client_driver])
16
26
  driver.navigate.to(url)
17
27
 
18
- Selenium::WebDriver::Wait.new(timeout: 180, interval: 0.01, message: "Timed out").until do
28
+ Selenium::WebDriver::Wait.new(driver_options).until do
19
29
  done = driver.execute_script("return window.Teaspoon && window.Teaspoon.finished")
20
30
  driver.execute_script("return window.Teaspoon && window.Teaspoon.getMessages() || []").each do |line|
21
31
  runner.process("#{line}\n")
22
32
  end
23
33
  done
24
34
  end
25
-
26
- runner.failure_count
27
35
  ensure
28
36
  driver.quit if driver
29
37
  end
38
+
39
+ protected
40
+
41
+ def driver_options
42
+ @driver_options ||= HashWithIndifferentAccess.new({
43
+ client_driver: :firefox,
44
+ timeout: Teaspoon.configuration.driver_timeout.to_i,
45
+ interval: 0.01,
46
+ message: "Timed out"
47
+ }).merge(@options)
48
+ end
30
49
  end
31
50
  end
32
51
  end
@@ -1,30 +1,50 @@
1
- require File.expand_path(__FILE__, '../../../app/controllers/teaspoon/spec_controller')
1
+ require "teaspoon/environment"
2
+ require "teaspoon/suite"
3
+ require "teaspoon/instrumentation"
2
4
 
3
5
  module Teaspoon
4
6
  class Engine < ::Rails::Engine
5
7
 
6
8
  isolate_namespace Teaspoon
7
9
 
8
- initializer :assets, :group => :all do |app|
9
- # default the root if it's not set
10
- Teaspoon.configuration.root ||= app.root
10
+ initializer :assets, group: :all do |app|
11
+ begin
12
+ Teaspoon::Environment.require_environment
13
+ rescue Teaspoon::EnvironmentNotFound
14
+ # it's ok for this to fail sometimes, like before the initializer is run etc
15
+ end
16
+
17
+ Teaspoon::Engine.default_root_path(app.root) # default the root if it's not set
18
+ Teaspoon::Engine.append_asset_paths(app.config.assets) # append the asset paths from the configuration
19
+ end
20
+
21
+ config.after_initialize do |app|
22
+ Teaspoon::Engine.inject_instrumentation # inject our sprockets hack for instrumenting javascripts
23
+ Teaspoon::Engine.prepend_routes(app) # prepend routes so a catchall doesn't get in the way
24
+ end
11
25
 
12
- # set proper root url
13
- Teaspoon.configuration.context ||= app.config.relative_url_root
26
+ private
14
27
 
15
- # append the asset paths from the configuration
28
+ def self.default_root_path(root)
29
+ Teaspoon.configuration.root ||= root
30
+ end
31
+
32
+ def self.append_asset_paths(assets)
16
33
  Teaspoon.configuration.asset_paths.each do |path|
17
- app.config.assets.paths << Teaspoon.configuration.root.join(path).to_s
34
+ assets.paths << Teaspoon.configuration.root.join(path).to_s
18
35
  end
19
36
  end
20
37
 
21
- config.after_initialize do |app|
22
- # inject our sprockets hack for instrumenting javascripts
38
+ def self.inject_instrumentation
23
39
  Sprockets::Environment.send(:include, Teaspoon::SprocketsInstrumentation)
40
+ end
41
+
42
+ def self.prepend_routes(app)
43
+ return if Teaspoon::Engine.routes.recognize_path('/') rescue nil
44
+ require Teaspoon::Engine.root.join("app/controllers/teaspoon/suite_controller")
24
45
 
25
- # prepend routes so a catchall doesn't get in the way
26
46
  app.routes.prepend do
27
- mount Teaspoon::Engine => Teaspoon.configuration.mount_at
47
+ mount Teaspoon::Engine => Teaspoon.configuration.mount_at, as: "teaspoon"
28
48
  end
29
49
  end
30
50
  end
@@ -8,41 +8,45 @@ module Teaspoon
8
8
  raise "Rails environment not found." unless rails_loaded?
9
9
 
10
10
  require "teaspoon"
11
- require "teaspoon/suite"
12
11
  require "teaspoon/server"
13
- require "teaspoon/exception_handling"
12
+ require "teaspoon/runner"
13
+ require "teaspoon/coverage"
14
+ require "teaspoon/exporter"
14
15
 
15
- configure_from_options(options)
16
+ Teaspoon.configuration.override_from_options(options)
17
+ Teaspoon::ExceptionHandling.add_rails_handling
16
18
  end
17
19
 
18
20
  def self.require_environment(override = nil)
19
- return require_env(File.expand_path(override, Dir.pwd)) if override
21
+ override ||= ENV["TEASPOON_ENV"]
22
+ if override
23
+ override = File.expand_path(override, Dir.pwd)
24
+ ENV["TEASPOON_ENV"] = override
25
+ return require_env(override)
26
+ end
20
27
 
21
28
  standard_environments.each do |filename|
22
29
  file = File.expand_path(filename, Dir.pwd)
23
30
  return require_env(file) if File.exists?(file)
31
+ #file = File.expand_path(filename, File.join(Dir.pwd, '../..'))
32
+ #return require_env(file) if File.exists?(file)
24
33
  end
25
34
 
26
- raise Teaspoon::EnvironmentNotFound
35
+ raise Teaspoon::EnvironmentNotFound, "Unable to load Teaspoon environment in {#{standard_environments.join(', ')}}"
27
36
  end
28
37
 
29
38
  def self.standard_environments
30
39
  ["spec/teaspoon_env.rb", "test/teaspoon_env.rb", "teaspoon_env.rb"]
31
40
  end
32
41
 
33
- def self.configure_from_options(options)
34
- options.each do |key, value|
35
- Teaspoon.configuration.send("#{key.downcase}=", value) if Teaspoon.configuration.respond_to?("#{key.downcase}=")
36
- end
37
- end
42
+ private
38
43
 
39
44
  def self.require_env(file)
40
- require(file)
45
+ ::Kernel.load(file)
41
46
  end
42
47
 
43
48
  def self.rails_loaded?
44
49
  defined?(Rails)
45
50
  end
46
-
47
51
  end
48
52
  end
@@ -1,7 +1,43 @@
1
1
  module Teaspoon
2
- class Failure < Exception; end
3
- class UnknownSuite < Exception; end
4
- class RunnerException < Exception; end
5
- class AssetNotServable < Exception; end
6
- class EnvironmentNotFound < Exception; end
2
+ class Error < Exception; end
3
+ class EnvironmentNotFound < Teaspoon::Error; end
4
+ class MissingDependency < Teaspoon::Error; end
5
+ class ServerException < Teaspoon::Error; end
6
+ class RunnerException < Teaspoon::Error; end
7
+ class ExporterException < Teaspoon::Error; end
8
+ class UnknownFramework < Teaspoon::Error; end
9
+ class UnknownDriver < Teaspoon::Error; end
10
+ class UnknownDriverOptions < Teaspoon::Error; end
11
+ class UnknownFormatter < Teaspoon::Error; end
12
+ class UnknownSuite < Teaspoon::Error; end
13
+ class AssetNotServable < Teaspoon::Error; end
14
+ class Failure < Teaspoon::Error; end
15
+ class DependencyFailure < Teaspoon::Error; end
16
+ class ThresholdNotMet < Teaspoon::Error; end
17
+ class FileNotWritable < Teaspoon::Error; end
18
+
19
+ module ExceptionHandling
20
+
21
+ def self.add_rails_handling
22
+ return unless Teaspoon.configuration.driver == "phantomjs"
23
+
24
+ #Rails.application.config.assets.debug = false # debugging should be off to display errors in the suite_controller
25
+ Rails.application.config.action_dispatch.show_exceptions = true # we want rails to display exceptions
26
+
27
+ # override the render exception method in ActionDispatch to raise a javascript exception
28
+ render_exceptions_with_javascript
29
+ end
30
+
31
+ private
32
+
33
+ def self.render_exceptions_with_javascript
34
+ ActionDispatch::DebugExceptions.class_eval do
35
+ def render_exception(env, exception)
36
+ message = "#{exception.class.name}: #{exception.message}"
37
+ body = "<script>throw Error(#{[message, exception.backtrace].join("\n").inspect})</script>"
38
+ [200, {'Content-Type' => "text/html;", 'Content-Length' => body.bytesize.to_s}, [body]]
39
+ end
40
+ end
41
+ end
42
+ end
7
43
  end
@@ -0,0 +1,52 @@
1
+ module Teaspoon
2
+ class Exporter
3
+ include Teaspoon::Utility
4
+
5
+ def initialize(suite, url, output_path)
6
+ @suite = suite
7
+ @url = url
8
+ @output_path = File.join(File.expand_path(output_path || "export"), @suite.to_s)
9
+ end
10
+
11
+ def export
12
+ Dir.mktmpdir do |temp_path|
13
+ Dir.chdir(temp_path) do
14
+ %x{#{executable} --convert-links --adjust-extension --page-requisites --span-hosts #{@url.shellescape} 2>&1}
15
+ raise Teaspoon::ExporterException, "Unable to export #{@suite} suite." unless $?.exitstatus == 0
16
+ create_export(File.join(temp_path, @url.match(/^http:\/\/([^\/]+).*/)[1]))
17
+ end
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def executable
24
+ return @executable if @executable
25
+ @executable = which("wget")
26
+ return @executable unless @executable.blank?
27
+ raise Teaspoon::MissingDependency, "Could not find wget for exporting."
28
+ end
29
+
30
+ def create_export(path)
31
+ Dir.chdir(path) do
32
+ update_relative_paths
33
+ cleanup_output
34
+ move_output
35
+ end
36
+ end
37
+
38
+ def update_relative_paths
39
+ html = File.read(".#{Teaspoon.configuration.mount_at}/#{@suite}.html")
40
+ File.write("index.html", html.gsub!('"../', '"'))
41
+ end
42
+
43
+ def cleanup_output
44
+ FileUtils.rm_r(Dir["{.#{Teaspoon.configuration.mount_at},robots.txt.html}"])
45
+ end
46
+
47
+ def move_output
48
+ FileUtils.mkdir_p(@output_path)
49
+ FileUtils.mv(Dir["*"], @output_path, force: true)
50
+ end
51
+ end
52
+ end