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
@@ -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