assets_test.rb 18.6 KB
Newer Older
1
# -*- coding: utf-8 -*-
2 3
require 'isolation/abstract_unit'
require 'rack/test'
J
Joshua Peek 已提交
4
require 'active_support/json'
5 6

module ApplicationTests
7
  class AssetsTest < ActiveSupport::TestCase
8 9 10 11
    include ActiveSupport::Testing::Isolation
    include Rack::Test::Methods

    def setup
12
      build_app(initializers: true)
13 14 15
      boot_rails
    end

16 17 18 19
    def teardown
      teardown_app
    end

20
    def precompile!(env = nil)
21
      quietly do
J
Jeremy Kemper 已提交
22
        precompile_task = "bundle exec rake assets:precompile #{env} --trace 2>&1"
23 24 25
        output = Dir.chdir(app_path) { %x[ #{precompile_task} ] }
        assert $?.success?, output
        output
26 27 28 29 30
      end
    end

    def clean_assets!
      quietly do
J
Joshua Peek 已提交
31
        assert Dir.chdir(app_path) { system('bundle exec rake assets:clobber') }
32 33 34
      end
    end

35
    def assert_file_exists(filename)
J
Joshua Peek 已提交
36
      assert Dir[filename].first, "missing #{filename}"
37 38 39
    end

    def assert_no_file_exists(filename)
40
      assert !File.exist?(filename), "#{filename} does exist"
41 42
    end

43
    test "assets routes have higher priority" do
44
      app_file "app/assets/images/rails.png", "notactuallyapng"
45
      app_file "app/assets/javascripts/demo.js.erb", "a = <%= image_path('rails.png').inspect %>;"
46 47

      app_file 'config/routes.rb', <<-RUBY
48
        Rails.application.routes.draw do
49
          get '*path', to: lambda { |env| [200, { "Content-Type" => "text/html" }, ["Not an asset"]] }
50 51 52
        end
      RUBY

53 54
      require "#{app_path}/config/environment"

55
      get "/assets/demo.js"
56
      assert_equal 'a = "/assets/rails.png";', last_response.body.strip
57
    end
J
José Valim 已提交
58

J
José Valim 已提交
59 60
    test "assets do not require compressors until it is used" do
      app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
61
      add_to_env_config "production", "config.assets.compile = true"
62

J
José Valim 已提交
63 64 65 66 67 68 69 70 71
      ENV["RAILS_ENV"] = "production"
      require "#{app_path}/config/environment"

      assert !defined?(Uglifier)
      get "/assets/demo.js"
      assert_match "alert()", last_response.body
      assert defined?(Uglifier)
    end

S
Santiago Pastorino 已提交
72
    test "precompile creates the file, gives it the original asset's content and run in production as default" do
73
      app_file "app/assets/javascripts/application.js", "alert();"
74
      app_file "app/assets/javascripts/foo/application.js", "alert();"
75

76
      ENV["RAILS_ENV"] = nil
77 78
      precompile!

J
Jon Leighton 已提交
79 80
      files = Dir["#{app_path}/public/assets/application-*.js"]
      files << Dir["#{app_path}/public/assets/foo/application-*.js"].first
81 82
      files.each do |file|
        assert_not_nil file, "Expected application.js asset to be generated, but none found"
J
Joshua Peek 已提交
83
        assert_equal "alert();\n", File.read(file)
84
      end
85 86
    end

87 88 89
    def test_precompile_does_not_hit_the_database
      app_file "app/assets/javascripts/application.js", "alert();"
      app_file "app/assets/javascripts/foo/application.js", "alert();"
P
Prathamesh Sonpatki 已提交
90 91
      app_file "app/controllers/users_controller.rb", <<-eoruby
        class UsersController < ApplicationController; end
92 93
      eoruby
      app_file "app/models/user.rb", <<-eoruby
94
        class User < ActiveRecord::Base; raise 'should not be reached'; end
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
      eoruby

      ENV['RAILS_ENV']  = 'production'
      ENV['DATABASE_URL'] = 'postgresql://baduser:badpass@127.0.0.1/dbname'

      precompile!

      files = Dir["#{app_path}/public/assets/application-*.js"]
      files << Dir["#{app_path}/public/assets/foo/application-*.js"].first
      files.each do |file|
        assert_not_nil file, "Expected application.js asset to be generated, but none found"
        assert_equal "alert();".strip, File.read(file).strip
      end
    ensure
      ENV.delete 'RAILS_ENV'
      ENV.delete 'DATABASE_URL'
    end

113
    test "precompile application.js and application.css and all other non JS/CSS files" do
114 115
      app_file "app/assets/javascripts/application.js", "alert();"
      app_file "app/assets/stylesheets/application.css", "body{}"
116 117 118 119

      app_file "app/assets/javascripts/someapplication.js", "alert();"
      app_file "app/assets/stylesheets/someapplication.css", "body{}"

120 121 122
      app_file "app/assets/javascripts/something.min.js", "alert();"
      app_file "app/assets/stylesheets/something.min.css", "body{}"

123 124 125
      app_file "app/assets/javascripts/something.else.js.erb", "alert();"
      app_file "app/assets/stylesheets/something.else.css.erb", "body{}"

126
      images_should_compile = ["a.png", "happyface.png", "happy_face.png", "happy.face.png",
127
                               "happy-face.png", "happy.happy_face.png", "happy_happy.face.png",
128 129
                               "happy.happy.face.png", "-happy.png", "-happy.face.png",
                               "_happy.face.png", "_happy.png"]
130

131 132 133 134
      images_should_compile.each do |filename|
        app_file "app/assets/images/#{filename}", "happy"
      end

135
      precompile!
136

J
Joshua Peek 已提交
137 138 139 140 141
      images_should_compile = ["a-*.png", "happyface-*.png", "happy_face-*.png", "happy.face-*.png",
                               "happy-face-*.png", "happy.happy_face-*.png", "happy_happy.face-*.png",
                               "happy.happy.face-*.png", "-happy-*.png", "-happy.face-*.png",
                               "_happy.face-*.png", "_happy-*.png"]

142
      images_should_compile.each do |filename|
143
        assert_file_exists("#{app_path}/public/assets/#{filename}")
144
      end
145

J
Joshua Peek 已提交
146 147
      assert_file_exists("#{app_path}/public/assets/application-*.js")
      assert_file_exists("#{app_path}/public/assets/application-*.css")
148

J
Joshua Peek 已提交
149 150
      assert_no_file_exists("#{app_path}/public/assets/someapplication-*.js")
      assert_no_file_exists("#{app_path}/public/assets/someapplication-*.css")
151

J
Joshua Peek 已提交
152 153
      assert_no_file_exists("#{app_path}/public/assets/something.min-*.js")
      assert_no_file_exists("#{app_path}/public/assets/something.min-*.css")
154

J
Joshua Peek 已提交
155 156
      assert_no_file_exists("#{app_path}/public/assets/something.else-*.js")
      assert_no_file_exists("#{app_path}/public/assets/something.else-*.css")
157 158
    end

159 160 161
    test "precompile something.js for directory containing index file" do
      add_to_config "config.assets.precompile = [ 'something.js' ]"
      app_file "app/assets/javascripts/something/index.js.erb", "alert();"
162

163 164
      precompile!

J
Joshua Peek 已提交
165
      assert_file_exists("#{app_path}/public/assets/something-*.js")
166 167
    end

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    test 'precompile use assets defined in app env config' do
      add_to_env_config 'production', 'config.assets.precompile = [ "something.js" ]'

      app_file 'app/assets/javascripts/something.js.erb', 'alert();'

      precompile! 'RAILS_ENV=production'

      assert_file_exists("#{app_path}/public/assets/something-*.js")
    end

    test 'precompile use assets defined in app config and reassigned in app env config' do
      add_to_config 'config.assets.precompile = [ "something.js" ]'
      add_to_env_config 'production', 'config.assets.precompile += [ "another.js" ]'

      app_file 'app/assets/javascripts/something.js.erb', 'alert();'
      app_file 'app/assets/javascripts/another.js.erb', 'alert();'

      precompile! 'RAILS_ENV=production'

      assert_file_exists("#{app_path}/public/assets/something-*.js")
      assert_file_exists("#{app_path}/public/assets/another-*.js")
    end

191
    test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do
192 193 194
      add_to_config "config.assets.digest = true"
      add_to_config "config.action_controller.perform_caching = false"

195 196 197 198 199 200
      ENV["RAILS_ENV"] = "production"
      require "#{app_path}/config/environment"

      assert_equal Sprockets::Index, Rails.application.assets.class
    end

201
    test "precompile creates a manifest file with all the assets listed" do
202
      app_file "app/assets/images/rails.png", "notactuallyapng"
203
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
204
      app_file "app/assets/javascripts/application.js", "alert();"
205
      # digest is default in false, we must enable it for test environment
206
      add_to_config "config.assets.digest = true"
207

208
      precompile!
J
Joshua Peek 已提交
209
      manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
210

J
Joshua Peek 已提交
211 212 213
      assets = ActiveSupport::JSON.decode(File.read(manifest))
      assert_match(/application-([0-z]+)\.js/, assets["assets"]["application.js"])
      assert_match(/application-([0-z]+)\.css/, assets["assets"]["application.css"])
214 215
    end

216 217
    test "the manifest file should be saved by default in the same assets folder" do
      app_file "app/assets/javascripts/application.js", "alert();"
218
      # digest is default in false, we must enable it for test environment
219 220
      add_to_config "config.assets.digest = true"
      add_to_config "config.assets.prefix = '/x'"
221

222
      precompile!
223

J
Joshua Peek 已提交
224 225 226
      manifest = Dir["#{app_path}/public/x/manifest-*.json"].first
      assets = ActiveSupport::JSON.decode(File.read(manifest))
      assert_match(/application-([0-z]+)\.js/, assets["assets"]["application.js"])
227 228
    end

229
    test "assets do not require any assets group gem when manifest file is present" do
230
      app_file "app/assets/javascripts/application.js", "alert();"
231
      add_to_env_config "production", "config.serve_static_assets = true"
232 233

      ENV["RAILS_ENV"] = "production"
234 235
      precompile!

J
Joshua Peek 已提交
236 237 238
      manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
      assets = ActiveSupport::JSON.decode(File.read(manifest))
      asset_path = assets["assets"]["application.js"]
239 240 241 242 243 244 245 246 247 248

      require "#{app_path}/config/environment"

      # Checking if Uglifier is defined we can know if Sprockets was reached or not
      assert !defined?(Uglifier)
      get "/assets/#{asset_path}"
      assert_match "alert()", last_response.body
      assert !defined?(Uglifier)
    end

D
David Chapman 已提交
249
    test "precompile properly refers files referenced with asset_path and runs in the provided RAILS_ENV" do
250
      app_file "app/assets/images/rails.png", "notactuallyapng"
251
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
252
      # digest is default in false, we must enable it for test environment
253
      add_to_env_config "test", "config.assets.digest = true"
254

255 256
      precompile!('RAILS_ENV=test')

J
Jon Leighton 已提交
257
      file = Dir["#{app_path}/public/assets/application-*.css"].first
258
      assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
259 260
    end

J
Joshua Peek 已提交
261
    test "precompile shouldn't use the digests present in manifest.json" do
262 263
      app_file "app/assets/images/rails.png", "notactuallyapng"

264
      app_file "app/assets/stylesheets/application.css.erb", "p { url: <%= asset_path('rails.png') %> }"
265 266 267 268

      ENV["RAILS_ENV"] = "production"
      precompile!

J
Joshua Peek 已提交
269 270 271
      manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
      assets = ActiveSupport::JSON.decode(File.read(manifest))
      asset_path = assets["assets"]["application.css"]
272

J
Joshua Peek 已提交
273
      app_file "app/assets/images/rails.png", "p { url: change }"
274 275

      precompile!
J
Joshua Peek 已提交
276
      assets = ActiveSupport::JSON.decode(File.read(manifest))
277

J
Joshua Peek 已提交
278
      assert_not_equal asset_path, assets["assets"]["application.css"]
279 280
    end

J
Joshua Peek 已提交
281
    test "precompile appends the md5 hash to files referenced with asset_path and run in production with digest true" do
282
      app_file "app/assets/images/rails.png", "notactuallyapng"
283
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
284
      add_to_config "config.assets.compile = true"
J
Joshua Peek 已提交
285
      add_to_config "config.assets.digest = true"
286 287

      ENV["RAILS_ENV"] = nil
288 289 290

      precompile!('RAILS_GROUPS=assets')

J
Jon Leighton 已提交
291
      file = Dir["#{app_path}/public/assets/application-*.css"].first
292
      assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
293 294
    end

295
    test "precompile should handle utf8 filenames" do
296
      filename = "レイルズ.png"
297
      app_file "app/assets/images/#{filename}", "not an image really"
K
kennyj 已提交
298
      add_to_config "config.assets.precompile = [ /\.png$/, /application.(css|js)$/ ]"
299

300
      precompile!
J
Joshua Peek 已提交
301 302 303

      manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
      assets = ActiveSupport::JSON.decode(File.read(manifest))
304
      assert asset_path = assets["assets"].find { |(k, _)| k && k =~ /.png/ }[1]
J
Joshua Peek 已提交
305

306
      require "#{app_path}/config/environment"
307

J
Joshua Peek 已提交
308
      get "/assets/#{URI.parser.escape(asset_path)}"
309
      assert_match "not an image really", last_response.body
J
Joshua Peek 已提交
310
      assert_file_exists("#{app_path}/public/assets/#{asset_path}")
311 312
    end

313 314 315 316 317
    test "assets are cleaned up properly" do
      app_file "public/assets/application.js", "alert();"
      app_file "public/assets/application.css", "a { color: green; }"
      app_file "public/assets/subdir/broken.png", "not really an image file"

318
      clean_assets!
319

320 321
      files = Dir["#{app_path}/public/assets/**/*", "#{app_path}/tmp/cache/assets/development/*",
                  "#{app_path}/tmp/cache/assets/test/*", "#{app_path}/tmp/cache/assets/production/*"]
322 323 324
      assert_equal 0, files.length, "Expected no assets, but found #{files.join(', ')}"
    end

325 326
    test "assets routes are not drawn when compilation is disabled" do
      app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
G
Guillermo Iguaran 已提交
327
      add_to_config "config.assets.compile = false"
328 329 330 331 332 333 334 335

      ENV["RAILS_ENV"] = "production"
      require "#{app_path}/config/environment"

      get "/assets/demo.js"
      assert_equal 404, last_response.status
    end

J
José Valim 已提交
336
    test "does not stream session cookies back" do
337 338 339
      app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"

      app_file "config/routes.rb", <<-RUBY
340
        Rails.application.routes.draw do
341
          get '/omg', :to => "omg#index"
342 343 344 345 346 347 348 349
        end
      RUBY

      require "#{app_path}/config/environment"

      class ::OmgController < ActionController::Base
        def index
          flash[:cool_story] = true
350
          render text: "ok"
351 352 353 354 355 356 357 358 359
        end
      end

      get "/omg"
      assert_equal 'ok', last_response.body

      get "/assets/demo.js"
      assert_match "alert()", last_response.body
      assert_equal nil, last_response.headers["Set-Cookie"]
J
José Valim 已提交
360
    end
361 362 363 364 365 366 367 368 369 370 371 372 373 374

    test "files in any assets/ directories are not added to Sprockets" do
      %w[app lib vendor].each do |dir|
        app_file "#{dir}/assets/#{dir}_test.erb", "testing"
      end

      app_file "app/assets/javascripts/demo.js", "alert();"

      require "#{app_path}/config/environment"

      get "/assets/demo.js"
      assert_match "alert();", last_response.body
      assert_equal 200, last_response.status
    end
375 376 377 378 379 380 381 382 383 384 385 386 387 388

    test "assets are concatenated when debug is off and compile is off either if debug_assets param is provided" do
      app_with_assets_in_view

      # config.assets.debug and config.assets.compile are false for production environment
      ENV["RAILS_ENV"] = "production"
      precompile!

      require "#{app_path}/config/environment"

      class ::PostsController < ActionController::Base ; end

      # the debug_assets params isn't used if compile is off
      get '/posts?debug_assets=true'
389 390
      assert_match(/<script src="\/assets\/application-([0-z]+)\.js"><\/script>/, last_response.body)
      assert_no_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js"><\/script>/, last_response.body)
391 392
    end

393 394 395 396 397 398 399
    test "assets can access model information when precompiling" do
      app_file "app/models/post.rb", "class Post; end"
      app_file "app/assets/javascripts/application.js", "//= require_tree ."
      app_file "app/assets/javascripts/xmlhr.js.erb", "<%= Post.name %>"

      add_to_config "config.assets.digest = false"
      precompile!
J
Joshua Peek 已提交
400
      assert_equal "Post;\n", File.read(Dir["#{app_path}/public/assets/application-*.js"].first)
401 402
    end

403 404 405 406 407 408
    test "initialization on the assets group should set assets_dir" do
      require "#{app_path}/config/application"
      Rails.application.initialize!(:assets)
      assert_not_nil Rails.application.config.action_controller.assets_dir
    end

409 410 411 412 413 414
    test "enhancements to assets:precompile should only run once" do
      app_file "lib/tasks/enhance.rake", "Rake::Task['assets:precompile'].enhance { puts 'enhancement' }"
      output = precompile!
      assert_equal 1, output.scan("enhancement").size
    end

M
Mark J. Titorenko 已提交
415
    test "digested assets are not mistakenly removed" do
416
      app_file "app/assets/application.js", "alert();"
M
Mark J. Titorenko 已提交
417 418 419
      add_to_config "config.assets.compile = true"
      add_to_config "config.assets.digest = true"

420
      precompile!
M
Mark J. Titorenko 已提交
421 422 423 424 425

      files = Dir["#{app_path}/public/assets/application-*.js"]
      assert_equal 1, files.length, "Expected digested application.js asset to be generated, but none found"
    end

426 427 428 429 430
    test "digested assets are removed from configured path" do
      app_file "public/production_assets/application.js", "alert();"
      add_to_env_config "production", "config.assets.prefix = 'production_assets'"

      ENV["RAILS_ENV"] = nil
431 432

      clean_assets!
433

J
Joshua Peek 已提交
434
      files = Dir["#{app_path}/public/production_assets/application-*.js"]
435 436 437
      assert_equal 0, files.length, "Expected application.js asset to be removed, but still exists"
    end

438 439 440 441 442 443 444 445 446 447 448 449 450
    test "asset urls should use the request's protocol by default" do
      app_with_assets_in_view
      add_to_config "config.asset_host = 'example.com'"
      require "#{app_path}/config/environment"
      class ::PostsController < ActionController::Base; end

      get '/posts', {}, {'HTTPS'=>'off'}
      assert_match('src="http://example.com/assets/application.js', last_response.body)
      get '/posts', {}, {'HTTPS'=>'on'}
      assert_match('src="https://example.com/assets/application.js', last_response.body)
    end

    test "asset urls should be protocol-relative if no request is in scope" do
451
      app_file "app/assets/images/rails.png", "notreallyapng"
452
      app_file "app/assets/javascripts/image_loader.js.erb", "var src='<%= image_path('rails.png') %>';"
453 454 455 456
      add_to_config "config.assets.precompile = %w{image_loader.js}"
      add_to_config "config.asset_host = 'example.com'"
      precompile!

457
      assert_match "src='//example.com/assets/rails.png'", File.read(Dir["#{app_path}/public/assets/image_loader-*.js"].first)
458 459
    end

460 461
    test "asset paths should use RAILS_RELATIVE_URL_ROOT by default" do
      ENV["RAILS_RELATIVE_URL_ROOT"] = "/sub/uri"
462
      app_file "app/assets/images/rails.png", "notreallyapng"
463

464
      app_file "app/assets/javascripts/app.js.erb", "var src='<%= image_path('rails.png') %>';"
465 466 467
      add_to_config "config.assets.precompile = %w{app.js}"
      precompile!

468
      assert_match "src='/sub/uri/assets/rails.png'", File.read(Dir["#{app_path}/public/assets/app-*.js"].first)
469 470
    end

471 472 473 474 475
    test "assets:cache:clean should clean cache" do
      ENV["RAILS_ENV"] = "production"
      precompile!

      quietly do
J
Joshua Peek 已提交
476
        Dir.chdir(app_path){ `bundle exec rake assets:clobber` }
477 478
      end

J
Joshua Peek 已提交
479
      assert !File.exist?("#{app_path}/tmp/cache/assets")
480 481
    end

482
    private
483

484 485 486 487 488 489
    def app_with_assets_in_view
      app_file "app/assets/javascripts/application.js", "//= require_tree ."
      app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }"
      app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>"

      app_file "config/routes.rb", <<-RUBY
490
        Rails.application.routes.draw do
491
          get '/posts', :to => "posts#index"
492 493 494
        end
      RUBY
    end
495 496
  end
end