assets_test.rb 17.8 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 < Test::Unit::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

J
José Valim 已提交
20 21 22 23
    def app
      @app ||= Rails.application
    end

24
    def precompile!
25
      quietly do
26 27 28 29
        Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
      end
    end

30
    test "assets routes have higher priority" do
31
      app_file "app/assets/javascripts/demo.js.erb", "a = <%= image_path('rails.png').inspect %>;"
32 33 34 35 36 37 38

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

39 40
      require "#{app_path}/config/environment"

41
      get "/assets/demo.js"
42
      assert_equal 'a = "/assets/rails.png";', last_response.body.strip
43
    end
J
José Valim 已提交
44

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

J
José Valim 已提交
49 50 51 52 53 54 55 56 57
      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 已提交
58
    test "precompile creates the file, gives it the original asset's content and run in production as default" do
59
      app_file "app/assets/javascripts/application.js", "alert();"
60
      app_file "app/assets/javascripts/foo/application.js", "alert();"
61

62
      ENV["RAILS_ENV"] = nil
63 64
      precompile!

J
Jon Leighton 已提交
65
      files = Dir["#{app_path}/public/assets/application-*.js"]
66
      files << Dir["#{app_path}/public/assets/application.js"].first
J
Jon Leighton 已提交
67
      files << Dir["#{app_path}/public/assets/foo/application-*.js"].first
68
      files << Dir["#{app_path}/public/assets/foo/application.js"].first
69 70
      files.each do |file|
        assert_not_nil file, "Expected application.js asset to be generated, but none found"
71
        assert_equal "alert()", File.read(file)
72
      end
73 74
    end

75 76 77
    test "precompile application.js and application.css and all other files not ending with .js or .css by default" do
      app_file "app/assets/javascripts/application.js", "alert();"
      app_file "app/assets/stylesheets/application.css", "body{}"
78 79 80 81

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

82 83 84 85 86 87 88 89
      app_file "app/assets/javascripts/something.min.js", "alert();"
      app_file "app/assets/stylesheets/something.min.css", "body{}"

      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", "happy.face", "-happyface",
                               "-happy.png", "-happy.face.png", "_happyface", "_happy.face.png",
                               "_happy.png"]
90

91 92 93 94
      images_should_compile.each do |filename|
        app_file "app/assets/images/#{filename}", "happy"
      end

95
      precompile!
96 97 98 99

      images_should_compile.each do |filename|
        assert File.exists?("#{app_path}/public/assets/#{filename}")
      end
100

101 102
      assert File.exists?("#{app_path}/public/assets/application.js")
      assert File.exists?("#{app_path}/public/assets/application.css")
103 104 105 106

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

107 108 109 110
      assert !File.exists?("#{app_path}/public/assets/something.min.js")
      assert !File.exists?("#{app_path}/public/assets/something.min.css")
    end

111
    test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do
112 113 114
      add_to_config "config.assets.digest = true"
      add_to_config "config.action_controller.perform_caching = false"

115 116 117 118 119 120
      ENV["RAILS_ENV"] = "production"
      require "#{app_path}/config/environment"

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

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

127
      precompile!
128 129 130
      manifest = "#{app_path}/public/assets/manifest.yml"

      assets = YAML.load_file(manifest)
131 132
      assert_match(/application-([0-z]+)\.js/, assets["application.js"])
      assert_match(/application-([0-z]+)\.css/, assets["application.css"])
133 134
    end

135 136 137
    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();"
138
      # digest is default in false, we must enable it for test environment
139 140
      add_to_config "config.assets.digest = true"
      add_to_config "config.assets.manifest = '#{app_path}/shared'"
141

142
      precompile!
143 144 145
      manifest = "#{app_path}/shared/manifest.yml"

      assets = YAML.load_file(manifest)
146 147
      assert_match(/application-([0-z]+)\.js/, assets["application.js"])
      assert_match(/application-([0-z]+)\.css/, assets["application.css"])
148 149
    end

150 151
    test "the manifest file should be saved by default in the same assets folder" do
      app_file "app/assets/javascripts/application.js", "alert();"
152
      # digest is default in false, we must enable it for test environment
153 154
      add_to_config "config.assets.digest = true"
      add_to_config "config.assets.prefix = '/x'"
155

156
      precompile!
157 158 159

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

163 164 165
    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();"
166
      add_to_config "config.assets.digest = false"
167

168
      precompile!
169 170 171 172 173 174 175 176 177 178 179

      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

180
    test "assets do not require any assets group gem when manifest file is present" do
181
      app_file "app/assets/javascripts/application.js", "alert();"
182
      add_to_env_config "production", "config.serve_static_assets = true"
183 184

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

187 188 189 190 191 192 193 194 195 196 197 198 199
      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

200
    test "assets raise AssetNotPrecompiledError when manifest file is present and requested file isn't precompiled" do
201 202 203 204 205 206 207 208 209
      app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'app' %>"

      app_file "config/routes.rb", <<-RUBY
        AppTemplate::Application.routes.draw do
          match '/posts', :to => "posts#index"
        end
      RUBY

      ENV["RAILS_ENV"] = "production"
210
      precompile!
211 212 213 214

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

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

      get '/posts'
219
      assert_match(/AssetNotPrecompiledError/, last_response.body)
220 221 222 223 224
      assert_match(/app.js isn't precompiled/, last_response.body)
    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' %>"
225
      add_to_config "config.assets.compile = false"
226 227 228 229 230 231 232 233

      app_file "config/routes.rb", <<-RUBY
        AppTemplate::Application.routes.draw do
          match '/posts', :to => "posts#index"
        end
      RUBY

      ENV["RAILS_ENV"] = "development"
234
      precompile!
235 236 237 238 239 240 241 242 243

      # 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)
244
      assert_match(/app.js isn't precompiled/, last_response.body)
245 246
    end

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

252
      quietly do
253
        Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_ENV=test` }
S
Santiago Pastorino 已提交
254
      end
255 256
      file = Dir["#{app_path}/public/assets/application.css"].first
      assert_match(/\/assets\/rails\.png/, File.read(file))
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

261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
    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

279 280
    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') %>"
281
      add_to_config "config.assets.compile = true"
282 283

      ENV["RAILS_ENV"] = nil
284
      quietly do
285
        Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_GROUPS=assets` }
286
      end
J
Jon Leighton 已提交
287
      file = Dir["#{app_path}/public/assets/application-*.css"].first
288
      assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
289 290
    end

291
    test "precompile should handle utf8 filenames" do
292 293 294 295 296 297
      if `uname` =~ /Darwin/
        skip 'Asset lookup with Unicode filenames is a problematic due to different normalization forms. Mac uses NKD for filenames; Windows and Linux use NFC. So your asset lookups may mysteriously fail. Sprockets should handle these platform issues transparently.'
      end

      filename = "レイルズ.png"
      app_file "app/assets/images/#{filename}", "not a image really"
298 299
      add_to_config "config.assets.precompile = [ /\.png$$/, /application.(css|js)$/ ]"

300
      precompile!
301
      assert File.exists?("#{app_path}/public/assets/#{filename}")
302 303 304

      manifest = "#{app_path}/public/assets/manifest.yml"
      assets = YAML.load_file(manifest)
305
      assert_equal filename, assets[filename], assets.inspect
306 307
    end

308 309 310 311 312
    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"

313
      quietly do
314 315 316
        Dir.chdir(app_path){ `bundle exec rake assets:clean` }
      end

317
      files = Dir["#{app_path}/public/assets/**/*", "#{app_path}/tmp/cache/*"]
318 319 320
      assert_equal 0, files.length, "Expected no assets, but found #{files.join(', ')}"
    end

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

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

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

J
José Valim 已提交
332
    test "does not stream session cookies back" do
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
      app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"

      app_file "config/routes.rb", <<-RUBY
        AppTemplate::Application.routes.draw do
          match '/omg', :to => "omg#index"
        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 已提交
356
    end
357 358 359 360 361 362 363 364 365 366 367 368 369 370

    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
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403

    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'
      assert_match(/<script src="\/assets\/application-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body)
      assert_no_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body)
    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'
      assert_match(/<script src="\/assets\/application-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body)
      assert_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body)
    end

404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
    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

426 427 428 429 430 431
    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 已提交
432
    test "digested assets are not mistakenly removed" do
433
      app_file "app/assets/application.js", "alert();"
M
Mark J. Titorenko 已提交
434 435 436 437 438 439 440 441 442 443 444
      add_to_config "config.assets.compile = true"
      add_to_config "config.assets.digest = true"

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

      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

445 446 447 448 449 450 451 452 453 454 455 456 457
    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
      quietly do
        Dir.chdir(app_path){ `bundle exec rake assets:clean` }
      end

      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

458
    private
459

460 461 462 463 464 465 466 467 468 469 470
    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
          match '/posts', :to => "posts#index"
        end
      RUBY
    end
471 472
  end
end