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,9 +1,13 @@
1
1
  require "spec_helper"
2
- require "teaspoon/formatters/teamcity_formatter"
3
- require "teaspoon/result"
4
2
 
5
3
  describe Teaspoon::Formatters::TeamcityFormatter do
6
4
 
5
+ let(:suite) { double(label: "_suite_")}
6
+ let(:passing_spec) { double(passing?: true, description: "_passing_[desc]\rip|'o\n_") }
7
+ let(:pending_spec) { double(passing?: false, pending?: true, description: "_pending_[desc]_") }
8
+ let(:failing_spec) { double(passing?: false, pending?: false, description: "_failing_[desc]_", message: "_failure_[mess]age_") }
9
+ let(:result) { double }
10
+
7
11
  before do
8
12
  @log = ""
9
13
  STDOUT.stub(:print) { |s| @log << s }
@@ -11,79 +15,132 @@ describe Teaspoon::Formatters::TeamcityFormatter do
11
15
 
12
16
  describe "#runner" do
13
17
 
14
- let(:json) { {"start" => "_start_", "total" => 20} }
18
+ let(:result) { double(total: 42, start: "_start_") }
15
19
 
16
- it "logs the information" do
17
- result = Teaspoon::Result.build_from_json(json)
18
- subject.should_receive(:log).with("##teamcity[testSuiteStarted name='Jasmine']")
20
+ it "starts the suite" do
21
+ Time.should_receive(:now).and_return(double(to_json: "_json_time_"))
19
22
  subject.runner(result)
23
+ expect(@log).to include("##teamcity[enteredTheMatrix timestamp='_json_time_']\n")
24
+ expect(@log).to include("##teamcity[testCount count='42' timestamp='_start_']\n")
20
25
  end
21
26
 
22
27
  end
23
28
 
24
- describe "#spec" do
29
+ describe "#suite" do
30
+
31
+ it "logs the suite" do
32
+ subject.suite(suite)
33
+ expect(@log).to include(%Q{##teamcity[testSuiteStarted name='_suite_']})
34
+ end
35
+
36
+ it "closes the last suite if there was one" do
37
+ subject.instance_variable_set(:@last_suite, suite)
38
+ subject.suite(suite)
39
+ expect(@log).to include(%Q{##teamcity[testSuiteFinished name='_suite_']})
40
+ end
41
+
42
+ end
25
43
 
26
- describe "passing spec" do
44
+ describe "#spec" do
27
45
 
28
- let(:json) { {"status" => "passed", "suite" => "My Suite", "label" => "My Label"} }
46
+ it "logs a passing testcase on passing results" do
47
+ subject.spec(passing_spec)
48
+ expect(@log).to include(%Q{##teamcity[testStarted name='_passing_|[desc|]|rip|||'o|n_' captureStandardOutput='true']\n})
49
+ expect(@log).to include(%Q{##teamcity[testFinished name='_passing_|[desc|]|rip|||'o|n_']\n})
50
+ end
29
51
 
30
- it "calls passing_spec" do
31
- result = Teaspoon::Result.build_from_json(json)
32
- subject.spec(result)
52
+ it "logs a skipped testcase on pending results" do
53
+ subject.spec(pending_spec)
54
+ expect(@log).to include(%Q{##teamcity[testIgnored name='_pending_|[desc|]_' captureStandardOutput='true']\n})
55
+ expect(@log).to include(%Q{##teamcity[testFinished name='_pending_|[desc|]_']\n})
56
+ end
33
57
 
34
- @log.should include "##teamcity[testStarted name='My Suite My Label' captureStandardOutput='false']
35
- ##teamcity[testFinished name='My Suite My Label']"
36
- end
58
+ it "logs a failing testcase with the message on failing results" do
59
+ subject.spec(failing_spec)
60
+ expect(@log).to include(%Q{##teamcity[testStarted name='_failing_|[desc|]_' captureStandardOutput='true']\n})
61
+ expect(@log).to include(%Q{##teamcity[testFailed name='_failing_|[desc|]_' message='_failure_|[mess|]age_']\n})
62
+ expect(@log).to include(%Q{##teamcity[testFinished name='_failing_|[desc|]_']\n})
63
+ end
37
64
 
65
+ it "captures stdout and puts it in the right place" do
66
+ subject.instance_variable_set(:@stdout, "_stdout_\n")
67
+ subject.spec(pending_spec)
68
+ expect(@log).to include(%Q{##teamcity[testIgnored name='_pending_|[desc|]_' captureStandardOutput='true']\n})
69
+ expect(@log).to include(%Q{_stdout_\n})
70
+ expect(@log).to include(%Q{##teamcity[testFinished name='_pending_|[desc|]_']\n})
38
71
  end
39
72
 
40
- describe "pending spec" do
73
+ end
41
74
 
42
- let(:json) { {"status" => "pending", "suite" => "My Suite", "label" => "My Label"} }
75
+ describe "#error" do
43
76
 
44
- it "calls pending_spec" do
45
- result = Teaspoon::Result.build_from_json(json)
46
- subject.spec(result)
47
- @log.should include "##teamcity[testStarted name='My Suite My Label' captureStandardOutput='false']
48
- ##teamcity[testFinished name='My Suite My Label']"
49
- end
77
+ let(:result) { double(message: "_error_message_", trace: [{"file" => "myfile.js", "line" => "420"}, {"file" => "myfile.js", "line" => "666"}]) }
50
78
 
79
+ it "logs the error" do
80
+ subject.error(result)
81
+ expect(@log).to include(%Q{##teamcity[message text='_error_message_' errorDetails='myfile.js:420|nmyfile.js:666' status='ERROR']\n})
51
82
  end
52
83
 
53
- describe "failing spec" do
84
+ end
54
85
 
55
- let(:json) { {"status" => "fail", "suite" => "My Suite", "label" => "My Label", "message" => "Error, oh no"} }
86
+ describe "#result" do
56
87
 
57
- it "calls failing_spec" do
58
- result = Teaspoon::Result.build_from_json(json)
59
- subject.spec(result)
60
- @log.should include "##teamcity[testStarted name='My Suite My Label' captureStandardOutput='false']
61
- ##teamcity[testFailed name='My Suite My Label' message='Error, oh no']
62
- ##teamcity[testFinished name='My Suite My Label']"
63
- end
88
+ it "closes any open suites" do
89
+ subject.instance_variable_set(:@last_suite, double(label: "_last_suite_label_"))
90
+ subject.result(result)
91
+ expect(@log).to include(%Q{##teamcity[testSuiteFinished name='_last_suite_label_']})
92
+ end
64
93
 
94
+ it "assigns @result" do
95
+ subject.result(result)
96
+ expect(subject.instance_variable_get(:@result)).to eq(result)
65
97
  end
66
98
 
67
99
  end
68
100
 
69
- describe "#error" do
101
+ describe "#coverage" do
102
+
103
+ it "logs the coverage" do
104
+ subject.coverage("_text_\n\n_text_summary_")
105
+ expect(@log).to include(%Q{##teamcity[testSuiteStarted name='Coverage summary']\n})
106
+ expect(@log).to include(%Q{_text_\n\n_text_summary_\n})
107
+ expect(@log).to include(%Q{##teamcity[testSuiteFinished name='Coverage summary']\n})
108
+ end
109
+
110
+ end
70
111
 
71
- let(:json) { {"status" => "error", "message" => "Error, oh no", "trace" => [{"file" => "myfile.js", "line" => "33"}] } }
112
+ describe "#threshold_failure" do
72
113
 
73
- it "logs error" do
74
- error = Teaspoon::Result.build_from_json(json)
75
- subject.error(error)
76
- @log.should include "##teamcity[message text='Error, oh no' errorDetails='myfile.js:33' status='ERROR']"
114
+ it "logs the threshold failures" do
115
+ subject.threshold_failure("_was_not_met_\n_was_not_met_")
116
+ expect(@log).to include(%Q{##teamcity[testSuiteStarted name='Coverage thresholds']\n})
117
+ expect(@log).to include(%Q{##teamcity[testStarted name='Coverage thresholds' captureStandardOutput='true']\n})
118
+ expect(@log).to include(%Q{##teamcity[testFailed name='Coverage thresholds' message='were not met']\n})
119
+ expect(@log).to include(%Q{_was_not_met_\n_was_not_met_\n})
120
+ expect(@log).to include(%Q{##teamcity[testFinished name='Coverage thresholds']\n})
121
+ expect(@log).to include(%Q{##teamcity[testSuiteFinished name='Coverage thresholds']\n})
77
122
  end
78
123
 
79
124
  end
80
125
 
81
- describe "#result" do
126
+ describe "#complete" do
82
127
 
83
- it "ends the suite" do
84
- subject.result('result')
128
+ let(:result) { double(elapsed: 3.1337, coverage: nil) }
129
+
130
+ before do
131
+ subject.instance_variable_set(:@result, result)
85
132
 
86
- @log.should include "##teamcity[testSuiteFinished name='Jasmine']"
133
+ subject.run_count = 6
134
+ subject.passes = [1, 2]
135
+ subject.failures = [1]
136
+ subject.errors = [1]
137
+ subject.pendings = [1, 2]
138
+ end
139
+
140
+ it "ends the suite" do
141
+ subject.complete(1)
142
+ expect(@log).to include(%Q{Finished in 3.1337 seconds\n})
143
+ expect(@log).to include(%Q{6 examples, 1 failure, 2 pending\n\n})
87
144
  end
88
145
 
89
146
  end
@@ -7,24 +7,47 @@ describe Teaspoon::Instrumentation do
7
7
 
8
8
  subject { Teaspoon::Instrumentation }
9
9
 
10
- let(:asset) { double('asset', source: nil, pathname: 'path/to/instrument.js') }
10
+ let(:asset) { double(source: source, pathname: 'path/to/instrument.js') }
11
+ let(:source) { "function add(a, b) { return a + b } // ☃ " }
11
12
  let(:response) { [200, {"Content-Type" => "application/javascript"}, asset] }
12
13
  let(:env) { {"QUERY_STRING" => "instrument=true"} }
13
14
 
14
- before do
15
- Teaspoon::Instrumentation.stub(:istanbul).and_return("/path/to/istanbul")
16
- Teaspoon::Instrumentation.instance_variable_set(:@executable, nil)
17
- end
15
+ describe ".add_to" do
18
16
 
19
- after do
20
- Teaspoon::Instrumentation.instance_variable_set(:@executable, nil)
21
- end
17
+ before do
18
+ Teaspoon::Instrumentation.stub(:executable).and_return("/path/to/istanbul")
19
+ end
20
+
21
+ before do
22
+ Teaspoon::Instrumentation.stub(:add?).and_return(true)
23
+ asset.should_receive(:clone).and_return(asset)
22
24
 
23
- describe ".executable" do
25
+ File.stub(:open)
26
+ subject.any_instance.stub(:instrument).and_return(source + " // instrumented")
24
27
 
25
- it "returns the executable" do
26
- expect(subject.executable).to eq("/path/to/istanbul")
27
- expect(subject.instance_variable_get(:@executable)).to eq("/path/to/istanbul")
28
+ path = nil
29
+ Dir.mktmpdir { |p| path = p }
30
+ Dir.stub(:mktmpdir).and_yield(path)
31
+ @output = File.join(path, "instrument.js")
32
+ end
33
+
34
+ it "writes the file to a tmp path" do
35
+ file = double('file')
36
+ File.should_receive(:open).with(@output, "w").and_yield(file)
37
+ file.should_receive(:write).with("function add(a, b) { return a + b } // ☃ ")
38
+ subject.add_to(response, env)
39
+ end
40
+
41
+ it "instruments the javascript file" do
42
+ subject.any_instance.should_receive(:instrument).with(@output).and_return("_instrumented_")
43
+ subject.add_to(response, env)
44
+ end
45
+
46
+ it "replaces the response array with the appropriate information" do
47
+ response = [666, {"Content-Type" => "application/javascript"}, asset]
48
+ expected = [666, {"Content-Type" => "application/javascript", "Content-Length" => "59"}, asset]
49
+
50
+ expect(subject.add_to(response, env)).to eq(expected)
28
51
  end
29
52
 
30
53
  end
@@ -32,7 +55,7 @@ describe Teaspoon::Instrumentation do
32
55
  describe ".add?" do
33
56
 
34
57
  before do
35
- subject.stub(:executable).and_return("/path/to/istanbul")
58
+ Teaspoon::Instrumentation.stub(:executable).and_return("/path/to/istanbul")
36
59
  end
37
60
 
38
61
  it "returns true when everything is good" do
@@ -64,42 +87,19 @@ describe Teaspoon::Instrumentation do
64
87
 
65
88
  end
66
89
 
67
- describe ".add_to" do
90
+ describe "integration" do
68
91
 
69
- let(:asset) { double(source: source, pathname: 'path/to/instrument.js') }
70
- let(:source) { "function add(a, b) { return a + b } // ☃ " }
92
+ let(:asset) { Rails.application.assets.find_asset('instrumented1.coffee') }
71
93
 
72
94
  before do
73
- Teaspoon::Instrumentation.stub(:add?).and_return(true)
74
- asset.should_receive(:clone).and_return(asset)
75
-
76
- File.stub(:open)
77
- subject.any_instance.stub(:instrument).and_return(source + " // instrumented")
78
-
79
- path = nil
80
- Dir.mktmpdir { |p| path = p }
81
- Dir.stub(:mktmpdir).and_yield(path)
82
- @output = File.join(path, "instrument.js")
83
- end
84
-
85
- it "writes the file to a tmp path" do
86
- file = double('file')
87
- File.should_receive(:open).with(@output, "w").and_yield(file)
88
- file.should_receive(:write).with("function add(a, b) { return a + b } // ☃ ")
89
- subject.add_to(response, env)
95
+ pending("needs istanbul to be installed") unless Teaspoon::Instrumentation.executable
90
96
  end
91
97
 
92
- it "instruments the javascript file" do
93
- subject.any_instance.should_receive(:instrument).with(@output).and_return("_instrumented_")
94
- subject.add_to(response, env)
95
- end
96
-
97
- it "replaces the response array with the appropriate information" do
98
- response = [666, {"Content-Type" => "application/javascript"}, asset]
99
- expected = [666, {"Content-Type" => "application/javascript", "Content-Length" => "59"}, asset]
100
-
101
- subject.add_to(response, env)
102
- expect(response).to eq(expected)
98
+ it "instruments a file" do
99
+ status, headers, asset = subject.add_to(response, {"QUERY_STRING" => "instrument=true"})
100
+ expect(status).to eq(200)
101
+ expect(headers).to include("Content-Type" => "application/javascript")
102
+ expect(asset.source).to match(/var __cov_.+ = \(Function\('return this'\)\)\(\);/)
103
103
  end
104
104
 
105
105
  end
@@ -54,4 +54,41 @@ describe Teaspoon::Result do
54
54
 
55
55
  end
56
56
 
57
+ describe "#failing?" do
58
+
59
+ it "returns a boolean based on status" do
60
+ subject.status = "foo"
61
+ expect(subject.failing?).to be_true
62
+ subject.status = "bar"
63
+ expect(subject.failing?).to be_true
64
+ subject.status = "passed"
65
+ expect(subject.failing?).to be_false
66
+ subject.status = "pending"
67
+ expect(subject.failing?).to be_false
68
+ end
69
+
70
+ end
71
+
72
+ describe "#passing?" do
73
+
74
+ it "returns a boolean based on status" do
75
+ subject.status = "passed"
76
+ expect(subject.passing?).to be_true
77
+ subject.status = "foo"
78
+ expect(subject.passing?).to be_false
79
+ end
80
+
81
+ end
82
+
83
+ describe "#pending?" do
84
+
85
+ it "returns a boolean based on status" do
86
+ subject.status = "pending"
87
+ expect(subject.pending?).to be_true
88
+ subject.status = "foo"
89
+ expect(subject.pending?).to be_false
90
+ end
91
+
92
+ end
93
+
57
94
  end
@@ -1,102 +1,113 @@
1
1
  require "spec_helper"
2
2
  require "teaspoon/runner"
3
3
  require "teaspoon/exceptions"
4
+ require "teaspoon/coverage"
4
5
 
5
6
  describe Teaspoon::Runner do
6
7
 
7
8
  before do
8
- @log = ""
9
- STDOUT.stub(:print) { |s| @log << s }
9
+ Teaspoon.configuration.stub(:formatters).and_return([])
10
10
  end
11
11
 
12
- describe "constructor" do
12
+ describe "#initialize" do
13
+
14
+ it "sets @suite_name and @failure_count" do
15
+ subject = Teaspoon::Runner.new(:foo)
16
+ expect(subject.instance_variable_get(:@suite_name)).to eq(:foo)
17
+ expect(subject.failure_count).to eq(0)
18
+ end
13
19
 
14
20
  it "instantiates formatters based on configuration" do
15
- Teaspoon.configuration.should_receive(:formatters).and_return(["dot", "xml"])
21
+ Teaspoon.configuration.stub(:formatters).and_return(["dot", "xml"])
16
22
  Teaspoon::Formatters::XmlFormatter = Class.new do
17
- def initialize(suite_name = :default) end
23
+ def initialize(_suite_name = :default, _output_file = nil) end
18
24
  end
19
- expect(subject.formatters[0]).to be_a(Teaspoon::Formatters::DotFormatter)
20
- expect(subject.formatters[1]).to be_a(Teaspoon::Formatters::XmlFormatter)
21
- end
22
-
23
- end
24
-
25
- describe "#suppress_logs?" do
26
-
27
- it "returns true if the configuration is true" do
28
- Teaspoon.configuration.should_receive(:suppress_log).and_return(true)
29
- expect(subject.suppress_logs?).to be(true)
25
+ expect(subject.instance_variable_get(:@formatters)[0]).to be_a(Teaspoon::Formatters::DotFormatter)
26
+ expect(subject.instance_variable_get(:@formatters)[1]).to be_a(Teaspoon::Formatters::XmlFormatter)
30
27
  end
31
28
 
32
- it "asks each formatter if it needs to suppress logs" do
33
- Teaspoon.configuration.should_receive(:suppress_log).and_return(false)
34
- subject.formatters = [double(suppress_logs?: true)]
35
- expect(subject.suppress_logs?).to be(true)
36
- end
37
-
38
- it "memoizes" do
39
- Teaspoon.configuration.should_not_receive(:suppress_log)
40
- subject.instance_variable_set(:@suppress_logs, true)
41
- expect(subject.suppress_logs?).to be(true)
29
+ it "raises a Teaspoon::UnknownFormatter exception when a formatter isn't found" do
30
+ Teaspoon.configuration.stub(:formatters).and_return(["bar"])
31
+ expect { Teaspoon::Runner.new(:foo) }.to raise_error Teaspoon::UnknownFormatter, "Unknown formatter: \"bar\""
42
32
  end
43
33
 
44
34
  end
45
35
 
46
36
  describe "#process" do
47
37
 
38
+ let(:formatter) { double }
39
+ let(:coverage) { double(generate_reports: nil, check_thresholds: nil) }
40
+
48
41
  before do
49
- subject.instance_variable_set(:@suppress_logs, false)
42
+ subject.instance_variable_set(:@formatters, [formatter])
50
43
  end
51
44
 
52
- it "just outputs logs that it doesn't understand" do
53
- subject.should_receive(:log).with("_line_")
54
- subject.should_receive(:output_from).and_return(false)
55
- subject.process("_line_")
45
+ it "notifies formatters when it understands the log" do
46
+ formatter.should_receive(:foo)
47
+ formatter.should_not_receive(:bar)
48
+ subject.process('{"_teaspoon":true,"type":"foo"}')
49
+ subject.process('{"_teaspoon":false,"type":"bar"}')
56
50
  end
57
51
 
58
- it "doesn't output logs when suppressed" do
59
- subject.should_receive(:suppress_logs?).and_return(true)
60
- subject.should_not_receive(:log).with("_line_")
61
- subject.should_receive(:output_from).and_return(false)
52
+ it "notifies formatters of console output when it doesn't understand the log" do
53
+ formatter.should_receive(:console).with("_line_")
54
+ subject.should_receive(:result_from_line).and_return(false)
62
55
  subject.process("_line_")
63
56
  end
64
57
 
65
- it "handles lines and notifies formatters when it should" do
66
- formatter = double('formatter')
67
- subject.formatters = [ formatter ]
68
- formatter.should_receive(:spec)
69
- formatter.should_receive(:error)
70
- formatter.should_receive(:results)
71
- formatter.should_receive(:exception)
72
- formatter.should_not_receive(:log)
73
- subject.process('{"_teaspoon": true, "type": "spec"}')
74
- subject.process('{"_teaspoon": true, "type": "error"}')
75
- subject.process('{"_teaspoon": true, "type": "results"}')
76
- subject.process('{"_teaspoon": true, "type": "exception"}')
77
- end
78
-
79
58
  it "handles bad json" do
80
- subject.should_receive(:log).with("{bad: true}")
59
+ formatter.should_receive(:console).with("{bad: true}")
81
60
  subject.process("{bad: true}")
82
61
  end
83
62
 
84
63
  it "handles json when it's not intended for it" do
85
- subject.should_receive(:log).with('{"good": true}')
64
+ formatter.should_receive(:console).with('{"good": true}')
86
65
  subject.process('{"good": true}')
87
66
  end
88
67
 
89
- it 'keeps a count of errors' do
90
- subject.formatters = []
91
- subject.process('{"_teaspoon": true, "type": "spec"}')
92
- subject.process('{"_teaspoon": true, "type": "spec", "status": "passed"}')
93
- subject.process('{"_teaspoon": true, "type": "spec", "status": "pending"}')
94
- subject.process('{"_teaspoon": true, "type": "error"}')
95
- subject.process('{"_teaspoon": true, "type": "exception"}')
96
- subject.process('{"_teaspoon": true, "type": "results"}')
68
+ it "keeps a count of errors" do
69
+ subject.process('{"_teaspoon":true,"type":"spec"}')
70
+ subject.process('{"_teaspoon":true,"type":"spec", "status": "passed"}')
71
+ subject.process('{"_teaspoon":true,"type":"spec", "status": "pending"}')
72
+ subject.process('{"_teaspoon":true,"type":"error"}')
73
+ subject.process('{"_teaspoon":true,"type":"results"}')
97
74
  expect(subject.failure_count).to be(1)
98
75
  end
99
76
 
77
+ describe "with an exception" do
78
+
79
+ it "notifies itself, and raises Teaspoon::RunnerException" do
80
+ subject.should_receive(:on_exception).and_call_original
81
+ expect { subject.process('{"_teaspoon":true,"type":"exception","message":"_message_"}') }.to raise_error Teaspoon::RunnerException, "_message_"
82
+ end
83
+
84
+ end
85
+
86
+ describe "with a result" do
87
+
88
+ before do
89
+ Teaspoon::Coverage.stub(:new).and_return(coverage)
90
+ end
91
+
92
+ it "notifies itself" do
93
+ subject.should_receive(:on_result)
94
+ subject.process('{"_teaspoon":true,"type":"result"}')
95
+ end
96
+
97
+ it "resolves coverage" do
98
+ Teaspoon.configuration.should_receive(:use_coverage).twice.and_return("_coverage_config_")
99
+ Teaspoon::Coverage.should_receive(:new).with(:default, "_coverage_config_", "_coverage_").and_return(coverage)
100
+ coverage.should_receive(:generate_reports).and_yield("_generated_reports_")
101
+ coverage.should_receive(:check_thresholds).and_yield("_threshold_failures_")
102
+ subject.should_receive(:notify_formatters).once.with("coverage", "_generated_reports_")
103
+ subject.should_receive(:notify_formatters).once.with("threshold_failure", "_threshold_failures_")
104
+ subject.should_receive(:notify_formatters).exactly(2).times.and_call_original
105
+ subject.process('{"_teaspoon":true,"type":"result","coverage":"_coverage_"}')
106
+ expect(subject.failure_count).to eq(1)
107
+ end
108
+
109
+ end
110
+
100
111
  end
101
112
 
102
113
  end