spec/lib/percy/capybara/client/snapshots_spec.rb in percy-capybara-0.1.0 vs spec/lib/percy/capybara/client/snapshots_spec.rb in percy-capybara-0.1.1

- old
+ new

@@ -1,14 +1,14 @@ require 'json' require 'digest' -RSpec.describe Percy::Capybara::Client::Snapshots do +RSpec.describe Percy::Capybara::Client::Snapshots, type: :feature do let(:capybara_client) { Percy::Capybara::Client.new } # Start a temp webserver that serves the testdata directory. # You can test this server manually by running: - # ruby -run -e httpd spec/lib/percy/capybara/testdata -p 9090 + # ruby -run -e httpd spec/lib/percy/capybara/client/testdata/ -p 9090 before(:all) do port = get_random_open_port Capybara.app_host = "http://localhost:#{port}" Capybara.run_server = false @@ -17,14 +17,29 @@ @process = IO.popen([ 'ruby', '-run', '-e', 'httpd', dir, '-p', port.to_s, err: [:child, :out] ].flatten) # Block until the server is up. + WebMock.disable_net_connect!(allow_localhost: true) verify_server_up(Capybara.app_host) end after(:all) { Process.kill('INT', @process.pid) } + before(:each) do + # Special setting for capybara-webkit. If clients are using capybara-webkit they would + # also have to have this setting enabled since apparently all resources are blocked by default. + page.driver.respond_to?(:allow_url) && page.driver.allow_url('*') + end + + def find_resource(resources, regex) + begin + resources.select { |resource| resource.resource_url.match(regex) }.fetch(0) + rescue IndexError + raise "Missing expected image with resource_url that matches: #{regex}" + end + end + describe '#_get_root_html_resource', type: :feature, js: true do it 'includes the root DOM HTML' do visit '/' resource = capybara_client.send(:_get_root_html_resource, page) @@ -35,73 +50,147 @@ expect(resource.sha).to eq(Digest::SHA256.hexdigest(resource.content)) end end describe '#_get_css_resources', type: :feature, js: true do it 'includes all linked and imported stylesheets' do - # For capybara-webkit. - page.driver.respond_to?(:allow_url) && page.driver.allow_url('maxcdn.bootstrapcdn.com') - visit '/test-css.html' resources = capybara_client.send(:_get_css_resources, page) - expect(resources.length).to eq(7) - expect(resources.collect(&:mimetype).uniq).to eq(['text/css']) + resource = find_resource(resources, /http:\/\/localhost:\d+\/css\/base\.css/) - resource = resources.select do |resource| - resource.resource_url.match(/http:\/\/localhost:\d+\/css\/base\.css/) - end.fetch(0) - expect(resource.is_root).to be_falsey - expect(resource.content).to include('.colored-by-base { color: red; }') expect(resource.sha).to eq(Digest::SHA256.hexdigest(resource.content)) - resource = resources.select do |resource| - resource.resource_url.match(/http:\/\/localhost:\d+\/css\/simple-imports\.css/) - end.fetch(0) - expect(resource.is_root).to be_falsey - expect(resource.content).to include('@import url("imports.css")') + resource = find_resource(resources, /http:\/\/localhost:\d+\/css\/simple-imports\.css/) + expect(resource.content).to include("@import url('imports.css');") expect(resource.sha).to eq(Digest::SHA256.hexdigest(resource.content)) - resource = resources.select do |resource| - resource.resource_url.match(/http:\/\/localhost:\d+\/css\/imports\.css/) - end.fetch(0) - expect(resource.is_root).to be_falsey + resource = find_resource(resources, /http:\/\/localhost:\d+\/css\/imports\.css/) expect(resource.content).to include('.colored-by-imports { color: red; }') expect(resource.sha).to eq(Digest::SHA256.hexdigest(resource.content)) - resource = resources.select do |resource| - resource.resource_url.match(/http:\/\/localhost:\d+\/css\/level0-imports\.css/) - end.fetch(0) - expect(resource.is_root).to be_falsey - expect(resource.content).to include('@import url("level1-imports.css")') + resource = find_resource(resources, /http:\/\/localhost:\d+\/css\/level0-imports\.css/) + expect(resource.content).to include("@import url('level1-imports.css')") expect(resource.content).to include('.colored-by-level0-imports { color: red; }') expect(resource.sha).to eq(Digest::SHA256.hexdigest(resource.content)) - resource = resources.select do |resource| - resource.resource_url.match(/http:\/\/localhost:\d+\/css\/level1-imports\.css/) - end.fetch(0) - expect(resource.is_root).to be_falsey - expect(resource.content).to include('@import url("level2-imports.css")') + resource = find_resource(resources, /http:\/\/localhost:\d+\/css\/level1-imports\.css/) + expect(resource.content).to include("@import url('level2-imports.css')") expect(resource.content).to include('.colored-by-level1-imports { color: red; }') expect(resource.sha).to eq(Digest::SHA256.hexdigest(resource.content)) - resource = resources.select do |resource| - resource.resource_url.match(/http:\/\/localhost:\d+\/css\/level2-imports\.css/) - end.fetch(0) - expect(resource.is_root).to be_falsey + resource = find_resource(resources, /http:\/\/localhost:\d+\/css\/level2-imports\.css/) expect(resource.content).to include(".colored-by-level2-imports { color: red; }") expect(resource.sha).to eq(Digest::SHA256.hexdigest(resource.content)) - resource = resources.select do |resource| - resource.resource_url == ( - 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css') - end.fetch(0) - expect(resource.is_root).to be_falsey + resource = find_resource( + resources, /https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.4\/css\/bootstrap.min.css/) expect(resource.content).to include('Bootstrap v3.3.4 (http://getbootstrap.com)') expect(resource.sha).to eq(Digest::SHA256.hexdigest(resource.content)) + + expect(resources.length).to eq(7) + expect(resources.collect(&:mimetype).uniq).to eq(['text/css']) + expect(resources.collect(&:is_root).uniq).to match_array([nil]) end end + describe '#_get_image_resources', type: :feature, js: true do + it 'includes all images' do + visit '/test-images.html' + resources = capybara_client.send(:_get_image_resources, page) + + # The order of these is just for convenience, they match the order in test-images.html. + + resource = find_resource(resources, /http:\/\/localhost:\d+\/images\/img-relative\.png/) + content = File.read(File.expand_path('../testdata/images/img-relative.png', __FILE__)) + expect(resource.mimetype).to eq('image/png') + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + resource = find_resource(resources, /http:\/\/localhost:\d+\/images\/img-relative-to-root\.png/) + content = File.read(File.expand_path('../testdata/images/img-relative-to-root.png', __FILE__)) + expect(resource.mimetype).to eq('image/png') + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + resource = find_resource(resources, /http:\/\/localhost:\d+\/images\/percy\.svg/) + content = File.read(File.expand_path('../testdata/images/percy.svg', __FILE__)) + # In Ruby 1.9.3 the SVG mimetype is not registered so our mini ruby webserver doesn't serve + # the correct content type. Allow either to work here so we can test older Rubies fully. + expect(resource.mimetype).to match(/image\/svg\+xml|application\/octet-stream/) + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + resource = find_resource(resources, /http:\/\/i.imgur.com\/Umkjdao.png/) + content = Faraday.get('http://i.imgur.com/Umkjdao.png').body + expect(resource.mimetype).to eq('image/png') + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + resource = find_resource(resources, /http:\/\/localhost:\d+\/images\/bg-relative\.png/) + content = File.read(File.expand_path('../testdata/images/bg-relative.png', __FILE__)) + expect(resource.mimetype).to eq('image/png') + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + resource = find_resource(resources, /http:\/\/localhost:\d+\/images\/bg-relative-to-root\.png/) + content = File.read(File.expand_path('../testdata/images/bg-relative-to-root.png', __FILE__)) + expect(resource.mimetype).to eq('image/png') + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + resource = find_resource(resources, /http:\/\/i.imgur.com\/5mLoBs1.png/) + content = Faraday.get('http://i.imgur.com/5mLoBs1.png').body + expect(resource.mimetype).to eq('image/png') + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + resource = find_resource(resources, /http:\/\/localhost:\d+\/images\/bg-stacked\.png/) + content = File.read(File.expand_path('../testdata/images/bg-stacked.png', __FILE__)) + expect(resource.mimetype).to eq('image/png') + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + resource = find_resource(resources, /http:\/\/i.imgur.com\/61AQuplb.jpg/) + content = Faraday.get('http://i.imgur.com/61AQuplb.jpg').body + expect(resource.mimetype).to eq('image/jpeg') + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + resource = find_resource(resources, /http:\/\/localhost:\d+\/images\/srcset-base\.png/) + content = File.read(File.expand_path('../testdata/images/srcset-base.png', __FILE__)) + expect(resource.mimetype).to eq('image/png') + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + resource = find_resource(resources, /http:\/\/localhost:\d+\/images\/srcset-first\.png/) + content = File.read(File.expand_path('../testdata/images/srcset-first.png', __FILE__)) + expect(resource.mimetype).to eq('image/png') + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + resource = find_resource(resources, /http:\/\/localhost:\d+\/images\/srcset-second\.png/) + content = File.read(File.expand_path('../testdata/images/srcset-second.png', __FILE__)) + expect(resource.mimetype).to eq('image/png') + expected_sha = Digest::SHA256.hexdigest(content) + expect(Digest::SHA256.hexdigest(resource.content)).to eq(expected_sha) + expect(resource.sha).to eq(expected_sha) + + expect(resources.length).to eq(12) + expect(resources.collect(&:is_root).uniq).to match_array([nil]) + end + end describe '#snapshot', type: :feature, js: true do context 'simple page with no resources' do let(:content) { '<html><body>Hello World!</body><head></head></html>' } it 'creates a snapshot and uploads missing resource' do @@ -138,9 +227,15 @@ .to_return(status: 201, body: mock_response.to_json) stub_request(:post, "https://percy.io/api/v1/builds/123/resources/") .with(body: /#{resource.sha}/).to_return(status: 201, body: {success: true}.to_json) + expect(capybara_client).to receive(:_get_root_html_resource) + .with(page).once.and_call_original + expect(capybara_client).to receive(:_get_css_resources) + .with(page).once.and_call_original + expect(capybara_client).to receive(:_get_image_resources) + .with(page).once.and_call_original resource_map = capybara_client.snapshot(page) end end end end