Class: Percy::Capybara::Loaders::SprocketsLoader

Inherits:
BaseLoader
  • Object
show all
Defined in:
lib/percy/capybara/loaders/sprockets_loader.rb

Overview

Resource loader that loads assets via Sprockets (ie. the Rails asset pipeline).

Constant Summary collapse

SKIP_RESOURCE_EXTENSIONS =
[
  '.map',  # Ignore source maps.
]
MAX_FILESIZE_BYTES =

15 MB.

15 * 1024**2

Constants inherited from BaseLoader

BaseLoader::URL_REGEX

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ SprocketsLoader



21
22
23
24
25
# File 'lib/percy/capybara/loaders/sprockets_loader.rb', line 21

def initialize(options = {})
  @sprockets_environment = options[:sprockets_environment]
  @sprockets_options = options[:sprockets_options]
  super
end

Instance Attribute Details

#pageObject (readonly)

Returns the value of attribute page.



12
13
14
# File 'lib/percy/capybara/loaders/sprockets_loader.rb', line 12

def page
  @page
end

#sprockets_environmentObject (readonly)

Returns the value of attribute sprockets_environment.



13
14
15
# File 'lib/percy/capybara/loaders/sprockets_loader.rb', line 13

def sprockets_environment
  @sprockets_environment
end

#sprockets_optionsObject (readonly)

Returns the value of attribute sprockets_options.



14
15
16
# File 'lib/percy/capybara/loaders/sprockets_loader.rb', line 14

def sprockets_options
  @sprockets_options
end

Instance Method Details

#_asset_logical_pathsObject



90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/percy/capybara/loaders/sprockets_loader.rb', line 90

def _asset_logical_paths
  # Re-implement the same technique that "rake assets:precompile" uses to generate the
  # list of asset paths to include in compiled assets. https://goo.gl/sy2R4z
  # We can't just use environment.each_logical_path without any filters, because then
  # we will attempt to compile assets before they're rendered (such as _mixins.css).
  precompile_list = sprockets_options.precompile
  logical_paths = sprockets_environment.each_logical_path(*precompile_list).to_a
  logical_paths += precompile_list.flatten.select do |filename|
    Pathname.new(filename).absolute? if filename.is_a?(String)
  end
  logical_paths.uniq
end

#_railsObject



86
87
88
# File 'lib/percy/capybara/loaders/sprockets_loader.rb', line 86

def _rails
  Rails if defined?(Rails)
end

#build_resourcesObject



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/percy/capybara/loaders/sprockets_loader.rb', line 31

def build_resources
  resources = []
  loaded_resource_urls = Set.new

  # Load resources from the asset pipeline.
  _asset_logical_paths.each do |logical_path|
    next if SKIP_RESOURCE_EXTENSIONS.include?(File.extname(logical_path))

    asset = sprockets_environment.find_asset(logical_path)
    content = asset.to_s
    sha = Digest::SHA256.hexdigest(content)

    if defined?(ActionController)
      # Ask Rails where this asset is (this handles asset_hosts, digest paths, etc.).
      resource_url = ActionController::Base.helpers.asset_path(logical_path)
    else
      # TODO: more robust support for Sprockets usage outside Rails, ie Sinatra.
      # How do we find the correct path in that case?
      path = sprockets_options.digest ? asset.digest_path : logical_path
      resource_url = URI.escape("/assets/#{path}")
    end

    next if SKIP_RESOURCE_EXTENSIONS.include?(File.extname(resource_url))

    loaded_resource_urls.add(resource_url)
    resources << Percy::Client::Resource.new(resource_url, sha: sha, content: content)
  end

  # Load resources from the public/ directory, if a Rails app.
  if _rails
    public_path = _rails.public_path.to_s
    Find.find(public_path).each do |path|
      # Skip directories.
      next if !FileTest.file?(path)
      # Skip certain extensions.
      next if SKIP_RESOURCE_EXTENSIONS.include?(File.extname(path))
      # Skip large files, these are hopefully downloads and not used in page rendering.
      next if File.size(path) > MAX_FILESIZE_BYTES

      # Strip the public_path from the beginning of the resource_url.
      # This assumes that everything in the Rails public/ directory is served at the root
      # of the app.
      resource_url = path.sub(public_path, '')

      # Skip precompiled files already included via the asset pipeline.
      next if loaded_resource_urls.include?(resource_url)

      sha = Digest::SHA256.hexdigest(File.read(path))
      resources << Percy::Client::Resource.new(resource_url, sha: sha, path: path)
    end
  end

  resources
end

#snapshot_resourcesObject



27
28
29
# File 'lib/percy/capybara/loaders/sprockets_loader.rb', line 27

def snapshot_resources
  [root_html_resource] + iframes_resources
end