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.
- checksums.yaml +4 -4
- data/README.md +382 -260
- data/app/assets/javascripts/teaspoon-angular.js +108 -26241
- data/app/assets/javascripts/teaspoon-jasmine.js +103 -2642
- data/app/assets/javascripts/teaspoon-mocha.js +109 -5416
- data/app/assets/javascripts/teaspoon-qunit.js +107 -2255
- data/app/assets/javascripts/teaspoon-teaspoon.js +0 -1
- data/app/assets/javascripts/teaspoon/angular.coffee +3 -1
- data/app/assets/javascripts/teaspoon/base/hook.coffee +21 -0
- data/app/assets/javascripts/teaspoon/base/reporters/html.coffee +26 -14
- data/app/assets/javascripts/teaspoon/base/reporters/html/progress_view.coffee +1 -1
- data/app/assets/javascripts/teaspoon/base/reporters/html/template.coffee +3 -3
- data/app/assets/javascripts/teaspoon/base/teaspoon.coffee +10 -1
- data/app/assets/javascripts/teaspoon/jasmine.coffee +3 -1
- data/app/assets/javascripts/teaspoon/mocha.coffee +3 -1
- data/app/assets/javascripts/teaspoon/mocha/reporters/html.coffee +1 -1
- data/app/assets/javascripts/teaspoon/qunit.coffee +3 -1
- data/app/assets/javascripts/teaspoon/qunit/reporters/html.coffee +1 -1
- data/app/assets/javascripts/teaspoon/teaspoon.coffee +0 -1
- data/app/assets/stylesheets/teaspoon.css +12 -8
- data/app/controllers/teaspoon/suite_controller.rb +32 -0
- data/app/views/teaspoon/suite/_body.html.erb +0 -0
- data/app/views/teaspoon/suite/_boot.html.erb +4 -0
- data/app/views/teaspoon/suite/_boot_require_js.html.erb +19 -0
- data/app/views/teaspoon/{spec/suites.html.erb → suite/index.html.erb} +6 -7
- data/app/views/teaspoon/suite/show.html.erb +19 -0
- data/bin/teaspoon +1 -1
- data/config/routes.rb +14 -4
- data/lib/generators/teaspoon/install/POST_INSTALL +2 -2
- data/lib/generators/teaspoon/install/install_generator.rb +22 -11
- data/lib/generators/teaspoon/install/templates/_body.html.erb +0 -0
- data/lib/generators/teaspoon/install/templates/_boot.html.erb +4 -0
- data/lib/generators/teaspoon/install/templates/jasmine/env.rb +11 -0
- data/lib/generators/teaspoon/install/templates/jasmine/env_comments.rb +182 -0
- data/lib/generators/teaspoon/install/templates/jasmine/spec_helper.coffee +8 -6
- data/lib/generators/teaspoon/install/templates/jasmine/spec_helper.js +8 -7
- data/lib/generators/teaspoon/install/templates/mocha/env.rb +11 -0
- data/lib/generators/teaspoon/install/templates/mocha/env_comments.rb +182 -0
- data/lib/generators/teaspoon/install/templates/mocha/spec_helper.coffee +13 -13
- data/lib/generators/teaspoon/install/templates/mocha/spec_helper.js +13 -13
- data/lib/generators/teaspoon/install/templates/qunit/env.rb +11 -0
- data/lib/generators/teaspoon/install/templates/qunit/env_comments.rb +182 -0
- data/lib/generators/teaspoon/install/templates/qunit/test_helper.coffee +6 -5
- data/lib/generators/teaspoon/install/templates/qunit/test_helper.js +6 -5
- data/lib/tasks/teaspoon.rake +9 -2
- data/lib/teaspoon.rb +4 -6
- data/lib/teaspoon/command_line.rb +116 -134
- data/lib/teaspoon/configuration.rb +144 -66
- data/lib/teaspoon/console.rb +70 -37
- data/lib/teaspoon/coverage.rb +42 -15
- data/lib/teaspoon/deprecated.rb +65 -0
- data/lib/teaspoon/drivers/base.rb +10 -0
- data/lib/teaspoon/drivers/phantomjs/runner.js +9 -11
- data/lib/teaspoon/drivers/phantomjs_driver.rb +21 -21
- data/lib/teaspoon/drivers/selenium_driver.rb +32 -13
- data/lib/teaspoon/engine.rb +32 -12
- data/lib/teaspoon/environment.rb +16 -12
- data/lib/teaspoon/exceptions.rb +41 -5
- data/lib/teaspoon/exporter.rb +52 -0
- data/lib/teaspoon/formatters/base.rb +171 -0
- data/lib/teaspoon/formatters/clean_formatter.rb +2 -4
- data/lib/teaspoon/formatters/documentation_formatter.rb +60 -0
- data/lib/teaspoon/formatters/dot_formatter.rb +12 -90
- data/lib/teaspoon/formatters/json_formatter.rb +36 -0
- data/lib/teaspoon/formatters/junit_formatter.rb +51 -32
- data/lib/teaspoon/formatters/modules/report_module.rb +76 -0
- data/lib/teaspoon/formatters/pride_formatter.rb +23 -27
- data/lib/teaspoon/formatters/snowday_formatter.rb +7 -11
- data/lib/teaspoon/formatters/swayze_or_oprah_formatter.rb +88 -64
- data/lib/teaspoon/formatters/tap_formatter.rb +18 -27
- data/lib/teaspoon/formatters/tap_y_formatter.rb +35 -45
- data/lib/teaspoon/formatters/teamcity_formatter.rb +69 -31
- data/lib/teaspoon/instrumentation.rb +33 -33
- data/lib/teaspoon/result.rb +2 -1
- data/lib/teaspoon/runner.rb +40 -28
- data/lib/teaspoon/server.rb +23 -25
- data/lib/teaspoon/suite.rb +52 -72
- data/lib/teaspoon/utility.rb +3 -14
- data/lib/teaspoon/version.rb +1 -1
- data/spec/dummy/app/assets/javascripts/integration/integration_spec.coffee +3 -0
- data/spec/dummy/app/assets/javascripts/integration/spec_helper.coffee +2 -0
- data/spec/dummy/config/application.rb +3 -0
- data/spec/features/console_reporter_spec.rb +48 -18
- data/spec/features/hooks_spec.rb +23 -41
- data/spec/features/html_reporter_spec.rb +38 -21
- data/spec/features/install_generator_spec.rb +34 -20
- data/spec/features/instrumentation_spec.rb +3 -2
- data/spec/fixtures/coverage.json +243 -0
- data/spec/javascripts/fixtures/_body.html.erb +1 -0
- data/spec/javascripts/jasmine_helper.coffee +1 -1
- data/spec/javascripts/teaspoon/base/fixture_spec.coffee +4 -4
- data/spec/javascripts/teaspoon/base/reporters/html_spec.coffee +9 -10
- data/spec/javascripts/teaspoon/mocha/reporters/html_mspec.coffee +0 -6
- data/spec/javascripts/teaspoon/phantomjs/runner_spec.coffee +5 -6
- data/spec/javascripts/turbolinks_helper.coffee +1 -1
- data/spec/spec_helper.rb +3 -4
- data/spec/teaspoon/command_line_spec.rb +139 -23
- data/spec/teaspoon/configuration_spec.rb +164 -46
- data/spec/teaspoon/console_spec.rb +142 -47
- data/spec/teaspoon/coverage_spec.rb +98 -28
- data/spec/teaspoon/drivers/base_spec.rb +5 -0
- data/spec/teaspoon/drivers/phantomjs_driver_spec.rb +32 -14
- data/spec/teaspoon/drivers/selenium_driver_spec.rb +32 -24
- data/spec/teaspoon/engine_spec.rb +8 -5
- data/spec/teaspoon/environment_spec.rb +56 -33
- data/spec/teaspoon/exceptions_spec.rb +57 -0
- data/spec/teaspoon/exporter_spec.rb +96 -0
- data/spec/teaspoon/formatters/base_spec.rb +259 -0
- data/spec/teaspoon/formatters/clean_formatter_spec.rb +37 -0
- data/spec/teaspoon/formatters/documentation_formatter_spec.rb +127 -0
- data/spec/teaspoon/formatters/dot_formatter_spec.rb +52 -56
- data/spec/teaspoon/formatters/json_formatter_spec.rb +77 -0
- data/spec/teaspoon/formatters/junit_formatter_spec.rb +72 -35
- data/spec/teaspoon/formatters/pride_formatter_spec.rb +37 -0
- data/spec/teaspoon/formatters/snowday_formatter_spec.rb +35 -0
- data/spec/teaspoon/formatters/tap_formatter_spec.rb +29 -81
- data/spec/teaspoon/formatters/tap_y_formatter_spec.rb +31 -141
- data/spec/teaspoon/formatters/teamcity_formatter_spec.rb +99 -42
- data/spec/teaspoon/instrumentation_spec.rb +44 -44
- data/spec/teaspoon/result_spec.rb +37 -0
- data/spec/teaspoon/runner_spec.rb +70 -59
- data/spec/teaspoon/server_spec.rb +34 -52
- data/spec/teaspoon/suite_spec.rb +42 -188
- data/spec/teaspoon_env.rb +39 -28
- data/vendor/assets/javascripts/{angular-scenario-1.0.5.js → angular/1.0.5.js} +0 -0
- data/vendor/assets/javascripts/{angular-scenario-1.0.5.MIT-LICENSE → angular/MIT-LICENSE} +0 -0
- data/vendor/assets/javascripts/{jasmine-1.3.1.js → jasmine/1.3.1.js} +0 -0
- data/vendor/assets/javascripts/jasmine/2.0.0.js +2412 -0
- data/vendor/assets/javascripts/{jasmine-1.3.1.MIT.LICENSE → jasmine/MIT.LICENSE} +0 -0
- data/vendor/assets/javascripts/{mocha-1.10.0.js → mocha/1.10.0.js} +1 -0
- data/vendor/assets/javascripts/mocha/1.17.1.js +5813 -0
- data/vendor/assets/javascripts/{mocha-1.10.1.MIT.LICENSE → mocha/MIT.LICENSE} +0 -0
- data/vendor/assets/javascripts/{qunit-1.12.0.js → qunit/1.12.0.js} +1 -1
- data/vendor/assets/javascripts/qunit/1.14.0.js +2288 -0
- data/vendor/assets/javascripts/{qunit-1.12.0.MIT.LICENSE → qunit/MIT.LICENSE} +0 -0
- data/vendor/assets/javascripts/support/chai.js +827 -385
- data/vendor/assets/javascripts/support/jasmine-jquery-1.7.0.js +720 -0
- data/vendor/assets/javascripts/support/jasmine-jquery-2.0.0.js +812 -0
- data/vendor/assets/javascripts/support/sinon-chai.js +17 -0
- data/vendor/assets/javascripts/support/sinon.js +1138 -643
- metadata +57 -36
- data/app/controllers/teaspoon/spec_controller.rb +0 -38
- data/app/helpers/teaspoon/spec_helper.rb +0 -36
- data/app/views/teaspoon/spec/_require_js.html.erb +0 -21
- data/app/views/teaspoon/spec/_standard.html.erb +0 -4
- data/app/views/teaspoon/spec/runner.html.erb +0 -19
- data/lib/generators/teaspoon/install/templates/env.rb +0 -38
- data/lib/generators/teaspoon/install/templates/jasmine/initializer.rb +0 -64
- data/lib/generators/teaspoon/install/templates/mocha/initializer.rb +0 -64
- data/lib/generators/teaspoon/install/templates/qunit/initializer.rb +0 -64
- data/lib/teaspoon/check_coverage.rb +0 -33
- data/lib/teaspoon/drivers/base_driver.rb +0 -10
- data/lib/teaspoon/exception_handling.rb +0 -18
- data/lib/teaspoon/formatters/base_formatter.rb +0 -63
- data/spec/dummy/config/initializers/teaspoon.rb +0 -41
- data/spec/teaspoon/check_coverage_spec.rb +0 -50
- data/spec/teaspoon/formatters/base_formatter_spec.rb +0 -45
- data/vendor/assets/javascripts/support/chai.MIT.LICENSE +0 -22
- data/vendor/assets/javascripts/support/expect.MIT.LICENSE +0 -22
- data/vendor/assets/javascripts/support/jasmine-jquery.MIT.LICENSE +0 -20
- data/vendor/assets/javascripts/support/jasmine-jquery.js +0 -659
- data/vendor/assets/javascripts/support/sinon-chai.MIT-ISH.LICENSE +0 -13
- 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
|
|
@@ -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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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(
|
|
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 <
|
|
9
|
+
class PhantomjsDriver < Base
|
|
12
10
|
include Teaspoon::Utility
|
|
13
11
|
|
|
14
|
-
def
|
|
15
|
-
|
|
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
|
-
|
|
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
|
|
33
|
-
[
|
|
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
|
|
38
|
-
executable =
|
|
39
|
-
if executable.blank?
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
2
|
-
require "
|
|
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 <
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
data/lib/teaspoon/engine.rb
CHANGED
|
@@ -1,30 +1,50 @@
|
|
|
1
|
-
require
|
|
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, :
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
13
|
-
Teaspoon.configuration.context ||= app.config.relative_url_root
|
|
26
|
+
private
|
|
14
27
|
|
|
15
|
-
|
|
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
|
-
|
|
34
|
+
assets.paths << Teaspoon.configuration.root.join(path).to_s
|
|
18
35
|
end
|
|
19
36
|
end
|
|
20
37
|
|
|
21
|
-
|
|
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
|
data/lib/teaspoon/environment.rb
CHANGED
|
@@ -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/
|
|
12
|
+
require "teaspoon/runner"
|
|
13
|
+
require "teaspoon/coverage"
|
|
14
|
+
require "teaspoon/exporter"
|
|
14
15
|
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
data/lib/teaspoon/exceptions.rb
CHANGED
|
@@ -1,7 +1,43 @@
|
|
|
1
1
|
module Teaspoon
|
|
2
|
-
class
|
|
3
|
-
class
|
|
4
|
-
class
|
|
5
|
-
class
|
|
6
|
-
class
|
|
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
|