opal-spec 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
1
  source :rubygems
2
+ gemspec
2
3
 
3
4
  gem 'rake'
4
- gem 'opal'
5
+ gem 'opal'
6
+ gem 'sprockets'
data/README.md CHANGED
@@ -1,5 +1,4 @@
1
- opal-spec
2
- =========
1
+ # opal-spec
3
2
 
4
3
  opal-spec is a minimal spec lib for opal, inspired by RSpec and MSpec.
5
4
  It is designed to run on [opal](http://opalrb.org), and provides the
@@ -31,7 +30,7 @@ The best place to do this is inside `spec/spec_helper.rb`, and with a
31
30
  simple call:
32
31
 
33
32
  ```ruby
34
- OpalSpec::Runner.autorun
33
+ Opal::Spec::Runner.autorun
35
34
  ```
36
35
 
37
36
  ### Async examples
@@ -58,8 +57,8 @@ result, you also need to use a `run_async` call inside some future handler:
58
57
  ```ruby
59
58
  async 'HTTP requests should work' do
60
59
  HTTP.get('users/1.json') do |response|
61
- run\_async {
62
- response.ok?.should be\_true
60
+ run_async {
61
+ response.ok?.should be_true
63
62
  }
64
63
  end
65
64
  end
@@ -71,8 +70,9 @@ done with this test, so it can move on.
71
70
  Change Log
72
71
  ----------
73
72
 
74
- ### Edge
73
+ ### 0.2.7
75
74
 
75
+ * Can be built using asset pipeline/sprockets
76
76
  * BrowserFormatter is now default
77
77
 
78
78
  ### 0.0.3
data/Rakefile CHANGED
@@ -1,9 +1,27 @@
1
- require 'bundler/setup'
2
- require 'opal/rake_task'
1
+ require 'bundler'
2
+ Bundler.require
3
3
 
4
- Opal::RakeTask.new do |t|
5
- t.name = 'opal-spec'
6
- t.dependencies = []
4
+ desc "Build opal-spec (with opal) into build"
5
+ task :build => [:dir] do
6
+ File.open('build/opal-spec.js', 'w+') do |out|
7
+ out.puts Opal.process('opal-spec')
8
+ end
7
9
  end
8
10
 
9
- task :default => [:opal]
11
+ desc "Build example specs ready to run"
12
+ task :build_specs => [:dir] do
13
+ Opal.append_path File.join(File.dirname(__FILE__), 'spec')
14
+
15
+ File.open('build/specs.js', 'w+') do |out|
16
+ out.puts Opal.process('specs')
17
+ end
18
+ end
19
+ task :dir do
20
+ FileUtils.mkdir_p 'build'
21
+ end
22
+
23
+ task :test do
24
+ Opal::Spec.runner
25
+ end
26
+
27
+ task :default => [:build_specs, :test]
@@ -0,0 +1,194 @@
1
+ module Opal
2
+ module Spec
3
+ class BrowserFormatter
4
+ CSS = <<-EOS
5
+
6
+ body {
7
+ font-size: 14px;
8
+ font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
9
+ }
10
+
11
+ pre {
12
+ font-family: "Bitstream Vera Sans Mono", Monaco, "Lucida Console", monospace;
13
+ font-size: 12px;
14
+ color: #444444;
15
+ white-space: pre;
16
+ padding: 3px 0px 3px 12px;
17
+ margin: 0px 0px 8px;
18
+
19
+ background: #FAFAFA;
20
+ -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
21
+ -webkit-border-radius: 3px;
22
+ -moz-border-radius: 3px;
23
+ border-radius: 3px;
24
+ border: 1px solid #DDDDDD;
25
+ }
26
+
27
+ ul.example_groups {
28
+ list-style-type: none;
29
+ }
30
+
31
+ li.group.passed .group_description {
32
+ color: #597800;
33
+ font-weight: bold;
34
+ }
35
+
36
+ li.group.failed .group_description {
37
+ color: #FF000E;
38
+ font-weight: bold;
39
+ }
40
+
41
+ li.example.passed {
42
+ color: #597800;
43
+ }
44
+
45
+ li.example.failed {
46
+ color: #FF000E;
47
+ }
48
+
49
+ .examples {
50
+ list-style-type: none;
51
+ }
52
+ EOS
53
+
54
+ def initialize
55
+ @examples = []
56
+ @failed_examples = []
57
+ end
58
+
59
+ def start
60
+ %x{
61
+ if (!document || !document.body) {
62
+ #{ raise "Not running in browser." };
63
+ }
64
+
65
+ var summary_element = document.createElement('p');
66
+ summary_element.className = 'summary';
67
+ summary_element.innerHTML = "Running...";
68
+
69
+ var groups_element = document.createElement('ul');
70
+ groups_element.className = 'example_groups';
71
+
72
+ var target = document.getElementById('opal-spec-output');
73
+
74
+ if (!target) {
75
+ target = document.body;
76
+ }
77
+
78
+ target.appendChild(summary_element);
79
+ target.appendChild(groups_element);
80
+
81
+ var styles = document.createElement('style');
82
+ styles.type = 'text/css';
83
+
84
+ if (styles.styleSheet) {
85
+ styles.styleSheet.cssText = __scope.CSS;
86
+ }
87
+ else {
88
+ styles.appendChild(document.createTextNode(__scope.CSS));
89
+ }
90
+
91
+ document.getElementsByTagName('head')[0].appendChild(styles);
92
+ }
93
+
94
+ @start_time = Time.now.to_f
95
+ @groups_element = `groups_element`
96
+ @summary_element = `summary_element`
97
+ end
98
+
99
+ def finish
100
+ time = Time.now.to_f - @start_time
101
+ text = "\n#{example_count} examples, #{@failed_examples.size} failures (time taken: #{time})"
102
+ `#{@summary_element}.innerHTML = text`
103
+ end
104
+
105
+ def example_group_started group
106
+ @example_group = group
107
+ @example_group_failed = false
108
+
109
+ %x{
110
+ var group_element = document.createElement('li');
111
+
112
+ var description = document.createElement('span');
113
+ description.className = 'group_description';
114
+ description.innerHTML = #{group.description.to_s};
115
+ group_element.appendChild(description);
116
+
117
+ var example_list = document.createElement('ul');
118
+ example_list.className = 'examples';
119
+ group_element.appendChild(example_list);
120
+
121
+ #@groups_element.appendChild(group_element);
122
+ }
123
+
124
+ @group_element = `group_element`
125
+ @example_list = `example_list`
126
+ end
127
+
128
+ def example_group_finished group
129
+ if @example_group_failed
130
+ `#@group_element.className = 'group failed';`
131
+ else
132
+ `#@group_element.className = 'group passed';`
133
+ end
134
+ end
135
+
136
+ def example_started example
137
+ @examples << example
138
+ @example = example
139
+ end
140
+
141
+ def example_failed example
142
+ @failed_examples << example
143
+ @example_group_failed = true
144
+
145
+ exception = example.exception
146
+
147
+ case exception
148
+ when Opal::Spec::ExpectationNotMetError
149
+ output = exception.message
150
+ else
151
+ output = "#{exception.class.name}: #{exception.message}\n"
152
+ output += " #{exception.backtrace.join "\n "}\n"
153
+ end
154
+
155
+ %x{
156
+ var wrapper = document.createElement('li');
157
+ wrapper.className = 'example failed';
158
+
159
+ var description = document.createElement('span');
160
+ description.className = 'example_description';
161
+ description.innerHTML = #{example.description};
162
+
163
+ var exception = document.createElement('pre');
164
+ exception.className = 'exception';
165
+ exception.innerHTML = output;
166
+
167
+ wrapper.appendChild(description);
168
+ wrapper.appendChild(exception);
169
+
170
+ #@example_list.appendChild(wrapper);
171
+ #@example_list.style.display = 'list-item';
172
+ }
173
+ end
174
+
175
+ def example_passed example
176
+ %x{
177
+ var wrapper = document.createElement('li');
178
+ wrapper.className = 'example passed';
179
+
180
+ var description = document.createElement('span');
181
+ description.className = 'example_description';
182
+ description.innerHTML = #{example.description};
183
+
184
+ wrapper.appendChild(description);
185
+ #@example_list.appendChild(wrapper);
186
+ }
187
+ end
188
+
189
+ def example_count
190
+ @examples.size
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,78 @@
1
+ module Opal
2
+ module Spec
3
+ class Example
4
+ attr_reader :description, :example_group, :exception
5
+ attr_accessor :asynchronous
6
+
7
+ def initialize(group, desc, block)
8
+ @example_group = group
9
+ @description = desc
10
+ @__block__ = block
11
+ end
12
+
13
+ def finish_running
14
+ if @exception
15
+ @example_group.example_failed self
16
+ else
17
+ @example_group.example_passed self
18
+ end
19
+ end
20
+
21
+ def run
22
+ begin
23
+ @example_group.example_started self
24
+ run_before_hooks
25
+ instance_eval(&@__block__)
26
+ rescue => e
27
+ @exception = e
28
+ ensure
29
+ run_after_hooks unless @asynchronous
30
+ end
31
+
32
+ if @asynchronous
33
+ # must wait ...
34
+ else
35
+ finish_running
36
+ end
37
+ end
38
+
39
+ def run_after_hooks
40
+ begin
41
+ @example_group.after_hooks.each do |after|
42
+ instance_eval &after
43
+ end
44
+ rescue => e
45
+ @exception = e
46
+ end
47
+ end
48
+
49
+ def run_before_hooks
50
+ @example_group.before_hooks.each do |before|
51
+ instance_eval &before
52
+ end
53
+ end
54
+
55
+ def run_async(&block)
56
+ begin
57
+ block.call
58
+ rescue => e
59
+ @exception = e
60
+ ensure
61
+ run_after_hooks
62
+ end
63
+
64
+ finish_running
65
+ end
66
+
67
+ def set_timeout(duration, &block)
68
+ %x{
69
+ setTimeout(function() {
70
+ #{ block.call };
71
+ }, duration);
72
+ }
73
+
74
+ self
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,94 @@
1
+ module Opal
2
+ module Spec
3
+ class ExampleGroup
4
+ @example_groups = []
5
+ def self.example_groups
6
+ @example_groups
7
+ end
8
+
9
+ @stack = []
10
+ def self.create desc, block
11
+ group = self.new desc, @stack.last
12
+ @example_groups << group
13
+
14
+ @stack << group
15
+ group.instance_eval &block
16
+ @stack.pop
17
+ end
18
+
19
+ def initialize desc, parent
20
+ @desc = desc.to_s
21
+ @parent = parent
22
+ @examples = []
23
+
24
+ @before_hooks = []
25
+ @after_hooks = []
26
+ end
27
+
28
+ def it(desc, &block)
29
+ @examples << Example.new(self, desc, block)
30
+ end
31
+
32
+ def async(desc, &block)
33
+ example = Example.new(self, desc, block)
34
+ example.asynchronous = true
35
+ @examples << example
36
+ end
37
+
38
+ def it_behaves_like(*objs)
39
+ end
40
+
41
+ def before type = :each, &block
42
+ raise "unsupported before type: #{type}" unless type == :each
43
+ @before_hooks << block
44
+ end
45
+
46
+ def after type = :each, &block
47
+ raise "unsupported after type: #{type}" unless type == :each
48
+ @after_hooks << block
49
+ end
50
+
51
+ def before_hooks
52
+ @parent ? [].concat(@parent.before_hooks).concat(@before_hooks) : @before_hooks
53
+ end
54
+
55
+ def after_hooks
56
+ @parent ? [].concat(@parent.after_hooks).concat(@after_hooks) : @after_hooks
57
+ end
58
+
59
+ def run(runner)
60
+ @runner = runner
61
+ @runner.example_group_started self
62
+
63
+ @running_examples = @examples.dup
64
+ run_next_example
65
+ end
66
+
67
+ def run_next_example
68
+ if @running_examples.empty?
69
+ @runner.example_group_finished self
70
+ else
71
+ @running_examples.shift.run
72
+ end
73
+ end
74
+
75
+ def example_started(example)
76
+ @runner.example_started(example)
77
+ end
78
+
79
+ def example_passed(example)
80
+ @runner.example_passed(example)
81
+ run_next_example
82
+ end
83
+
84
+ def example_failed(example)
85
+ @runner.example_failed(example)
86
+ run_next_example
87
+ end
88
+
89
+ def description
90
+ @parent ? "#{@parent.description} #{@desc}" : @desc
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,55 @@
1
+ module Opal
2
+ module Spec
3
+ class ExpectationNotMetError < StandardError; end
4
+
5
+ module Expectations
6
+ def should matcher = nil
7
+ if matcher
8
+ matcher.match self
9
+ else
10
+ Opal::Spec::PositiveOperatorMatcher.new self
11
+ end
12
+ end
13
+
14
+ def should_not matcher = nil
15
+ if matcher
16
+ matcher.not_match self
17
+ else
18
+ Opal::Spec::NegativeOperatorMatcher.new self
19
+ end
20
+ end
21
+
22
+ def be_kind_of expected
23
+ Opal::Spec::BeKindOfMatcher.new expected
24
+ end
25
+
26
+ def be_nil
27
+ Opal::Spec::BeNilMatcher.new nil
28
+ end
29
+
30
+ def be_true
31
+ Opal::Spec::BeTrueMatcher.new true
32
+ end
33
+
34
+ def be_false
35
+ Opal::Spec::BeFalseMatcher.new false
36
+ end
37
+
38
+ def eq(expected)
39
+ Opal::Spec::EqlMatcher.new expected
40
+ end
41
+
42
+ def equal expected
43
+ Opal::Spec::EqualMatcher.new expected
44
+ end
45
+
46
+ def raise_error expected
47
+ Opal::Spec::RaiseErrorMatcher.new expected
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ class Object
54
+ include Opal::Spec::Expectations
55
+ end
@@ -1,9 +1,9 @@
1
1
  module Kernel
2
2
  def describe desc, &block
3
- OpalSpec::ExampleGroup.create desc, block
3
+ Opal::Spec::ExampleGroup.create desc, block
4
4
  end
5
5
 
6
6
  def mock obj
7
7
  Object.new
8
8
  end
9
- end
9
+ end
@@ -0,0 +1,106 @@
1
+ module Opal
2
+ module Spec
3
+ class Matcher
4
+ def initialize actual
5
+ @actual = actual
6
+ end
7
+
8
+ def failure message
9
+ raise Opal::Spec::ExpectationNotMetError, message
10
+ end
11
+ end
12
+
13
+ class PositiveOperatorMatcher < Matcher
14
+ def == expected
15
+ if @actual == expected
16
+ true
17
+ else
18
+ failure "expected: #{expected.inspect}, got: #{@actual.inspect} (using ==)."
19
+ end
20
+ end
21
+ end
22
+
23
+ class NegativeOperatorMatcher < Matcher
24
+ def == expected
25
+ if @actual == expected
26
+ failure "expected: #{expected.inspect} not to be #{@actual.inspect} (using ==)."
27
+ end
28
+ end
29
+ end
30
+
31
+ class BeKindOfMatcher < Matcher
32
+ def match expected
33
+ unless expected.kind_of? @actual
34
+ failure "expected #{expected.inspect} to be a kind of #{@actual.name}, not #{expected.class.name}."
35
+ end
36
+ end
37
+ end
38
+
39
+ class BeNilMatcher < Matcher
40
+ def match expected
41
+ unless expected.nil?
42
+ failure "expected #{expected.inspect} to be nil."
43
+ end
44
+ end
45
+ end
46
+
47
+ class BeTrueMatcher < Matcher
48
+ def match expected
49
+ unless expected == true
50
+ failure "expected #{expected.inspect} to be true."
51
+ end
52
+ end
53
+ end
54
+
55
+ class BeFalseMatcher < Matcher
56
+ def match expected
57
+ unless expected == false
58
+ failure "expected #{expected.inspect} to be false."
59
+ end
60
+ end
61
+ end
62
+
63
+ class EqlMatcher < Matcher
64
+ def match(expected)
65
+ unless expected == @actual
66
+ failure "expected: #{expected.inspect}, got: #{@actual.inspect} (using ==)."
67
+ end
68
+ end
69
+
70
+ def not_match(expected)
71
+ if expected.equal? @actual
72
+ failure "expected: #{expected.inspect} not to be #{@actual.inspect} (using ==)."
73
+ end
74
+ end
75
+ end
76
+
77
+ class EqualMatcher < Matcher
78
+ def match expected
79
+ unless expected.equal? @actual
80
+ failure "expected #{@actual.inspect} to be the same as #{expected.inspect}."
81
+ end
82
+ end
83
+
84
+ def not_match expected
85
+ if expected.equal? @actual
86
+ failure "expected #{@actual.inspect} not to be equal to #{expected.inspect}."
87
+ end
88
+ end
89
+ end
90
+
91
+ class RaiseErrorMatcher < Matcher
92
+ def match block
93
+ should_raise = false
94
+ begin
95
+ block.call
96
+ should_raise = true
97
+ rescue => e
98
+ end
99
+
100
+ if should_raise
101
+ failure "expected #{@actual} to be raised, but nothing was."
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,93 @@
1
+ module Opal
2
+ module Spec
3
+ class PhantomFormatter
4
+ def initialize
5
+ @examples = []
6
+ @failed_examples = []
7
+ end
8
+
9
+ def log_green(str)
10
+ `console.log('\\033[32m' + str + '\\033[0m')`
11
+ end
12
+
13
+ def log_red(str)
14
+ `console.log('\\033[31m' + str + '\\033[0m')`
15
+ end
16
+
17
+ def log(str)
18
+ `console.log(str)`
19
+ end
20
+
21
+ def start
22
+ @start_time = Time.now.to_f
23
+ end
24
+
25
+ def finish
26
+ time = Time.now.to_f - @start_time
27
+ if @failed_examples.empty?
28
+ log "\nFinished"
29
+ log_green "#{example_count} examples, 0 failures (time taken: #{time})"
30
+ finish_with_code(0)
31
+ else
32
+ log "\nFailures:"
33
+ @failed_examples.each_with_index do |example, idx|
34
+ log "\n #{idx+1}. #{example.example_group.description} #{example.description}"
35
+
36
+ exception = example.exception
37
+ case exception
38
+ when Opal::Spec::ExpectationNotMetError
39
+ output = exception.message
40
+ else
41
+ output = "#{exception.class.name}: #{exception.message}\n"
42
+ output += " #{exception.backtrace.join "\n "}\n"
43
+ end
44
+ log_red " #{output}"
45
+ end
46
+
47
+ log "\nFinished"
48
+ log_red "#{example_count} examples, #{@failed_examples.size} failures (time taken: #{time})"
49
+ finish_with_code(1)
50
+ end
51
+ end
52
+
53
+ def finish_with_code(code)
54
+ %x{
55
+ if (typeof(phantom) !== 'undefined') {
56
+ return phantom.exit(code);
57
+ }
58
+ else {
59
+ window.OPAL_SPEC_CODE = code;
60
+ }
61
+ }
62
+ end
63
+
64
+ def example_group_started group
65
+ @example_group = group
66
+ @example_group_failed = false
67
+ log "\n#{group.description}"
68
+ end
69
+
70
+ def example_group_finished group
71
+ end
72
+
73
+ def example_started example
74
+ @examples << example
75
+ @example = example
76
+ end
77
+
78
+ def example_failed example
79
+ @failed_examples << example
80
+ @example_group_failed = true
81
+ log_red " #{example.description}"
82
+ end
83
+
84
+ def example_passed example
85
+ log_green " #{example.description}"
86
+ end
87
+
88
+ def example_count
89
+ @examples.size
90
+ end
91
+ end
92
+ end
93
+ end