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.
  '.gz', # Ignore gzipped files.
].freeze
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

Returns a new instance of SprocketsLoader.



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

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



95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/percy/capybara/loaders/sprockets_loader.rb', line 95

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



91
92
93
# File 'lib/percy/capybara/loaders/sprockets_loader.rb', line 91

def _rails
  Rails if defined?(Rails)
end

#build_resourcesObject



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
85
86
87
88
89
# File 'lib/percy/capybara/loaders/sprockets_loader.rb', line 32

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)

    # Skip large files, these are hopefully downloads and not used in page rendering.
    next if asset.length > MAX_FILESIZE_BYTES

    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 unless 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



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

def snapshot_resources
  [root_html_resource] + iframes_resources
end