gaffo-jasmine_webos 0.0.1

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,57 @@
1
+ require 'optparse'
2
+ require 'fileutils'
3
+
4
+ module Jasminewebos
5
+ class CLI
6
+ def self.execute(stdout, arguments=[])
7
+ command = ""
8
+ mandatory_options = %w( )
9
+
10
+ generate = false
11
+ start_server = false
12
+
13
+ parser = OptionParser.new do |opts|
14
+ opts.banner = <<-BANNER.gsub(/^ /,'')
15
+ Tools for working with jasmine_webos
16
+
17
+ Usage:
18
+ #{File.basename($0)} -g
19
+ generates the jasmine files in the current directory
20
+
21
+ #{File.basename($0)} -s
22
+ starts the jasmine server from the current directory
23
+
24
+ Options:
25
+ BANNER
26
+ opts.separator ""
27
+ opts.on("-g", String,
28
+ "Starts the jasmine server from the current directory") { generate = true }
29
+ opts.on("-s", String,
30
+ "Generate the jasmine files in the current directory") { start_server = true }
31
+ opts.on("-h", "--help",
32
+ "Show this help message.") { stdout.puts opts; exit }
33
+ opts.parse!(arguments)
34
+
35
+ if mandatory_options && mandatory_options.find { |option| options[option.to_sym].nil? }
36
+ stdout.puts opts; exit
37
+ end
38
+ end
39
+
40
+ config = Jasminewebos::Configuration.new(FileUtils.pwd)
41
+
42
+ self.generate_stub(config) if generate
43
+ self.launch_server(config) if start_server
44
+
45
+ end
46
+
47
+ def self.generate_stub(config)
48
+ puts("Generating jasmine_webos required files")
49
+ Jasminewebos::Generator.new(config).run
50
+ puts(" Complete.")
51
+ end
52
+
53
+ def self.launch_server(config)
54
+ Jasminewebos::Server.new(config).start
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,16 @@
1
+ module Jasminewebos
2
+ class Configuration
3
+ attr_accessor :port, :jasmine_root, :application_root, :specs_dir,
4
+ :matchers_dir, :sources_json, :jasminewebos_root
5
+
6
+ def initialize(application_root)
7
+ @port = 8888
8
+ @jasminewebos_root = File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
9
+ @jasmine_root = File.join(@jasminewebos_root, "vendor", "jasmine")
10
+ @application_root = application_root
11
+ @specs_dir = File.join(@application_root, "spec", "javascript", "spec")
12
+ @matchers_dir = File.join(@application_root, "spec", "javascript", "matchers")
13
+ @sources_json = File.join(@application_root, "sources.json")
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ require 'fileutils'
2
+ module Jasminewebos
3
+ class Generator
4
+ def initialize(config)
5
+ @config = config
6
+ end
7
+ def run
8
+ from = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "templates", "webos", "spec"))
9
+ FileUtils.cp_r(from,
10
+ @config.application_root)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,68 @@
1
+ module Jasminewebos
2
+ class Server
3
+ def initialize(configuration)
4
+ @configuration = configuration
5
+ end
6
+
7
+ def start
8
+ puts "Starting JasmineWebOS Server from #{@configuration.application_root}"
9
+
10
+ require File.expand_path(File.join(@configuration.jasmine_root,
11
+ "contrib",
12
+ "ruby",
13
+ "jasmine_spec_builder"))
14
+
15
+
16
+ puts source_files
17
+ Jasmine::SimpleServer.start(@configuration.port,
18
+ lambda{spec_files},
19
+ dir_mappings,
20
+ lambda{source_files})
21
+ end
22
+
23
+ def spec_files
24
+ raw_specs = Dir.glob(File.join(@configuration.specs_dir, "**/*[Ss]pec.js"))
25
+ raw_specs.collect {|f| f.sub(@configuration.specs_dir, "/spec")}
26
+ end
27
+
28
+ def source_files
29
+ jasmine = Dir.glob(File.join(jasmine_lib_dir, "*"))
30
+ jasmine = jasmine.collect {|f| f.sub(jasmine_lib_dir, "/lib")}
31
+
32
+ matchers = Dir.glob(File.join(@configuration.matchers_dir, "**/*.js"))
33
+ matchers = matchers.collect {|f| f.sub(@configuration.matchers_dir, "/matchers")}
34
+
35
+ sources = Dir.glob(File.join(application_src_dir, "**/*.js"))
36
+ sources = sources.collect {|f| f.sub(application_src_dir, "/app")}
37
+
38
+ framework = Dir.glob(File.join(framework_dir, "**/*.js"))
39
+ framework = framework.collect {|f| f.sub(framework_dir, "/framework")}
40
+
41
+ framework + jasmine.sort.reverse + matchers.sort + sources.sort
42
+ end
43
+
44
+ def dir_mappings
45
+ {
46
+ "/framework" => framework_dir,
47
+ "/app" => application_src_dir,
48
+ "/spec" => @configuration.specs_dir,
49
+ "/matchers" => @configuration.matchers_dir,
50
+ "/lib" => jasmine_lib_dir,
51
+ "/matchers" => @configuration.matchers_dir
52
+ }
53
+ end
54
+
55
+ private
56
+ def framework_dir
57
+ File.join(@configuration.jasminewebos_root, "jslib")
58
+ end
59
+
60
+ def application_src_dir
61
+ File.join(@configuration.application_root, "app")
62
+ end
63
+
64
+ def jasmine_lib_dir
65
+ File.expand_path(File.join(@configuration.jasmine_root, "lib"))
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,20 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module Jasminewebos
5
+ VERSION = '0.0.1'
6
+
7
+ # def configure(&block)
8
+ # @@configuration = Jasminewebos::Configuration.new
9
+ # yield @@configuration
10
+ # end
11
+ #
12
+ # def configuration
13
+ # @@configuration
14
+ # end
15
+ end
16
+
17
+ require "jasminewebos/cli"
18
+ require "jasminewebos/server"
19
+ require "jasminewebos/generator"
20
+ require "jasminewebos/configuration"
@@ -0,0 +1,12 @@
1
+ /**
2
+ * This file contains matchers that are for all tests
3
+ */
4
+ /**
5
+ * Matcher that expects to be undefined
6
+ */
7
+ jasmine.Matchers.prototype.toBeUndefined = function() {
8
+ return this.report((this.actual === undefined),
9
+ 'Expected a value to be undefined but it was defined (' + this.report + ').');
10
+ };
11
+ /** @deprecated */
12
+ jasmine.Matchers.prototype.should_be_defined = jasmine.Matchers.prototype.toBeDefined;
@@ -0,0 +1,5 @@
1
+ describe("sample", function(){
2
+ it("should allow true to be true", function(){
3
+ expect(true).toEqual(true);
4
+ });
5
+ });
@@ -0,0 +1,38 @@
1
+ require File.dirname(__FILE__) + '/../test_helper.rb'
2
+
3
+ class Jasminewebos::TestConfiguration < Test::Unit::TestCase
4
+
5
+ context "with a default config" do
6
+ setup do
7
+ @config = Jasminewebos::Configuration.new(File.dirname(__FILE__))
8
+ end
9
+ should "have default port" do
10
+ assert_equal(8888, @config.port)
11
+ end
12
+ should "have jasmine_root" do
13
+ assert_equal(File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "vendor", "jasmine")),
14
+ @config.jasmine_root)
15
+ end
16
+ should "have an app root" do
17
+ assert_equal(File.dirname(__FILE__), @config.application_root)
18
+ end
19
+
20
+ should "have sources.json" do
21
+ assert_equal(File.join(File.dirname(__FILE__), "sources.json"), @config.sources_json)
22
+ end
23
+
24
+ should "have specs_dir" do
25
+ assert_equal(File.join(File.dirname(__FILE__), "spec", "javascript", "spec"), @config.specs_dir)
26
+ end
27
+
28
+ should "have matchers_dir" do
29
+ assert_equal(File.join(File.dirname(__FILE__), "spec", "javascript", "matchers"), @config.matchers_dir)
30
+ end
31
+
32
+ should "have jasminewebos_root" do
33
+ assert_equal(File.expand_path(File.join(File.dirname(__FILE__), "..", "..")),
34
+ @config.jasminewebos_root)
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), "/../test_helper.rb")
2
+ require 'jasminewebos/cli'
3
+
4
+ class TestJasminewebosCli < Test::Unit::TestCase
5
+ # def setup
6
+ # Jasminewebos::CLI.execute(@stdout_io = StringIO.new, [])
7
+ # @stdout_io.rewind
8
+ # @stdout = @stdout_io.read
9
+ # end
10
+ #
11
+ # def test_print_default_output
12
+ # assert_match(/To update this executable/, @stdout)
13
+ # end
14
+
15
+ def test_true
16
+
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + '/../test_helper.rb'
2
+
3
+ class Jasminewebos::TestServer < Test::Unit::TestCase
4
+ def test_monkeys
5
+
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require File.dirname(__FILE__) + '/../lib/jasminewebos'
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestJasminewebos < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ assert true
10
+ end
11
+ end
@@ -0,0 +1,249 @@
1
+ require 'socket'
2
+ require 'erb'
3
+ require 'json'
4
+
5
+ module Jasmine
6
+ def self.root
7
+ File.expand_path(File.join(File.dirname(__FILE__), '../..'))
8
+ end
9
+
10
+ # this seemingly-over-complex method is necessary to get an open port on at least some of our Macs
11
+ def self.open_socket_on_unused_port
12
+ infos = Socket::getaddrinfo("localhost", nil, Socket::AF_UNSPEC, Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE)
13
+ families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten]
14
+
15
+ return TCPServer.open('0.0.0.0', 0) if families.has_key?('AF_INET')
16
+ return TCPServer.open('::', 0) if families.has_key?('AF_INET6')
17
+ return TCPServer.open(0)
18
+ end
19
+
20
+ def self.find_unused_port
21
+ socket = open_socket_on_unused_port
22
+ port = socket.addr[1]
23
+ socket.close
24
+ port
25
+ end
26
+
27
+ def self.server_is_listening_on(hostname, port)
28
+ require 'socket'
29
+ begin
30
+ socket = TCPSocket.open(hostname, port)
31
+ rescue Errno::ECONNREFUSED
32
+ return false
33
+ end
34
+ socket.close
35
+ true
36
+ end
37
+
38
+ def self.wait_for_listener(port, name = "required process", seconds_to_wait = 10)
39
+ time_out_at = Time.now + seconds_to_wait
40
+ until server_is_listening_on "localhost", port
41
+ sleep 0.1
42
+ puts "Waiting for #{name} on #{port}..."
43
+ raise "#{name} didn't show up on port #{port} after #{seconds_to_wait} seconds." if Time.now > time_out_at
44
+ end
45
+ end
46
+
47
+ def self.kill_process_group(process_group_id, signal="TERM")
48
+ Process.kill signal, -process_group_id # negative pid means kill process group. (see man 2 kill)
49
+ end
50
+
51
+ def self.cachebust(files, root_dir="", replace=nil, replace_with=nil)
52
+ files.collect do |file_name|
53
+ real_file_name = replace && replace_with ? file_name.sub(replace, replace_with) : file_name
54
+ begin
55
+ digest = Digest::MD5.hexdigest(File.read("#{root_dir}#{real_file_name}"))
56
+ rescue
57
+ digest = "MISSING-FILE"
58
+ end
59
+ "#{file_name}?cachebust=#{digest}"
60
+ end
61
+ end
62
+
63
+ class RunAdapter
64
+ def initialize(spec_files_or_proc, jasmine_files = nil)
65
+ @spec_files_or_proc = spec_files_or_proc
66
+ @jasmine_files = jasmine_files || [
67
+ "/__JASMINE_ROOT__/lib/" + File.basename(Dir.glob("#{Jasmine.root}/lib/jasmine*.js").first),
68
+ "/__JASMINE_ROOT__/lib/TrivialReporter.js",
69
+ "/__JASMINE_ROOT__/lib/json2.js"
70
+ ]
71
+ end
72
+
73
+ def call(env)
74
+ spec_files = @spec_files_or_proc
75
+ spec_files = spec_files.call if spec_files.respond_to?(:call)
76
+
77
+ jasmine_files = @jasmine_files
78
+ jasmine_files = jasmine_files.call if jasmine_files.respond_to?(:call)
79
+
80
+ css_files = ["/__JASMINE_ROOT__/lib/jasmine.css"]
81
+
82
+ body = ERB.new(File.read(File.join(File.dirname(__FILE__), "run.html"))).result(binding)
83
+ [
84
+ 200,
85
+ { 'Content-Type' => 'text/html' },
86
+ body
87
+ ]
88
+ end
89
+ end
90
+
91
+ class Redirect
92
+ def initialize(url)
93
+ @url = url
94
+ end
95
+
96
+ def call(env)
97
+ [
98
+ 302,
99
+ { 'Location' => @url },
100
+ []
101
+ ]
102
+ end
103
+ end
104
+
105
+ class JsAlert
106
+ def call(env)
107
+ [
108
+ 200,
109
+ { 'Content-Type' => 'application/javascript' },
110
+ "document.write('<p>Couldn\\'t load #{env["PATH_INFO"]}!</p>');"
111
+ ]
112
+ end
113
+ end
114
+
115
+ class SimpleServer
116
+ def self.start(port, spec_files_or_proc, mappings, jasmine_files = nil)
117
+ require 'thin'
118
+
119
+ config = {
120
+ '/run.html' => Jasmine::Redirect.new('/'),
121
+ '/' => Jasmine::RunAdapter.new(spec_files_or_proc, jasmine_files)
122
+ }
123
+ mappings.each do |from, to|
124
+ config[from] = Rack::File.new(to)
125
+ end
126
+
127
+ config["/__JASMINE_ROOT__"] = Rack::File.new(Jasmine.root)
128
+
129
+ app = Rack::Cascade.new([
130
+ Rack::URLMap.new(config),
131
+ JsAlert.new
132
+ ])
133
+
134
+ Thin::Server.start('0.0.0.0', port, app)
135
+ end
136
+ end
137
+
138
+ class SimpleClient
139
+ def initialize(selenium_host, selenium_port, selenium_browser_start_command, http_address)
140
+ require 'selenium/client'
141
+ @driver = Selenium::Client::Driver.new(
142
+ selenium_host,
143
+ selenium_port,
144
+ selenium_browser_start_command,
145
+ http_address
146
+ )
147
+ @http_address = http_address
148
+ end
149
+
150
+ def tests_have_finished?
151
+ @driver.get_eval("window.jasmine.getEnv().currentRunner.finished") == "true"
152
+ end
153
+
154
+ def connect
155
+ @driver.start
156
+ @driver.open("/")
157
+ end
158
+
159
+ def disconnect
160
+ @driver.stop
161
+ end
162
+
163
+ def run
164
+ until tests_have_finished? do
165
+ sleep 0.1
166
+ end
167
+
168
+ puts @driver.get_eval("window.getResults()")
169
+ failed_count = @driver.get_eval("window.jasmine.getEnv().currentRunner.getResults().failedCount").to_i
170
+ failed_count == 0
171
+ end
172
+
173
+ def eval_js(script)
174
+ escaped_script = "'" + script.gsub(/(['\\])/) { '\\' + $1 } + "'"
175
+
176
+ begin
177
+ result = @driver.get_eval("window.eval(#{escaped_script})")
178
+ rescue Selenium::CommandError
179
+ result = @driver.get_eval("eval(#{escaped_script}, window)")
180
+ end
181
+ JSON.parse("[#{result}]")[0]
182
+ end
183
+ end
184
+
185
+ class Runner
186
+ def initialize(selenium_jar_path, spec_files, dir_mappings, jasmine_files = nil)
187
+ @selenium_jar_path = selenium_jar_path
188
+ @spec_files = spec_files
189
+ @dir_mappings = dir_mappings
190
+ @jasmine_files = jasmine_files
191
+
192
+ @selenium_pid = nil
193
+ @jasmine_server_pid = nil
194
+ end
195
+
196
+ def start
197
+ start_servers
198
+ @client = Jasmine::SimpleClient.new("localhost", @selenium_server_port, "*firefox", "http://localhost:#{@jasmine_server_port}/")
199
+ @client.connect
200
+ end
201
+
202
+ def stop
203
+ @client.disconnect
204
+ stop_servers
205
+ end
206
+
207
+ def start_servers
208
+ @jasmine_server_port = Jasmine::find_unused_port
209
+ @selenium_server_port = Jasmine::find_unused_port
210
+
211
+ @selenium_pid = fork do
212
+ Process.setpgrp
213
+ exec "java -jar #{@selenium_jar_path} -port #{@selenium_server_port} > /dev/null 2>&1"
214
+ end
215
+ puts "selenium started. pid is #{@selenium_pid}"
216
+
217
+ @jasmine_server_pid = fork do
218
+ Process.setpgrp
219
+ Jasmine::SimpleServer.start(@jasmine_server_port, @spec_files, @dir_mappings, @jasmine_files)
220
+ exit! 0
221
+ end
222
+ puts "jasmine server started. pid is #{@jasmine_server_pid}"
223
+
224
+ Jasmine::wait_for_listener(@selenium_server_port, "selenium server")
225
+ Jasmine::wait_for_listener(@jasmine_server_port, "jasmine server")
226
+ end
227
+
228
+ def stop_servers
229
+ puts "shutting down the servers..."
230
+ Jasmine::kill_process_group(@selenium_pid) if @selenium_pid
231
+ Jasmine::kill_process_group(@jasmine_server_pid) if @jasmine_server_pid
232
+ end
233
+
234
+ def run
235
+ begin
236
+ start
237
+ puts "servers are listening on their ports -- running the test script..."
238
+ tests_passed = @client.run
239
+ ensure
240
+ stop
241
+ end
242
+ return tests_passed
243
+ end
244
+
245
+ def eval_js(script)
246
+ @client.eval_js(script)
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,146 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "jasmine_runner.rb"))
2
+
3
+ module Jasmine
4
+
5
+ class SpecBuilder
6
+ attr_accessor :suites
7
+
8
+ def initialize(spec_files, runner)
9
+ @spec_files = spec_files
10
+ @runner = runner
11
+ end
12
+
13
+ def start
14
+ guess_example_locations
15
+
16
+ @runner.start
17
+ load_suite_info
18
+ @spec_results = {}
19
+ end
20
+
21
+ def stop
22
+ @runner.stop
23
+ end
24
+
25
+ def script_path
26
+ File.expand_path(__FILE__)
27
+ end
28
+
29
+ def guess_example_locations
30
+ @example_locations = {}
31
+
32
+ example_name_parts = []
33
+ previous_indent_level = 0
34
+ @spec_files.each do |filename|
35
+ line_number = 1
36
+ File.open(filename, "r") do |file|
37
+ file.readlines.each do |line|
38
+ match = /^(\s*)(describe|it)\s*\(\s*["'](.*)["']\s*,\s*function/.match(line)
39
+ if (match)
40
+ indent_level = match[1].length / 2
41
+ example_name = match[3]
42
+ example_name_parts[indent_level] = example_name
43
+
44
+ full_example_name = example_name_parts.slice(0, indent_level + 1).join(" ")
45
+ @example_locations[full_example_name] = "#{filename}:#{line_number}: in `it'"
46
+ end
47
+ line_number += 1
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ def load_suite_info
54
+ started = Time.now
55
+ while !eval_js('jsApiReporter && jsApiReporter.started') do
56
+ raise "couldn't connect to Jasmine after 60 seconds" if (started + 60 < Time.now)
57
+ sleep 0.1
58
+ end
59
+
60
+ @suites = eval_js('JSON.stringify(jsApiReporter.suites)')
61
+ end
62
+
63
+ def results_for(spec_id)
64
+ spec_id = spec_id.to_s
65
+ return @spec_results[spec_id] if @spec_results[spec_id]
66
+
67
+ @spec_results[spec_id] = eval_js("JSON.stringify(jsApiReporter.results[#{spec_id}])")
68
+ while @spec_results[spec_id].nil? do
69
+ sleep 0.1
70
+ @spec_results[spec_id] = eval_js("JSON.stringify(jsApiReporter.results[#{spec_id}])")
71
+ end
72
+
73
+ @spec_results[spec_id]
74
+ end
75
+
76
+ def declare_suites
77
+ me = self
78
+ suites.each do |suite|
79
+ declare_suite(self, suite)
80
+ end
81
+ end
82
+
83
+ def declare_suite(parent, suite)
84
+ me = self
85
+ parent.describe suite["name"] do
86
+ suite["children"].each do |suite_or_spec|
87
+ type = suite_or_spec["type"]
88
+ if type == "suite"
89
+ me.declare_suite(self, suite_or_spec)
90
+ elsif type == "spec"
91
+ me.declare_spec(self, suite_or_spec)
92
+ else
93
+ raise "unknown type #{type} for #{suite_or_spec.inspect}"
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ def declare_spec(parent, spec)
100
+ me = self
101
+ example_name = spec["name"]
102
+
103
+ backtrace = @example_locations[parent.description + " " + example_name]
104
+ parent.it example_name, {}, backtrace do
105
+ me.report_spec(spec["id"])
106
+ end
107
+ end
108
+
109
+ def report_spec(spec_id)
110
+ spec_results = results_for(spec_id)
111
+
112
+ out = ""
113
+ messages = spec_results['messages'].each do |message|
114
+ case
115
+ when message["type"] == "MessageResult"
116
+ puts message["text"]
117
+ puts "\n"
118
+ else
119
+ unless message["message"] =~ /^Passed.$/
120
+ STDERR << message["message"]
121
+ STDERR << "\n"
122
+
123
+ out << message["message"]
124
+ out << "\n"
125
+ end
126
+
127
+ unless message["passed_"]
128
+ stack_trace = message["trace"]["stack"].gsub(/<br \/>/, "\n").gsub(/<\/?b>/, " ")
129
+ STDERR << stack_trace.gsub(/\(.*\)@http:\/\/localhost:[0-9]+\/specs\//, "/spec/")
130
+ STDERR << "\n"
131
+ end
132
+ end
133
+
134
+ end
135
+ fail out unless spec_results['result'] == 'passed'
136
+ puts out unless out.empty?
137
+ end
138
+
139
+ private
140
+
141
+ def eval_js(js)
142
+ @runner.eval_js(js)
143
+ end
144
+ end
145
+ end
146
+