evergreen 0.3.0 → 0.4.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 (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