提交 a5b83123 编写于 作者: R Rafael França 提交者: GitHub

Merge pull request #28098 from rails/rails-ujs-intergration

Better integrate rails-ujs in our repository
......@@ -20,3 +20,5 @@ pkg
/railties/doc
/railties/tmp
/guides/output
node_modules/
/actionview/log
......@@ -6,6 +6,8 @@ cache:
directories:
- /tmp/cache/unicode_conformance
- /tmp/beanstalkd-1.10
- node_modules
- $HOME/.nvm
services:
- memcached
......@@ -21,6 +23,11 @@ before_install:
- "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)"
- "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:
# Set Sauce Labs username and access key. Obfuscated, purposefully not encrypted.
......@@ -52,6 +59,8 @@ rvm:
matrix:
include:
- rvm: 2.4.0
env: "GEM=av:ujs"
- rvm: 2.2.6
env: "GEM=aj:integration"
services:
......
require "rake/testtask"
require "fileutils"
desc "Default Task"
task default: :test
......@@ -25,6 +26,32 @@ namespace :test do
t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION)
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
desc "ActiveRecord Integration Tests"
Rake::TestTask.new(:active_record) do |t|
......
Copyright (c) 2007-2017 Rails Core team
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Ruby on Rails unobtrusive scripting adapter.
========================================
This unobtrusive scripting support file is developed for the Ruby on Rails framework, but is not strictly tied to any specific backend. You can drop this into any application to:
- force confirmation dialogs for various actions;
- make non-GET requests from hyperlinks;
- make forms or hyperlinks submit data asynchronously with Ajax;
- have submit buttons become automatically disabled on form submit to prevent double-clicking.
These features are achieved by adding certain ["data" attributes][data] to your HTML markup. In Rails, they are added by the framework's template helpers.
Requirements
------------
- HTML5 doctype (optional).
If you don't use HTML5, adding "data" attributes to your HTML4 or XHTML pages might make them fail [W3C markup validation][validator]. However, this shouldn't create any issues for web browsers or other user agents.
Installation using npm
------------
Run `npm install rails-ujs --save` to install the rails-ujs package.
Installation using Yarn
------------
Run `yarn add rails-ujs` to install the rails-ujs package.
Usage
------------
Require `rails-ujs` into your application.js manifest.
```javascript
//= require rails-ujs
```
How to run tests
------------
Run `bundle exec rake ujs:server` first, and then run the web tests by visiting [[http://localhost:4567]] in your browser.
## License
rails-ujs is released under the [MIT License](MIT-LICENSE).
[data]: http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes "Embedding custom non-visible data with the data-* attributes"
[validator]: http://validator.w3.org/
[csrf]: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
{
"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"
}
}
......@@ -12,7 +12,7 @@
"scripts": {
"build": "bundle exec blade build",
"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": {
"type": "git",
......
$LOAD_PATH.unshift File.expand_path("..", __FILE__)
require "server"
run UJS::Server
require "rack"
require "rails"
require "action_controller/railtie"
require "action_view/railtie"
require "blade"
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
class Server < Rails::Application
routes.append do
......@@ -18,7 +17,7 @@ class Server < Rails::Application
config.cache_classes = false
config.eager_load = false
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.logger = Logger.new(STDOUT)
config.log_level = :error
......@@ -26,32 +25,6 @@ class Server < Rails::Application
end
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)
names = ["/vendor/qunit.js", "settings"] + names
names.map { |name| script_tag name }.join("\n").html_safe
......@@ -61,10 +34,6 @@ def script_tag(src)
src = "/test/#{src}.js" unless src.index("/")
%(<script src="#{src}" type="text/javascript"></script>).html_safe
end
def jquery_versions
JQUERY_VERSIONS
end
end
class TestsController < ActionController::Base
......@@ -72,8 +41,6 @@ class TestsController < ActionController::Base
layout "application"
def index
params[:version] ||= ENV["JQUERY_VERSION"] || "1.11.0"
params[:cdn] ||= "jquery"
render :index
end
......
......@@ -3,30 +3,15 @@
<head>
<title><%= @title %></title>
<link href="/vendor/qunit.css" media="screen" rel="stylesheet" type="text/css" media="screen, projection" />
<style>
#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_tag "http://code.jquery.com/jquery-2.2.0.js" %>
<script>
// This is for test in override.js.
// Must go before rails-ujs.
$(document).bind('rails:attachBindings', function() {
$.rails.linkClickSelector += ', a[data-custom-remote-link]';
document.addEventListener('rails:attachBindings', function() {
window.Rails.linkClickSelector += ', a[data-custom-remote-link]';
// Hijacks link click before ujs binds any handlers
// 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();
});
});
......
......@@ -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' %>
<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>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
......
/*
* 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);
}
})();
......@@ -36,8 +36,10 @@ def initialize(component, options = {})
def run!(options = {})
self.options.update(options)
Dir.chdir(dir) do
announce(heading)
if guides?
run_bug_report_templates
else
......@@ -69,7 +71,7 @@ def tasks
end
tasks
else
["test", ("isolated" if isolated?), ("integration" if integration?)].compact.join(":")
["test", ("isolated" if isolated?), ("integration" if integration?), ("ujs" if ujs?)].compact.join(":")
end
end
......@@ -92,6 +94,10 @@ def guides?
gem == "guides"
end
def ujs?
component.split(":").last == "ujs"
end
def isolated?
options[:isolated]
end
......@@ -151,6 +157,7 @@ def run_bug_report_templates
next if gem == "ac:integration" && isolated
next if gem == "aj:integration" && isolated
next if gem == "guides" && isolated
next if gem == "av:ujs" && isolated
build = Build.new(gem, isolated: isolated)
results[build.key] = build.run!
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册