opal-rspec 0.0.1.beta1

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.
File without changes
@@ -0,0 +1,146 @@
1
+ module RSpec
2
+ module Core
3
+ module SharedExampleGroup
4
+ # @overload shared_examples(name, &block)
5
+ # @overload shared_examples(name, tags, &block)
6
+ #
7
+ # Wraps the `block` in a module which can then be included in example
8
+ # groups using `include_examples`, `include_context`, or
9
+ # `it_behaves_like`.
10
+ #
11
+ # @param [String] name to match when looking up this shared group
12
+ # @param block to be eval'd in a nested example group generated by `it_behaves_like`
13
+ #
14
+ # @example
15
+ #
16
+ # shared_examples "auditable" do
17
+ # it "stores an audit record on save!" do
18
+ # lambda { auditable.save! }.should change(Audit, :count).by(1)
19
+ # end
20
+ # end
21
+ #
22
+ # class Account do
23
+ # it_behaves_like "auditable" do
24
+ # def auditable; Account.new; end
25
+ # end
26
+ # end
27
+ #
28
+ # @see ExampleGroup.it_behaves_like
29
+ # @see ExampleGroup.include_examples
30
+ # @see ExampleGroup.include_context
31
+ def shared_examples(*args, &block)
32
+ SharedExampleGroup.registry.add_group(self, *args, &block)
33
+ end
34
+
35
+ alias_method :shared_context, :shared_examples
36
+ alias_method :share_examples_for, :shared_examples
37
+ alias_method :shared_examples_for, :shared_examples
38
+
39
+ def shared_example_groups
40
+ SharedExampleGroup.registry.shared_example_groups_for('main', *ancestors[0..-1])
41
+ end
42
+
43
+ module TopLevelDSL
44
+ def shared_examples(*args, &block)
45
+ SharedExampleGroup.registry.add_group('main', *args, &block)
46
+ end
47
+
48
+ alias_method :shared_context, :shared_examples
49
+ alias_method :share_examples_for, :shared_examples
50
+ alias_method :shared_examples_for, :shared_examples
51
+
52
+ def shared_example_groups
53
+ SharedExampleGroup.registry.shared_example_groups_for('main')
54
+ end
55
+ end
56
+
57
+ def self.registry
58
+ @registry ||= Registry.new
59
+ end
60
+
61
+ # @private
62
+ #
63
+ # Used internally to manage the shared example groups and
64
+ # constants. We want to limit the number of methods we add
65
+ # to objects we don't own (main and Module) so this allows
66
+ # us to have helper methods that don't get added to those
67
+ # objects.
68
+ class Registry
69
+ def add_group(source, *args, &block)
70
+ ensure_block_has_source_location(block, CallerFilter.first_non_rspec_line)
71
+
72
+ if key? args.first
73
+ key = args.shift
74
+ warn_if_key_taken source, key, block
75
+ add_shared_example_group source, key, block
76
+ end
77
+
78
+ unless args.empty?
79
+ mod = Module.new
80
+ (class << mod; self; end).send :define_method, :extended do |host|
81
+ host.class_eval(&block)
82
+ end
83
+ RSpec.configuration.extend mod, *args
84
+ end
85
+ end
86
+
87
+ def shared_example_groups_for(*sources)
88
+ Collection.new(sources, shared_example_groups)
89
+ end
90
+
91
+ def shared_example_groups
92
+ @shared_example_groups ||= Hash.new { |hash,key| hash[key] = Hash.new }
93
+ end
94
+
95
+ def clear
96
+ shared_example_groups.clear
97
+ end
98
+
99
+ private
100
+
101
+ def add_shared_example_group(source, key, block)
102
+ shared_example_groups[source][key] = block
103
+ end
104
+
105
+ def key?(candidate)
106
+ [String, Symbol, Module].any? { |cls| cls === candidate }
107
+ end
108
+
109
+ def warn_if_key_taken(source, key, new_block)
110
+ return unless existing_block = example_block_for(source, key)
111
+
112
+ RSpec.warn_with <<-WARNING
113
+ WARN: Shared example group '#{key}' has been previously defined at:
114
+ WARN
115
+ WARN
116
+ WARN
117
+ WARN
118
+ WARNING
119
+ end
120
+
121
+ def formatted_location(block)
122
+ block.source_location.join ":"
123
+ end
124
+
125
+ def example_block_for(source, key)
126
+ shared_example_groups[source][key]
127
+ end
128
+
129
+ if Proc.method_defined?(:source_location)
130
+ def ensure_block_has_source_location(block, caller_line); end
131
+ else # for 1.8.7
132
+ def ensure_block_has_source_location(block, caller_line)
133
+ block.extend Module.new {
134
+ define_method :source_location do
135
+ caller_line.split(':')
136
+ end
137
+ }
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ extend RSpec::Core::SharedExampleGroup::TopLevelDSL
146
+ Module.send(:include, RSpec::Core::SharedExampleGroup::TopLevelDSL)
@@ -0,0 +1,27 @@
1
+ module RSpec
2
+ module Core
3
+ module SharedExampleGroup
4
+ class Collection
5
+
6
+ def initialize(sources, examples)
7
+ @sources, @examples = sources, examples
8
+ end
9
+
10
+ def [](key)
11
+ fetch_examples(key)
12
+ end
13
+
14
+ private
15
+
16
+ def fetch_examples(key)
17
+ @examples[source_for(key)][key]
18
+ end
19
+
20
+ def source_for(key)
21
+ @sources.reverse.find { |source| @examples[source].has_key? key }
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+ end
File without changes
data/config.ru ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+
4
+ Opal::Processor.source_map_enabled = false
5
+
6
+ run Opal::Server.new { |s|
7
+ s.main = 'opal/rspec/sprockets_runner'
8
+ s.append_path 'spec'
9
+ s.debug = false
10
+ }
data/lib/opal-rspec.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'opal/rspec'
2
+
data/lib/opal/rspec.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'opal'
2
+ require 'opal/rspec/version'
3
+
4
+ # Just register our opal code path with opal build tools
5
+ Opal.append_path File.expand_path('../../../opal', __FILE__)
6
+
@@ -0,0 +1,44 @@
1
+ require 'opal/rspec'
2
+ require 'opal-sprockets'
3
+
4
+ module Opal
5
+ module RSpec
6
+ class RakeTask
7
+ include Rake::DSL if defined? Rake::DSL
8
+
9
+ RUNNER = File.expand_path('../../../../vendor/spec_runner.js', __FILE__)
10
+ PORT = 9999
11
+ URL = "http://localhost:9999/"
12
+
13
+ def initialize(name = 'opal:rspec', &block)
14
+ desc "Run opal specs in phantomjs"
15
+ task name do
16
+ require 'rack'
17
+ require 'webrick'
18
+
19
+ server = fork do
20
+ app = Opal::Server.new { |s|
21
+ s.main = 'opal/rspec/sprockets_runner'
22
+ s.append_path 'spec'
23
+ s.debug = false
24
+
25
+ block.call s if block
26
+ }
27
+
28
+ Rack::Server.start(:app => app, :Port => PORT, :AccessLog => [],
29
+ :Logger => WEBrick::Log.new("/dev/null"))
30
+ end
31
+
32
+ system "phantomjs #{RUNNER} \"#{URL}\""
33
+ success = $?.success?
34
+
35
+ Process.kill(:SIGINT, server)
36
+ Process.wait
37
+
38
+ exit 1 unless success
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,6 @@
1
+ module Opal
2
+ module RSpec
3
+ VERSION = '0.0.1.beta1'
4
+ end
5
+ end
6
+
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/opal/rspec/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'opal-rspec'
6
+ s.version = Opal::RSpec::VERSION
7
+ s.author = 'Adam Beynon'
8
+ s.email = 'adam.beynon@gmail.com'
9
+ s.homepage = 'http://opalrb.org'
10
+ s.summary = 'RSpec for Opal'
11
+ s.description = 'Opal compatible rspec library'
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.files << 'opal/opal/rspec/rspec.js'
15
+
16
+ s.require_paths = ['lib']
17
+
18
+ s.add_dependency 'opal', '~> 0.4.4'
19
+ s.add_dependency 'opal-sprockets', '~> 0.2.0'
20
+
21
+ s.add_development_dependency 'rake'
22
+ end
23
+
@@ -0,0 +1 @@
1
+ require 'opal/rspec'
@@ -0,0 +1,21 @@
1
+ require 'file'
2
+ require 'dir'
3
+ require 'thread'
4
+
5
+ # vendor a pre-built rspec
6
+ require 'opal/rspec/rspec'
7
+
8
+ require 'opal/rspec/fixes'
9
+ require 'opal/rspec/text_formatter'
10
+ require 'opal/rspec/browser_formatter'
11
+ require 'opal/rspec/runner'
12
+
13
+ RSpec.configure do |config|
14
+ # For now, always use our custom formatter for results
15
+ config.formatter = Opal::RSpec::Runner.default_formatter
16
+
17
+ # Always support expect() and .should syntax (we should not do this really..)
18
+ config.expect_with :rspec do |c|
19
+ c.syntax = [:should, :expect]
20
+ end
21
+ end
@@ -0,0 +1,194 @@
1
+ module Opal
2
+ module RSpec
3
+ class BrowserFormatter < ::RSpec::Core::Formatters::BaseFormatter
4
+
5
+ def start(example_count)
6
+ super
7
+
8
+ @summary_element = Element.new(:p, class_name: 'summary', text: 'Runner...')
9
+ @groups_element = Element.new(:ul, class_name: 'example_groups')
10
+
11
+ target = Element.new(`document.body`)
12
+ target << @summary_element
13
+ target << @groups_element
14
+
15
+ styles = Element.new(:style, type: 'text/css', css_text: CSS_STYLES)
16
+ styles.append_to_head
17
+ end
18
+
19
+ def example_group_started(example_group)
20
+ super
21
+
22
+ @example_group_failed = false
23
+ @group_element = Element.new(:li, class_name: 'group passed')
24
+
25
+ description = Element.new(:span, class_name: 'group_description', text: example_group.description)
26
+ @group_element << description
27
+
28
+ @example_list = Element.new(:ul, class_name: 'examples')
29
+ @group_element << @example_list
30
+
31
+ @groups_element << @group_element
32
+ end
33
+
34
+ def example_group_finished(example_group)
35
+ super
36
+
37
+ if @example_group_failed
38
+ @group_element.class_name = 'group failed'
39
+ end
40
+ end
41
+
42
+ def example_failed(example)
43
+ super
44
+
45
+ @example_group_failed = true
46
+
47
+ error = example.execution_result[:exception]
48
+ error_name = error.class.name.to_s
49
+ output = "#{short_padding}#{error_name}:\n"
50
+ error.message.to_s.split("\n").each { |line| output += "#{long_padding} #{line}\n" }
51
+
52
+ wrapper = Element.new(:li, class_name: 'example failed')
53
+
54
+ description = Element.new(:span, class_name: 'example_description', text: example.description)
55
+ wrapper << description
56
+
57
+ exception = Element.new(:pre, class_name: 'exception', text: output)
58
+ wrapper << exception
59
+
60
+ @example_list << wrapper
61
+ @example_list.style :display, 'list-item'
62
+ end
63
+
64
+ def example_passed(example)
65
+ super
66
+
67
+ wrapper = Element.new(:li, class_name: 'example passed')
68
+ description = Element.new(:span, class_name: 'example_description', text: example.description)
69
+
70
+ wrapper << description
71
+ @example_list << wrapper
72
+ end
73
+
74
+ def dump_summary(duration, example_count, failure_count, pending_count)
75
+ super
76
+
77
+ summary = "\n#{example_count} examples, #{failure_count} failures (time taken: #{duration})"
78
+ @summary_element.text = summary
79
+ end
80
+
81
+ def short_padding
82
+ ' '
83
+ end
84
+
85
+ def long_padding
86
+ ' '
87
+ end
88
+
89
+ class Element
90
+ attr_reader :native
91
+
92
+ def initialize(el, attrs={})
93
+ if String === el
94
+ @native = `document.createElement(el)`
95
+ else
96
+ @native = el
97
+ end
98
+
99
+ attrs.each { |name, val| __send__ "#{name}=", val }
100
+ end
101
+
102
+ def class_name=(name)
103
+ `#@native.className = #{name}`
104
+ end
105
+
106
+ def html=(html)
107
+ `#@native.innerHTML = #{html}`
108
+ end
109
+
110
+ def text=(text)
111
+ self.html = text.gsub(/</, '&lt').gsub(/>/, '&gt')
112
+ end
113
+
114
+ def type=(type)
115
+ `#@native.type = #{type}`
116
+ end
117
+
118
+ def append(child)
119
+ `#@native.appendChild(#{child.native})`
120
+ end
121
+
122
+ alias << append
123
+
124
+ def css_text=(text)
125
+ %x{
126
+ if (#@native.styleSheet) {
127
+ #@native.styleSheet.cssText = #{text};
128
+ }
129
+ else {
130
+ #@native.appendChild(document.createTextNode(#{text}));
131
+ }
132
+ }
133
+ end
134
+
135
+ def style(name, value)
136
+ `#@native.style[#{name}] = value`
137
+ end
138
+
139
+ def append_to_head
140
+ `document.getElementsByTagName('head')[0].appendChild(#@native)`
141
+ end
142
+ end
143
+
144
+ CSS_STYLES = <<-EOF
145
+ body {
146
+ font-size: 14px;
147
+ font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
148
+ }
149
+
150
+ pre {
151
+ font-family: "Bitstream Vera Sans Mono", Monaco, "Lucida Console", monospace;
152
+ font-size: 12px;
153
+ color: #444444;
154
+ white-space: pre;
155
+ padding: 3px 0px 3px 12px;
156
+ margin: 0px 0px 8px;
157
+
158
+ background: #FAFAFA;
159
+ -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
160
+ -webkit-border-radius: 3px;
161
+ -moz-border-radius: 3px;
162
+ border-radius: 3px;
163
+ border: 1px solid #DDDDDD;
164
+ }
165
+
166
+ ul.example_groups {
167
+ list-style-type: none;
168
+ }
169
+
170
+ li.group.passed .group_description {
171
+ color: #597800;
172
+ font-weight: bold;
173
+ }
174
+
175
+ li.group.failed .group_description {
176
+ color: #FF000E;
177
+ font-weight: bold;
178
+ }
179
+
180
+ li.example.passed {
181
+ color: #597800;
182
+ }
183
+
184
+ li.example.failed {
185
+ color: #FF000E;
186
+ }
187
+
188
+ .examples {
189
+ list-style-type: none;
190
+ }
191
+ EOF
192
+ end
193
+ end
194
+ end