javascript_features 1.0.0
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/lib/javascript_features/compiler.rb +28 -0
- data/lib/javascript_features/helper.rb +33 -0
- data/lib/javascript_features/test_case/servlet.rb +32 -0
- data/lib/javascript_features/test_case.rb +91 -0
- data/lib/javascript_features.rb +7 -0
- data/lib/rack/javascript_features.rb +48 -0
- data/rails/init.rb +1 -0
- data/test/compiler_test.rb +33 -0
- data/test/fixtures/public/javascripts/alternative/alternative.js +5 -0
- data/test/fixtures/public/javascripts/javascript_test/disabled_feature.js +7 -0
- data/test/fixtures/public/javascripts/javascript_test/enabled_feature.js +7 -0
- data/test/fixtures/public/javascripts/javascript_test/global_feature.js +7 -0
- data/test/fixtures/public/javascripts/lib/jquery_plugin.js +1 -0
- data/test/fixtures/public/javascripts/main/my_feature.js +5 -0
- data/test/fixtures/public/javascripts/xhr_test/global_load.js +5 -0
- data/test/fixtures/public/javascripts/xhr_test/load.js +5 -0
- data/test/fixtures/public/javascripts/xhr_test/xhr.js +11 -0
- data/test/helper_test.rb +108 -0
- data/test/javascript_test.rb +22 -0
- data/test/jslint_test.rb +14 -0
- data/test/rack_test.rb +79 -0
- data/test/test_case_test.rb +59 -0
- data/test/test_helper.rb +18 -0
- data/test/xhr_test.rb +33 -0
- metadata +201 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'jsmin'
|
2
|
+
|
3
|
+
module JavascriptFeatures
|
4
|
+
module Compiler
|
5
|
+
def self.compile(options = {})
|
6
|
+
defaults = {:minify => true, :package => 'main'}
|
7
|
+
options = defaults.merge(options)
|
8
|
+
|
9
|
+
files = files_for_package(options[:package])
|
10
|
+
compiled = files.map{|file| File.read(file) }.join("\n")
|
11
|
+
minified = JSMin.minify(compiled) if options[:minify]
|
12
|
+
|
13
|
+
minified || compiled
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.package_modified_time(package = 'main')
|
17
|
+
files_for_package(package).map{|f| File.new(f).mtime }.max
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def self.files_for_package(package)
|
22
|
+
lib_files = Dir.glob(Rails.root + 'public/javascripts/lib/**/*.js')
|
23
|
+
init_files = [File.join(File.dirname(__FILE__), *%w[ .. .. assets init.js ])]
|
24
|
+
feature_files = Dir.glob(Rails.root + "public/javascripts/#{package}/**/*.js")
|
25
|
+
lib_files + init_files + feature_files
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module JavascriptFeatures
|
2
|
+
module Helper
|
3
|
+
|
4
|
+
def self.included(controller)
|
5
|
+
controller.helper_method :use_javascript_for, :use_javascript_for?, :javascript_feature_classes, :include_javascript_features if controller.respond_to? :helper_method
|
6
|
+
end
|
7
|
+
|
8
|
+
def use_javascript_for(*features)
|
9
|
+
@javascript_features ||= []
|
10
|
+
@javascript_features += features.map{|f| f.to_s.downcase }
|
11
|
+
response.headers['X-JavascriptFeatures-Init'] = @javascript_features.uniq.join(' ') if request && request.xhr?
|
12
|
+
end
|
13
|
+
|
14
|
+
def use_javascript_for?(feature)
|
15
|
+
@javascript_features.include?(feature.to_s.downcase)
|
16
|
+
end
|
17
|
+
|
18
|
+
def javascript_feature_classes
|
19
|
+
(@javascript_features || []).uniq.map{ |feature| "with-js-#{feature}" }.join(" ")
|
20
|
+
end
|
21
|
+
|
22
|
+
def include_javascript_features(package = 'main')
|
23
|
+
query = Compiler.package_modified_time(package).to_i
|
24
|
+
tag = %Q{<script type="text/javascript" src="/javascripts/packaged/#{package}.js?#{query}"></script>}
|
25
|
+
if tag.respond_to?(:html_safe)
|
26
|
+
tag.html_safe
|
27
|
+
else
|
28
|
+
tag
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module JavascriptFeatures
|
2
|
+
class TestCase
|
3
|
+
class Servlet < ::WEBrick::HTTPServlet::AbstractServlet
|
4
|
+
def initialize(server, pages)
|
5
|
+
super server
|
6
|
+
@pages = pages
|
7
|
+
end
|
8
|
+
|
9
|
+
def service(req, res)
|
10
|
+
page = @pages[req.path]
|
11
|
+
if page
|
12
|
+
res.status = 200
|
13
|
+
res['Content-Type'] = 'text/html'
|
14
|
+
if page.is_a?(Hash)
|
15
|
+
page[:headers].each{ |k,v| res[k] = v }
|
16
|
+
res.body = page[:body]
|
17
|
+
else
|
18
|
+
res.body = page
|
19
|
+
end
|
20
|
+
elsif req.path =~ %r[^/javascripts/packaged/([^/]+).js$]
|
21
|
+
res.status = 200
|
22
|
+
res['Content-Type'] = 'text/javascript'
|
23
|
+
res.body = JavascriptFeatures::Compiler.compile(:package => $1)
|
24
|
+
else
|
25
|
+
res.status = 404
|
26
|
+
res['Content-Type'] = 'text/plain'
|
27
|
+
res.body = 'Not found'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'active_support/test_case'
|
2
|
+
require 'harmony'
|
3
|
+
|
4
|
+
module JavascriptFeatures
|
5
|
+
class TestCase < ::ActiveSupport::TestCase
|
6
|
+
extend JavascriptFeatures::Helper
|
7
|
+
|
8
|
+
autoload :Servlet, 'javascript_features/test_case/servlet'
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def request
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def uses_feature_package(package)
|
16
|
+
@feature_package = package
|
17
|
+
end
|
18
|
+
|
19
|
+
def feature_package
|
20
|
+
@feature_package ||= 'main'
|
21
|
+
end
|
22
|
+
|
23
|
+
def tests_feature(*names)
|
24
|
+
@feature_names = names
|
25
|
+
end
|
26
|
+
|
27
|
+
def feature_names
|
28
|
+
@feature_names ||= [self.name.downcase.sub(/test$/, '')]
|
29
|
+
end
|
30
|
+
|
31
|
+
def stubs_http_request(url, options)
|
32
|
+
@server_pages = server_pages.merge(url => options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def server_pages
|
36
|
+
@server_pages ||= {}
|
37
|
+
end
|
38
|
+
|
39
|
+
def uses_html(&block)
|
40
|
+
define_method(:setup) do
|
41
|
+
self.class.feature_names.each{ |f| self.class.use_javascript_for f }
|
42
|
+
@html = yield.strip
|
43
|
+
|
44
|
+
server_config = {:BindAddress => '0.0.0.0', :Port => 8076, :AccessLog => [], :Logger => WEBrick::Log::new('/dev/null', 7)}
|
45
|
+
@server = ::WEBrick::HTTPServer.new(server_config)
|
46
|
+
pages = self.class.server_pages.merge(
|
47
|
+
'/index.html' => @html,
|
48
|
+
'/jquery.js' => File.read(File.expand_path('../../../assets/jquery.js', __FILE__))
|
49
|
+
)
|
50
|
+
@server.mount('/', JavascriptFeatures::TestCase::Servlet, pages)
|
51
|
+
Thread.new{ @server.start }
|
52
|
+
|
53
|
+
@page = Harmony::Page.fetch("http://#{server_config[:BindAddress]}:#{server_config[:Port]}/index.html")
|
54
|
+
Harmony::Page::Window::BASE_RUNTIME.wait
|
55
|
+
end
|
56
|
+
|
57
|
+
define_method(:teardown) do
|
58
|
+
@server.shutdown
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def uses_html_body
|
63
|
+
uses_html do
|
64
|
+
%%
|
65
|
+
<!DOCTYPE html>
|
66
|
+
<html lang="en">
|
67
|
+
<head>
|
68
|
+
<title>Test page</title>
|
69
|
+
</head>
|
70
|
+
<body class="#{javascript_feature_classes}">
|
71
|
+
#{yield.strip}
|
72
|
+
|
73
|
+
<script src='/jquery.js'></script>
|
74
|
+
#{include_javascript_features(feature_package)}
|
75
|
+
</body>
|
76
|
+
</html>
|
77
|
+
%
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def execute_js(*args)
|
83
|
+
@page.execute_js(*args)
|
84
|
+
end
|
85
|
+
|
86
|
+
def assert_selector_count(expected_count, selector)
|
87
|
+
real_count = execute_js("jQuery(#{selector.to_json}).length")
|
88
|
+
assert_equal expected_count, real_count, "Expected #{expected_count} elements matching selector #{selector}, found #{real_count}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module JavascriptFeatures
|
2
|
+
autoload :Compiler, 'javascript_features/compiler'
|
3
|
+
autoload :Helper, 'javascript_features/helper'
|
4
|
+
autoload :TestCase, 'javascript_features/test_case'
|
5
|
+
end
|
6
|
+
|
7
|
+
ActionController::Base.send(:include, JavascriptFeatures::Helper) if defined?(ActionController)
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'javascript_features'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class JavascriptFeatures
|
5
|
+
|
6
|
+
DEFAULT_OPTIONS = {:minify => true}
|
7
|
+
|
8
|
+
def initialize(app, options = {})
|
9
|
+
@app = app
|
10
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
request = Rack::Request.new(env)
|
15
|
+
|
16
|
+
if package = package_for_path(request.path)
|
17
|
+
etag = package_etag(package)
|
18
|
+
if etag == env['HTTP_IF_NONE_MATCH']
|
19
|
+
[304, {}, []]
|
20
|
+
else
|
21
|
+
javascript = package_javascript(package)
|
22
|
+
[200, {"Content-Type" => "text/javascript", "Cache-Control" => "private", "ETag" => etag}, [javascript]]
|
23
|
+
end
|
24
|
+
else
|
25
|
+
@app.call(env)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def package_for_path(path)
|
32
|
+
relevant_url = path =~ %r{javascripts/packaged/([^/]+)\.js}
|
33
|
+
package_name = relevant_url && $1
|
34
|
+
real_package = package_name && ::File.exists?(::File.join(Rails.root, 'public', 'javascripts', package_name))
|
35
|
+
real_package && package_name
|
36
|
+
end
|
37
|
+
|
38
|
+
def package_etag(package_name)
|
39
|
+
mtime = ::JavascriptFeatures::Compiler.package_modified_time(package_name)
|
40
|
+
etag = Digest::MD5.hexdigest("#{package_name}/#{mtime.to_i}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def package_javascript(package_name)
|
44
|
+
::JavascriptFeatures::Compiler.compile(:package => package_name, :minify => @options[:minify])
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'javascript_features'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'jsmin'
|
3
|
+
require File.join(File.dirname(__FILE__), *%w[test_helper])
|
4
|
+
|
5
|
+
class CompilerTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
common_files = [
|
9
|
+
File.join(Rails.root, *%w[ public javascripts lib jquery_plugin.js ]),
|
10
|
+
File.join(File.dirname(__FILE__), *%w[ .. assets init.js ])
|
11
|
+
]
|
12
|
+
|
13
|
+
@main_files = common_files + [ File.join(Rails.root, *%w[ public javascripts main my_feature.js ]) ]
|
14
|
+
@alternative_files = common_files + [ File.join(Rails.root, *%w[ public javascripts alternative alternative.js ]) ]
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'compiling the main JavaScript package' do
|
18
|
+
should 'concatenate the relevant files in the correct order and minify the result' do
|
19
|
+
assert_equal JSMin.minify(@main_files.map{|f| File.read(f) }.join("\n")), JavascriptFeatures::Compiler.compile
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'optionally disable minification' do
|
23
|
+
assert_equal @main_files.map{|f| File.read(f) }.join("\n"), JavascriptFeatures::Compiler.compile(:minify => false)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'compiling the alternative JavaScript package' do
|
28
|
+
should 'take feature files from the /alternative directory instead of /main' do
|
29
|
+
assert_equal JSMin.minify(@alternative_files.map{|f| File.read(f) }.join("\n")), JavascriptFeatures::Compiler.compile(:package => 'alternative')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
jQuery.plugin = {};
|
data/test/helper_test.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[test_helper])
|
2
|
+
|
3
|
+
class HelperTest < Test::Unit::TestCase
|
4
|
+
include JavascriptFeatures::Helper
|
5
|
+
|
6
|
+
class TestRequest
|
7
|
+
def initialize(options)
|
8
|
+
@xhr = options[:xhr]
|
9
|
+
end
|
10
|
+
|
11
|
+
def xhr?
|
12
|
+
@xhr
|
13
|
+
end
|
14
|
+
|
15
|
+
def xml_http_request?
|
16
|
+
@xhr
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class TestResponse
|
21
|
+
attr_accessor :headers
|
22
|
+
def initialize
|
23
|
+
@headers = {'Content-Type' => 'text/html'}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when a JavaScript feature is enabled during a normal request" do
|
28
|
+
setup do
|
29
|
+
self.request = TestRequest.new(:xhr => false)
|
30
|
+
self.response = TestResponse.new
|
31
|
+
use_javascript_for "something"
|
32
|
+
end
|
33
|
+
|
34
|
+
should "set the corresponding body class" do
|
35
|
+
assert_equal "with-js-something", javascript_feature_classes
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'not modify the headers' do
|
39
|
+
assert_equal({'Content-Type' => 'text/html'}, response.headers)
|
40
|
+
end
|
41
|
+
|
42
|
+
should 'be able to check that it is enabled' do
|
43
|
+
assert use_javascript_for?('something')
|
44
|
+
assert !use_javascript_for?('something-else')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when a JavaScript feature is enabled during an XHR request' do
|
49
|
+
setup do
|
50
|
+
self.request = TestRequest.new(:xhr => true)
|
51
|
+
self.response = TestResponse.new
|
52
|
+
use_javascript_for "something"
|
53
|
+
use_javascript_for "something_else"
|
54
|
+
end
|
55
|
+
|
56
|
+
should 'modify the headers' do
|
57
|
+
assert_equal({'Content-Type' => 'text/html', 'X-JavascriptFeatures-Init' => 'something something_else'}, response.headers)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "when the same feature is enabled multiple times" do
|
62
|
+
setup do
|
63
|
+
use_javascript_for "something"
|
64
|
+
use_javascript_for "something-else"
|
65
|
+
use_javascript_for "something"
|
66
|
+
end
|
67
|
+
should "only include each class once" do
|
68
|
+
assert_equal "with-js-something with-js-something-else", javascript_feature_classes
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when no features have been enabled" do
|
73
|
+
should "not produce any classes" do
|
74
|
+
assert_equal "", javascript_feature_classes
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
should "allow to pass several features at one call" do
|
79
|
+
use_javascript_for "something", "something-else"
|
80
|
+
assert_equal "with-js-something with-js-something-else", javascript_feature_classes
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'including the packaged JavaScript' do
|
84
|
+
setup{ @script_tag = include_javascript_features }
|
85
|
+
should 'write a script tag containing the correct URL' do
|
86
|
+
assert_match %r{/javascripts/packaged/main\.js}, @script_tag
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'including an alternative JavaScript package' do
|
91
|
+
setup{ @script_tag = include_javascript_features(:alternative) }
|
92
|
+
should 'write a script tag containing the correct URL' do
|
93
|
+
assert_match %r{/javascripts/packaged/alternative\.js}, @script_tag
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'including the packaged JavaScript after one of the files has been modified' do
|
98
|
+
setup do
|
99
|
+
@before_modified = include_javascript_features
|
100
|
+
FileUtils.touch File.join(Rails.root, %w[ public javascripts main my_feature.js ])
|
101
|
+
@after_modified = include_javascript_features
|
102
|
+
end
|
103
|
+
|
104
|
+
should 'include different query strings to avoid caching' do
|
105
|
+
assert @before_modified != @after_modified, "Expected #{@before_modified.inspect} and #{@after_modified.inspect} to be different"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[test_helper])
|
2
|
+
require 'harmony'
|
3
|
+
require 'webrick'
|
4
|
+
|
5
|
+
class JavascriptTest < JavascriptFeatures::TestCase
|
6
|
+
uses_html_body{ '<h1>Test page</h1>' }
|
7
|
+
uses_feature_package :javascript_test
|
8
|
+
tests_feature :enabled_feature
|
9
|
+
|
10
|
+
should 'initialise the enabled feature' do
|
11
|
+
assert_selector_count 1, 'div.enabled_feature'
|
12
|
+
end
|
13
|
+
|
14
|
+
should 'not initialise the disabled feature' do
|
15
|
+
assert_selector_count 0, 'div.disabled_feature'
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'initialise the global feature' do
|
19
|
+
assert_selector_count 1, 'div.global_feature'
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/test/jslint_test.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[test_helper])
|
2
|
+
require 'jslint'
|
3
|
+
|
4
|
+
class JslintTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context 'all built-in JavaScript' do
|
7
|
+
should 'pass JSLint' do
|
8
|
+
paths = File.join(File.dirname(__FILE__), '../assets/**/*.js')
|
9
|
+
exclude = File.join(File.dirname(__FILE__), '../assets/jquery.js')
|
10
|
+
JSLint::Lint.new(:paths => paths, :exclude_paths => exclude).run
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
data/test/rack_test.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[test_helper])
|
2
|
+
require 'rack/test'
|
3
|
+
require 'rack/javascript_features'
|
4
|
+
|
5
|
+
class RackTest < Test::Unit::TestCase
|
6
|
+
include Rack::Test::Methods
|
7
|
+
|
8
|
+
def app
|
9
|
+
app = lambda{|env| [200, {"Content-Type" => "text/plain"}, ["all is well"]]}
|
10
|
+
Rack::JavascriptFeatures.new(app)
|
11
|
+
end
|
12
|
+
|
13
|
+
context "when JavaScript isn't being requested" do
|
14
|
+
setup do
|
15
|
+
get '/some/other/path'
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'delegate to the app' do
|
19
|
+
assert_equal 200, last_response.status
|
20
|
+
assert_equal 'all is well', last_response.body
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when the main JavaScript package is being requested" do
|
25
|
+
setup do
|
26
|
+
get '/javascripts/packaged/main.js'
|
27
|
+
end
|
28
|
+
|
29
|
+
should 'respond with the compiled JavaScript' do
|
30
|
+
assert_equal 200, last_response.status
|
31
|
+
assert_equal JavascriptFeatures::Compiler.compile, last_response.body
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when the main JavaScript package is being requested with a valid ETag" do
|
36
|
+
setup do
|
37
|
+
get '/javascripts/packaged/main.js'
|
38
|
+
assert_not_nil etag = last_response.headers['ETag'], 'Expected an ETag'
|
39
|
+
get '/javascripts/packaged/main.js', {}, {'HTTP_IF_NONE_MATCH' => etag}
|
40
|
+
end
|
41
|
+
|
42
|
+
should "respond with 'not modified'" do
|
43
|
+
assert_equal 304, last_response.status
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when the main JavaScript package is being requested with a valid ETag" do
|
48
|
+
setup do
|
49
|
+
get '/javascripts/package/main.js', {}, {'HTTP_IF_NONE_MATCH' => '12345'}
|
50
|
+
end
|
51
|
+
|
52
|
+
should "respond with some JavaScript" do
|
53
|
+
assert_equal 200, last_response.status
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when an alternative JavaScript package is being requested" do
|
58
|
+
setup do
|
59
|
+
get '/javascripts/packaged/alternative.js'
|
60
|
+
end
|
61
|
+
|
62
|
+
should 'respond with the compiled JavaScript' do
|
63
|
+
assert_equal 200, last_response.status
|
64
|
+
assert_equal JavascriptFeatures::Compiler.compile(:package => 'alternative'), last_response.body
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "when an unknown JavaScript package is being requested" do
|
69
|
+
setup do
|
70
|
+
get '/javascripts/packaged/does_not_exist.js'
|
71
|
+
end
|
72
|
+
|
73
|
+
should 'delegate to the app' do
|
74
|
+
assert_equal 200, last_response.status
|
75
|
+
assert_equal 'all is well', last_response.body
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[test_helper])
|
2
|
+
|
3
|
+
class TestCaseTest < JavascriptFeatures::TestCase
|
4
|
+
uses_html_body{ '<div class="foo"></div>' }
|
5
|
+
|
6
|
+
should 'have some HTML' do
|
7
|
+
assert_not_nil @html
|
8
|
+
end
|
9
|
+
|
10
|
+
should 'include the main JS package' do
|
11
|
+
assert_match %r{<script [^>]*src="/javascripts/packaged/main\.js(\?\d+)?"}, @html
|
12
|
+
end
|
13
|
+
|
14
|
+
should 'take the enabled feature name from the class name' do
|
15
|
+
assert_match %r{<body class="with-js-testcase">}, @html
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'create a Harmony::Page for the HTML' do
|
19
|
+
assert_not_nil @page
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'load the JavaScript in the Harmony::Page' do
|
23
|
+
assert_equal 'object', @page.execute_js('typeof Features')
|
24
|
+
end
|
25
|
+
|
26
|
+
should 'provide a method of executing JS without knowing about the @page variable' do
|
27
|
+
assert_equal 'object', execute_js('typeof Features')
|
28
|
+
end
|
29
|
+
|
30
|
+
should 'provide a custom assertion for counting DOM nodes' do
|
31
|
+
assert_nothing_raised{ assert_selector_count(1, 'div.foo') }
|
32
|
+
assert_raises(Test::Unit::AssertionFailedError){ assert_selector_count(2, 'div.foo') }
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
class CustomFeatureTest < JavascriptFeatures::TestCase
|
38
|
+
uses_html_body{ '<div class="foo"></div>' }
|
39
|
+
tests_feature 'foo'
|
40
|
+
|
41
|
+
should 'use the custom feature instead of deriving the feature from the class name' do
|
42
|
+
assert_match %r{<body class="with-js-foo">}, @html
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class MultipleFeatureTest < JavascriptFeatures::TestCase
|
47
|
+
uses_html_body{ '<div class="foo"></div>' }
|
48
|
+
tests_feature 'foo', 'bar', 'baz'
|
49
|
+
|
50
|
+
should 'use all of the custom features' do
|
51
|
+
['foo', 'bar', 'baz'].each do |feature|
|
52
|
+
assert execute_js("jQuery('body').hasClass('with-js-#{feature}')")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
should 'not use the feature name derived from the class name' do
|
57
|
+
assert execute_js('!jQuery("body").hasClass("with-js-mulitplefeature")')
|
58
|
+
end
|
59
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'yaml'
|
3
|
+
require 'bundler'
|
4
|
+
Bundler.require(:default, :development)
|
5
|
+
|
6
|
+
class Test::Unit::TestCase
|
7
|
+
attr_accessor :request, :response
|
8
|
+
end
|
9
|
+
|
10
|
+
module Rails
|
11
|
+
def self.root
|
12
|
+
File.join(File.dirname(__FILE__), 'fixtures') + '/'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.backtrace_cleaner
|
16
|
+
ActiveSupport::BacktraceCleaner.new
|
17
|
+
end
|
18
|
+
end
|
data/test/xhr_test.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[test_helper])
|
2
|
+
require 'harmony'
|
3
|
+
|
4
|
+
class XhrTest < JavascriptFeatures::TestCase
|
5
|
+
|
6
|
+
uses_html_body{%%
|
7
|
+
<h1>Test page</h1>
|
8
|
+
<div class="xhr-target"></div>
|
9
|
+
<div class="unrelated xhr-response">Unrelated</div>
|
10
|
+
%}
|
11
|
+
|
12
|
+
uses_feature_package :xhr_test
|
13
|
+
|
14
|
+
stubs_http_request('/xhr', :body => '<p class="real xhr-response">Hello, world</p>', :headers => {'X-JavascriptFeatures-Init' => 'load'})
|
15
|
+
|
16
|
+
should 'complete the XHR request' do
|
17
|
+
assert_selector_count 1, '.real.xhr-response'
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'initialise the feature required by the XHR content' do
|
21
|
+
assert_match(/touched-by-load/, execute_js('jQuery(".real.xhr-response").attr("class")'))
|
22
|
+
end
|
23
|
+
|
24
|
+
should 'limit the scope of the feature required by the XHR content to the XHR content itself' do
|
25
|
+
assert_no_match(/touched-by-load/, execute_js('jQuery(".unrelated.xhr-response").attr("class")'))
|
26
|
+
end
|
27
|
+
|
28
|
+
should 're-run global initialisation code when the XHR completes, limited to the scope of the XHR content' do
|
29
|
+
assert_selector_count 1, '.real.xhr-response .touched-by-global-init'
|
30
|
+
assert_selector_count 1, '.unrelated.xhr-response .touched-by-global-init'
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: javascript_features
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- George Brocklehurst
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-03-15 00:00:00 +00:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: jsmin
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: harmony
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: shoulda
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: redgreen
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :development
|
76
|
+
version_requirements: *id004
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: rack-test
|
79
|
+
prerelease: false
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
type: :development
|
90
|
+
version_requirements: *id005
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: jslint_on_rails
|
93
|
+
prerelease: false
|
94
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
hash: 3
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
type: :development
|
104
|
+
version_requirements: *id006
|
105
|
+
- !ruby/object:Gem::Dependency
|
106
|
+
name: activesupport
|
107
|
+
prerelease: false
|
108
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
hash: 3
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
version: "0"
|
117
|
+
type: :development
|
118
|
+
version_requirements: *id007
|
119
|
+
- !ruby/object:Gem::Dependency
|
120
|
+
name: json
|
121
|
+
prerelease: false
|
122
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
hash: 3
|
128
|
+
segments:
|
129
|
+
- 0
|
130
|
+
version: "0"
|
131
|
+
type: :development
|
132
|
+
version_requirements: *id008
|
133
|
+
description:
|
134
|
+
email: george.brocklehurst@gmail.com
|
135
|
+
executables: []
|
136
|
+
|
137
|
+
extensions: []
|
138
|
+
|
139
|
+
extra_rdoc_files: []
|
140
|
+
|
141
|
+
files:
|
142
|
+
- test/compiler_test.rb
|
143
|
+
- test/fixtures/public/javascripts/alternative/alternative.js
|
144
|
+
- test/fixtures/public/javascripts/javascript_test/disabled_feature.js
|
145
|
+
- test/fixtures/public/javascripts/javascript_test/enabled_feature.js
|
146
|
+
- test/fixtures/public/javascripts/javascript_test/global_feature.js
|
147
|
+
- test/fixtures/public/javascripts/lib/jquery_plugin.js
|
148
|
+
- test/fixtures/public/javascripts/main/my_feature.js
|
149
|
+
- test/fixtures/public/javascripts/xhr_test/global_load.js
|
150
|
+
- test/fixtures/public/javascripts/xhr_test/load.js
|
151
|
+
- test/fixtures/public/javascripts/xhr_test/xhr.js
|
152
|
+
- test/helper_test.rb
|
153
|
+
- test/javascript_test.rb
|
154
|
+
- test/jslint_test.rb
|
155
|
+
- test/rack_test.rb
|
156
|
+
- test/test_case_test.rb
|
157
|
+
- test/test_helper.rb
|
158
|
+
- test/xhr_test.rb
|
159
|
+
- lib/javascript_features/compiler.rb
|
160
|
+
- lib/javascript_features/helper.rb
|
161
|
+
- lib/javascript_features/test_case/servlet.rb
|
162
|
+
- lib/javascript_features/test_case.rb
|
163
|
+
- lib/javascript_features.rb
|
164
|
+
- lib/rack/javascript_features.rb
|
165
|
+
- rails/init.rb
|
166
|
+
has_rdoc: true
|
167
|
+
homepage: http://georgebrock.com
|
168
|
+
licenses: []
|
169
|
+
|
170
|
+
post_install_message:
|
171
|
+
rdoc_options: []
|
172
|
+
|
173
|
+
require_paths:
|
174
|
+
- lib
|
175
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
176
|
+
none: false
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
hash: 3
|
181
|
+
segments:
|
182
|
+
- 0
|
183
|
+
version: "0"
|
184
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
hash: 3
|
190
|
+
segments:
|
191
|
+
- 0
|
192
|
+
version: "0"
|
193
|
+
requirements: []
|
194
|
+
|
195
|
+
rubyforge_project:
|
196
|
+
rubygems_version: 1.4.2
|
197
|
+
signing_key:
|
198
|
+
specification_version: 3
|
199
|
+
summary: Structured, unobtrusive JavaScript for Rails applications
|
200
|
+
test_files: []
|
201
|
+
|