approvals 0.0.22 → 0.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6f444a0aa1c3b1b8adeade0729913ffd0bc77af0
4
- data.tar.gz: fcb304998044a0f34fdcf339d3bac514e6175529
3
+ metadata.gz: 18211b4ae23de30297af8004404da5497abc99b9
4
+ data.tar.gz: 8f4ed09ce1ad7a43719049363969dc3dcd3a5158
5
5
  SHA512:
6
- metadata.gz: 0425fc7fab8349a9d762e8f134feebeba3d49c632f2bc3e4dc09df1b35041526acf86a6eda2f98b44b6443c968c2e32778741d984e73632124195f98c666f1ee
7
- data.tar.gz: 503eef74aa5ed03cf9591ca43dc771bfc5fde4c5fb2d57bd1823ea7dfab4cbcbd95bebeba4cd1cb448b8fea32bf8bc4909b206fa1934b7eab2c8906170729dfd
6
+ metadata.gz: 0d093bc47d069b7a70562e71cbcc5588b38cf37a5a8320f1e7df33b2834d27da8644633ccfafd9ac6e09f796257bd2ab8d1e6895c122d4d0183d44d95e394d08
7
+ data.tar.gz: 64faeb4c33be84e307bc9e27e05476fbf0cb979c702a1480d1885c54d4bd984f832074fe6f2cda179f67b648a8a85475f1e0adfe25a40450c8d5eaeb64d2da54
data/.gitignore CHANGED
@@ -5,3 +5,5 @@ pkg/*
5
5
  *.received.txt
6
6
  .approvals
7
7
  tmp/
8
+
9
+ ext/Rakefile
@@ -5,6 +5,11 @@ rvm:
5
5
  - 2.0.0
6
6
  - 2.1.0
7
7
  - ruby-head
8
- - rbx-2
8
+ - rbx
9
+ matrix:
10
+ allow_failures:
11
+ - rvm: rbx
12
+ before_install:
13
+ - gem update bundler
9
14
  script: bundle exec rspec spec
10
15
  cache: bundler
data/README.md CHANGED
@@ -23,8 +23,8 @@ which Llewellyn Falco is interviewed about approvals.
23
23
  ## Configuration
24
24
 
25
25
  ```ruby
26
- Approvals.configure do |c|
27
- c.approvals_path = 'output/goes/here/'
26
+ Approvals.configure do |config|
27
+ config.approvals_path = 'output/goes/here/'
28
28
  end
29
29
  ```
30
30
 
@@ -42,18 +42,43 @@ Approvals.verify(your_subject, :format => :json)
42
42
 
43
43
  This will raise an `ApprovalError` in the case of a failure.
44
44
 
45
- The default writer uses the `:to_s` method on the subject will be used to generate the output for
46
- the `received` file. For custom complex objects you will need to override
47
- `:to_s` to get helpful output, rather than the default:
48
-
49
- #<Object:0x0000010105ea40> # or whatever the object id is
50
-
51
45
  The first time the approval is run, a file will be created with the contents of the subject of your approval:
52
46
 
53
47
  the_name_of_the_approval.received.txt # or .json, .html, .xml as appropriate
54
48
 
55
49
  Since you have not yet approved anything, the `*.approved` file does not exist, and the comparison will fail.
56
50
 
51
+ ### Customizing formatted output
52
+
53
+ The default writer uses the `:to_s` method on the subject to generate the output for the received file.
54
+ For custom complex objects you will need to provide a custom writer to get helpful output, rather than the default:
55
+
56
+ #<Object:0x0000010105ea40> # or whatever the object id is
57
+
58
+ Create a custom writer class somewhere accessible to your test:
59
+
60
+ ```
61
+ class MyCustomWriter < Approvals::Writers::TextWriter
62
+ def format(data)
63
+ # Custom data formatting here
64
+ end
65
+
66
+ def filter(data)
67
+ # Custom data filtering here
68
+ end
69
+ end
70
+ ```
71
+
72
+ In your test, use a string to reference your custom class:
73
+
74
+ ```
75
+ it "verifies a complex object" do
76
+ Approvals.verify hello, :format => "MyCustomWriter"
77
+ end
78
+ ```
79
+
80
+ Define and use different custom writers as needed!
81
+
57
82
  ## CLI
58
83
 
59
84
  The gem comes with a command-line tool that makes it easier to manage the
@@ -115,17 +140,17 @@ spec/fixtures/approvals/
115
140
  You can override this:
116
141
 
117
142
  ```ruby
118
- RSpec.configure do |c|
119
- c.approvals_path = 'some/other/path'
143
+ RSpec.configure do |config|
144
+ config.approvals_path = 'some/other/path'
120
145
  end
121
146
  ```
122
147
 
123
148
  The basic format of the approval is modeled after RSpec's `it`:
124
149
 
125
150
  ```ruby
126
- it "works" do
151
+ it 'works' do
127
152
  verify do
128
- "this is the the thing you want to verify"
153
+ 'this is the the thing you want to verify'
129
154
  end
130
155
  end
131
156
  ```
@@ -135,21 +160,21 @@ end
135
160
  When using RSpec, the namer is set for you, using the example's `full_description`.
136
161
 
137
162
  ```ruby
138
- Approvals.verify(thing, :name => "the name of your test")
163
+ Approvals.verify(thing, :name => 'the name of your test')
139
164
  ```
140
165
 
141
166
  ### Formatting
142
167
 
143
168
  You can pass a format for your output before it gets written to the file.
144
- At the moment, only text, xml, html, and json are supported.
169
+ At the moment, only text, xml, html, and json are supported, while text is the default.
145
170
 
146
171
  Simply add a `:format => :text`, `:format => :xml`, `:format => :html`, or `:format => :json` option to the example:
147
172
 
148
173
  ```ruby
149
- page = "<html><head></head><body><h1>ZOMG</h1></body></html>"
174
+ page = '<html><head></head><body><h1>ZOMG</h1></body></html>'
150
175
  Approvals.verify page, :format => :html
151
176
 
152
- data = "{\"beverage\":\"coffee\"}"
177
+ data = '{\'beverage\':\'coffee\'}'
153
178
  Approvals.verify data, :format => :json
154
179
  ```
155
180
 
@@ -157,19 +182,27 @@ In RSpec, it looks like this:
157
182
 
158
183
  ```ruby
159
184
  verify :format => :html do
160
- "<html><head></head><body><h1>ZOMG</h1></body></html>"
185
+ '<html><head></head><body><h1>ZOMG</h1></body></html>'
161
186
  end
162
187
 
163
188
  verify :format => :json do
164
- "{\"beverage\":\"coffee\"}"
189
+ '{\'beverage\':\'coffee\'}'
190
+ end
191
+ ```
192
+
193
+ If you like you could also change the default format globally with:
194
+
195
+ ```ruby
196
+ RSpec.configure do |config|
197
+ config.approvals_default_format = :json # or :xml, :html
165
198
  end
166
199
  ```
167
200
 
168
201
  ### Exclude dynamically changed values from json
169
202
 
170
203
  ```ruby
171
- Approvals.configure do |c|
172
- c.excluded_json_keys = {
204
+ Approvals.configure do |config|
205
+ config.excluded_json_keys = {
173
206
  :id =>/(\A|_)id$/,
174
207
  :date => /_at$/
175
208
  }
@@ -9,9 +9,9 @@ Gem::Specification.new do |s|
9
9
  s.licenses = ['MIT']
10
10
  s.authors = ["Katrina Owen"]
11
11
  s.email = ["katrina.owen@gmail.com"]
12
- s.homepage = ""
12
+ s.homepage = "https://github.com/kytrinyx/approvals"
13
13
  s.summary = %q{Approval Tests for Ruby}
14
- s.description = %q{Approval Tests for Ruby}
14
+ s.description = %q{A library to make it easier to do golden-master style testing in Ruby}
15
15
 
16
16
  s.rubyforge_project = "approvals"
17
17
 
@@ -19,9 +19,11 @@ Gem::Specification.new do |s|
19
19
  s.test_files = `git ls-files -- {spec}/*`.split("\n")
20
20
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
21
  s.require_paths = ["lib"]
22
+ s.extensions << 'ext/mkrf_conf.rb'
22
23
 
23
24
  s.add_development_dependency 'rspec', '~> 3.1'
24
- s.add_development_dependency 'json', '~> 1.8'
25
25
  s.add_dependency 'thor', '~> 0.18'
26
26
  s.add_dependency 'nokogiri', '~> 1.6'
27
+ # We also depend on the json gem, but the version we need is
28
+ # Ruby-version-specific. See `ext/mkrf_conf.rb`.
27
29
  end
@@ -0,0 +1,22 @@
1
+ require 'rubygems/dependency_installer'
2
+
3
+ # This is how we can depend on a different version of the same gem for
4
+ # different Ruby versions.
5
+ # See https://en.wikibooks.org/wiki/Ruby_Programming/RubyGems
6
+
7
+ installer = Gem::DependencyInstaller.new
8
+
9
+ begin
10
+ if RUBY_VERSION >= '2.0'
11
+ installer.install 'json', '~> 2.0'
12
+ else
13
+ installer.install 'json', '~> 1.8'
14
+ end
15
+ rescue
16
+ exit(1)
17
+ end
18
+
19
+ # Write fake Rakefile for rake since Makefile isn't used
20
+ File.open(File.join(File.dirname(__FILE__), 'Rakefile'), 'w') do |f|
21
+ f.write("task :default\n")
22
+ end
@@ -13,6 +13,7 @@ require 'approvals/executable'
13
13
  require 'approvals/reporters'
14
14
  require 'approvals/filter'
15
15
  require 'approvals/writer'
16
+ require 'approvals/verifier'
16
17
  require 'approvals/namers/default_namer'
17
18
 
18
19
  module Approvals
@@ -19,9 +19,9 @@ module Approvals
19
19
  # Add a Proc that tests if subject is a kind of format
20
20
  IDENTITIES = {
21
21
  hash: Proc.new(){|subject|subject.respond_to? :each_pair},
22
- array: Proc.new(){|subject|subject.respond_to? :each_with_index},
22
+ array: Proc.new(){|subject|subject.respond_to? :each_with_index},
23
23
  }
24
-
24
+
25
25
  def identify_format
26
26
  IDENTITIES.each_pair do |format, id_test|
27
27
  return format if id_test.call(subject)
@@ -34,6 +34,10 @@ module Approvals
34
34
  @writer ||= Writer.for(@format)
35
35
  end
36
36
 
37
+ def verifier
38
+ @verifier ||= Verifier.for(@format)
39
+ end
40
+
37
41
  def verify
38
42
  unless File.exist?(namer.output_dir)
39
43
  FileUtils.mkdir_p(namer.output_dir)
@@ -63,6 +67,10 @@ module Approvals
63
67
  BINARY_FORMATS = [:binary]
64
68
 
65
69
  def received_matches?
70
+ return verifier
71
+ .new(received_path, approved_path)
72
+ .verify if verifier
73
+
66
74
  if BINARY_FORMATS.include?(@format) # Read without ERB
67
75
  IO.read(received_path).chomp == IO.read(approved_path).chomp
68
76
  else
@@ -16,18 +16,18 @@ module Approvals
16
16
  end
17
17
 
18
18
  def censored value, key=nil
19
- case value
20
- when Array
21
- value.map { |item| censored(item) }
22
- when Hash
23
- Hash[value.map { |inner_key, inner_value| [inner_key, censored(inner_value, inner_key)] }]
19
+ if value.nil?
20
+ nil
21
+ elsif key && placeholder_for(key)
22
+ "<#{placeholder_for(key)}>"
24
23
  else
25
- if value.nil?
26
- nil
27
- elsif key && placeholder_for(key)
28
- "<#{placeholder_for(key)}>"
29
- else
30
- value
24
+ case value
25
+ when Array
26
+ value.map { |item| censored(item) }
27
+ when Hash
28
+ Hash[value.map { |inner_key, inner_value| [inner_key, censored(inner_value, inner_key)] }]
29
+ else
30
+ value
31
31
  end
32
32
  end
33
33
  end
@@ -0,0 +1,15 @@
1
+ require 'approvals/verifiers/json_verifier'
2
+
3
+ module Approvals
4
+ module Verifier
5
+ REGISTRY = {
6
+ json: Verifiers::JsonVerifier,
7
+ }
8
+
9
+ class << self
10
+ def for(format)
11
+ REGISTRY[format]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module Approvals
2
+ module Verifiers
3
+ class JsonVerifier
4
+ def initialize(received_path, approved_path)
5
+ self.received_path = received_path
6
+ self.approved_path = approved_path
7
+ end
8
+
9
+ def verify
10
+ approved == received
11
+ end
12
+
13
+ private
14
+
15
+ attr_accessor :approved_path, :received_path
16
+
17
+ def approved
18
+ JSON.parse(File.read(approved_path))
19
+ end
20
+
21
+ def received
22
+ JSON.parse(File.read(received_path))
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,3 @@
1
1
  module Approvals
2
- VERSION = '0.0.22'
2
+ VERSION = '0.0.24'
3
3
  end
@@ -16,15 +16,21 @@ module Approvals
16
16
  html: Writers::HtmlWriter.new,
17
17
  hash: Writers::HashWriter.new,
18
18
  array: Writers::ArrayWriter.new,
19
+ txt: Writers::TextWriter.new,
19
20
  }
20
21
 
21
22
 
22
23
  class << self
23
24
  def for(format)
24
- if REGISTRY.include?(format)
25
- REGISTRY[format]
26
- else
27
- TextWriter.new
25
+ begin
26
+ REGISTRY[format] || Object.const_get(format).new
27
+ rescue NameError => e
28
+ error = ApprovalError.new(
29
+ "Approval Error: #{ e }. Please define a custom writer as outlined"\
30
+ " in README section 'Customizing formatted output': "\
31
+ "https://github.com/kytrinyx/approvals#customizing-formatted-output"
32
+ )
33
+ raise error
28
34
  end
29
35
  end
30
36
  end
@@ -51,6 +51,32 @@ describe Approvals do
51
51
  Approvals.verify hello, :namer => namer
52
52
  end
53
53
 
54
+ context "custom writer" do
55
+ let(:hello) { Object.new }
56
+
57
+ class MyCustomWriter < Approvals::Writers::TextWriter
58
+ def format(data)
59
+ filter(data)
60
+ end
61
+
62
+ def filter(data)
63
+ data.to_s.chars.reject {|c| c =~ /[a-zA-Z0-9]/}
64
+ end
65
+ end
66
+
67
+ it "verifies a complex object" do
68
+ Approvals.verify hello, :namer => namer, :format => "MyCustomWriter"
69
+ end
70
+
71
+ it "raises an error with an uninitialized custom writer class" do
72
+ expect{
73
+ Approvals.verify hello, :namer => namer, :format => "UninitializedWriter"
74
+ }.to raise_error.with_message(
75
+ /Please define a custom writer as outlined in README section 'Customizing formatted output':/
76
+ )
77
+ end
78
+ end
79
+
54
80
  it "verifies html" do
55
81
  html = <<-HTML
56
82
  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"><html><head><title>Approval</title></head><body><h1>An Approval</h1><p>It has a paragraph</p></body></html>
@@ -79,6 +105,11 @@ describe Approvals do
79
105
  Approvals.verify json, :format => :json, :namer => namer
80
106
  end
81
107
 
108
+ it "ignores whitespace differences in json" do
109
+ hash = { foo: {} }
110
+
111
+ Approvals.verify hash, :format => :json, :namer => namer
112
+ end
82
113
 
83
114
  it "verifies json and is newline agnostic" do
84
115
  json = '{"pet":{"species":"turtle","color":"green","name":"Anthony"}}'
@@ -74,6 +74,40 @@ describe Approvals::Filter do
74
74
  })
75
75
  end
76
76
 
77
+ it "filters array keys" do
78
+ filter = Approvals::Filter.new({foolist: /^foolist$/})
79
+ input = {
80
+ foo: 'bar124',
81
+ foolist: [{foo: 'bar 145', bar: 'foo'}, 'foobar'],
82
+ nonfoo: 'bar',
83
+ }
84
+
85
+ output = filter.apply(input)
86
+
87
+ expect(output).to eq({
88
+ foo: 'bar124',
89
+ foolist: '<foolist>',
90
+ nonfoo: 'bar',
91
+ })
92
+ end
93
+
94
+ it "filters hash keys" do
95
+ filter = Approvals::Filter.new({foohash: /^foohash$/})
96
+ input = {
97
+ foo: 'bar124',
98
+ foohash: {foo: 'bar 145', barlist: ['foo', 'bar']},
99
+ nonfoo: 'bar',
100
+ }
101
+
102
+ output = filter.apply(input)
103
+
104
+ expect(output).to eq({
105
+ foo: 'bar124',
106
+ foohash: '<foohash>',
107
+ nonfoo: 'bar',
108
+ })
109
+ end
110
+
77
111
  it "takes the last applicable filter" do
78
112
  filter = Approvals::Filter.new({foo: /^foo/, bar: /bar$/})
79
113
  input = {
@@ -0,0 +1,3 @@
1
+ {
2
+ "foo": "2017-01-01 00:00:00 +0100"
3
+ }
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Approvals::Verifiers::JsonVerifier do
4
+ subject(:instance) do
5
+ described_class.new(received_path, approved_path)
6
+ end
7
+
8
+ context "with same json content but different formatting" do
9
+ let(:received_path) do
10
+ "./spec/fixtures/json_approval_with_different_whitespace/received.json"
11
+ end
12
+ let(:approved_path) do
13
+ "./spec/fixtures/json_approval_with_different_whitespace/approved.json"
14
+ end
15
+
16
+ it "passes verification" do
17
+ expect(instance.verify).to be_truthy
18
+ end
19
+ end
20
+
21
+ context "with different json content" do
22
+ let(:received_path) do
23
+ "./spec/fixtures/json_approval_with_different_whitespace/received_different_content.json"
24
+ end
25
+ let(:approved_path) do
26
+ "./spec/fixtures/json_approval_with_different_whitespace/approved.json"
27
+ end
28
+
29
+ it "does not passe verification" do
30
+ expect(instance.verify).to be_falsy
31
+ end
32
+ end
33
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: approvals
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.22
4
+ version: 0.0.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katrina Owen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-22 00:00:00.000000000 Z
11
+ date: 2018-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.1'
27
- - !ruby/object:Gem::Dependency
28
- name: json
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.8'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.8'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: thor
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,12 +52,13 @@ dependencies:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
54
  version: '1.6'
69
- description: Approval Tests for Ruby
55
+ description: A library to make it easier to do golden-master style testing in Ruby
70
56
  email:
71
57
  - katrina.owen@gmail.com
72
58
  executables:
73
59
  - approvals
74
- extensions: []
60
+ extensions:
61
+ - ext/mkrf_conf.rb
75
62
  extra_rdoc_files: []
76
63
  files:
77
64
  - ".gitignore"
@@ -83,6 +70,7 @@ files:
83
70
  - Rakefile
84
71
  - approvals.gemspec
85
72
  - bin/approvals
73
+ - ext/mkrf_conf.rb
86
74
  - lib/approvals.rb
87
75
  - lib/approvals/approval.rb
88
76
  - lib/approvals/cli.rb
@@ -112,6 +100,8 @@ files:
112
100
  - lib/approvals/rspec.rb
113
101
  - lib/approvals/scrubber.rb
114
102
  - lib/approvals/system_command.rb
103
+ - lib/approvals/verifier.rb
104
+ - lib/approvals/verifiers/json_verifier.rb
115
105
  - lib/approvals/version.rb
116
106
  - lib/approvals/writer.rb
117
107
  - lib/approvals/writers/array_writer.rb
@@ -127,6 +117,8 @@ files:
127
117
  - spec/executable_spec.rb
128
118
  - spec/extensions/rspec_approvals_spec.rb
129
119
  - spec/filter_spec.rb
120
+ - spec/fixtures/approvals/approvals_custom_writer_verifies_a_complex_object.approved.txt
121
+ - spec/fixtures/approvals/approvals_ignores_whitespace_differences_in_json.approved.json
130
122
  - spec/fixtures/approvals/approvals_passes_approved_files_through_erb.approved.txt
131
123
  - spec/fixtures/approvals/approvals_passes_the_received_files_through_erb.approved.txt
132
124
  - spec/fixtures/approvals/approvals_supports_excluded_keys_option_also_supports_an_array_of_hashes.approved.json
@@ -143,6 +135,7 @@ files:
143
135
  - spec/fixtures/approvals/approvals_verifies_html.approved.html
144
136
  - spec/fixtures/approvals/approvals_verifies_json.approved.json
145
137
  - spec/fixtures/approvals/approvals_verifies_json_and_is_newline_agnostic.approved.json
138
+ - spec/fixtures/approvals/approvals_verifies_json_with_a_time_object.approved.json
146
139
  - spec/fixtures/approvals/approvals_verifies_xml.approved.xml
147
140
  - spec/fixtures/approvals/verifications_a_string.approved.txt
148
141
  - spec/fixtures/approvals/verifies_a_complex_object.approved.txt
@@ -163,6 +156,9 @@ files:
163
156
  - spec/fixtures/approvals/verifies_html.approved.html
164
157
  - spec/fixtures/approvals/verifies_json.approved.json
165
158
  - spec/fixtures/approvals/verifies_xml.approved.xml
159
+ - spec/fixtures/json_approval_with_different_whitespace/approved.json
160
+ - spec/fixtures/json_approval_with_different_whitespace/received.json
161
+ - spec/fixtures/json_approval_with_different_whitespace/received_different_content.json
166
162
  - spec/fixtures/one.png
167
163
  - spec/fixtures/one.txt
168
164
  - spec/fixtures/two.png
@@ -180,7 +176,8 @@ files:
180
176
  - spec/scrubber_spec.rb
181
177
  - spec/spec_helper.rb
182
178
  - spec/system_command_spec.rb
183
- homepage: ''
179
+ - spec/verifiers/json_verifier_spec.rb
180
+ homepage: https://github.com/kytrinyx/approvals
184
181
  licenses:
185
182
  - MIT
186
183
  metadata: {}
@@ -200,9 +197,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
197
  version: '0'
201
198
  requirements: []
202
199
  rubyforge_project: approvals
203
- rubygems_version: 2.2.2
200
+ rubygems_version: 2.5.2
204
201
  signing_key:
205
202
  specification_version: 4
206
203
  summary: Approval Tests for Ruby
207
204
  test_files: []
208
- has_rdoc: