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