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

Sign up to get free protection for your applications and to get access to all the features.
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