discourse/lib/autospec/qunit_runner.rb
Sam Saffron 30990006a9 DEV: enable frozen string literal on all files
This reduces chances of errors where consumers of strings mutate inputs
and reduces memory usage of the app.

Test suite passes now, but there may be some stuff left, so we will run
a few sites on a branch prior to merging
2019-05-13 09:31:32 +08:00

192 lines
4.5 KiB
Ruby

# frozen_string_literal: true
require "demon/rails_autospec"
module Autospec
class QunitRunner < BaseRunner
WATCHERS = {}
def self.watch(pattern, &blk)
WATCHERS[pattern] = blk
end
def watchers
WATCHERS
end
# Discourse specific
watch(%r{^app/assets/javascripts/discourse/(.+)\.js.es6$}) { |m| "test/javascripts/#{m[1]}-test.js.es6" }
watch(%r{^app/assets/javascripts/admin/(.+)\.js.es6$}) { |m| "test/javascripts/admin/#{m[1]}-test.js.es6" }
watch(%r{^test/javascripts/.+\.js.es6$})
RELOADERS = Set.new
def self.reload(pattern)
RELOADERS << pattern
end
def reloaders
RELOADERS
end
# Discourse specific
reload(%r{^test/javascripts/fixtures/.+_fixtures\.js(\.es6)?$})
reload(%r{^test/javascripts/(helpers|mixins)/.+\.js(\.es6)?$})
reload("test/javascripts/test_helper.js")
watch(%r{^plugins/.*/test/.+\.js.es6$})
require "socket"
class ChromeNotInstalled < StandardError; end
def initialize
ensure_chrome_is_installed
end
def start
# ensure we can launch the rails server
unless port_available?(port)
puts "Port #{port} is not available"
puts "Either kill the process using that port or use the `TEST_SERVER_PORT` environment variable"
return
end
# start rails
start_rails_server
@running = true
end
def running?
@running
end
def run(specs)
puts "Running Qunit: #{specs}"
Demon::RailsAutospec.ensure_running
abort
qunit_url = "http://localhost:#{port}/qunit"
if specs != "spec"
module_or_filename, test_id, _name = specs.strip.split(":::")
module_name = module_or_filename
if !test_id
module_name = try_to_find_module_name(module_or_filename)
qunit_url << "?module=#{module_name}" if module_name
else
qunit_url << "?testId=#{test_id}"
end
end
cmd = "node #{Rails.root}/test/run-qunit.js \"#{qunit_url}\" 3000000 ./tmp/qunit_result"
@pid = Process.spawn(cmd)
_, status = Process.wait2(@pid)
status.exitstatus
end
def reload
stop_rails_server
sleep 1
start_rails_server
end
def abort
if @pid
children_processes(@pid).each { |pid| kill_process(pid) }
kill_process(@pid)
@pid = nil
end
end
def failed_specs
specs = []
path = './tmp/qunit_result'
specs = File.readlines(path) if File.exist?(path)
specs
end
def stop
abort
stop_rails_server
@running = false
end
private
def ensure_chrome_is_installed
binary = "google-chrome-stable" if system("command -v google-chrome-stable >/dev/null;")
binary ||= "google-chrome" if system("command -v google-chrome >/dev/null;")
raise ChromeNotInstalled.new if !binary
if Gem::Version.new(`#{binary} --version`.match(/[\d\.]+/)[0]) < Gem::Version.new("59")
raise "Chrome 59 or higher is required"
end
end
def port_available?(port)
TCPServer.open(port).close
true
rescue Errno::EADDRINUSE
false
end
def port
@port ||= ENV["TEST_SERVER_PORT"] || 60099
end
def start_rails_server
Demon::RailsAutospec.start(1)
end
def stop_rails_server
Demon::RailsAutospec.stop
end
def children_processes(base = Process.pid)
process_tree = Hash.new { |hash, key| hash[key] = [key] }
Hash[*`ps -eo pid,ppid`.scan(/\d+/).map(&:to_i)].each do |pid, ppid|
process_tree[ppid] << process_tree[pid]
end
process_tree[base].flatten - [base]
end
def kill_process(pid)
return unless pid
Process.kill("INT", pid) rescue nil
while (Process.getpgid(pid) rescue nil)
sleep 0.001
end
end
def try_to_find_module_name(file)
file, _ = file.split(/:\d+$/)
return unless File.exists?(file)
File.open(file, "r").each_line do |line|
if m = /module\(['"]([^'"]+)/i.match(line)
return m[1]
end
if m = /moduleForWidget\(['"]([^"']+)/i.match(line)
return "widget:#{m[1]}"
end
if m = /acceptance\(['"]([^"']+)/i.match(line)
return "Acceptance: #{m[1]}"
end
if m = /moduleFor\(['"]([^'"]+)/i.match(line)
return m[1]
end
if m = /moduleForComponent\(['"]([^"']+)/i.match(line)
return m[1]
end
end
nil
end
end
end