gusto 1.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/gusto +28 -0
- data/lib/HtmlReport.coffee +63 -0
- data/lib/Spec/DSL.coffee +119 -0
- data/lib/Spec/DelayedExpectation.coffee +61 -0
- data/lib/Spec/Matchers.coffee +69 -0
- data/lib/Spec/MethodStub/PossibleCall.coffee +81 -0
- data/lib/Spec/MethodStub.coffee +55 -0
- data/lib/Spec/MockObject.coffee +6 -0
- data/lib/Spec/ObjectDSL.coffee +26 -0
- data/lib/Spec/Report.coffee +23 -0
- data/lib/Spec/Suite.coffee +30 -0
- data/lib/Spec/Test.coffee +21 -0
- data/lib/Spec/Util.coffee +86 -0
- data/lib/Spec.coffee +62 -0
- data/lib/gusto/runner.rb +40 -0
- data/lib/gusto/server.rb +34 -0
- data/lib/gusto/version.rb +3 -0
- data/lib/gusto.rb +162 -0
- data/public/ie.js +5 -0
- data/public/jquery-1.5.2.js +8374 -0
- data/public/jsdiff.js +161 -0
- data/public/stacktrace.js +446 -0
- data/views/index.slim +19 -0
- metadata +180 -0
data/lib/Spec.coffee
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#= require Spec/Util
|
2
|
+
#= require Spec/Test
|
3
|
+
#= require Spec/Suite
|
4
|
+
#= require Spec/Report
|
5
|
+
#= require Spec/ObjectDSL
|
6
|
+
#= require Spec/DSL
|
7
|
+
#= require Spec/Matchers
|
8
|
+
#= require Spec/MethodStub
|
9
|
+
#= require Spec/MethodStub/PossibleCall
|
10
|
+
#= require Spec/DelayedExpectation
|
11
|
+
#= require Spec/MockObject
|
12
|
+
|
13
|
+
# Seaweed Coffeescript spec framework
|
14
|
+
|
15
|
+
window.Spec ||= {}
|
16
|
+
|
17
|
+
class window.Spec.ExpectationError extends Error
|
18
|
+
constructor: (@message) ->
|
19
|
+
|
20
|
+
class window.Spec.PendingError extends Error
|
21
|
+
constructor: (@message) ->
|
22
|
+
@status = Spec.Report.Pending
|
23
|
+
|
24
|
+
Spec.Util.extend window.Spec,
|
25
|
+
environmentExtended: false
|
26
|
+
suites: []
|
27
|
+
root: window
|
28
|
+
|
29
|
+
# Executes a test case
|
30
|
+
describe: (title, definition) ->
|
31
|
+
@extendEnvironment() unless @environmentExtended
|
32
|
+
suite = new Spec.Suite(title, definition)
|
33
|
+
suite.load window
|
34
|
+
@suites.push suite
|
35
|
+
|
36
|
+
# Extends a class or instance with object DSL
|
37
|
+
extend: (objects...) ->
|
38
|
+
for object in objects
|
39
|
+
Spec.Util.extend object, Spec.ObjectDSL
|
40
|
+
Spec.Util.extend object.prototype, Spec.ObjectDSL if object.prototype
|
41
|
+
|
42
|
+
# Extends the environment with test methods
|
43
|
+
extendEnvironment: ->
|
44
|
+
@environmentExtended = true
|
45
|
+
|
46
|
+
Spec.Util.extend(@root,
|
47
|
+
Spec.DSL,
|
48
|
+
Spec.Matchers
|
49
|
+
)
|
50
|
+
|
51
|
+
@extend(
|
52
|
+
Array,
|
53
|
+
Boolean,
|
54
|
+
Date,
|
55
|
+
Function,
|
56
|
+
Number,
|
57
|
+
RegExp,
|
58
|
+
String,
|
59
|
+
Element,
|
60
|
+
jQuery,
|
61
|
+
Spec.MockObject
|
62
|
+
)
|
data/lib/gusto/runner.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
|
4
|
+
module Gusto
|
5
|
+
class Runner
|
6
|
+
def load_gusto
|
7
|
+
require File.join(File.dirname(__FILE__), '..', 'gusto')
|
8
|
+
Gusto.load_configuration
|
9
|
+
Gusto.port = @port
|
10
|
+
end
|
11
|
+
|
12
|
+
def load_gusto_version
|
13
|
+
require File.join(File.dirname(__FILE__), '..', 'gusto', 'version')
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize mode, options={}, parser=nil
|
17
|
+
@port = options[:port] || 4567
|
18
|
+
|
19
|
+
if options[:version]
|
20
|
+
load_gusto_version
|
21
|
+
puts "Gusto Version #{Gusto::VERSION}"
|
22
|
+
else
|
23
|
+
case mode
|
24
|
+
when 's', 'server'
|
25
|
+
puts "Starting gusto server at http://127.0.0.1:#{@port}/"
|
26
|
+
load_gusto
|
27
|
+
Gusto.server
|
28
|
+
when 'c', 'cli'
|
29
|
+
load_gusto
|
30
|
+
Gusto.cli
|
31
|
+
when 'a', 'auto'
|
32
|
+
load_gusto
|
33
|
+
Gusto.autotest
|
34
|
+
else
|
35
|
+
puts parser || "Unknown mode “#{mode}”"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/gusto/server.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'sinatra'
|
4
|
+
require 'sass'
|
5
|
+
require 'slim'
|
6
|
+
require 'coffee-script'
|
7
|
+
require File.expand_path(File.dirname(__FILE__) + '/../gusto')
|
8
|
+
|
9
|
+
module Gusto
|
10
|
+
class Server < Sinatra::Application
|
11
|
+
# Configure paths
|
12
|
+
set :public_folder, ROOT + '/public'
|
13
|
+
set :views, ROOT + '/views'
|
14
|
+
|
15
|
+
# Configure slim for prettier code formatting
|
16
|
+
Slim::Engine.set_default_options :pretty => true
|
17
|
+
|
18
|
+
# Hide redundant log messages
|
19
|
+
disable :logging
|
20
|
+
|
21
|
+
# Processes request for page index
|
22
|
+
get "/" do
|
23
|
+
# Fetch list of all specification files in specs path
|
24
|
+
@scripts = []
|
25
|
+
Gusto.specs.each do |path|
|
26
|
+
Dir["#{Gusto::PROJECT_ROOT}/#{path}/**/*spec.coffee"].each do |file|
|
27
|
+
@scripts << $1 if file.match Regexp.new("^#{Regexp.escape Gusto::PROJECT_ROOT}\\/#{Regexp.escape path}\\/(.*).coffee$")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
render :slim, :index
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/gusto.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'sprockets'
|
5
|
+
require 'net/http'
|
6
|
+
require 'rack'
|
7
|
+
require 'json'
|
8
|
+
require File.join(File.dirname(__FILE__), 'gusto', 'version')
|
9
|
+
|
10
|
+
module Gusto
|
11
|
+
ROOT = File.expand_path File.join(File.dirname(__FILE__), '..')
|
12
|
+
PROJECT_ROOT = File.expand_path "."
|
13
|
+
|
14
|
+
CONFIG_PATHS = [
|
15
|
+
File.join(PROJECT_ROOT, 'gusto.json'),
|
16
|
+
File.join(PROJECT_ROOT, 'config', 'gusto.json')
|
17
|
+
]
|
18
|
+
|
19
|
+
@configuration = {}
|
20
|
+
|
21
|
+
class << self
|
22
|
+
|
23
|
+
def load_configuration
|
24
|
+
# Set configuration defaults
|
25
|
+
@configuration['port'] = 4567
|
26
|
+
@configuration['lib_paths'] = %w(lib)
|
27
|
+
@configuration['spec_paths'] = %w(spec)
|
28
|
+
|
29
|
+
# Load custom configuration file
|
30
|
+
CONFIG_PATHS.each do |path|
|
31
|
+
if File.exists? path
|
32
|
+
@configuration.merge! JSON.parse(File.read(path))
|
33
|
+
puts "Loaded configuration from “#{path}”"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def port
|
39
|
+
@configuration['port']
|
40
|
+
end
|
41
|
+
|
42
|
+
def port= value
|
43
|
+
@configuration['port'] = value
|
44
|
+
end
|
45
|
+
|
46
|
+
def root_url
|
47
|
+
"http://localhost:#{port}/"
|
48
|
+
end
|
49
|
+
|
50
|
+
def libs
|
51
|
+
@configuration['lib_paths']
|
52
|
+
end
|
53
|
+
|
54
|
+
def specs
|
55
|
+
@configuration['spec_paths']
|
56
|
+
end
|
57
|
+
|
58
|
+
def all_paths
|
59
|
+
libs + specs
|
60
|
+
end
|
61
|
+
|
62
|
+
def server
|
63
|
+
trap_sigint
|
64
|
+
spawn_server
|
65
|
+
Process.waitall
|
66
|
+
end
|
67
|
+
|
68
|
+
def cli
|
69
|
+
trap_sigint
|
70
|
+
spawn_server
|
71
|
+
result = run_suite
|
72
|
+
shut_down(result ? 0 : 1)
|
73
|
+
end
|
74
|
+
|
75
|
+
def autotest
|
76
|
+
trap_sigint
|
77
|
+
spawn_server
|
78
|
+
run_suite
|
79
|
+
watch_for_changes
|
80
|
+
Process.waitall
|
81
|
+
end
|
82
|
+
|
83
|
+
# Prepares a Sprockets::Environment object to serve coffeescript assets
|
84
|
+
def sprockets_environment
|
85
|
+
@environment ||= Sprockets::Environment.new.tap do |environment|
|
86
|
+
environment.append_path File.join(ROOT, 'lib')
|
87
|
+
environment.append_path File.join(ROOT, 'assets')
|
88
|
+
all_paths.each do |path|
|
89
|
+
environment.append_path path
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def start_server
|
95
|
+
app = Rack::Builder.app do
|
96
|
+
map '/assets' do
|
97
|
+
run Gusto::sprockets_environment
|
98
|
+
end
|
99
|
+
|
100
|
+
map '/' do
|
101
|
+
run Gusto::Server
|
102
|
+
end
|
103
|
+
end
|
104
|
+
Rack::Handler.default.run app, :Port => port
|
105
|
+
end
|
106
|
+
|
107
|
+
def spawn_server
|
108
|
+
@server = Process.fork{ $0 = 'gusto server'; start_server }
|
109
|
+
wait_for_server_at(root_url)
|
110
|
+
end
|
111
|
+
|
112
|
+
def run_suite
|
113
|
+
if @browser
|
114
|
+
@browser.navigate.refresh
|
115
|
+
else
|
116
|
+
require 'selenium/webdriver'
|
117
|
+
@browser = Selenium::WebDriver.for :firefox, profile: Selenium::WebDriver::Firefox::Profile.new
|
118
|
+
@browser.get "#{root_url}#terminal"
|
119
|
+
end
|
120
|
+
result = @browser[css: '.results'].text
|
121
|
+
puts result
|
122
|
+
!!result.match('passed, 0 failed')
|
123
|
+
end
|
124
|
+
|
125
|
+
def watch_for_changes
|
126
|
+
require 'listen'
|
127
|
+
|
128
|
+
@listener = Listen.to(PROJECT_ROOT)
|
129
|
+
|
130
|
+
# Match .coffee files in any project paths
|
131
|
+
@listener.filter Regexp.new('^(' + all_paths.map{ |s| Regexp.escape s}.join('|') + ')\/.*\.coffee$')
|
132
|
+
|
133
|
+
@listener.change { run_suite }
|
134
|
+
@listener.start false
|
135
|
+
end
|
136
|
+
|
137
|
+
def shut_down(status=0)
|
138
|
+
@listener.stop if @listener
|
139
|
+
@browser.close if @browser
|
140
|
+
Process.kill 'TERM', @server if @server
|
141
|
+
exit status
|
142
|
+
end
|
143
|
+
|
144
|
+
def trap_sigint
|
145
|
+
trap('SIGINT') do
|
146
|
+
puts "Shutting down..."
|
147
|
+
shut_down
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def wait_for_server_at(url)
|
154
|
+
page = Net::HTTP.get URI.parse(url)
|
155
|
+
rescue Errno::ECONNREFUSED
|
156
|
+
sleep 1
|
157
|
+
retry
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
require File.expand_path(File.dirname(__FILE__) + '/gusto/server')
|