evergreen 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/README.rdoc +30 -4
  2. data/config/routes.rb +1 -1
  3. data/lib/evergreen.rb +14 -50
  4. data/lib/evergreen/application.rb +46 -0
  5. data/lib/evergreen/cli.rb +2 -2
  6. data/lib/evergreen/rails.rb +4 -0
  7. data/lib/evergreen/resources/evergreen.css +3 -1
  8. data/lib/evergreen/resources/evergreen.js +3 -0
  9. data/lib/evergreen/runner.rb +124 -36
  10. data/lib/evergreen/server.rb +9 -18
  11. data/lib/evergreen/spec.rb +26 -14
  12. data/lib/evergreen/suite.rb +44 -0
  13. data/lib/evergreen/tasks.rb +6 -0
  14. data/lib/evergreen/template.rb +7 -10
  15. data/lib/evergreen/version.rb +1 -1
  16. data/lib/evergreen/views/layout.erb +1 -0
  17. data/lib/evergreen/views/list.erb +2 -2
  18. data/lib/evergreen/views/spec.erb +18 -10
  19. data/lib/jasmine/Gemfile +6 -0
  20. data/lib/jasmine/MIT.LICENSE +2 -2
  21. data/lib/jasmine/README.markdown +5 -459
  22. data/lib/jasmine/Rakefile +22 -16
  23. data/lib/jasmine/example/SpecRunner.html +1 -1
  24. data/lib/jasmine/jsdoc-template/allclasses.tmpl +17 -0
  25. data/lib/jasmine/jsdoc-template/allfiles.tmpl +56 -0
  26. data/lib/jasmine/jsdoc-template/class.tmpl +646 -0
  27. data/lib/jasmine/jsdoc-template/index.tmpl +39 -0
  28. data/lib/jasmine/jsdoc-template/publish.js +184 -0
  29. data/lib/jasmine/jsdoc-template/static/default.css +162 -0
  30. data/lib/jasmine/jsdoc-template/static/header.html +2 -0
  31. data/lib/jasmine/jsdoc-template/static/index.html +19 -0
  32. data/lib/jasmine/jsdoc-template/symbol.tmpl +35 -0
  33. data/lib/jasmine/lib/jasmine-html.js +12 -6
  34. data/lib/jasmine/lib/jasmine.js +122 -44
  35. data/lib/jasmine/spec/runner.html +0 -1
  36. data/lib/jasmine/spec/suites/CustomMatchersSpec.js +18 -9
  37. data/lib/jasmine/spec/suites/MatchersSpec.js +241 -162
  38. data/lib/jasmine/spec/suites/SpecRunningSpec.js +120 -62
  39. data/lib/jasmine/spec/suites/TrivialReporterSpec.js +3 -0
  40. data/lib/jasmine/spec/suites/WaitsForBlockSpec.js +9 -9
  41. data/lib/jasmine/src/Env.js +1 -0
  42. data/lib/jasmine/src/Matchers.js +35 -17
  43. data/lib/jasmine/src/Queue.js +6 -1
  44. data/lib/jasmine/src/Spec.js +34 -2
  45. data/lib/jasmine/src/WaitsForBlock.js +28 -13
  46. data/lib/jasmine/src/base.js +15 -8
  47. data/lib/jasmine/src/html/TrivialReporter.js +12 -6
  48. data/lib/jasmine/src/version.json +2 -2
  49. data/lib/tasks/evergreen.rake +1 -1
  50. data/spec/meta_spec.rb +21 -2
  51. data/spec/runner_spec.rb +16 -18
  52. data/spec/spec_helper.rb +12 -4
  53. data/spec/spec_spec.rb +4 -11
  54. data/spec/suite1/spec/javascripts/invalid_coffee_spec.coffee +1 -0
  55. data/spec/suite1/spec/javascripts/spec_helper.coffee +1 -1
  56. data/spec/suite2/config/evergreen.rb +5 -0
  57. data/spec/suite2/public_html/foo.js +1 -0
  58. data/spec/suite2/spec/awesome_spec.js +12 -0
  59. data/spec/suite2/spec/failing_spec.js +5 -0
  60. data/spec/suite2/templates/foo.html +1 -0
  61. data/spec/suite_spec.rb +26 -0
  62. data/spec/template_spec.rb +3 -9
  63. metadata +52 -20
  64. data/lib/jasmine/lib/consolex.js +0 -28
@@ -73,14 +73,46 @@ jasmine.Spec.prototype.expect = function(actual) {
73
73
  return positive;
74
74
  };
75
75
 
76
+ /**
77
+ * Waits a fixed time period before moving to the next block.
78
+ *
79
+ * @deprecated Use waitsFor() instead
80
+ * @param {Number} timeout milliseconds to wait
81
+ */
76
82
  jasmine.Spec.prototype.waits = function(timeout) {
77
83
  var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
78
84
  this.addToQueue(waitsFunc);
79
85
  return this;
80
86
  };
81
87
 
82
- jasmine.Spec.prototype.waitsFor = function(timeout, latchFunction, timeoutMessage) {
83
- var waitsForFunc = new jasmine.WaitsForBlock(this.env, timeout, latchFunction, timeoutMessage, this);
88
+ /**
89
+ * Waits for the latchFunction to return true before proceeding to the next block.
90
+ *
91
+ * @param {Function} latchFunction
92
+ * @param {String} optional_timeoutMessage
93
+ * @param {Number} optional_timeout
94
+ */
95
+ jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
96
+ var latchFunction_ = null;
97
+ var optional_timeoutMessage_ = null;
98
+ var optional_timeout_ = null;
99
+
100
+ for (var i = 0; i < arguments.length; i++) {
101
+ var arg = arguments[i];
102
+ switch (typeof arg) {
103
+ case 'function':
104
+ latchFunction_ = arg;
105
+ break;
106
+ case 'string':
107
+ optional_timeoutMessage_ = arg;
108
+ break;
109
+ case 'number':
110
+ optional_timeout_ = arg;
111
+ break;
112
+ }
113
+ }
114
+
115
+ var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
84
116
  this.addToQueue(waitsForFunc);
85
117
  return this;
86
118
  };
@@ -1,37 +1,52 @@
1
+ /**
2
+ * A block which waits for some condition to become true, with timeout.
3
+ *
4
+ * @constructor
5
+ * @extends jasmine.Block
6
+ * @param {jasmine.Env} env The Jasmine environment.
7
+ * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
8
+ * @param {Function} latchFunction A function which returns true when the desired condition has been met.
9
+ * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
10
+ * @param {jasmine.Spec} spec The Jasmine spec.
11
+ */
1
12
  jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
2
- this.timeout = timeout;
13
+ this.timeout = timeout || env.defaultTimeoutInterval;
3
14
  this.latchFunction = latchFunction;
4
15
  this.message = message;
5
16
  this.totalTimeSpentWaitingForLatch = 0;
6
17
  jasmine.Block.call(this, env, null, spec);
7
18
  };
8
-
9
19
  jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
10
20
 
11
- jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 100;
21
+ jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
12
22
 
13
- jasmine.WaitsForBlock.prototype.execute = function (onComplete) {
14
- var self = this;
15
- self.env.reporter.log('>> Jasmine waiting for ' + (self.message || 'something to happen'));
23
+ jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
24
+ this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
16
25
  var latchFunctionResult;
17
26
  try {
18
- latchFunctionResult = self.latchFunction.apply(self.spec);
27
+ latchFunctionResult = this.latchFunction.apply(this.spec);
19
28
  } catch (e) {
20
- self.spec.fail(e);
29
+ this.spec.fail(e);
21
30
  onComplete();
22
31
  return;
23
32
  }
24
33
 
25
34
  if (latchFunctionResult) {
26
35
  onComplete();
27
- } else if (self.totalTimeSpentWaitingForLatch >= self.timeout) {
28
- var message = 'timed out after ' + self.timeout + ' msec waiting for ' + (self.message || 'something to happen');
29
- self.spec.fail({
36
+ } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
37
+ var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
38
+ this.spec.fail({
30
39
  name: 'timeout',
31
40
  message: message
32
41
  });
42
+
43
+ this.abort = true;
44
+ onComplete();
33
45
  } else {
34
- self.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
35
- self.env.setTimeout(function () { self.execute(onComplete); }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
46
+ this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
47
+ var self = this;
48
+ this.env.setTimeout(function() {
49
+ self.execute(onComplete);
50
+ }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
36
51
  }
37
52
  };
@@ -21,11 +21,16 @@ jasmine.unimplementedMethod_ = function() {
21
21
  jasmine.undefined = jasmine.___undefined___;
22
22
 
23
23
  /**
24
- * Default interval for event loop yields. Small values here may result in slow test running. Zero means no updates until all tests have completed.
24
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
25
25
  *
26
26
  */
27
27
  jasmine.DEFAULT_UPDATE_INTERVAL = 250;
28
28
 
29
+ /**
30
+ * Default timeout interval in milliseconds for waitsFor() blocks.
31
+ */
32
+ jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
33
+
29
34
  jasmine.getGlobal = function() {
30
35
  function getGlobal() {
31
36
  return this;
@@ -490,22 +495,24 @@ var runs = function(func) {
490
495
  };
491
496
 
492
497
  /**
493
- * Waits for a timeout before moving to the next runs()-defined block.
494
- * @param {Number} timeout
498
+ * Waits a fixed time period before moving to the next block.
499
+ *
500
+ * @deprecated Use waitsFor() instead
501
+ * @param {Number} timeout milliseconds to wait
495
502
  */
496
503
  var waits = function(timeout) {
497
504
  jasmine.getEnv().currentSpec.waits(timeout);
498
505
  };
499
506
 
500
507
  /**
501
- * Waits for the latchFunction to return true before proceeding to the next runs()-defined block.
508
+ * Waits for the latchFunction to return true before proceeding to the next block.
502
509
  *
503
- * @param {Number} timeout
504
510
  * @param {Function} latchFunction
505
- * @param {String} message
511
+ * @param {String} optional_timeoutMessage
512
+ * @param {Number} optional_timeout
506
513
  */
507
- var waitsFor = function(timeout, latchFunction, message) {
508
- jasmine.getEnv().currentSpec.waitsFor(timeout, latchFunction, message);
514
+ var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
515
+ jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
509
516
  };
510
517
 
511
518
  /**
@@ -34,7 +34,7 @@ jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
34
34
  this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
35
35
  this.createDom('div', { className: 'banner' },
36
36
  this.createDom('div', { className: 'logo' },
37
- "Jasmine",
37
+ this.createDom('a', { href: 'http://pivotal.github.com/jasmine/', target: "_blank" }, "Jasmine"),
38
38
  this.createDom('span', { className: 'version' }, runner.env.versionString())),
39
39
  this.createDom('div', { className: 'options' },
40
40
  "Show ",
@@ -70,16 +70,16 @@ jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
70
70
  this.startedAt = new Date();
71
71
 
72
72
  var self = this;
73
- showPassed.onchange = function(evt) {
74
- if (evt.target.checked) {
73
+ showPassed.onclick = function(evt) {
74
+ if (showPassed.checked) {
75
75
  self.outerDiv.className += ' show-passed';
76
76
  } else {
77
77
  self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
78
78
  }
79
79
  };
80
80
 
81
- showSkipped.onchange = function(evt) {
82
- if (evt.target.checked) {
81
+ showSkipped.onclick = function(evt) {
82
+ if (showSkipped.checked) {
83
83
  self.outerDiv.className += ' show-skipped';
84
84
  } else {
85
85
  self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
@@ -162,7 +162,13 @@ jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
162
162
 
163
163
  jasmine.TrivialReporter.prototype.log = function() {
164
164
  var console = jasmine.getGlobal().console;
165
- if (console && console.log) console.log.apply(console, arguments);
165
+ if (console && console.log) {
166
+ if (console.log.apply) {
167
+ console.log.apply(console, arguments);
168
+ } else {
169
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
170
+ }
171
+ }
166
172
  };
167
173
 
168
174
  jasmine.TrivialReporter.prototype.getLocation = function() {
@@ -1,5 +1,5 @@
1
1
  {
2
- "major": 0,
3
- "minor": 11,
2
+ "major": 1,
3
+ "minor": 0,
4
4
  "build": 1
5
5
  }
@@ -1,7 +1,7 @@
1
1
  namespace :spec do
2
2
  desc "Run JavaScript specs via Evergreen"
3
3
  task :javascripts do
4
- result = Evergreen::Runner.run(Rails.root)
4
+ result = Evergreen::Suite.new(Rails.root).run
5
5
  Kernel.exit(1) unless result
6
6
  end
7
7
  end
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Evergreen::Runner do
4
- subject { Evergreen::Runner.new(spec) }
5
- let(:spec) { Evergreen::Spec.new(root, template) }
4
+ let(:suite) { Evergreen::Suite.new(root) }
5
+ subject { Evergreen::Spec.new(suite, template) }
6
6
 
7
7
  context "with standard setup" do
8
8
  let(:root) { File.expand_path('suite1', File.dirname(__FILE__)) }
@@ -22,10 +22,29 @@ describe Evergreen::Runner do
22
22
  it { should pass }
23
23
  end
24
24
 
25
+ context "invalid coffee" do
26
+ let(:template) { 'invalid_coffee_spec.coffee' }
27
+ it { should_not pass }
28
+ end
29
+
25
30
  context "with slow failing spec" do
26
31
  let(:template) { 'slow_spec.coffee' }
27
32
  it { should_not pass }
28
33
  end
29
34
  end
35
+
36
+ context "with modified setup" do
37
+ let(:root) { File.expand_path('suite2', File.dirname(__FILE__)) }
38
+
39
+ context "with awesome spec" do
40
+ let(:template) { 'awesome_spec.js' }
41
+ it { should pass }
42
+ end
43
+
44
+ context "with failing spec" do
45
+ let(:template) { 'failing_spec.js' }
46
+ it { should_not pass }
47
+ end
48
+ end
30
49
  end
31
50
 
@@ -2,34 +2,32 @@ require 'spec_helper'
2
2
 
3
3
  describe Evergreen::Runner do
4
4
  let(:root) { File.expand_path('suite1', File.dirname(__FILE__)) }
5
+ let(:suite) { Evergreen::Suite.new(root) }
6
+ let(:runner) { Evergreen::Runner.new(suite, buffer) }
7
+ let(:buffer) { StringIO.new }
5
8
 
6
- context "with passing spec" do
7
- let(:spec) { Evergreen::Spec.new(root, 'testing_spec.js') }
8
- subject { Evergreen::Runner.new(spec) }
9
+ describe '#run' do
10
+ before { runner.run }
9
11
 
10
- it { should be_passed }
11
- its(:spec) { should == spec }
12
- its(:failure_message) { should be_empty }
13
- end
14
-
15
- context "with failing spec" do
16
- let(:spec) { Evergreen::Spec.new(root, 'failing_spec.js') }
17
- subject { Evergreen::Runner.new(spec) }
12
+ describe 'the buffer' do
13
+ subject { buffer.rewind; buffer.read }
18
14
 
19
- it { should_not be_passed }
20
- its(:spec) { should == spec }
21
- its(:failure_message) { should include("Expected 'bar' to equal 'noooooo'") }
15
+ it { should include('.F..') }
16
+ it { should include("Expected 'bar' to equal 'noooooo'") }
17
+ it { should include("17 examples, 3 failures") }
18
+ end
22
19
  end
23
20
 
24
- describe '.run' do
25
- let(:buffer) { StringIO.new }
26
- before { Evergreen::Runner.run(root, buffer) }
21
+ describe '#run_spec' do
22
+ let(:spec) { suite.get_spec('failing_spec.js') }
23
+ before { runner.spec_runner(spec).run }
27
24
 
28
25
  describe 'the buffer' do
29
26
  subject { buffer.rewind; buffer.read }
30
27
 
31
- it { should include('.F..') }
28
+ it { should include('.F') }
32
29
  it { should include("Expected 'bar' to equal 'noooooo'") }
30
+ it { should include("2 examples, 1 failures") }
33
31
  end
34
32
  end
35
33
  end
@@ -5,19 +5,23 @@ require 'evergreen'
5
5
  require 'rspec'
6
6
 
7
7
  require 'capybara/dsl'
8
+ require 'capybara/envjs'
8
9
 
9
- Capybara.app = Evergreen.application(File.expand_path('suite1', File.dirname(__FILE__)))
10
- Capybara.default_driver = :selenium
10
+ TEST_DRIVER = :envjs
11
+
12
+ Capybara.app = Evergreen::Suite.new(File.expand_path('suite1', File.dirname(__FILE__))).application
13
+ Capybara.default_driver = TEST_DRIVER
11
14
 
12
15
  module EvergreenMatchers
13
16
  class PassSpec # :nodoc:
14
17
  def matches?(actual)
15
18
  @actual = actual
16
- @actual.passed?
19
+ @runner = Evergreen::Runner.new(actual.suite, StringIO.new).spec_runner(@actual)
20
+ @runner.passed?
17
21
  end
18
22
 
19
23
  def failure_message
20
- "expected #{@actual.name} to pass, but it failed with:\n\n#{@actual.failure_message}"
24
+ "expected #{@actual.name} to pass, but it failed with:\n\n#{@runner.failure_messages}"
21
25
  end
22
26
 
23
27
  def negative_failure_message
@@ -32,4 +36,8 @@ end
32
36
 
33
37
  RSpec.configure do |config|
34
38
  config.include EvergreenMatchers
39
+ config.before do
40
+ Evergreen.use_defaults!
41
+ Evergreen.driver = TEST_DRIVER
42
+ end
35
43
  end
@@ -2,7 +2,8 @@ require 'spec_helper'
2
2
 
3
3
  describe Evergreen::Spec do
4
4
  let(:root) { File.expand_path('suite1', File.dirname(__FILE__)) }
5
- subject { Evergreen::Spec.new(root, 'testing_spec.js') }
5
+ let(:suite) { Evergreen::Suite.new(root) }
6
+ subject { Evergreen::Spec.new(suite, 'testing_spec.js') }
6
7
 
7
8
  its(:name) { should == 'testing_spec.js' }
8
9
  its(:root) { should == root }
@@ -10,16 +11,8 @@ describe Evergreen::Spec do
10
11
  its(:url) { should == "/run/testing_spec.js" }
11
12
  its(:contents) { should =~ /describe\('testing'/ }
12
13
 
13
- describe '.all' do
14
- subject { Evergreen::Spec.all(root) }
15
-
16
- it "should find all specs in the given root directory" do
17
- subject.map(&:name).should include('testing_spec.js', 'foo_spec.js', 'bar_spec.js', 'coffeescript_spec.coffee')
18
- end
19
- end
20
-
21
14
  context "with coffeescript" do
22
- subject { Evergreen::Spec.new(root, 'coffeescript_spec.coffee') }
15
+ subject { Evergreen::Spec.new(suite, 'coffeescript_spec.coffee') }
23
16
  its(:contents) { should =~ /describe\('coffeescript', function/ }
24
17
  end
25
18
 
@@ -28,7 +21,7 @@ describe Evergreen::Spec do
28
21
  end
29
22
 
30
23
  context "with missing spec file" do
31
- subject { Evergreen::Spec.new(root, 'does_not_exist.js') }
24
+ subject { Evergreen::Spec.new(suite, 'does_not_exist.js') }
32
25
  it { should_not exist }
33
26
  end
34
27
 
@@ -0,0 +1 @@
1
+ this => is &! not ( valid coffee script
@@ -1 +1 @@
1
- window.CoffeeSpecHelper: { coffee: 'script' }
1
+ window.CoffeeSpecHelper = { coffee: 'script' }
@@ -0,0 +1,5 @@
1
+ Evergreen.configure do |config|
2
+ config.public_dir = 'public_html'
3
+ config.template_dir = 'templates'
4
+ config.spec_dir = 'spec'
5
+ end
@@ -0,0 +1 @@
1
+ var foo = "The Foo";
@@ -0,0 +1,12 @@
1
+ require('/foo.js')
2
+
3
+ describe('awesome', function() {
4
+ template('foo.html');
5
+
6
+ it('requires public files', function() {
7
+ expect(foo).toEqual('The Foo');
8
+ });
9
+ it('loads templates', function() {
10
+ expect(document.getElementById('foo').innerHTML).toEqual('The foo template');
11
+ });
12
+ });
@@ -0,0 +1,5 @@
1
+ describe('failing', function() {
2
+ it('fails', function() {
3
+ expect('llama').toEqual('monkey');
4
+ });
5
+ });
@@ -0,0 +1 @@
1
+ <div id="foo">The foo template</div>
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Evergreen::Suite do
4
+ let(:root) { File.expand_path('suite1', File.dirname(__FILE__)) }
5
+ subject { Evergreen::Suite.new(root) }
6
+
7
+ its(:root) { should == root }
8
+
9
+ describe '#get_spec' do
10
+ subject { Evergreen::Suite.new(root).get_spec('testing_spec.js') }
11
+ its (:name) { should == 'testing_spec.js' }
12
+ its (:root) { should == root }
13
+ end
14
+
15
+ describe '#specs' do
16
+ it "should find all specs in the given root directory" do
17
+ subject.specs.map(&:name).should include('testing_spec.js', 'foo_spec.js', 'bar_spec.js', 'coffeescript_spec.coffee')
18
+ end
19
+ end
20
+
21
+ describe '#templates' do
22
+ it "should find all specs in the given root directory" do
23
+ subject.templates.map(&:name).should include('one_template.html', 'another_template.html')
24
+ end
25
+ end
26
+ end