1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Test rails-ujs in our travis matrix

This commit is contained in:
Rafael Mendonça França 2017-02-21 13:41:17 -05:00
parent f24c2f09f8
commit fe4a5706ac
No known key found for this signature in database
GPG key ID: FC23B6D0F1EEE948
11 changed files with 338 additions and 70 deletions

2
.gitignore vendored
View file

@ -20,3 +20,5 @@ pkg
/railties/doc /railties/doc
/railties/tmp /railties/tmp
/guides/output /guides/output
node_modules/
/actionview/log

View file

@ -6,6 +6,8 @@ cache:
directories: directories:
- /tmp/cache/unicode_conformance - /tmp/cache/unicode_conformance
- /tmp/beanstalkd-1.10 - /tmp/beanstalkd-1.10
- node_modules
- $HOME/.nvm
services: services:
- memcached - memcached
@ -21,6 +23,11 @@ before_install:
- "gem update bundler" - "gem update bundler"
- "[ -f /tmp/beanstalkd-1.10/Makefile ] || (curl -L https://github.com/kr/beanstalkd/archive/v1.10.tar.gz | tar xz -C /tmp)" - "[ -f /tmp/beanstalkd-1.10/Makefile ] || (curl -L https://github.com/kr/beanstalkd/archive/v1.10.tar.gz | tar xz -C /tmp)"
- "pushd /tmp/beanstalkd-1.10 && make && (./beanstalkd &); popd" - "pushd /tmp/beanstalkd-1.10 && make && (./beanstalkd &); popd"
- "[[ $GEM != 'av:ujs' ]] || nvm install node"
- "[[ $GEM != 'av:ujs' ]] || node --version"
- "[[ $GEM != 'av:ujs' ]] || (cd actionview && npm install)"
- "[[ $GEM != 'av:ujs' ]] || [[ $(phantomjs --version) > '2' ]] || npm install -g phantomjs-prebuilt"
before_script: before_script:
# Set Sauce Labs username and access key. Obfuscated, purposefully not encrypted. # Set Sauce Labs username and access key. Obfuscated, purposefully not encrypted.
@ -52,6 +59,8 @@ rvm:
matrix: matrix:
include: include:
- rvm: 2.4.0
env: "GEM=av:ujs"
- rvm: 2.2.6 - rvm: 2.2.6
env: "GEM=aj:integration" env: "GEM=aj:integration"
services: services:

View file

@ -1,4 +1,5 @@
require "rake/testtask" require "rake/testtask"
require "fileutils"
desc "Default Task" desc "Default Task"
task default: :test task default: :test
@ -25,6 +26,32 @@ namespace :test do
t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION)
end end
task :ujs do
begin
Dir.mkdir("log")
pid = spawn("bundle exec rackup test/ujs/config.ru -p 4567 -s puma > log/test.log 2>&1")
start_time = Time.now
loop do
break if system("lsof -i :4567 >/dev/null")
if Time.now - start_time > 5
puts "Timed out after 5 seconds"
exit 1
end
end
system("npm run lint && phantomjs ../ci/phantomjs.js http://localhost:4567/")
status = $?.to_i
ensure
Process.kill("KILL", pid) if pid
FileUtils.rm_f("log")
end
exit status
end
namespace :integration do namespace :integration do
desc "ActiveRecord Integration Tests" desc "ActiveRecord Integration Tests"
Rake::TestTask.new(:active_record) do |t| Rake::TestTask.new(:active_record) do |t|

135
actionview/coffeelint.json Normal file
View file

@ -0,0 +1,135 @@
{
"arrow_spacing": {
"level": "warn"
},
"braces_spacing": {
"level": "warn",
"spaces": 1,
"empty_object_spaces": 0
},
"camel_case_classes": {
"level": "error"
},
"coffeescript_error": {
"level": "error"
},
"colon_assignment_spacing": {
"level": "warn",
"spacing": {
"left": 0,
"right": 1
}
},
"cyclomatic_complexity": {
"level": "warn",
"value": 10
},
"duplicate_key": {
"level": "error"
},
"empty_constructor_needs_parens": {
"level": "warn"
},
"ensure_comprehensions": {
"level": "warn"
},
"eol_last": {
"level": "warn"
},
"indentation": {
"value": 2,
"level": "error"
},
"line_endings": {
"level": "warn",
"value": "unix"
},
"max_line_length": {
"value": 80,
"level": "ignore",
"limitComments": true
},
"missing_fat_arrows": {
"level": "ignore"
},
"newlines_after_classes": {
"value": 3,
"level": "warn"
},
"no_backticks": {
"level": "error"
},
"no_debugger": {
"level": "warn",
"console": false
},
"no_empty_functions": {
"level": "warn"
},
"no_empty_param_list": {
"level": "warn"
},
"no_implicit_braces": {
"level": "ignore",
"strict": true
},
"no_implicit_parens": {
"level": "ignore",
"strict": true
},
"no_interpolation_in_single_quotes": {
"level": "warn"
},
"no_nested_string_interpolation": {
"level": "warn"
},
"no_plusplus": {
"level": "warn"
},
"no_private_function_fat_arrows": {
"level": "warn"
},
"no_stand_alone_at": {
"level": "warn"
},
"no_tabs": {
"level": "error"
},
"no_this": {
"level": "warn"
},
"no_throwing_strings": {
"level": "error"
},
"no_trailing_semicolons": {
"level": "error"
},
"no_trailing_whitespace": {
"level": "error",
"allowed_in_comments": false,
"allowed_in_empty_lines": true
},
"no_unnecessary_double_quotes": {
"level": "warn"
},
"no_unnecessary_fat_arrows": {
"level": "warn"
},
"non_empty_constructor_needs_parens": {
"level": "warn"
},
"prefer_english_operator": {
"level": "ignore",
"doubleNotLevel": "warn"
},
"space_operators": {
"level": "warn"
},
"spacing_after_comma": {
"level": "warn"
},
"transform_messes_up_line_numbers": {
"level": "warn"
}
}

View file

@ -12,7 +12,7 @@
"scripts": { "scripts": {
"build": "bundle exec blade build", "build": "bundle exec blade build",
"test": "echo \"See the README: https://github.com/rails/rails-ujs#how-to-run-tests\" && exit 1", "test": "echo \"See the README: https://github.com/rails/rails-ujs#how-to-run-tests\" && exit 1",
"lint": "coffeelint src && eslint test/public/test", "lint": "coffeelint app/assets/javascripts && eslint test/public/test"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View file

@ -1,3 +1,4 @@
$LOAD_PATH.unshift File.expand_path("..", __FILE__) $LOAD_PATH.unshift File.expand_path("..", __FILE__)
require "server" require "server"
run UJS::Server run UJS::Server

View file

@ -1,11 +1,10 @@
require "rack"
require "rails" require "rails"
require "action_controller/railtie" require "action_controller/railtie"
require "action_view/railtie" require "action_view/railtie"
require "blade" require "blade"
require "json" require "json"
JQUERY_VERSIONS = %w[ 1.8.0 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 1.10.0 1.10.1 1.10.2 1.11.0 2.0.0 2.1.0].freeze
module UJS module UJS
class Server < Rails::Application class Server < Rails::Application
routes.append do routes.append do
@ -18,7 +17,7 @@ module UJS
config.cache_classes = false config.cache_classes = false
config.eager_load = false config.eager_load = false
config.secret_key_base = "59d7a4dbd349fa3838d79e330e39690fc22b931e7dc17d9162f03d633d526fbb92dfdb2dc9804c8be3e199631b9c1fbe43fc3e4fc75730b515851849c728d5c7" config.secret_key_base = "59d7a4dbd349fa3838d79e330e39690fc22b931e7dc17d9162f03d633d526fbb92dfdb2dc9804c8be3e199631b9c1fbe43fc3e4fc75730b515851849c728d5c7"
config.paths["app/views"].unshift("#{Rails.root / "views"}") config.paths["app/views"].unshift("#{Rails.root}/views")
config.public_file_server.enabled = true config.public_file_server.enabled = true
config.logger = Logger.new(STDOUT) config.logger = Logger.new(STDOUT)
config.log_level = :error config.log_level = :error
@ -26,32 +25,6 @@ module UJS
end end
module TestsHelper module TestsHelper
def jquery_link(version)
if params[:version] == version
"[#{version}]"
else
"<a href='/?version=#{version}&cdn=#{params[:cdn]}'>#{version}</a>".html_safe
end
end
def cdn_link(cdn)
if params[:cdn] == cdn
"[#{cdn}]"
else
"<a href='/?version=#{params[:version]}&cdn=#{cdn}'>#{cdn}</a>".html_safe
end
end
def jquery_src
if params[:version] == "edge"
"/vendor/jquery.js"
elsif params[:cdn] && params[:cdn] == "googleapis"
"https://ajax.googleapis.com/ajax/libs/jquery/#{params[:version]}/jquery.min.js"
else
"http://code.jquery.com/jquery-#{params[:version]}.js"
end
end
def test_to(*names) def test_to(*names)
names = ["/vendor/qunit.js", "settings"] + names names = ["/vendor/qunit.js", "settings"] + names
names.map { |name| script_tag name }.join("\n").html_safe names.map { |name| script_tag name }.join("\n").html_safe
@ -61,10 +34,6 @@ module TestsHelper
src = "/test/#{src}.js" unless src.index("/") src = "/test/#{src}.js" unless src.index("/")
%(<script src="#{src}" type="text/javascript"></script>).html_safe %(<script src="#{src}" type="text/javascript"></script>).html_safe
end end
def jquery_versions
JQUERY_VERSIONS
end
end end
class TestsController < ActionController::Base class TestsController < ActionController::Base
@ -72,8 +41,6 @@ class TestsController < ActionController::Base
layout "application" layout "application"
def index def index
params[:version] ||= ENV["JQUERY_VERSION"] || "1.11.0"
params[:cdn] ||= "jquery"
render :index render :index
end end

View file

@ -3,30 +3,15 @@
<head> <head>
<title><%= @title %></title> <title><%= @title %></title>
<link href="/vendor/qunit.css" media="screen" rel="stylesheet" type="text/css" media="screen, projection" /> <link href="/vendor/qunit.css" media="screen" rel="stylesheet" type="text/css" media="screen, projection" />
<style> <%= script_tag "http://code.jquery.com/jquery-2.2.0.js" %>
#jquery-cdn, #jquery-version {
padding: 0 2em .8em 0;
text-align: right;
font-family: sans-serif;
line-height: 1;
color: #8699A4;
background-color: #0d3349;
}
#jquery-cdn a, #jquery-version a {
color: white;
text-decoration: underline;
}
</style>
<%= script_tag jquery_src %>
<script> <script>
// This is for test in override.js. // This is for test in override.js.
// Must go before rails-ujs. // Must go before rails-ujs.
$(document).bind('rails:attachBindings', function() { document.addEventListener('rails:attachBindings', function() {
$.rails.linkClickSelector += ', a[data-custom-remote-link]'; window.Rails.linkClickSelector += ', a[data-custom-remote-link]';
// Hijacks link click before ujs binds any handlers // Hijacks link click before ujs binds any handlers
// This is only used for ctrl-clicking test on remote links // This is only used for ctrl-clicking test on remote links
$.rails.delegate(document, '#qunit-fixture a', 'click', function(e) { window.Rails.delegate(document, '#qunit-fixture a', 'click', function(e) {
e.preventDefault(); e.preventDefault();
}); });
}); });

View file

@ -3,20 +3,6 @@
<%= test_to 'data-confirm', 'data-remote', 'data-disable', 'data-disable-with', 'call-remote', 'call-remote-callbacks', 'data-method', 'override', 'csrf-refresh', 'csrf-token' %> <%= test_to 'data-confirm', 'data-remote', 'data-disable', 'data-disable-with', 'call-remote', 'call-remote-callbacks', 'data-method', 'override', 'csrf-refresh', 'csrf-token' %>
<h1 id="qunit-header"><%= @title %></h1> <h1 id="qunit-header"><%= @title %></h1>
<div id="jquery-cdn">
CDN:
<%= cdn_link 'jquery' %> •
<%= cdn_link 'googleapis' %>
</div>
<div id="jquery-version">
jQuery version:
<% jquery_versions.each do |v| %>
<%= ' • ' if v != jquery_versions.first %>
<%= jquery_link v %>
<% end %>
<%= (' • ' + jquery_link('edge')) if File.exist?(Rails.root + '/public/vendor/jquery.js') %>
</div>
<h2 id="qunit-banner"></h2> <h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div> <div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2> <h2 id="qunit-userAgent"></h2>

149
ci/phantomjs.js Normal file
View file

@ -0,0 +1,149 @@
/*
* PhantomJS Runner QUnit Plugin 1.2.0
*
* PhantomJS binaries: http://phantomjs.org/download.html
* Requires PhantomJS 1.6+ (1.7+ recommended)
*
* Run with:
* phantomjs runner.js [url-of-your-qunit-testsuite]
*
* e.g.
* phantomjs runner.js http://localhost/qunit/test/index.html
*/
/*global phantom:false, require:false, console:false, window:false, QUnit:false */
(function() {
'use strict';
var url, page, timeout,
args = require('system').args;
// arg[0]: scriptName, args[1...]: arguments
if (args.length < 2 || args.length > 3) {
console.error('Usage:\n phantomjs runner.js [url-of-your-qunit-testsuite] [timeout-in-seconds]');
phantom.exit(1);
}
url = args[1];
page = require('webpage').create();
if (args[2] !== undefined) {
timeout = parseInt(args[2], 10);
}
// Route `console.log()` calls from within the Page context to the main Phantom context (i.e. current `this`)
page.onConsoleMessage = function(msg) {
console.log(msg);
};
page.onInitialized = function() {
page.evaluate(addLogging);
};
page.onCallback = function(message) {
var result,
failed;
if (message) {
if (message.name === 'QUnit.done') {
result = message.data;
failed = !result || !result.total || result.failed;
if (!result.total) {
console.error('No tests were executed. Are you loading tests asynchronously?');
}
phantom.exit(failed ? 1 : 0);
}
}
};
page.open(url, function(status) {
if (status !== 'success') {
console.error('Unable to access network: ' + status);
phantom.exit(1);
} else {
// Cannot do this verification with the 'DOMContentLoaded' handler because it
// will be too late to attach it if a page does not have any script tags.
var qunitMissing = page.evaluate(function() { return (typeof QUnit === 'undefined' || !QUnit); });
if (qunitMissing) {
console.error('The `QUnit` object is not present on this page.');
phantom.exit(1);
}
// Set a timeout on the test running, otherwise tests with async problems will hang forever
if (typeof timeout === 'number') {
setTimeout(function() {
console.error('The specified timeout of ' + timeout + ' seconds has expired. Aborting...');
phantom.exit(1);
}, timeout * 1000);
}
// Do nothing... the callback mechanism will handle everything!
}
});
function addLogging() {
window.document.addEventListener('DOMContentLoaded', function() {
var currentTestAssertions = [];
QUnit.log(function(details) {
var response;
// Ignore passing assertions
if (details.result) {
return;
}
response = details.message || '';
if (typeof details.expected !== 'undefined') {
if (response) {
response += ', ';
}
response += 'expected: ' + details.expected + ', but was: ' + details.actual;
}
if (details.source) {
response += "\n" + details.source;
}
currentTestAssertions.push('Failed assertion: ' + response);
});
QUnit.testDone(function(result) {
var i,
len,
name = '';
if (result.module) {
name += result.module + ': ';
}
name += result.name;
if (result.failed) {
console.log('\n' + 'Test failed: ' + name);
for (i = 0, len = currentTestAssertions.length; i < len; i++) {
console.log(' ' + currentTestAssertions[i]);
}
}
currentTestAssertions.length = 0;
});
QUnit.done(function(result) {
console.log('\n' + 'Took ' + result.runtime + 'ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.');
if (typeof window.callPhantom === 'function') {
window.callPhantom({
'name': 'QUnit.done',
'data': result
});
}
});
}, false);
}
})();

View file

@ -36,8 +36,10 @@ class Build
def run!(options = {}) def run!(options = {})
self.options.update(options) self.options.update(options)
Dir.chdir(dir) do Dir.chdir(dir) do
announce(heading) announce(heading)
if guides? if guides?
run_bug_report_templates run_bug_report_templates
else else
@ -69,7 +71,7 @@ class Build
end end
tasks tasks
else else
["test", ("isolated" if isolated?), ("integration" if integration?)].compact.join(":") ["test", ("isolated" if isolated?), ("integration" if integration?), ("ujs" if ujs?)].compact.join(":")
end end
end end
@ -92,6 +94,10 @@ class Build
gem == "guides" gem == "guides"
end end
def ujs?
component.split(":").last == "ujs"
end
def isolated? def isolated?
options[:isolated] options[:isolated]
end end
@ -151,6 +157,7 @@ ENV["GEM"].split(",").each do |gem|
next if gem == "ac:integration" && isolated next if gem == "ac:integration" && isolated
next if gem == "aj:integration" && isolated next if gem == "aj:integration" && isolated
next if gem == "guides" && isolated next if gem == "guides" && isolated
next if gem == "av:ujs" && isolated
build = Build.new(gem, isolated: isolated) build = Build.new(gem, isolated: isolated)
results[build.key] = build.run! results[build.key] = build.run!