js-test-driver-rails 0.4.3 → 0.5.0.pre1

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.
data/Gemfile.lock CHANGED
@@ -1,17 +1,32 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- js-test-driver-rails (0.4.2)
4
+ js-test-driver-rails (0.4.3)
5
+ commander
5
6
  json
6
7
  rake
8
+ selenium-webdriver
7
9
 
8
10
  GEM
9
11
  remote: http://rubygems.org/
10
12
  specs:
11
- json (1.4.6)
13
+ childprocess (0.1.9)
14
+ ffi (~> 1.0.6)
15
+ commander (4.0.4)
16
+ highline (>= 1.5.0)
17
+ ffi (1.0.9)
18
+ highline (1.6.2)
19
+ json (1.5.1)
20
+ json_pure (1.5.1)
12
21
  mocha (0.9.9)
13
22
  rake
14
23
  rake (0.8.7)
24
+ rubyzip (0.9.4)
25
+ selenium-webdriver (0.2.1)
26
+ childprocess (>= 0.1.7)
27
+ ffi (>= 1.0.7)
28
+ json_pure
29
+ rubyzip
15
30
 
16
31
  PLATFORMS
17
32
  ruby
data/TODO ADDED
@@ -0,0 +1,6 @@
1
+ * add remote/selenium browser runner
2
+ * add output coloring
3
+ * add simple watchr integration
4
+ * replace rake tasks with commandline runner
5
+ * implement own output formatter (based on Eclipse/IntelliJ plugins)
6
+ * clean up the whole test-output situation
data/bin/jstd ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.push File.expand_path("../../lib", __FILE__)
4
+
5
+ require 'js_test_driver'
6
+
7
+ require 'commander/import'
8
+
9
+ def browser_option(c)
10
+ c.option '-b', '--browsers STRING', String, 'Comma-separated list of browsers to capture'
11
+ end
12
+
13
+ def tests_option(c)
14
+ c.option '-t', '--tests STRING', String, 'Test cases to run, defaults to all'
15
+ end
16
+
17
+ program :name, 'JS Test Driver'
18
+ program :version, JsTestDriver::VERSION
19
+ program :description, 'A Ruby Wrapper for Google js-test-driver'
20
+ program :help, 'Author', 'Adam Pohorecki <adam@pohorecki.pl>'
21
+
22
+ runtime_opts = {}
23
+
24
+ global_option('-c', '--config FILE', 'path to Ruby configuration file') do |file|
25
+ runtime_opts[:config_path] = file
26
+ end
27
+
28
+ command :'start server' do |c|
29
+ c.description = 'Starts the js-test-driver server'
30
+ c.syntax = 'jstd [--config FILE] start server'
31
+
32
+ c.action do |args, opts|
33
+ JsTestDriver::Application.new(runtime_opts).start_server(opts.__hash__)
34
+ end
35
+ end
36
+
37
+ command :'capture browsers' do |c|
38
+ c.description = 'captures all the defined browsers in strict mode'
39
+ c.syntax = 'jstd [--config FILE] capture browsers [OPTIONS]'
40
+
41
+ browser_option(c)
42
+
43
+ c.action do |args, opts|
44
+ JsTestDriver::Application.new(runtime_opts).capture_browsers(opts.__hash__)
45
+ end
46
+ end
47
+
48
+ command :'run tests' do |c|
49
+ c.description = 'Runs the defined tests in an already running server'
50
+ c.syntax = 'jstd [--config FILE] run tests [OPTIONS]'
51
+
52
+ tests_option(c)
53
+
54
+ c.action do |args, opts|
55
+ JsTestDriver::Application.new(runtime_opts).run_tests(opts.__hash__)
56
+ end
57
+ end
58
+
59
+ command :run do |c|
60
+ c.description = 'Starts the server, captures browsers and runs tests'
61
+ c.syntax = 'jstd [--config FILE] run [OPTIONS]'
62
+
63
+ browser_option(c)
64
+ tests_option(c)
65
+ c.option '--[no-]output-xml', 'output test results in JUnit xml format'
66
+ c.option '--[no-]capture-console', 'capture browser console'
67
+ c.option '--[no-]verbose', 'verbose test output'
68
+ c.option '--runner-mode STRING', 'change runner mode to output more information'
69
+ c.option '--browser-timeout INT', Integer, 'number of seconds after which a browser is considered dead'
70
+
71
+ c.action do |args, opts|
72
+ JsTestDriver::Application.new(runtime_opts).run(opts.__hash__)
73
+ end
74
+ end
@@ -16,6 +16,8 @@ Gem::Specification.new do |s|
16
16
 
17
17
  s.add_dependency 'json'
18
18
  s.add_dependency 'rake'
19
+ s.add_dependency 'commander'
20
+ s.add_dependency 'selenium-webdriver'
19
21
  s.add_development_dependency 'mocha'
20
22
 
21
23
  s.files = `git ls-files`.split("\n")
@@ -0,0 +1,52 @@
1
+ module JsTestDriver
2
+
3
+ class Application
4
+
5
+ attr_reader :runtime_config
6
+
7
+ def initialize(opts = {})
8
+ @runtime_config = JsTestDriver::RuntimeConfig.new(opts)
9
+ @runtime_config.config_factory = config_factory
10
+ end
11
+
12
+ def config
13
+ runtime_config.config
14
+ end
15
+
16
+ def start_server(opts = {})
17
+ JsTestDriver::CLI::StartServer.new(jstd_jar_command, runner).run(opts)
18
+ end
19
+
20
+ def capture_browsers(opts = {})
21
+ JsTestDriver::CLI::CaptureBrowsers.new(config, runner).run(opts)
22
+ end
23
+
24
+ def run_tests(opts = {})
25
+ JsTestDriver::CLI::RunTests.new(jstd_jar_command, runner).run(opts)
26
+ end
27
+
28
+ def run(opts = {})
29
+ JsTestDriver::CLI::Run.new(jstd_jar_command, runner, config, coverage_command).run(opts)
30
+ end
31
+
32
+ def config_factory
33
+ JsTestDriver::ConfigFactory.new(runtime_config)
34
+ end
35
+
36
+ protected
37
+
38
+ def runner
39
+ JsTestDriver::Runner.new
40
+ end
41
+
42
+ def jstd_jar_command
43
+ JsTestDriver::Commands::JstdJarCommand.new(runtime_config, config)
44
+ end
45
+
46
+ def coverage_command
47
+ JsTestDriver::Commands::GenerateCoverageReport.new(runtime_config)
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,34 @@
1
+ module JsTestDriver
2
+ module CLI
3
+
4
+ class CaptureBrowsers
5
+
6
+ attr_reader :config, :runner
7
+
8
+ def initialize(config, runner)
9
+ @config = config
10
+ @runner = runner
11
+ end
12
+
13
+ def run(opts = {})
14
+ browsers = opts[:browsers] || ''
15
+ browsers = browsers.split(',')
16
+ browsers = config.browsers if browsers.empty?
17
+
18
+ url = config.server + "/capture?strict"
19
+
20
+ browsers.each do |name|
21
+ runner.runbg(browser_command(name, url))
22
+ end
23
+ end
24
+
25
+ protected
26
+
27
+ def browser_command(name, url)
28
+ JsTestDriver::Commands::BaseCommand.new(name).arg(url).to_s
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,56 @@
1
+ module JsTestDriver
2
+ module CLI
3
+
4
+ class Run
5
+
6
+ attr_reader :command, :runner, :config, :coverage_command
7
+
8
+ def initialize(jstd_jar_command, runner, config, coverage_command)
9
+ @command = jstd_jar_command
10
+ @runner = runner
11
+ @config = config
12
+ @coverage_command = coverage_command
13
+ end
14
+
15
+ def run(opts = {})
16
+ result = run_jstd_command(opts)
17
+ generate_coverage_report(opts)
18
+ return result
19
+ end
20
+
21
+ protected
22
+
23
+ def run_jstd_command(opts)
24
+ command
25
+ .start_server
26
+ .with_config
27
+ .capture_browsers(opts[:browsers])
28
+ .run_tests(opts[:tests])
29
+
30
+ command.output_xml if opts[:output_xml]
31
+ command.capture_console if opts[:capture_console]
32
+ command.verbose if opts[:verbose]
33
+ command.run_mode(opts[:runner_mode]) if opts[:runner_mode]
34
+ command.browser_timeout(opts[:browser_timeout]) if opts[:browser_timeout]
35
+
36
+ return runner.run(command.to_s)
37
+ end
38
+
39
+ def generate_coverage_report(opts)
40
+ return unless config.measure_coverage? && opts[:output_xml]
41
+
42
+ if genhtml_installed?
43
+ runner.run(coverage_command.to_s)
44
+ else
45
+ puts "Could not find genhtml. You must install lcov (sudo apt-get install lcov)"
46
+ end
47
+ end
48
+
49
+ def genhtml_installed?
50
+ !%x[which genhtml].strip.empty?
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,22 @@
1
+ module JsTestDriver
2
+ module CLI
3
+
4
+ class RunTests
5
+
6
+ attr_reader :jstd_jar_command, :runner
7
+
8
+ def initialize(jstd_jar_command, runner)
9
+ @jstd_jar_command = jstd_jar_command
10
+ @runner = runner
11
+ end
12
+
13
+ def run(opts = {})
14
+ jstd_jar_command.with_config.run_tests(opts[:tests])
15
+
16
+ runner.run(jstd_jar_command.to_s)
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ module JsTestDriver
2
+ module CLI
3
+
4
+ class StartServer
5
+
6
+ attr_reader :jstd_jar_command, :runner
7
+
8
+ def initialize(jstd_jar_command, runner)
9
+ @jstd_jar_command = jstd_jar_command
10
+ @runner = runner
11
+ end
12
+
13
+ def run(opts = {})
14
+ runner.run(jstd_jar_command.start_server.to_s)
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,43 @@
1
+ module JsTestDriver
2
+ module Commands
3
+
4
+ class BaseCommand
5
+ def initialize(executable)
6
+ @command = "#{executable}"
7
+ ensure_installed!
8
+
9
+ @options = []
10
+ @args = []
11
+ end
12
+
13
+ def option(name, value = nil)
14
+ @options << name
15
+ @options << escape(value)
16
+ self
17
+ end
18
+
19
+ def arg(value)
20
+ @args << escape(value)
21
+ self
22
+ end
23
+
24
+ def to_s
25
+ return ([@command] + @options + @args).compact.join(' ')
26
+ end
27
+
28
+ private
29
+
30
+ def ensure_installed!
31
+ if %x[which #{@command}].strip.empty?
32
+ raise JsTestDriver::MissingDependencyError.new("Could not find executable: #{@command}")
33
+ end
34
+ end
35
+
36
+ def escape(value)
37
+ return "'#{value}'" if value && value =~ /\s/
38
+ return value
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,17 @@
1
+ module JsTestDriver
2
+ module Commands
3
+
4
+ class GenerateCoverageReport < BaseCommand
5
+
6
+ attr_reader :runtime_config
7
+
8
+ def initialize(runtime_config)
9
+ super('genhtml')
10
+ option('-o', runtime_config.coverage_files_path)
11
+ arg(runtime_config.coverage_data_file)
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,61 @@
1
+ module JsTestDriver
2
+ module Commands
3
+
4
+ class JstdJarCommand < BaseCommand
5
+
6
+ attr_reader :runtime_config, :config
7
+
8
+ def initialize(runtime_config, config)
9
+ super('java')
10
+ @runtime_config = runtime_config
11
+ @config = config
12
+
13
+ option('-jar', runtime_config.jar_path)
14
+ option('--serverHandlerPrefix', 'jstd')
15
+ end
16
+
17
+ def with_config
18
+ return option('--config', runtime_config.config_yml_path)
19
+ end
20
+
21
+ def start_server
22
+ return option('--port', config.port)
23
+ end
24
+
25
+ def run_tests(tests = nil)
26
+ return option('--tests', tests || "all")
27
+ end
28
+
29
+ def capture_browsers(browsers = nil)
30
+ browsers ||= config.browsers.join(',')
31
+ raise ArgumentError.new("No browsers defined!") if browsers == ""
32
+ return option('--browser', browsers)
33
+ end
34
+
35
+ def output_directory(path)
36
+ return option('--testOutput', path)
37
+ end
38
+
39
+ def output_xml
40
+ return output_directory(runtime_config.test_xml_data_path)
41
+ end
42
+
43
+ def capture_console
44
+ return option('--captureConsole')
45
+ end
46
+
47
+ def verbose
48
+ return option('--verbose')
49
+ end
50
+
51
+ def runner_mode(mode)
52
+ return option('--runnerMode', mode)
53
+ end
54
+
55
+ def browser_timeout(timeout)
56
+ return option('--browserTimeout', timeout)
57
+ end
58
+ end
59
+
60
+ end
61
+ end
@@ -9,7 +9,8 @@ module JsTestDriver
9
9
  # user a significant amount of freedom in terms of what is and is not loaded, and so on
10
10
  class Config
11
11
 
12
- def initialize(attributes = {})
12
+ def initialize(runtime_config, attributes = {})
13
+ @runtime_config = runtime_config
13
14
  self.attributes = attributes
14
15
  end
15
16
 
@@ -37,6 +38,16 @@ module JsTestDriver
37
38
  end
38
39
  end
39
40
 
41
+ # This allows you to control browsers on remote machines with Selenium
42
+ # To be able to use this, the remote server has to be running selenium-server
43
+ #
44
+ # Available options are: host and browser (as in WebDriver::Remote::Capabilities)
45
+ def remote_browser(host, opts = {})
46
+ remote_browser = JsTestDriver::RemoteBrowser.new(host, opts)
47
+ remote_browsers << remote_browser
48
+ browser remote_browser_file_name(remote_browser.name)
49
+ end
50
+
40
51
  # Defines a HTML fixture directory
41
52
  #
42
53
  # the first argument is the directory to scan for html fixtures
@@ -73,6 +84,11 @@ module JsTestDriver
73
84
  }
74
85
  end
75
86
 
87
+ # Adds a proxy matcher to configuration. This can be used for integration testing.
88
+ def proxy(pattern)
89
+ return Proxy.new(pattern, proxies)
90
+ end
91
+
76
92
  def measure_coverage?
77
93
  !!@measure_coverage
78
94
  end
@@ -82,6 +98,16 @@ module JsTestDriver
82
98
  @plugins ||= []
83
99
  end
84
100
 
101
+ def guess_local_ip
102
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
103
+ UDPSocket.open do |s|
104
+ s.connect '64.233.187.99', 1
105
+ return s.addr.last
106
+ end
107
+ ensure
108
+ Socket.do_not_reverse_lookup = orig
109
+ end
110
+
85
111
  # config variable which has a regular setter,
86
112
  # but also can be set by calling the "getter" with an argument
87
113
  # and if called without an argument the getter will return the passed block
@@ -132,44 +158,78 @@ module JsTestDriver
132
158
  @html_fixtures ||= []
133
159
  end
134
160
 
161
+ def proxies
162
+ @proxies ||= []
163
+ end
164
+
135
165
  attr_writer :browsers
136
166
 
137
167
  def browsers
138
168
  @browsers ||= []
139
169
  end
140
170
 
171
+ attr_writer :remote_browsers
172
+
173
+ def remote_browsers
174
+ @remote_browsers ||= []
175
+ end
176
+
141
177
  def to_s
142
178
  hash = {'server' => server, 'basepath' => base_path}
143
179
  hash['load'] = loaded_files unless loaded_files.empty?
144
180
  hash['exclude'] = map_paths(excluded_files) unless excluded_files.empty?
145
181
  hash['plugin'] = plugins unless plugins.empty?
182
+ hash['proxy'] = proxies unless proxies.empty?
146
183
  return hash.to_yaml
147
184
  end
148
185
 
149
- def self.parse(string)
150
- config = new
151
- config.instance_eval(string)
152
- return config
186
+ # this is where the config files are saved (ex. RAILS_ROOT/.js_test_driver)
187
+ def config_dir
188
+ runtime_config.generated_files_dir
153
189
  end
154
190
 
155
- attr_writer :config_dir
191
+ # this is where the config files are saved (ex. RAILS_ROOT/.js_test_driver/fixtures)
192
+ def fixture_dir
193
+ runtime_config.fixture_dir
194
+ end
156
195
 
157
- # this is where the config files are saved (ex. RAILS_ROOT/.js_test_driver)
158
- def config_dir
159
- @config_dir ||= File.expand_path(".")
196
+ def save
197
+ File.open(runtime_config.config_yml_path, "w+") { |f| f.puts self.to_s }
198
+ save_fixtures
199
+ save_remote_browsers
200
+ return self
160
201
  end
161
202
 
203
+ private
204
+
205
+ attr_reader :runtime_config
206
+
162
207
  def save_fixtures
163
208
  html_fixtures.each do |fixture|
164
209
  path = fixture_file_name(fixture)
165
- FileUtils.mkdir_p(File.dirname(path))
166
210
  File.open(path, "w+") do |f|
167
211
  f.puts fixture.to_s
168
212
  end
169
213
  end
170
214
  end
171
215
 
172
- private
216
+ def save_remote_browsers
217
+ remote_browsers.each do |browser|
218
+ path = remote_browser_file_name(browser.name)
219
+ File.open(path, "w+") do |f|
220
+ f.puts browser.to_s
221
+ end
222
+ File.chmod(0755, path)
223
+ end
224
+ end
225
+
226
+ def fixture_file_name(fixture)
227
+ File.join(fixture_dir, fixture.namespace, "#{fixture.name}.js")
228
+ end
229
+
230
+ def remote_browser_file_name(name)
231
+ File.join(runtime_config.remote_browsers_dir, name)
232
+ end
173
233
 
174
234
  def vendor_directory
175
235
  this_directory = File.dirname(__FILE__)
@@ -181,10 +241,6 @@ module JsTestDriver
181
241
  return with_expanded_paths.map{|path| path.include?('*') ? Dir[path].sort : path}.flatten
182
242
  end
183
243
 
184
- def fixture_file_name(fixture)
185
- File.expand_path(File.join(config_dir, "fixtures", fixture.namespace, "#{fixture.name}.js"))
186
- end
187
-
188
244
  def loaded_files
189
245
  files = included_files + html_fixtures.collect { |fixture| fixture_file_name(fixture) }
190
246
 
@@ -205,5 +261,18 @@ module JsTestDriver
205
261
  end
206
262
  end
207
263
 
264
+ class Proxy
265
+ attr_reader :pattern, :proxies
266
+
267
+ def initialize(pattern, proxies)
268
+ @pattern = pattern
269
+ @proxies = proxies
270
+ end
271
+
272
+ def to(server)
273
+ self.proxies << {'matcher' => pattern, 'server' => server}
274
+ end
275
+ end
276
+
208
277
  end
209
278
  end
@@ -0,0 +1,21 @@
1
+ module JsTestDriver
2
+ class ConfigFactory
3
+
4
+ attr_reader :runtime_config
5
+
6
+ def initialize(runtime_config)
7
+ @runtime_config = runtime_config
8
+ end
9
+
10
+ def new(opts = {})
11
+ JsTestDriver::Config.new(runtime_config, opts)
12
+ end
13
+
14
+ def parse(string)
15
+ config = new
16
+ config.instance_eval(string)
17
+ return config
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module JsTestDriver
2
+ class MissingDependencyError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,57 @@
1
+ module JsTestDriver
2
+
3
+ class RemoteBrowser
4
+
5
+ attr_reader :host, :browser, :driver
6
+
7
+ def initialize(host, opts = {})
8
+ @host = host
9
+ @browser = opts[:browser]
10
+ end
11
+
12
+ def name
13
+ ["remote-browser", host, browser].join('-') + '.rb'
14
+ end
15
+
16
+ def run(url)
17
+ trap_signals
18
+
19
+ opts = {:url => "http://#{host}/wd/hub"}
20
+ opts[:desired_capabilities] = browser if browser
21
+
22
+ @driver = Selenium::WebDriver.for(:remote, opts)
23
+ driver.navigate.to url
24
+
25
+ while(true) do
26
+ sleep(1)
27
+ end
28
+ end
29
+
30
+ def to_s
31
+ jstd_dir = File.expand_path(File.join('..', '..'), __FILE__)
32
+ <<RUBY
33
+ #!/usr/bin/env ruby
34
+
35
+ $:.push "#{jstd_dir}"
36
+
37
+ require "rubygems"
38
+ require "js_test_driver"
39
+
40
+ JsTestDriver::RemoteBrowser.new(#{host.inspect}, :browser => #{browser.inspect}).run(ARGV[0])
41
+ RUBY
42
+ end
43
+
44
+ private
45
+
46
+ def trap_signals
47
+ [:INT, :QUIT, :TERM].each do |sig|
48
+ trap(sig) do
49
+ driver.quit
50
+ exit(0)
51
+ end
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ end