Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ rails_dependencies =
gem 'jdbc-sqlite3', platform: :jruby
gem 'net-ftp'
gem 'combustion'
gem 'capybara'
end

appraisals = {
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Features

- Inspect and diff Capybara nodes without walking into the driver.

### Other changes
- Fixed "Using parts of SuperDiff directly" documentation. [#313](https://github.com/splitwise/super_diff/pull/313)
- Allow diff-lcs 2. [#317](https://github.com/splitwise/super_diff/pull/317) by [@andrewfader](https://github.com/andrewfader)
Expand Down
12 changes: 12 additions & 0 deletions docs/users/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ such as matchers.

You can now continue on to [customizing SuperDiff](./customization.md).

## Capybara

A Capybara node holds the session, and through it the driver and the browser.
SuperDiff prints and diffs nodes the way Capybara inspects them
instead of walking into the browser connection.
This is loaded by `super_diff/rspec` when Capybara is already loaded;
otherwise, add:

```ruby
require "super_diff/capybara"
```

## Binary Strings

SuperDiff can diff binary strings (`Encoding::ASCII_8BIT`) using a hex-dump
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_7_0_rspec_gte_3_10.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 7.0.0"
gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw]
gem "rspec", "3.12.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_7_0_rspec_gte_3_13.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 7.0.0"
gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw]
gem "rspec", "3.13.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_7_0_rspec_lt_3_10.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 7.0.0"
gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw]
gem "rspec", "~> 3.9.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_7_1_rspec_gte_3_10.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 7.1.0"
gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw]
gem "rspec", "3.12.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_7_1_rspec_gte_3_13.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 7.1.0"
gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw]
gem "rspec", "3.13.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_7_1_rspec_lt_3_10.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 7.1.0"
gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw]
gem "rspec", "~> 3.9.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_7_2_rspec_gte_3_10.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 7.2.0"
gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw]
gem "rspec", "3.12.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_7_2_rspec_gte_3_13.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 7.2.0"
gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw]
gem "rspec", "3.13.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_7_2_rspec_lt_3_10.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 7.2.0"
gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw]
gem "rspec", "~> 3.9.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_8_0_rspec_gte_3_10.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 8.0.0"
gem "sqlite3", ">= 2.1", platform: [:ruby, :mswin, :mingw]
gem "rspec", "3.12.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_8_0_rspec_gte_3_13.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 8.0.0"
gem "sqlite3", ">= 2.1", platform: [:ruby, :mswin, :mingw]
gem "rspec", "3.13.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_8_0_rspec_lt_3_10.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 8.0.0"
gem "sqlite3", ">= 2.1", platform: [:ruby, :mswin, :mingw]
gem "rspec", "~> 3.9.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_8_1_rspec_gte_3_10.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 8.1.0"
gem "sqlite3", ">= 2.1", platform: [:ruby, :mswin, :mingw]
gem "rspec", "3.12.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_8_1_rspec_gte_3_13.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 8.1.0"
gem "sqlite3", ">= 2.1", platform: [:ruby, :mswin, :mingw]
gem "rspec", "3.13.0"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_8_1_rspec_lt_3_10.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
gem "jdbc-sqlite3", platform: :jruby
gem "net-ftp"
gem "combustion"
gem "capybara"
gem "rails", "~> 8.1.0"
gem "sqlite3", ">= 2.1", platform: [:ruby, :mswin, :mingw]
gem "rspec", "~> 3.9.0"
Expand Down
22 changes: 22 additions & 0 deletions lib/super_diff/capybara.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

require 'super_diff/capybara/differs'
require 'super_diff/capybara/inspection_tree_builders'

module SuperDiff
module Capybara
def self.applies_to?(*values)
values.all? do |value|
value.is_a?(::Capybara::Node::Base) ||
value.is_a?(::Capybara::Driver::Node)
end
end

SuperDiff.configure do |config|
config.prepend_extra_differ_classes(Differs::Node)
config.prepend_extra_inspection_tree_builder_classes(
InspectionTreeBuilders::Node
)
end
end
end
9 changes: 9 additions & 0 deletions lib/super_diff/capybara/differs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module SuperDiff
module Capybara
module Differs
autoload :Node, 'super_diff/capybara/differs/node'
end
end
end
31 changes: 31 additions & 0 deletions lib/super_diff/capybara/differs/node.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module SuperDiff
module Capybara
module Differs
# Nodes are compared as opaque values, since their instance variables
# lead to the session, the driver and the browser connection.
class Node < Core::AbstractDiffer
def self.applies_to?(expected, actual)
SuperDiff::Capybara.applies_to?(expected, actual)
end

def call
Core::TieredLinesFormatter.call(
[line(:delete, expected), line(:insert, actual)]
)
end

private

def line(type, node)
Core::Line.new(
type: type,
indentation_level: indent_level,
value: SuperDiff.inspect_object(node, as_lines: false)
)
end
end
end
end
end
12 changes: 12 additions & 0 deletions lib/super_diff/capybara/inspection_tree_builders.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

module SuperDiff
module Capybara
module InspectionTreeBuilders
autoload(
:Node,
'super_diff/capybara/inspection_tree_builders/node'
)
end
end
end
32 changes: 32 additions & 0 deletions lib/super_diff/capybara/inspection_tree_builders/node.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

module SuperDiff
module Capybara
module InspectionTreeBuilders
# A node holds the session, and through it the driver and the browser
# connection. Walking its instance variables can take minutes, so it is
# rendered the way Capybara prints it.
class Node < Core::AbstractInspectionTreeBuilder
def self.applies_to?(value)
SuperDiff::Capybara.applies_to?(value)
end

def call
Core::InspectionTree.new do |t1|
t1.as_lines_when_rendering_to_lines do |t2|
t2.add_text inspection
end
end
end

private

def inspection
object.inspect
rescue StandardError
"#<#{object.class.name}>"
end
end
end
end
end
2 changes: 2 additions & 0 deletions lib/super_diff/rspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,6 @@ def self.rspec_version

require_relative 'rspec/monkey_patches'

require 'super_diff/capybara' if defined?(Capybara)

RSpec.configuration.filter_gems_from_backtrace('super_diff')
7 changes: 7 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
# ActionDispatch isn't available (presumably because we're not testing it)
end

begin
require 'capybara'
rescue LoadError
# Capybara isn't available (presumably because we're not testing it)
end

Dir
.glob(File.expand_path('support/**/*.rb', __dir__))
.reject { |file| file.include?('/models/active_record/') && !active_record_available }
Expand Down Expand Up @@ -59,6 +65,7 @@

config.filter_run_excluding active_record: true unless active_record_available
config.filter_run_excluding action_dispatch: true unless defined?(ActionDispatch)
config.filter_run_excluding capybara: true unless defined?(Capybara)
config.filter_run_excluding active_support: true unless defined?(ActiveSupport)
config.filter_run_excluding with_superdiff_rspec: false

Expand Down
63 changes: 63 additions & 0 deletions spec/unit/capybara/diff_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe SuperDiff, type: :unit do
describe '.diff', 'for Capybara objects', capybara: true do
let(:session) do
app = ->(_env) { [200, { 'content-type' => 'text/html' }, ['<h1>Hello</h1><h2>World</h2>']] }
Capybara::Session.new(:rack_test, app).tap { |s| s.visit('/') }
end

let(:expected) { session.find(:css, 'h1') }
let(:actual) { session.find(:css, 'h2') }

context 'given two Capybara::Node::Elements' do
it 'diffs the inspections Capybara gives them' do
expect(described_class.diff(expected, actual)).to eq(<<~DIFF.chomp)
- #<Capybara::Node::Element tag="h1" path="/html/body/h1">
+ #<Capybara::Node::Element tag="h2" path="/html/body/h2">
DIFF
end

it 'does not read their instance variables' do
allow(expected).to receive(:instance_variables).and_call_original
allow(actual).to receive(:instance_variables).and_call_original

described_class.diff(expected, actual)

expect(expected).not_to have_received(:instance_variables)
expect(actual).not_to have_received(:instance_variables)
end
end

context 'given two Capybara::Driver::Nodes' do
it 'diffs the inspections the driver gives them' do
expect(described_class.diff(expected.base, actual.base)).to eq(<<~DIFF.chomp)
- #<Capybara::RackTest::Node tag="h1" path="/html/body/h1">
+ #<Capybara::RackTest::Node tag="h2" path="/html/body/h2">
DIFF
end
end

context 'given nodes of different classes' do
it 'diffs the inspections Capybara gives them' do
expect(described_class.diff(session.document, actual)).to eq(<<~DIFF.chomp)
- #<Capybara::Document>
+ #<Capybara::Node::Element tag="h2" path="/html/body/h2">
DIFF
end
end

context 'given nodes inside a collection' do
it 'diffs the inspections Capybara gives them' do
expect(described_class.diff({ heading: expected }, { heading: actual })).to eq(<<~DIFF.chomp)
\s {
- heading: #<Capybara::Node::Element tag="h1" path="/html/body/h1">
+ heading: #<Capybara::Node::Element tag="h2" path="/html/body/h2">
\s }
DIFF
end
end
end
end
Loading
Loading