opal-spec 0.2.6 → 0.2.7

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