snapdragon 0.1.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.
@@ -0,0 +1,72 @@
1
+ module Snapdragon
2
+ class SpecFile
3
+ def initialize(path, line_number = nil)
4
+ @path = path
5
+ @line_number = line_number
6
+ end
7
+
8
+ def read
9
+ f = File.open(@path, 'r')
10
+ content = f.read
11
+ f.close
12
+ return content
13
+ end
14
+
15
+ def require_paths
16
+ f = File.open(@path, 'r')
17
+ lines = f.readlines
18
+ f.close
19
+
20
+ require_paths = []
21
+
22
+ lines.each do |line|
23
+ if line =~ /\/\/+\s+require_relative\(['"](.+)['"]\)\s+$/
24
+ require_paths << File.expand_path(File.join(File.dirname(@path), $1))
25
+ end
26
+ end
27
+
28
+ return require_paths
29
+ end
30
+
31
+ def filtered?
32
+ return true if @line_number
33
+ return false
34
+ end
35
+
36
+ def spec_query_param
37
+ return '' if !filtered?
38
+
39
+ # Work our way from the line number up to build the spec query param
40
+ # description
41
+ initial_line_number = @line_number
42
+ initial_line_index = initial_line_number - 1
43
+
44
+ f = open(@path, 'r')
45
+ lines = f.readlines
46
+ f.close
47
+
48
+ desc_components = []
49
+
50
+ already_been_inside_an_it = false
51
+ already_been_inside_a_describe = false
52
+ last_describe_indent_spaces = 1232131312
53
+
54
+ cur_line_index = initial_line_index
55
+ while cur_line_index >= 0
56
+ if lines[cur_line_index] =~ /it\s*\(\s*"(.+)"\s*,/ && !already_been_inside_an_it && !already_been_inside_a_describe # line matches it statement
57
+ desc_components.push($1)
58
+ already_been_inside_an_it = true
59
+ elsif lines[cur_line_index] =~ /(\s*)describe\s*\(\s*"(.+)"\s*,/ # line matches a describe block
60
+ if $1.length < last_describe_indent_spaces # use indent depth to identify parent
61
+ desc_components.push($2)
62
+ last_describe_indent_spaces = $1.length
63
+ end
64
+ already_been_inside_a_describe = true
65
+ end
66
+ cur_line_index -= 1
67
+ end
68
+
69
+ return desc_components.reverse.join(" ")
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,47 @@
1
+ module Snapdragon
2
+ class Suite
3
+ def initialize
4
+ @specs = []
5
+ @require_paths = Set.new
6
+ @filtered = false
7
+ @spec_query_param = ''
8
+ end
9
+
10
+ def add_spec_file(spec_file)
11
+ if spec_file.filtered?
12
+ @filtered = true
13
+ @spec_query_param = spec_file.spec_query_param
14
+ end
15
+ @specs << spec_file
16
+ @require_paths.merge(spec_file.require_paths)
17
+ end
18
+
19
+ def add_spec_files(spec_files)
20
+ spec_files.each do |spec|
21
+ add_spec_file(spec)
22
+ end
23
+ end
24
+
25
+ def spec_files
26
+ @specs
27
+ end
28
+
29
+ def output_spec_dependencies
30
+ require_content = ""
31
+ @require_paths.each do |require_path|
32
+ f = File.open(require_path, 'r')
33
+ require_content << f.read
34
+ f.close
35
+ end
36
+ return require_content
37
+ end
38
+
39
+ def spec_query_param
40
+ @spec_query_param
41
+ end
42
+
43
+ def filtered?
44
+ @filtered
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ module Snapdragon
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE HTML>
2
+
3
+ <html>
4
+ <head>
5
+ </head>
6
+ <body>
7
+
8
+ <%= yield %>
9
+
10
+ </body>
11
+ </html>
@@ -0,0 +1,27 @@
1
+ <link rel="stylesheet" type="text/css" href="/jasmine-core/jasmine.css">
2
+ <script type="text/javascript" src="/jasmine-core/jasmine.js"></script>
3
+ <script type="text/javascript" src="/jasmine-core/jasmine-html.js"></script>
4
+
5
+ <script type="text/javascript" src="/resources/ConsoleReporter.js"></script>
6
+
7
+ <script type="text/javascript" src="/jasmine-core/boot.js"></script>
8
+
9
+ <script type="text/javascript">
10
+ // standard jasmine code to add console reporter in the jasmine runner
11
+ var env = jasmine.getEnv();
12
+ var consoleReporterFunc = getJasmineRequireObj().ConsoleReporter();
13
+ var consoleReporter = new consoleReporterFunc({});
14
+ env.addReporter(consoleReporter);
15
+ </script>
16
+
17
+ <script type="text/javascript">
18
+ // The implementation code the spec files being tested need
19
+ <%= @suite.output_spec_dependencies %>
20
+ </script>
21
+
22
+ <script type="text/javascript">
23
+ // The spec file contents
24
+ <% @suite.spec_files.each do |spec| %>
25
+ <%= spec.read %>
26
+ <% end %>
27
+ </script>
@@ -0,0 +1,26 @@
1
+ require 'sinatra/base'
2
+ require 'erb'
3
+
4
+ module Snapdragon
5
+ class WebApplication < Sinatra::Base
6
+ set :static, false
7
+ set :root, File.expand_path('.', File.dirname(__FILE__))
8
+
9
+ def initialize(app = nil, suite)
10
+ super()
11
+ @suite = suite
12
+ end
13
+
14
+ get "/run" do
15
+ erb :run
16
+ end
17
+
18
+ get "/jasmine-core/*" do |path|
19
+ send_file File.expand_path(File.join('../jasmine/lib/jasmine-core', path), File.dirname(__FILE__))
20
+ end
21
+
22
+ get "/resources/*" do |path|
23
+ send_file File.expand_path(File.join('resources', path), File.dirname(__FILE__))
24
+ end
25
+ end
26
+ end
data/lib/snapdragon.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "snapdragon/version"
2
+
3
+ module Snapdragon
4
+ # Your code goes here...
5
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'snapdragon/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "snapdragon"
8
+ spec.version = Snapdragon::VERSION
9
+ spec.authors = ["Andrew De Ponte"]
10
+ spec.email = ["cyphactor@gmail.com"]
11
+ spec.description = %q{A Jasmine JavaScript test runner that lets you run tests on the command-line similar to RSpec.}
12
+ spec.summary = %q{A command-line Jasmine JavaScript test runner.}
13
+ spec.homepage = "http://github.com/reachlocal/snapdragon"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "capybara", "~> 2.1.0"
22
+ spec.add_dependency "poltergeist", "~> 1.3.0"
23
+ spec.add_dependency "sinatra", "~> 1.4.3"
24
+ spec.add_dependency "launchy", "~> 2.3.0"
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec", "~> 2.13.0"
28
+ end
@@ -0,0 +1,221 @@
1
+ require_relative '../../../lib/snapdragon/cli_application'
2
+
3
+ describe Snapdragon::CliApplication do
4
+ describe "#initialize" do
5
+ it "stores a copy of the given command line arguments" do
6
+ cmd_line_args = stub('command_line_args')
7
+ cli_app = Snapdragon::CliApplication.new(cmd_line_args)
8
+ cli_app.instance_variable_get(:@args).should eq(cmd_line_args)
9
+ end
10
+
11
+ it "creates an empty Suite" do
12
+ Snapdragon::Suite.should_receive(:new)
13
+ Snapdragon::CliApplication.new(stub)
14
+ end
15
+
16
+ it "assigns the new Suite to an instance variable" do
17
+ suite = stub('suite')
18
+ Snapdragon::Suite.stub(:new).and_return(suite)
19
+ app = Snapdragon::CliApplication.new(stub)
20
+ app.instance_variable_get(:@suite).should eq(suite)
21
+ end
22
+ end
23
+
24
+ describe "#run" do
25
+ it "parses the given command line arguements" do
26
+ arguements = stub
27
+ app = Snapdragon::CliApplication.new(arguements)
28
+ app.should_receive(:parse_arguements).with(arguements)
29
+ app.stub(:run_suite)
30
+ app.run
31
+ end
32
+
33
+ it "runs the Jasmine suite" do
34
+ app = Snapdragon::CliApplication.new(['/some/path/to_some_spec.js'])
35
+ app.stub(:parse_arguements)
36
+ app.should_receive(:run_suite)
37
+ app.run
38
+ end
39
+
40
+ it "returns 0 representing success" do
41
+ app = Snapdragon::CliApplication.new(['/some/path/to_some_spec.js'])
42
+ app.stub(:parse_arguements)
43
+ app.stub(:run_suite)
44
+ app.run.should eq(0)
45
+ end
46
+ end
47
+
48
+ describe "#parse_arguements" do
49
+ let(:arguements) { ['some/path/to/some_spec.js:23', 'some/path/to/some_other_spec.js'] }
50
+ subject { Snapdragon::CliApplication.new(arguements) }
51
+
52
+ it "iterates over each of the arguments parsing each one" do
53
+ subject.should_receive(:parse_arguement).with('some/path/to/some_spec.js:23')
54
+ subject.should_receive(:parse_arguement).with('some/path/to/some_other_spec.js')
55
+ subject.send(:parse_arguements, arguements)
56
+ end
57
+ end
58
+
59
+ describe "#parse_arguement" do
60
+ subject { Snapdragon::CliApplication.new(stub) }
61
+
62
+ context "when the arg represents a file + line number" do
63
+ before do
64
+ subject.stub(:is_a_file_path_and_line_number?).and_return(true)
65
+ end
66
+
67
+ it "creates a SpecFile with the specified path and line number" do
68
+ Snapdragon::SpecFile.should_receive(:new).with('some/path/to/some_spec.js', 45).and_return(stub.as_null_object)
69
+ subject.send(:parse_arguement, 'some/path/to/some_spec.js:45')
70
+ end
71
+
72
+ it "appends the created SpecFile to the applications Suite" do
73
+ spec_file = stub('spec_file')
74
+ suite = mock('suite')
75
+ subject.instance_variable_set(:@suite, suite)
76
+ Snapdragon::SpecFile.stub(:new).and_return(spec_file)
77
+ suite.should_receive(:add_spec_file).with(spec_file)
78
+ subject.send(:parse_arguement, 'some/path/to/some_spec.js:45')
79
+ end
80
+ end
81
+
82
+ context "when the arg represents a file without a line number" do
83
+ before do
84
+ subject.stub(:is_a_file_path_and_line_number?).and_return(false)
85
+ subject.stub(:is_a_file_path?).and_return(true)
86
+ end
87
+
88
+ it "creates a SpecFile object with the specified path" do
89
+ Snapdragon::SpecFile.should_receive(:new).with('some/path/to/some_spec.js').and_return(stub.as_null_object)
90
+ subject.send(:parse_arguement, 'some/path/to/some_spec.js')
91
+ end
92
+
93
+ it "appends the created SpecFile to the application Suite" do
94
+ spec_file = stub('spec_file')
95
+ suite = mock('suite')
96
+ subject.instance_variable_set(:@suite, suite)
97
+ Snapdragon::SpecFile.stub(:new).and_return(spec_file)
98
+ suite.should_receive(:add_spec_file).with(spec_file)
99
+ subject.send(:parse_arguement, 'some/path/to/some_spec.js')
100
+ end
101
+ end
102
+
103
+ context "when the arg respesents a directory" do
104
+ before do
105
+ subject.stub(:is_a_file_path_and_line_number?).and_return(false)
106
+ subject.stub(:is_a_file_path?).and_return(false)
107
+ subject.stub(:is_a_directory?).and_return(true)
108
+ end
109
+
110
+ it "creates a SpecDirectory with the given directory path" do
111
+ Snapdragon::SpecDirectory.should_receive(:new).with('some/path/to/some_directory').and_return(stub(:spec_files => []))
112
+ subject.send(:parse_arguement, 'some/path/to/some_directory')
113
+ end
114
+
115
+ it "gets all of the SpecFiles recursively identified in the SpecDirectory path" do
116
+ spec_dir = mock
117
+ Snapdragon::SpecDirectory.stub(:new).and_return(spec_dir)
118
+ spec_dir.should_receive(:spec_files).and_return([])
119
+ subject.send(:parse_arguement, 'some/path/to/some_directory')
120
+ end
121
+
122
+ it "appends the SpecFiles to the application Suite" do
123
+ spec_dir = stub('spec_dir')
124
+ spec_files = stub('spec_files')
125
+ suite = mock('suite')
126
+ subject.instance_variable_set(:@suite, suite)
127
+ Snapdragon::SpecDirectory.stub(:new).and_return(spec_dir)
128
+ spec_dir.stub(:spec_files).and_return(spec_files)
129
+ suite.should_receive(:add_spec_files).with(spec_files)
130
+ subject.send(:parse_arguement, 'some/path/to/some_directory')
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "#is_a_file_path_and_line_number?" do
136
+ let(:arguements) { stub('arguments') }
137
+ subject { Snapdragon::CliApplication.new(arguements) }
138
+
139
+ context "when it matches the pattern of a file path and line number" do
140
+ it "returns true" do
141
+ subject.send(:is_a_file_path_and_line_number?, 'some/path/to/some_spec.js:534').should be_true
142
+ end
143
+ end
144
+
145
+ context "when it does NOT match the pattern of a file path and line number" do
146
+ it "returns false" do
147
+ subject.send(:is_a_file_path_and_line_number?, 'some/path/to/some_spec.js').should be_false
148
+ end
149
+ end
150
+ end
151
+
152
+ describe "#is_a_file_path?" do
153
+ let(:arguements) { stub('arguments') }
154
+ subject { Snapdragon::CliApplication.new(arguements) }
155
+
156
+ context "when it matches the pattern of a file path" do
157
+ it "returns true" do
158
+ subject.send(:is_a_file_path?, 'some/path/to/some_spec.js').should be_true
159
+ end
160
+ end
161
+
162
+ context "when it does NOT match the pattern of a file path" do
163
+ it "returns false" do
164
+ subject.send(:is_a_file_path?, 'some/path/to/some.js').should be_false
165
+ end
166
+ end
167
+ end
168
+
169
+ describe "#is_a_directory?" do
170
+ let(:arguements) { stub('arguments') }
171
+ subject { Snapdragon::CliApplication.new(arguements) }
172
+
173
+ context "when it matches the pattern of a directory path" do
174
+ it "returns true" do
175
+ subject.send(:is_a_directory?, 'some/path/to/some_directory').should be_true
176
+ end
177
+ end
178
+
179
+ context "when it does NOT match the pattern of a directory path" do
180
+ it "returns false" do
181
+ subject.send(:is_a_directory?, 'some/path/to/some_spec.js').should be_false
182
+ end
183
+ end
184
+ end
185
+
186
+ describe "#run_suite" do
187
+ let(:arguements) { stub('arguments') }
188
+ subject { Snapdragon::CliApplication.new(arguements) }
189
+
190
+ it "creates a capybara session" do
191
+ Capybara::Session.should_receive(:new).and_return(stub.as_null_object)
192
+ subject.send(:run_suite)
193
+ end
194
+
195
+ context "when suite is filtered" do
196
+ before do
197
+ subject.instance_variable_set(:@suite, stub(:filtered? => true, :spec_query_param => 'some_query_param_spec_filter'))
198
+ end
199
+
200
+ it "visits /run with the spec query param in the capybara session" do
201
+ session = mock
202
+ Capybara::Session.stub(:new).and_return(session)
203
+ session.should_receive(:visit).with("/run?spec=some_query_param_spec_filter")
204
+ subject.send(:run_suite)
205
+ end
206
+ end
207
+
208
+ context "when suite is NOT filtered" do
209
+ before do
210
+ subject.instance_variable_set(:@suite, stub(:filtered? => false))
211
+ end
212
+
213
+ it "visits /run in that capybara session" do
214
+ session = mock
215
+ Capybara::Session.stub(:new).and_return(session)
216
+ session.should_receive(:visit).with('/run')
217
+ subject.send(:run_suite)
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,14 @@
1
+ require_relative '../../../lib/snapdragon/spec_directory'
2
+
3
+ describe Snapdragon::SpecDirectory do
4
+ describe "#initialize" do
5
+ it "assigns the given directory path" do
6
+ spec_dir = Snapdragon::SpecDirectory.new('some/directory/path')
7
+ spec_dir.instance_variable_get(:@path).should eq('some/directory/path')
8
+ end
9
+ end
10
+
11
+ describe "#spec_files" do
12
+ it "needs to be tested"
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+ require_relative "../../../lib/snapdragon/spec_file"
2
+
3
+ describe Snapdragon::SpecFile do
4
+ describe "#initialize" do
5
+ it "assigns the given path" do
6
+ spec_file = Snapdragon::SpecFile.new('some/path/to_some_spec.js')
7
+ spec_file.instance_variable_get(:@path).should eq('some/path/to_some_spec.js')
8
+ end
9
+
10
+ it "assigns the given line number" do
11
+ spec_file = Snapdragon::SpecFile.new('some/path/to_some_spec.js', 54)
12
+ spec_file.instance_variable_get(:@line_number).should eq(54)
13
+ end
14
+
15
+ it "line number defaults to nil when not assigned" do
16
+ spec_file = Snapdragon::SpecFile.new('some/path/to_some_spec.js')
17
+ spec_file.instance_variable_get(:@line_number).should eq(nil)
18
+ end
19
+ end
20
+
21
+ describe "#read" do
22
+ it "needs to be tested"
23
+ end
24
+
25
+ describe "#require_paths" do
26
+ it "needs to be tested"
27
+ end
28
+
29
+ describe "#filtered?" do
30
+ it "needs to be tested"
31
+ end
32
+
33
+ describe "#spec_query_param" do
34
+ it "needs to be tested"
35
+ end
36
+ end
@@ -0,0 +1,111 @@
1
+ require_relative '../../../lib/snapdragon/suite'
2
+
3
+ describe Snapdragon::Suite do
4
+ describe "#initialize" do
5
+ it "assigns an empty array to hold all the spec files" do
6
+ suite = Snapdragon::Suite.new
7
+ suite.instance_variable_get(:@specs).should eq([])
8
+ end
9
+
10
+ it "assigns an empty set to hold all the require files" do
11
+ suite = Snapdragon::Suite.new
12
+ suite.instance_variable_get(:@require_paths).should be_kind_of(Set)
13
+ end
14
+
15
+ it "assigns @filtered to an initial state of false" do
16
+ suite = Snapdragon::Suite.new
17
+ suite.instance_variable_get(:@filtered).should be_false
18
+ end
19
+
20
+ it "assigns @spec_query_param to an initial state of empty string" do
21
+ suite = Snapdragon::Suite.new
22
+ suite.instance_variable_get(:@spec_query_param).should eq('')
23
+ end
24
+ end
25
+
26
+ describe "#spec_files" do
27
+ it "returns the array of specs which the suite contains" do
28
+ spec_file = stub(:require_paths => [])
29
+ subject.instance_variable_set(:@specs, [spec_file])
30
+ subject.spec_files.should eq([spec_file])
31
+ end
32
+ end
33
+
34
+ describe "#add_spec_file" do
35
+ it "appends the given SpecFile to the suite of specs" do
36
+ spec_file = stub(:require_paths => [], :filtered? => false)
37
+ specs = mock
38
+ subject.instance_variable_set(:@specs, specs)
39
+ specs.should_receive(:<<).with(spec_file)
40
+ subject.add_spec_file(spec_file)
41
+ end
42
+
43
+ it "gets the require paths outlined in the spec" do
44
+ spec_file = mock(:filtered? => false)
45
+ spec_file.should_receive(:require_paths).and_return([])
46
+ subject.add_spec_file(spec_file)
47
+ end
48
+
49
+ it "contactinates the specs require paths to the suites require paths collection" do
50
+ spec_file = stub(:filtered? => false)
51
+ require_paths = stub
52
+ suite_require_paths = mock
53
+ subject.instance_variable_set(:@require_paths, suite_require_paths)
54
+ spec_file.stub(:require_paths).and_return(require_paths)
55
+ suite_require_paths.should_receive(:merge).with(require_paths)
56
+ subject.add_spec_file(spec_file)
57
+ end
58
+
59
+ context "when spec is filtered" do
60
+ it "assigns @filtered to true" do
61
+ spec_file = stub(:require_paths => [], :filtered? => true, :spec_query_param => '')
62
+ subject.add_spec_file(spec_file)
63
+ subject.instance_variable_get(:@filtered).should be_true
64
+ end
65
+
66
+ it "assigns @spec_query_parm to the spec_files spec_query_parma" do
67
+ spec_file = stub(:require_paths => [], :filtered? => true, :spec_query_param => 'some_spec_query_param')
68
+ subject.add_spec_file(spec_file)
69
+ subject.instance_variable_get(:@spec_query_param).should eq('some_spec_query_param')
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "#add_spec_files" do
75
+ it "adds each of the spec files" do
76
+ spec_file_one = stub('spec_file_one')
77
+ spec_file_two = stub('spec_file_two')
78
+ subject.should_receive(:add_spec_file).with(spec_file_one)
79
+ subject.should_receive(:add_spec_file).with(spec_file_two)
80
+ subject.add_spec_files([spec_file_one, spec_file_two])
81
+ end
82
+ end
83
+
84
+ describe "#spec_files" do
85
+ it "returns the internal collection of spec files" do
86
+ specs = stub
87
+ subject.instance_variable_set(:@specs, specs)
88
+ subject.spec_files.should eq(specs)
89
+ end
90
+ end
91
+
92
+ describe "#output_spec_dependencies" do
93
+ it "needs to be tested"
94
+ end
95
+
96
+ describe "#spec_query_param" do
97
+ it "returns the suites spec_query_param" do
98
+ spec_query_param = stub
99
+ subject.instance_variable_set(:@spec_query_param, spec_query_param)
100
+ subject.spec_query_param.should eq(spec_query_param)
101
+ end
102
+ end
103
+
104
+ describe "#filtered?" do
105
+ it "returns the filtered state of the suite" do
106
+ filtered = stub
107
+ subject.instance_variable_set(:@filtered, filtered)
108
+ subject.filtered?.should eq(filtered)
109
+ end
110
+ end
111
+ end
File without changes