assets_test.rb 20.0 KB
Newer Older
1
# -*- coding: utf-8 -*-
2
require 'isolation/abstract_unit'
3
require 'active_support/core_ext/kernel/reporting'
4 5 6
require 'rack/test'

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
22 23 24 25 26 27 28 29 30 31 32 33 34
        precompile_task = 'bundle exec rake assets:precompile'
        precompile_task += ' ' + env if env
        out = Dir.chdir(app_path){  %x[ #{precompile_task} ] }
        assert $?.exitstatus == 0,
               "#{precompile_task} has failed: #{out}.\
                Probably you didn't install JavaScript runtime."
        return out
      end
    end

    def clean_assets!
      quietly do
        assert Dir.chdir(app_path){ system('bundle exec rake assets:clean') }
35 36 37
      end
    end

38
    test "assets routes have higher priority" do
39
      app_file "app/assets/javascripts/demo.js.erb", "a = <%= image_path('rails.png').inspect %>;"
40 41 42

      app_file 'config/routes.rb', <<-RUBY
        AppTemplate::Application.routes.draw do
43
          get '*path', :to => lambda { |env| [200, { "Content-Type" => "text/html" }, "Not an asset"] }
44 45 46
        end
      RUBY

47 48
      require "#{app_path}/config/environment"

49
      get "/assets/demo.js"
50
      assert_equal 'a = "/assets/rails.png";', last_response.body.strip
51
    end
J
José Valim 已提交
52

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

J
José Valim 已提交
57 58 59 60 61 62 63 64 65
      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 已提交
66
    test "precompile creates the file, gives it the original asset's content and run in production as default" do
67
      app_file "app/assets/javascripts/application.js", "alert();"
68
      app_file "app/assets/javascripts/foo/application.js", "alert();"
69

70
      ENV["RAILS_ENV"] = nil
71 72
      precompile!

J
Jon Leighton 已提交
73
      files = Dir["#{app_path}/public/assets/application-*.js"]
74
      files << Dir["#{app_path}/public/assets/application.js"].first
J
Jon Leighton 已提交
75
      files << Dir["#{app_path}/public/assets/foo/application-*.js"].first
76
      files << Dir["#{app_path}/public/assets/foo/application.js"].first
77 78
      files.each do |file|
        assert_not_nil file, "Expected application.js asset to be generated, but none found"
S
Sergey Nartimov 已提交
79
        assert_equal "alert();", File.read(file)
80
      end
81 82
    end

83
    test "precompile application.js and application.css and all other non JS/CSS files" do
84 85
      app_file "app/assets/javascripts/application.js", "alert();"
      app_file "app/assets/stylesheets/application.css", "body{}"
86 87 88 89

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

90 91 92
      app_file "app/assets/javascripts/something.min.js", "alert();"
      app_file "app/assets/stylesheets/something.min.css", "body{}"

93 94 95
      app_file "app/assets/javascripts/something.else.js.erb", "alert();"
      app_file "app/assets/stylesheets/something.else.css.erb", "body{}"

96
      images_should_compile = ["a.png", "happyface.png", "happy_face.png", "happy.face.png",
97
                               "happy-face.png", "happy.happy_face.png", "happy_happy.face.png",
98 99 100
                               "happy.happy.face.png", "happy", "happy.face", "-happyface",
                               "-happy.png", "-happy.face.png", "_happyface", "_happy.face.png",
                               "_happy.png"]
101

102 103 104 105
      images_should_compile.each do |filename|
        app_file "app/assets/images/#{filename}", "happy"
      end

106
      precompile!
107 108

      images_should_compile.each do |filename|
109
        assert_file_exists "#{app_path}/public/assets/#{filename}"
110
      end
111

112 113
      assert_file_exists("#{app_path}/public/assets/application.js")
      assert_file_exists("#{app_path}/public/assets/application.css")
114

115 116
      assert_no_file_exists("#{app_path}/public/assets/someapplication.js")
      assert_no_file_exists("#{app_path}/public/assets/someapplication.css")
117

118 119
      assert_no_file_exists("#{app_path}/public/assets/something.min.js")
      assert_no_file_exists("#{app_path}/public/assets/something.min.css")
120

121 122 123 124 125 126 127 128 129 130
      assert_no_file_exists("#{app_path}/public/assets/something.else.js")
      assert_no_file_exists("#{app_path}/public/assets/something.else.css")
    end

    def assert_file_exists(filename)
      assert File.exists?(filename), "missing #{filename}"
    end

    def assert_no_file_exists(filename)
      assert !File.exists?(filename), "#{filename} does exist"
131 132
    end

133
    test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do
134 135 136
      add_to_config "config.assets.digest = true"
      add_to_config "config.action_controller.perform_caching = false"

137 138 139 140 141 142
      ENV["RAILS_ENV"] = "production"
      require "#{app_path}/config/environment"

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

143
    test "precompile creates a manifest file with all the assets listed" do
144 145
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
      app_file "app/assets/javascripts/application.js", "alert();"
146
      # digest is default in false, we must enable it for test environment
147
      add_to_config "config.assets.digest = true"
148

149
      precompile!
150 151 152
      manifest = "#{app_path}/public/assets/manifest.yml"

      assets = YAML.load_file(manifest)
153 154
      assert_match(/application-([0-z]+)\.js/, assets["application.js"])
      assert_match(/application-([0-z]+)\.css/, assets["application.css"])
155 156
    end

157 158 159
    test "precompile creates a manifest file in a custom path with all the assets listed" do
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
      app_file "app/assets/javascripts/application.js", "alert();"
160
      # digest is default in false, we must enable it for test environment
161 162
      add_to_config "config.assets.digest = true"
      add_to_config "config.assets.manifest = '#{app_path}/shared'"
163

164
      precompile!
165 166 167
      manifest = "#{app_path}/shared/manifest.yml"

      assets = YAML.load_file(manifest)
168 169
      assert_match(/application-([0-z]+)\.js/, assets["application.js"])
      assert_match(/application-([0-z]+)\.css/, assets["application.css"])
170 171
    end

172 173
    test "the manifest file should be saved by default in the same assets folder" do
      app_file "app/assets/javascripts/application.js", "alert();"
174
      # digest is default in false, we must enable it for test environment
175 176
      add_to_config "config.assets.digest = true"
      add_to_config "config.assets.prefix = '/x'"
177

178
      precompile!
179 180 181

      manifest = "#{app_path}/public/x/manifest.yml"
      assets = YAML.load_file(manifest)
182
      assert_match(/application-([0-z]+)\.js/, assets["application.js"])
183 184
    end

185 186 187
    test "precompile does not append asset digests when config.assets.digest is false" do
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
      app_file "app/assets/javascripts/application.js", "alert();"
188
      add_to_config "config.assets.digest = false"
189

190
      precompile!
191 192 193 194 195 196 197 198 199 200 201

      assert File.exists?("#{app_path}/public/assets/application.js")
      assert File.exists?("#{app_path}/public/assets/application.css")

      manifest = "#{app_path}/public/assets/manifest.yml"

      assets = YAML.load_file(manifest)
      assert_equal "application.js", assets["application.js"]
      assert_equal "application.css", assets["application.css"]
    end

202
    test "assets do not require any assets group gem when manifest file is present" do
203
      app_file "app/assets/javascripts/application.js", "alert();"
204
      add_to_env_config "production", "config.serve_static_assets = true"
205 206

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

209 210 211 212 213 214 215 216 217 218 219 220 221
      manifest = "#{app_path}/public/assets/manifest.yml"
      assets = YAML.load_file(manifest)
      asset_path = assets["application.js"]

      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

222
    test "assets raise AssetNotPrecompiledError when manifest file is present and requested file isn't precompiled" do
223 224 225 226
      app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'app' %>"

      app_file "config/routes.rb", <<-RUBY
        AppTemplate::Application.routes.draw do
227
          get '/posts', :to => "posts#index"
228 229 230 231
        end
      RUBY

      ENV["RAILS_ENV"] = "production"
232
      precompile!
233 234 235 236

      # Create file after of precompile
      app_file "app/assets/javascripts/app.js", "alert();"

237
      require "#{app_path}/config/environment"
J
José Valim 已提交
238 239 240
      class ::PostsController < ActionController::Base
        def show_detailed_exceptions?() true end
      end
241 242

      get '/posts'
243
      assert_match(/AssetNotPrecompiledError/, last_response.body)
R
Rafael Mendonça França 已提交
244
      assert_match(/app.js isn&#x27;t precompiled/, last_response.body)
245 246 247 248
    end

    test "assets raise AssetNotPrecompiledError when manifest file is present and requested file isn't precompiled if digest is disabled" do
      app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'app' %>"
249
      add_to_config "config.assets.compile = false"
250 251 252

      app_file "config/routes.rb", <<-RUBY
        AppTemplate::Application.routes.draw do
253
          get '/posts', :to => "posts#index"
254 255 256 257
        end
      RUBY

      ENV["RAILS_ENV"] = "development"
258
      precompile!
259 260 261 262 263 264 265 266 267

      # Create file after of precompile
      app_file "app/assets/javascripts/app.js", "alert();"

      require "#{app_path}/config/environment"
      class ::PostsController < ActionController::Base ; end

      get '/posts'
      assert_match(/AssetNotPrecompiledError/, last_response.body)
R
Rafael Mendonça França 已提交
268
      assert_match(/app.js isn&#x27;t precompiled/, last_response.body)
269 270
    end

271
    test "precompile properly refers files referenced with asset_path and and run in the provided RAILS_ENV" do
272
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
273
      # digest is default in false, we must enable it for test environment
274
      add_to_env_config "test", "config.assets.digest = true"
275

276 277
      precompile!('RAILS_ENV=test')

278 279
      file = Dir["#{app_path}/public/assets/application.css"].first
      assert_match(/\/assets\/rails\.png/, File.read(file))
J
Jon Leighton 已提交
280
      file = Dir["#{app_path}/public/assets/application-*.css"].first
281
      assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
282 283
    end

284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
    test "precompile shouldn't use the digests present in manifest.yml" do
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"

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

      manifest = "#{app_path}/public/assets/manifest.yml"
      assets = YAML.load_file(manifest)
      asset_path = assets["application.css"]

      app_file "app/assets/images/rails.png", "image changed"

      precompile!
      assets = YAML.load_file(manifest)

      assert_not_equal asset_path, assets["application.css"]
    end

302 303
    test "precompile appends the md5 hash to files referenced with asset_path and run in production as default even using RAILS_GROUPS=assets" do
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
304
      add_to_config "config.assets.compile = true"
305 306

      ENV["RAILS_ENV"] = nil
307 308 309

      precompile!('RAILS_GROUPS=assets')

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

314
    test "precompile should handle utf8 filenames" do
315 316
      filename = "レイルズ.png"
      app_file "app/assets/images/#{filename}", "not a image really"
K
kennyj 已提交
317
      add_to_config "config.assets.precompile = [ /\.png$/, /application.(css|js)$/ ]"
318

319
      precompile!
320
      require "#{app_path}/config/environment"
321

322
      get "/assets/#{URI.parser.escape(filename)}"
323 324
      assert_match "not a image really", last_response.body
      assert File.exists?("#{app_path}/public/assets/#{filename}")
325 326
    end

327 328 329 330 331
    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"

332
      clean_assets!
333

334
      files = Dir["#{app_path}/public/assets/**/*", "#{app_path}/tmp/cache/assets/*"]
335 336 337
      assert_equal 0, files.length, "Expected no assets, but found #{files.join(', ')}"
    end

338 339
    test "assets routes are not drawn when compilation is disabled" do
      app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
G
Guillermo Iguaran 已提交
340
      add_to_config "config.assets.compile = false"
341 342 343 344 345 346 347 348

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

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

J
José Valim 已提交
349
    test "does not stream session cookies back" do
350 351 352 353
      app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"

      app_file "config/routes.rb", <<-RUBY
        AppTemplate::Application.routes.draw do
354
          get '/omg', :to => "omg#index"
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
        end
      RUBY

      require "#{app_path}/config/environment"

      class ::OmgController < ActionController::Base
        def index
          flash[:cool_story] = true
          render :text => "ok"
        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 已提交
373
    end
374 375 376 377 378 379 380 381 382 383 384 385 386 387

    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
388 389 390 391 392 393 394 395 396 397 398 399 400 401

    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'
402 403
      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)
404 405 406 407 408 409 410 411 412 413 414 415 416
    end

    test "assets aren't concatened when compile is true is on and debug_assets params is true" do
      app_with_assets_in_view
      add_to_env_config "production", "config.assets.compile  = true"
      add_to_env_config "production", "config.assets.allow_debugging = true"

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

      class ::PostsController < ActionController::Base ; end

      get '/posts?debug_assets=true'
417 418
      assert_match(/<script src="\/assets\/application-([0-z]+)\.js\?body=1"><\/script>/, last_response.body)
      assert_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js\?body=1"><\/script>/, last_response.body)
419 420
    end

421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
    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!
      assert_equal "Post;\n", File.read("#{app_path}/public/assets/application.js")
    end

    test "assets can't access model information when precompiling if not initializing the app" 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", "<%= defined?(Post) || :NoPost %>"

      add_to_config "config.assets.digest = false"
      add_to_config "config.assets.initialize_on_precompile = false"

      precompile!
      assert_equal "NoPost;\n", File.read("#{app_path}/public/assets/application.js")
    end

443 444 445 446 447 448
    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

449 450 451 452 453 454
    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 已提交
455
    test "digested assets are not mistakenly removed" do
456
      app_file "app/assets/application.js", "alert();"
M
Mark J. Titorenko 已提交
457 458 459
      add_to_config "config.assets.compile = true"
      add_to_config "config.assets.digest = true"

460 461
      clean_assets!
      precompile!
M
Mark J. Titorenko 已提交
462 463 464 465 466

      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

467 468 469 470 471
    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
472 473

      clean_assets!
474 475 476 477 478

      files = Dir["#{app_path}/public/production_assets/application.js"]
      assert_equal 0, files.length, "Expected application.js asset to be removed, but still exists"
    end

479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
    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
      app_file "app/assets/javascripts/image_loader.js.erb", 'var src="<%= image_path("rails.png") %>";'
      add_to_config "config.assets.precompile = %w{image_loader.js}"
      add_to_config "config.asset_host = 'example.com'"
      precompile!

      assert_match 'src="//example.com/assets/rails.png"', File.read("#{app_path}/public/assets/image_loader.js")
    end

500 501 502 503 504 505 506 507 508
    test "asset paths should use RAILS_RELATIVE_URL_ROOT by default" do
      ENV["RAILS_RELATIVE_URL_ROOT"] = "/sub/uri"

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

      assert_match 'src="/sub/uri/assets/rails.png"', File.read("#{app_path}/public/assets/app.js")
    end
509

510 511 512 513 514 515 516 517 518 519 520 521
    test "assets:cache:clean should clean cache" do
      ENV["RAILS_ENV"] = "production"
      precompile!

      quietly do
        Dir.chdir(app_path){ `bundle exec rake assets:cache:clean` }
      end

      require "#{app_path}/config/environment"
      assert_equal 0, Dir.entries(Rails.application.assets.cache.cache_path).size - 2 # reject [".", ".."]
    end

522
    private
523

524 525 526 527 528 529 530
    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
        AppTemplate::Application.routes.draw do
531
          get '/posts', :to => "posts#index"
532 533 534
        end
      RUBY
    end
535 536
  end
end