snapdragon 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 060c173490d27d0726bb3e47791d9aeae29ed196
4
+ data.tar.gz: 2dd3df4162edd3d0fffb0862651c1cfb8a07c2d9
5
+ SHA512:
6
+ metadata.gz: 168b20c3b123901008ec0cbbbdd3320f44a63d3ce3eb3b3df2124d8b0eb20b9f22198e8e6fdcedfe756843d83ba3f06f58f3a0a663d24f8d565e299a0b6458fd
7
+ data.tar.gz: 3d169461aaa8517e85c8a98d8e82c84551aff91529480d0adb02b92d2a3ee6bbb11227c0ebd0d8dc0eb79e60550355e0ddcbfdf97fd439e06f8e15a8fa7c8edc
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "lib/jasmine"]
2
+ path = lib/jasmine
3
+ url = git://github.com/pivotal/jasmine.git
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ snapdragon
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.0.0-p0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jasmine-cl-runner.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andrew De Ponte, ReachLocal, Inc.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,225 @@
1
+ # Snapdragon
2
+
3
+ **A command-line [Jasmine](http://pivotal.github.io/jasmine/) (JavaScript) test runner built with developer workflow in mind.**
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'snapdragon'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install snapdragon
18
+
19
+ ## Install PhantomJS
20
+
21
+ You need at least [PhantomJS](http://phantomjs.org) 1.8.1. There are no other
22
+ external dependencies (you don't need Qt, or a running X server, etc.)
23
+
24
+ ### Mac OS X
25
+
26
+ I recommend installing [PhantomJS](http://phantomjs.org/) using
27
+ [Homebrew](http://mxcl.github.io/homebrew/) on Mac OS X. Using
28
+ [Homebrew](http://mxcl.github.io/homebrew/) it can be installed as easily as
29
+ running the following command:
30
+
31
+ $ brew install phantomjs
32
+
33
+ ## Quick Start Guide
34
+
35
+ For those of you that like to jump right in and start playing with new tools
36
+ follow the steps below to get started.
37
+
38
+ 1. Install [Snapdragon](http://github.com/reachlocal/snapdragon) and
39
+ [PhantomJS](http://phantomjs.org/) as outlined above.
40
+
41
+ 2. Create a simple [Jasmine](http://pivotal.github.io/jasmine/) spec file
42
+ `example/spec/hoopty_spec.js` with the following content. Note: the
43
+ `// require_relative()` directive at the top of the file. This tells
44
+ [Snapdragon](http://github.com/reachlocal/snapdragon) what
45
+ implementation file(s) it needs to run the specs in this file.
46
+
47
+ ```javascript
48
+ // require_relative('../src/hoopty.js')
49
+
50
+ describe("Hoopty", function() {
51
+ describe(".hello", function() {
52
+ it("says hello there", function() {
53
+ var f = new Hoopty();
54
+ expect(f.hello()).toBe("Hello There");
55
+ });
56
+ });
57
+ });
58
+ ```
59
+
60
+ 3. Create the implementation file for the spec file `example/src/hoopty.js`
61
+ with the following content.
62
+
63
+ ```javascript
64
+ var Hoopty = function() {
65
+ this.hello = function() {
66
+ return "Hello There";
67
+ }
68
+ };
69
+ ```
70
+
71
+ 4. Run your spec file with the following command:
72
+
73
+ ```text
74
+ $ snapdragon example/spec/hoopty_spec.js
75
+ ```
76
+
77
+ You should see output that looks similar to the following.
78
+
79
+ ```text
80
+ Running examples...
81
+
82
+ Finished in 0.001 seconds
83
+ 1 example, 0 failures
84
+ ```
85
+
86
+ Thats it, you now have [Snapdragon](http://github.com/reachlocal/snapdragon)
87
+ running a [Jasmine](http://pivotal.github.io/jasmine/) spec.
88
+
89
+ ## Usage (snapdragon)
90
+
91
+ The *snapdragon* command allows you to run your
92
+ [Jasmine](http://pivotal.github.io/jasmine/) specs from the command-line just
93
+ as you would with RSpec and other testing tools. The following are some usage
94
+ examples.
95
+
96
+ #### Run a specific describe/it block
97
+
98
+ The following runs the describe or it block that corresponds to line number
99
+ *23* in the *spec/javascript/foo_spec.js* file.
100
+
101
+ ```
102
+ snapdragon spec/javascript/foo_spec.js:23
103
+ ```
104
+
105
+ #### Run an entire spec file(s)
106
+
107
+ ```
108
+ snapdragon spec/javascript/foo_spec.js spec/javascript/bar_spec.js
109
+ ```
110
+
111
+ #### Run an entire directory of spec files
112
+
113
+ ```
114
+ snapdragon spec/javascripts
115
+ ```
116
+
117
+ #### Run combination of files and directories
118
+
119
+ ```
120
+ snapdragon spec/javascript custom_js/tests/foo_spec.js custom_js/test/bar_spec.js
121
+ ```
122
+
123
+ ## Usage (snapdragon_server)
124
+
125
+ The *snapdragon_server* command allows you to run your
126
+ [Jasmine](http://pivotal.github.io/jasmine/) specs in your browser. When this
127
+ command is run it will launch the *snapdragon_server* and open your default
128
+ browser to the proper URL to run your specified test suite. This is especially
129
+ useful if you want to debug some JavaScript as your browser most likely has a
130
+ JavaScript debugger built into it. A few examples of this commands usage
131
+ follow.
132
+
133
+ #### Run specific spec files
134
+
135
+ ```
136
+ snapdragon_server spec/javascript/foo_spec.js spec/javascript/bar_spec.js
137
+ ```
138
+
139
+ #### Run all the specs in directories
140
+
141
+ ```
142
+ snapdragon_server spec/javascript custom_js/specs
143
+ ```
144
+
145
+ #### Combine files and directories
146
+
147
+ ```
148
+ snapdragon_server spec/javascript custom_js/tests/foo_spec.js custom_js/test/bar_spec.js
149
+ ```
150
+
151
+ ## // require_relative() directive
152
+
153
+ Snapdragon also provides a `// require_relative()` directive that the
154
+ Snapdragon preprocessor looks for to identify the necessary implementation
155
+ files that need to be loaded for the spec files to run. This directive should
156
+ define the relative path to associated implementation files needed for a spec,
157
+ relative to that spec file. The following is an example spec and implemantion
158
+ file.
159
+
160
+ *example/src/hoopty.js*
161
+
162
+ ```javascript
163
+ var Hoopty = function() {
164
+ this.hello = function() {
165
+ return "Hello There";
166
+ }
167
+ };
168
+ ```
169
+
170
+ *example/spec/hoopty_spec.js*
171
+
172
+ ```javascript
173
+ // require_relative('../src/hoopty.js')
174
+
175
+ describe("Hoopty", function() {
176
+ it("exists", function() {
177
+ var f = new Hoopty();
178
+ expect(f).not.toBe(undefined);
179
+ });
180
+
181
+ describe(".hello", function() {
182
+ it("says hello there", function() {
183
+ var f = new Hoopty();
184
+ expect(f.hello()).toBe("Hello There");
185
+ });
186
+ });
187
+ });
188
+
189
+ ```
190
+
191
+ ## The Back Story
192
+
193
+ If you have ever used [Jasmine](http://pivotal.github.io/jasmine/) for your
194
+ JavaScript BDD style testing framework I am sure you have run into the
195
+ following issues just as I have.
196
+
197
+ 1. Getting up and running with [Jasmine](http://pivotal.github.io/jasmine/) is
198
+ quite a pain and the examples of how to setup your SpecRunner.html are
199
+ sparse.
200
+ 2. Having to manually add the dependency files and spec files to the
201
+ SpecRunner.html is a huge pain in the ass.
202
+ 3. Limiting a test run to a specific spec file is near impossible with the
203
+ only solution being to comment out script tags in your SpecRunner.html.
204
+ 4. Limiting a test run to a specific *describe* or *it* block is near
205
+ impossible because the only way to do it is with the *spec* query param that
206
+ matches the full description of the *describe* or *it* block including all
207
+ its parents. This can be very long and very prone to typos if you try to
208
+ do this.
209
+ 5. Oh, and did I mention that you have to do all of this in a browser with the
210
+ SpecRunner.html loaded which is not where you actually write your code.
211
+
212
+ The above issues created a horrible development workflow. Especially
213
+ since I came from the world of RSpec where the above issues are non-existent
214
+ and it is easily run from the command line and integrated into most editors.
215
+
216
+ Snapdragon is my preferred solution to the above listed issues.
217
+
218
+ ## Contributing
219
+
220
+ 1. Fork it
221
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
222
+ 3. Write your tests & dev your feature using BDD/TDD with RSpec.
223
+ 4. Commit your changes (`git commit -am 'Add some feature'`)
224
+ 5. Push to the branch (`git push origin my-new-feature`)
225
+ 6. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV[0].nil?
4
+ exit(1)
5
+ end
6
+
7
+ jspec_file_path, initial_line_number = ARGV[0].split(':')
8
+ if initial_line_number.nil?
9
+ # Run the file without spec query param set
10
+ else
11
+ # Work our way from the line number up to build the spec query param
12
+ # description
13
+ initial_line_number = initial_line_number.to_i
14
+
15
+ initial_line_index = initial_line_number - 1
16
+
17
+ f = open(jspec_file_path, 'r')
18
+ lines = f.readlines
19
+ f.close
20
+
21
+ desc_components = []
22
+
23
+ already_been_inside_an_it = false
24
+ already_been_inside_a_describe = false
25
+ last_describe_indent_spaces = 1232131312
26
+
27
+ cur_line_index = initial_line_index
28
+ while cur_line_index >= 0
29
+ if lines[cur_line_index] =~ /it\s*\(\s*"(.+)"\s*,/ && !already_been_inside_an_it && !already_been_inside_a_describe # line matches it statement
30
+ desc_components.push($1)
31
+ already_been_inside_an_it = true
32
+ elsif lines[cur_line_index] =~ /(\s*)describe\s*\(\s*"(.+)"\s*,/ # line matches a describe block
33
+ if $1.length < last_describe_indent_spaces # use indent depth to identify parent
34
+ desc_components.push($2)
35
+ last_describe_indent_spaces = $1.length
36
+ end
37
+ already_been_inside_a_describe = true
38
+ end
39
+ cur_line_index -= 1
40
+ end
41
+
42
+ puts desc_components.reverse.join(" ")
43
+ end
44
+
45
+
data/bin/snapdragon ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+
5
+ require 'rubygems'
6
+ require 'snapdragon/cli_application'
7
+
8
+ app = Snapdragon::CliApplication.new(ARGV)
9
+ exit(app.run)
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+
5
+ require 'rubygems'
6
+ require 'snapdragon/cli_application'
7
+
8
+ app = Snapdragon::CliApplication.new(ARGV)
9
+ app.serve
@@ -0,0 +1,24 @@
1
+ // require_relative('../src/hoopty.js')
2
+
3
+ // This is just some example Jasmine spec code to test that everything would
4
+ // work assuming that I can find a way to get the spec code loaded in here
5
+ // like this.
6
+ describe("Hoopty", function() {
7
+ it("exists", function() {
8
+ var f = new Hoopty();
9
+ expect(f).not.toBe(undefined);
10
+ });
11
+
12
+ it("handles pending", function() {
13
+ });
14
+
15
+ it("handles another pending", function() {
16
+ });
17
+
18
+ describe(".hello", function() {
19
+ it("says hello there", function() {
20
+ var f = new Hoopty();
21
+ expect(f.hello()).toBe("Hello There");
22
+ });
23
+ });
24
+ });
@@ -0,0 +1,8 @@
1
+ // This is just some test implementation code to test that everything would
2
+ // work assuming that I can find a way to get the implementation code
3
+ // loaded in here like this.
4
+ var Hoopty = function() {
5
+ this.hello = function() {
6
+ return "Hello There";
7
+ }
8
+ };
@@ -0,0 +1,73 @@
1
+ require 'capybara'
2
+ require 'capybara/poltergeist'
3
+ require 'launchy'
4
+
5
+ require_relative './web_application'
6
+ require_relative './suite'
7
+ require_relative './spec_file'
8
+ require_relative './spec_directory'
9
+
10
+ module Snapdragon
11
+ class CliApplication
12
+ def initialize(arguements)
13
+ @args = arguements
14
+ @suite = Snapdragon::Suite.new
15
+ end
16
+
17
+ def run
18
+ parse_arguements(@args)
19
+ run_suite
20
+ return 0
21
+ end
22
+
23
+ def serve
24
+ parse_arguements(@args)
25
+ server = Capybara::Server.new(Snapdragon::WebApplication.new(nil, @suite), 9292)
26
+ server.boot
27
+ Launchy.open('http://localhost:9292/run')
28
+ trap('SIGINT') { puts "Shutting down..."; exit 0 }
29
+ sleep
30
+ end
31
+
32
+ private
33
+
34
+ def parse_arguements(arguements)
35
+ arguements.each do |arguement|
36
+ parse_arguement(arguement)
37
+ end
38
+ end
39
+
40
+ def parse_arguement(arguement)
41
+ if is_a_file_path_and_line_number?(arguement)
42
+ path, line_num_str = arguement.split(':')
43
+ @suite.add_spec_file(SpecFile.new(path, line_num_str.to_i))
44
+ elsif is_a_file_path?(arguement)
45
+ @suite.add_spec_file(SpecFile.new(arguement))
46
+ elsif is_a_directory?(arguement)
47
+ spec_dir = Snapdragon::SpecDirectory.new(arguement)
48
+ @suite.add_spec_files(spec_dir.spec_files)
49
+ end
50
+ end
51
+
52
+ def is_a_file_path_and_line_number?(arguement)
53
+ arguement =~ /^[\w\/\-\d]+[s|S]pec\.js:\d+$/
54
+ end
55
+
56
+ def is_a_file_path?(arguement)
57
+ arguement =~ /^[\w\/\-\d]+[s|S]pec\.js$/
58
+ end
59
+
60
+ def is_a_directory?(arguement)
61
+ arguement =~ /^[\w\/\-\d]+$/
62
+ end
63
+
64
+ def run_suite
65
+ session = Capybara::Session.new(:poltergeist, Snapdragon::WebApplication.new(nil, @suite))
66
+ if @suite.filtered?
67
+ session.visit("/run?spec=#{@suite.spec_query_param}")
68
+ else
69
+ session.visit("/run")
70
+ end
71
+ end
72
+ end
73
+ end
File without changes
@@ -0,0 +1,137 @@
1
+ getJasmineRequireObj().ConsoleReporter = function() {
2
+ function ConsoleReporter(options) {
3
+ var print = function(msg) { console.log(msg); },
4
+ showColors = options.showColors || true,
5
+ onComplete = options.onComplete || function() {},
6
+ specCount,
7
+ failureCount,
8
+ passedCount,
9
+ failedSpecs = [],
10
+ pendingSpecs = [],
11
+ pendingCount,
12
+ ansi = {
13
+ green: '\033[32m',
14
+ red: '\033[31m',
15
+ yellow: '\033[33m',
16
+ none: '\033[0m'
17
+ };
18
+
19
+ this.jasmineStarted = function() {
20
+ specCount = 0;
21
+ failureCount = 0;
22
+ passedCount = 0;
23
+ pendingCount = 0;
24
+ print("Running examples...");
25
+ printNewline();
26
+ };
27
+
28
+ this.jasmineDone = function(options) {
29
+ if (pendingCount > 0) {
30
+ print("Pending:");
31
+ }
32
+
33
+ for (var i = 0; i < pendingSpecs.length; i++) {
34
+ specPendingDetails(pendingSpecs[i]);
35
+ }
36
+
37
+ if (failureCount > 0) {
38
+ print("Failures:");
39
+ printNewline();
40
+ }
41
+
42
+ for (var i = 0; i < failedSpecs.length; i++) {
43
+ specFailureDetails(failedSpecs[i], i + 1);
44
+ }
45
+
46
+ var specCounts = specCount + " " + plural("example", specCount) + ", " + failureCount + " " + plural("failure", failureCount);
47
+
48
+ if (pendingCount) {
49
+ specCounts += ", " + pendingCount + " pending";
50
+ }
51
+
52
+ var seconds = options.executionTime / 1000;
53
+ print("Finished in " + seconds + " " + plural("second", seconds));
54
+
55
+ if (failureCount > 0) { // have any failures
56
+ print(colored("red", specCounts));
57
+ } else if (pendingCount > 0) {
58
+ print(colored("yellow", specCounts));
59
+ } else {
60
+ print(colored("green", specCounts));
61
+ }
62
+
63
+ onComplete();
64
+ };
65
+
66
+ this.specDone = function(result) {
67
+ if (result.status !== "disabled") {
68
+ specCount++;
69
+ }
70
+
71
+ if (result.status == "pending") {
72
+ pendingCount++;
73
+ pendingSpecs.push(result);
74
+ return;
75
+ }
76
+
77
+ if (result.status == "passed") {
78
+ passedCount++;
79
+ return;
80
+ }
81
+
82
+ if (result.status == "failed") {
83
+ failureCount++;
84
+ failedSpecs.push(result);
85
+ return;
86
+ }
87
+ };
88
+
89
+ return this;
90
+
91
+ function printNewline() {
92
+ print("");
93
+ }
94
+
95
+ function colored(color, str) {
96
+ return showColors ? (ansi[color] + str + ansi.none) : str;
97
+ }
98
+
99
+ function plural(str, count) {
100
+ return count == 1 ? str : str + "s";
101
+ }
102
+
103
+ function repeat(thing, times) {
104
+ var arr = [];
105
+ for (var i = 0; i < times; i++) {
106
+ arr.push(thing);
107
+ }
108
+ return arr;
109
+ }
110
+
111
+ function indent(str, spaces) {
112
+ var lines = (str || '').split("\n");
113
+ var newArr = [];
114
+ for (var i = 0; i < lines.length; i++) {
115
+ newArr.push(repeat(" ", spaces).join("") + lines[i]);
116
+ }
117
+ return newArr.join("\n");
118
+ }
119
+
120
+ function specFailureDetails(result, failure_number) {
121
+ print(indent(failure_number + ") " + result.fullName, 2));
122
+
123
+ for (var i = 0; i < result.failedExpectations.length; i++) {
124
+ var failedExpectation = result.failedExpectations[i];
125
+ print(colored("red", indent(failedExpectation.message, 6)));
126
+ }
127
+ printNewline();
128
+ }
129
+
130
+ function specPendingDetails(result) {
131
+ print(indent(colored("yellow", result.fullName), 2));
132
+ printNewline();
133
+ }
134
+ }
135
+
136
+ return ConsoleReporter;
137
+ };
@@ -0,0 +1,19 @@
1
+ require_relative './spec_file'
2
+
3
+ module Snapdragon
4
+ class SpecDirectory
5
+ def initialize(path)
6
+ @path = path
7
+ end
8
+
9
+ def spec_files
10
+ spec_paths = []
11
+ Dir.glob("#{@path}/**/*").each do |path|
12
+ if path =~ /^[\w\/\-\d]+[s|S]pec\.js$/
13
+ spec_paths << Snapdragon::SpecFile.new(path)
14
+ end
15
+ end
16
+ return spec_paths
17
+ end
18
+ end
19
+ end