assets_test.rb 18.5 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
      add_to_env_config "development", "config.assets.digest = false"

55 56
      require "#{app_path}/config/environment"

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

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

J
José Valim 已提交
65 66 67 68 69 70 71 72 73
      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 已提交
74
    test "precompile creates the file, gives it the original asset's content and run in production as default" do
75
      app_file "app/assets/javascripts/application.js", "alert();"
76
      app_file "app/assets/javascripts/foo/application.js", "alert();"
77

78
      ENV["RAILS_ENV"] = nil
79 80
      precompile!

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

89 90 91
    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 已提交
92 93
      app_file "app/controllers/users_controller.rb", <<-eoruby
        class UsersController < ApplicationController; end
94 95
      eoruby
      app_file "app/models/user.rb", <<-eoruby
96
        class User < ActiveRecord::Base; raise 'should not be reached'; end
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
      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

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

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

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

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

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

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

137
      precompile!
138

J
Joshua Peek 已提交
139 140 141 142 143
      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"]

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

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

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

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

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

161 162 163
    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();"
164

165 166
      precompile!

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

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
    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

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

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

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

202
    test "precompile creates a manifest file with all the assets listed" do
203
      app_file "app/assets/images/rails.png", "notactuallyapng"
204
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
205 206
      app_file "app/assets/javascripts/application.js", "alert();"

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

J
Joshua Peek 已提交
210 211 212
      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"])
213 214
    end

215 216
    test "the manifest file should be saved by default in the same assets folder" do
      app_file "app/assets/javascripts/application.js", "alert();"
217
      add_to_config "config.assets.prefix = '/x'"
218

219
      precompile!
220

J
Joshua Peek 已提交
221 222 223
      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"])
224 225
    end

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

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

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

      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 已提交
246
    test "precompile properly refers files referenced with asset_path and runs in the provided RAILS_ENV" do
247
      app_file "app/assets/images/rails.png", "notactuallyapng"
248
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
249
      add_to_env_config "test", "config.assets.digest = true"
250

251 252
      precompile!('RAILS_ENV=test')

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

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

260
      app_file "app/assets/stylesheets/application.css.erb", "p { url: <%= asset_path('rails.png') %> }"
261 262 263 264

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

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

J
Joshua Peek 已提交
269
      app_file "app/assets/images/rails.png", "p { url: change }"
270 271

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

J
Joshua Peek 已提交
274
      assert_not_equal asset_path, assets["assets"]["application.css"]
275 276
    end

J
Joshua Peek 已提交
277
    test "precompile appends the md5 hash to files referenced with asset_path and run in production with digest true" do
278
      app_file "app/assets/images/rails.png", "notactuallyapng"
279
      app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
280

281 282
      ENV["RAILS_ENV"] = "production"
      precompile!
283

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

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

293
      precompile!
J
Joshua Peek 已提交
294 295 296

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

299
      require "#{app_path}/config/environment"
300

J
Joshua Peek 已提交
301
      get "/assets/#{URI.parser.escape(asset_path)}"
302
      assert_match "not an image really", last_response.body
J
Joshua Peek 已提交
303
      assert_file_exists("#{app_path}/public/assets/#{asset_path}")
304 305
    end

306 307 308 309 310
    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"

311
      clean_assets!
312

313 314
      files = Dir["#{app_path}/public/assets/**/*", "#{app_path}/tmp/cache/assets/development/*",
                  "#{app_path}/tmp/cache/assets/test/*", "#{app_path}/tmp/cache/assets/production/*"]
315 316 317
      assert_equal 0, files.length, "Expected no assets, but found #{files.join(', ')}"
    end

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

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

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

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

      app_file "config/routes.rb", <<-RUBY
333
        Rails.application.routes.draw do
334
          get '/omg', :to => "omg#index"
335 336 337
        end
      RUBY

338 339
      add_to_env_config "development", "config.assets.digest = false"

340 341 342 343 344
      require "#{app_path}/config/environment"

      class ::OmgController < ActionController::Base
        def index
          flash[:cool_story] = true
345
          render text: "ok"
346 347 348 349 350 351 352 353 354
        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 已提交
355
    end
356 357 358 359 360 361 362 363

    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();"

364 365
      add_to_env_config "development", "config.assets.digest = false"

366 367 368 369 370 371
      require "#{app_path}/config/environment"

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

    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'
386 387
      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)
388 389
    end

390 391 392 393 394 395
    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 %>"

      precompile!
J
Joshua Peek 已提交
396
      assert_equal "Post;\n", File.read(Dir["#{app_path}/public/assets/application-*.js"].first)
397 398
    end

399 400 401 402 403 404
    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

405 406 407 408 409 410
    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 已提交
411
    test "digested assets are not mistakenly removed" do
412
      app_file "app/assets/application.js", "alert();"
M
Mark J. Titorenko 已提交
413 414
      add_to_config "config.assets.compile = true"

415
      precompile!
M
Mark J. Titorenko 已提交
416 417 418 419 420

      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

421 422 423 424 425
    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
426 427

      clean_assets!
428

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

433 434 435
    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'"
436
      add_to_env_config "development", "config.assets.digest = false"
437 438 439 440 441 442 443 444 445 446
      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
447
      app_file "app/assets/images/rails.png", "notreallyapng"
448
      app_file "app/assets/javascripts/image_loader.js.erb", "var src='<%= image_path('rails.png') %>';"
449
      add_to_config "config.assets.precompile = %w{rails.png image_loader.js}"
450
      add_to_config "config.asset_host = 'example.com'"
451
      add_to_env_config "development", "config.assets.digest = false"
452 453
      precompile!

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

457 458
    test "asset paths should use RAILS_RELATIVE_URL_ROOT by default" do
      ENV["RAILS_RELATIVE_URL_ROOT"] = "/sub/uri"
459
      app_file "app/assets/images/rails.png", "notreallyapng"
460
      app_file "app/assets/javascripts/app.js.erb", "var src='<%= image_path('rails.png') %>';"
461
      add_to_config "config.assets.precompile = %w{rails.png app.js}"
462
      add_to_env_config "development", "config.assets.digest = false"
463 464
      precompile!

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

468 469 470 471 472
    test "assets:cache:clean should clean cache" do
      ENV["RAILS_ENV"] = "production"
      precompile!

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

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

479
    private
480

481 482 483 484 485 486
    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
487
        Rails.application.routes.draw do
488
          get '/posts', :to => "posts#index"
489 490 491
        end
      RUBY
    end
492 493
  end
end