rspec-rcv 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b08931127f4e12942b32aa34d5006d18728cc395
4
+ data.tar.gz: ba816c39170e25462586f6b26b130794ebe223f7
5
+ SHA512:
6
+ metadata.gz: 100479086b2e3f09d3573c01934d93eb294da1c33b0f89acde87b468a8a3bb0554f3b4b68a16f4df53d05947d1ab9f8cc698aaee8fdb1ad8b742a3dc3bcadae7
7
+ data.tar.gz: 2c4af36ebf6f81dcbf52d746081fb3e9ca487e1d82c4d068089cebae0448d579eba5431a1eda057c10c2e05b3564b0425c0c984a0a173dd91ef2c39df4573425
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .idea
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rspec-rcv.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,82 @@
1
+ # Purpose
2
+
3
+ The purpose of this gem is to provide a way to export the results of rspec tests to disk. In this way, a controller test can output the response body of the request, and then a front-end test can read that file in order to have predictable and maintainable front-end fixtures.
4
+
5
+ This gem currently only applies to the rspec testing framework.
6
+
7
+ # Usage
8
+
9
+ The gem is require'd in the rspec loading script, and will take effect from there by using the "fixture" option. For example, the following test would record response.body to spec/fixtures/widgets/index.json"
10
+
11
+ ```ruby
12
+ describe "GET index" do
13
+ it "is successful", fixture: "widgets/index.json" do
14
+ get :index
15
+ expect(response).to be_success
16
+ end
17
+ end
18
+ ```
19
+
20
+ The test itself does not need to do anything different, it is all in configuration.
21
+
22
+ If the file already exists, and the new content is not identical, the test will fail with a message indicating that this happened. This will prevent surprises from happening, and can be turned off in a configuration variable.
23
+
24
+ # Lifecycle
25
+
26
+ The result of the exportable variable is captured at the end of the test, after everything else has run. Because this is an
27
+ outer `after(:each)`, it will run after all of the other `after` blocks in the suite. This means you can't use the output of
28
+ the file in an after block (not that you should need to). See the spec suite here to understand how you *could* use the output of
29
+ the file in the spec suite.
30
+
31
+ # Configuration Options
32
+
33
+ The following options are available to override, as well as their default values:
34
+
35
+ ```ruby
36
+ config.exportable_proc = Proc.new { response.body }
37
+ config.compare_with = Proc.new { |existing, new| existing == new }
38
+ config.export_with = Proc.new do |hash|
39
+ begin
40
+ hash[:data] = JSON.parse(hash[:data])
41
+ rescue JSON::ParserError
42
+ end
43
+ JSON.pretty_generate(hash)
44
+ end
45
+ config.base_path = nil
46
+ config.fail_on_changed_output = true
47
+ ```
48
+
49
+ `exportable_proc`, `compare_with`, `export_with` must implement `.call`. For `exportable_proc`, the result will be written to disk
50
+ and should be a String. For `compare_with`, the proc should return true when existing and new are considered equal. For `export_with`
51
+ a hash will be passed in and the result will be a String written to disk.
52
+
53
+ `export_with` by default tries to take hash[:data] (a string) and JSON parse it. If it isn't successful, that is fine and hash[:data] isn't
54
+ changed. If it is JSON, then the pretty print will work more optimally.
55
+
56
+ Note: This can support things that aren't JSON because you can override Proc's that you need to. However, some of the internal workings assume JSON and so it is recommended to just keep the file as JSON.
57
+
58
+ # What about fields that change everytime I run the specs?
59
+
60
+ This is why you can override `compare_with`. For instance, here is a configuration to ignore `id, created_at, updated_at` in a Rails app:
61
+
62
+ ```ruby
63
+ RSpecRcv.configure do |config|
64
+ config.configure_rspec_metadata!
65
+
66
+ filters = [:id, :created_at, :updated_at]
67
+ config.compare_with = lambda do |existing, new|
68
+ existing = ActiveSupport::HashWithIndifferentAccess.new(existing)
69
+ new = ActiveSupport::HashWithIndifferentAccess.new(JSON.parse(new))
70
+
71
+ existing.except(*filters) != new.except(*filters)
72
+ end
73
+ end
74
+ ```
75
+
76
+ # What happens when fields change that shouldn't?
77
+
78
+ You will get a diff of the output to your console. Here is an example:
79
+
80
+ ![image](https://cloud.githubusercontent.com/assets/1231659/8729785/2a2aaa24-2bbb-11e5-90fe-99572a95ab7f.png)
81
+
82
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,26 @@
1
+ require "rspec-rcv/version"
2
+ require "rspec-rcv/configuration"
3
+ require "rspec-rcv/test_frameworks/rspec"
4
+
5
+ require "rspec-rcv/handler"
6
+ require "rspec-rcv/data_changed_error"
7
+
8
+ module RSpecRcv
9
+ extend self
10
+
11
+ module RSpec
12
+ autoload :Metadata, "rspec-stripe/test_frameworks/rspec"
13
+ end
14
+
15
+ def configure
16
+ yield configuration
17
+ end
18
+
19
+ def configuration
20
+ @configuration ||= Configuration.new
21
+ end
22
+
23
+ def config(overrides=nil)
24
+ @configuration.opts(overrides)
25
+ end
26
+ end
@@ -0,0 +1,77 @@
1
+ module RSpecRcv
2
+ class Configuration
3
+ DEFAULTS = {
4
+ exportable_proc: Proc.new { response.body },
5
+ compare_with: Proc.new { |existing, new| existing == new },
6
+ export_with: Proc.new do |hash|
7
+ begin
8
+ hash[:data] = JSON.parse(hash[:data])
9
+ rescue JSON::ParserError
10
+ end
11
+ JSON.pretty_generate(hash)
12
+ end,
13
+ fail_on_changed_output: true,
14
+ base_path: nil,
15
+ fixture: nil
16
+ }
17
+
18
+ def initialize
19
+ reset!
20
+ end
21
+
22
+ def configure_rspec_metadata!
23
+ unless @rspec_metadata_configured
24
+ RSpecRcv::RSpec::Metadata.configure!
25
+ @rspec_metadata_configured = true
26
+ end
27
+ end
28
+
29
+ def reset!
30
+ @opts = DEFAULTS.dup
31
+ end
32
+
33
+ def opts(overrides={})
34
+ @opts.merge(overrides)
35
+ end
36
+
37
+ def exportable_proc
38
+ @opts[:exportable_proc]
39
+ end
40
+
41
+ def exportable_proc=(val)
42
+ @opts[:exportable_proc] = val
43
+ end
44
+
45
+ def export_with
46
+ @opts[:export_with]
47
+ end
48
+
49
+ def export_with=(val)
50
+ @opts[:export_with] = val
51
+ end
52
+
53
+ def compare_with
54
+ @opts[:compare_with]
55
+ end
56
+
57
+ def compare_with=(val)
58
+ @opts[:compare_with] = val
59
+ end
60
+
61
+ def base_path
62
+ @opts[:base_path]
63
+ end
64
+
65
+ def base_path=(val)
66
+ @opts[:base_path] = val
67
+ end
68
+
69
+ def fail_on_changed_output
70
+ @opts[:fail_on_changed_output]
71
+ end
72
+
73
+ def fail_on_changed_output=(val)
74
+ @opts[:fail_on_changed_output] = val
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,3 @@
1
+ module RSpecRcv
2
+ DataChangedError = Class.new(StandardError)
3
+ end
@@ -0,0 +1,63 @@
1
+ require 'json'
2
+ require 'diffy'
3
+
4
+ module RSpecRcv
5
+ class Handler
6
+ def initialize(file_path, data, metadata: {})
7
+ @file_path = file_path
8
+ @opts = RSpecRcv.config(metadata)
9
+ @data = data.call(@opts)
10
+ end
11
+
12
+ def call
13
+ return if existing_data && existing_data["file"] == file_path && existing_data["data"] == data
14
+
15
+ output = { recorded_at: Time.now, file: file_path, data: data }
16
+ output = opts[:export_with].call(output) + "\n"
17
+
18
+ if existing_data
19
+ eq = opts[:compare_with].call(existing_data["data"], data)
20
+
21
+ if !eq && opts[:fail_on_changed_output]
22
+ diff = Diffy::Diff.new(existing_file, output)
23
+ raise RSpecRcv::DataChangedError.new("Existing data will be overwritten. Turn off this feature with fail_on_changed_output=false\n\n#{diff}")
24
+ end
25
+
26
+ return if eq
27
+ end
28
+
29
+ FileUtils.mkdir_p(File.dirname(path))
30
+ File.open(path, 'w') do |file|
31
+ file.write(output)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :file_path, :data, :opts
38
+
39
+ def path
40
+ if opts[:base_path]
41
+ File.join(opts[:base_path], opts[:fixture])
42
+ else
43
+ opts[:fixture]
44
+ end
45
+ end
46
+
47
+ def existing_file
48
+ @existing_file ||= if File.exists?(path)
49
+ File.read(path)
50
+ end
51
+ end
52
+
53
+ def existing_data
54
+ @existing_data ||= if File.exists?(path)
55
+ begin
56
+ JSON.parse(File.read(path))
57
+ rescue JSON::ParserError
58
+ # The file must not have been valid, so we will overwrite it
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,21 @@
1
+ module RSpecRcv
2
+ module RSpec
3
+ module Metadata
4
+ extend self
5
+
6
+ def configure!
7
+ ::RSpec.configure do |config|
8
+ when_tagged_with_rcv = { rcv: lambda { |val| !!val } }
9
+
10
+ config.after(:each, when_tagged_with_rcv) do |ex|
11
+ example = ex.respond_to?(:metadata) ? ex : ex.example
12
+ opts = example.metadata[:rcv]
13
+ data_proc = lambda { |opts| instance_eval(&opts[:exportable_proc]) }
14
+
15
+ Handler.new(ex.file_path, data_proc, metadata: opts).call
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module RSpecRcv
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rspec-rcv/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rspec-rcv"
8
+ spec.version = RSpecRcv::VERSION
9
+ spec.authors = ["Stephen Bussey"]
10
+ spec.email = ["steve.bussey@salesloft.com"]
11
+
12
+ spec.summary = %q{Export results of rspec tests to disk for integration testing.}
13
+ spec.homepage = "https://github.com/SalesLoft/rspec-rcv"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.required_ruby_version = '>= 2.0.0'
20
+ spec.add_development_dependency "bundler", "~> 1.10"
21
+ spec.add_development_dependency "rake", "~> 10.0"
22
+ spec.add_runtime_dependency "rspec"
23
+ spec.add_runtime_dependency "diffy"
24
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-rcv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Bussey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: diffy
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - steve.bussey@salesloft.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - lib/rspec-rcv.rb
83
+ - lib/rspec-rcv/configuration.rb
84
+ - lib/rspec-rcv/data_changed_error.rb
85
+ - lib/rspec-rcv/handler.rb
86
+ - lib/rspec-rcv/test_frameworks/rspec.rb
87
+ - lib/rspec-rcv/version.rb
88
+ - rspec-rcv.gemspec
89
+ homepage: https://github.com/SalesLoft/rspec-rcv
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: 2.0.0
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.4.6
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Export results of rspec tests to disk for integration testing.
113
+ test_files: []