rspec-stepwise 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5a90ad69a86866bac6f5cd8d5c163f9cad892df41a20639bf4424c2fc05e621f
4
+ data.tar.gz: b7f440c808536c92caaaa466412b394193c16d393c9a74b3cc473da342f080b0
5
+ SHA512:
6
+ metadata.gz: dc3bce1e9aa483eac641b691d509fa38792140e29ce32508ae091a315f087e64ad443a17b425c9355232adc0341dd9ad1c80bf94b484888c5addade74bf18b14
7
+ data.tar.gz: 995132c1190c4fcbed1cc74a2b5dba44b8cb22c6ad0c41b87420b92885598c16b8b800ef3d40a0aeeafaec95f48ad806975bd05b927fa3380584d672a8a0e934
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.0
7
+ before_install: gem install bundler -v 2.0.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rspec-stepwise.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Nikita Afanasenko
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.
data/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # RSpec Stepwise Executor
2
+
3
+ Provides a simple DSL on top of RSpec for defining a series of spec execution steps. Particularly useful for describing of human-readable integration testing scenarios.
4
+
5
+ RSpec Stepwise provides the following guarantees within the same steps group:
6
+
7
+ - Strict step execution order, even if RSpec is configured to run examples randomly.
8
+ - All steps share the same execution context, thus share instances defined in `let` etc.
9
+ - All steps after the failed one will be skipped.
10
+
11
+ ## Usage
12
+
13
+ Configure RSpec to use stepwise DSL:
14
+
15
+ ```ruby
16
+ require 'rspec/stepwise'
17
+
18
+ RSpec.configure do |config|
19
+ config.extend RSpec::Stepwise
20
+ # ...
21
+ end
22
+ ```
23
+
24
+ This adds `stepwise` method for creating ordered example groups and `step` method for describing particular step in a chain. See full usage example:
25
+
26
+ ```ruby
27
+ RSpec.describe 'User Scenarios' do
28
+ # Defines example group for account confirmation scenario.
29
+ # All steps within this group will run in an order.
30
+ stepwise 'Account Confirmation' do
31
+ # All RSpec APIs works as usual inside both group and steps.
32
+ let(:api) { ClientApi.new }
33
+ let(:mailbox) { Mailbox.new }
34
+ let(:user) { User.new }
35
+
36
+ step 'register' do
37
+ api.register(user)
38
+ end
39
+
40
+ step 'unable to sign in' do
41
+ response = api.sign_in(user)
42
+ expect(response).to be_forbidden
43
+ end
44
+
45
+ step 'confirm' do
46
+ mailbox.confirm(user)
47
+ fail 'Email not found in mailbox'
48
+ end
49
+
50
+ # This step will not be executed because previous one failed.
51
+ step 'successfully sign in' do
52
+ response = api.sign_in(user)
53
+ expect(response).to be_successfull
54
+ end
55
+
56
+ # Called after all steps, even if one failed.
57
+ after do
58
+ mailbox.clear
59
+ end
60
+
61
+ # Called only when a step failed.
62
+ on_fail do
63
+ puts api.logs
64
+ end
65
+ end
66
+ end
67
+ ```
68
+
69
+ ## Known Limitations
70
+
71
+ RSpec doubles should not be used in a shared stepwise context, otherwise it leads to:
72
+
73
+ _#<Double ...> was originally created in one example but has leaked into another example and can no longer be used. rspec-mocks' doubles are designed to only last for one example, and you need to create a new one in each example you wish to use it for._
74
+
75
+ So this will not work:
76
+
77
+ ```ruby
78
+ stepwise do
79
+ let(:api) { double(:api, call: nil) }
80
+
81
+ step 'one' do
82
+ api.call
83
+ end
84
+
85
+ step 'another' do
86
+ api.call
87
+ end
88
+ end
89
+ ```
90
+
91
+ Instead you have to do something like:
92
+
93
+ ```ruby
94
+ stepwise do
95
+ step 'one' do
96
+ api = double(:api, call: nil)
97
+ api.call
98
+ end
99
+
100
+ step 'another' do
101
+ api = double(:api, call: nil)
102
+ api.call
103
+ end
104
+ end
105
+ ```
106
+
107
+ ## Installation
108
+
109
+ Using Bundler:
110
+
111
+ ```ruby
112
+ gem 'rspec-stepwise', '~> 0.1.0'
113
+ ```
114
+
115
+ Or using rubygems:
116
+
117
+ ```bash
118
+ gem install rspec-stepwise
119
+ ```
120
+
121
+ ## Contributing
122
+
123
+ Bug reports and pull requests are welcome on GitHub at https://github.com/nikitug/rspec-stepwise.
124
+
125
+ ## License
126
+
127
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -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,5 @@
1
+ module RSpec
2
+ module Stepwise
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,135 @@
1
+ require 'rspec/stepwise/version'
2
+
3
+ module RSpec
4
+ # Provides DSL for defining a series of steps.
5
+ #
6
+ # @example
7
+ # RSpec.describe 'user registration and sign in' do
8
+ # stepwise do
9
+ # step 'register' do
10
+ # api.register(user)
11
+ # mailbox.confirm(user)
12
+ # end
13
+ #
14
+ # step 'sign in' do
15
+ # token = api.sign_in(user)
16
+ # expect(token).not_to be expired
17
+ # end
18
+ # end
19
+ # end
20
+ #
21
+ module Stepwise
22
+ # Defines new series of steps. Supports the same arguments as `RSpec.describe`.
23
+ # @see RSpec.describe
24
+ def stepwise(name = nil, *args, &block)
25
+ if args.last.is_a?(Hash)
26
+ args.last[:order] = :defined
27
+ else
28
+ args << { order: :defined }
29
+ end
30
+ describe(name, *args) do
31
+ Builder.new(self).instance_eval(&block)
32
+ end
33
+ end
34
+
35
+ # Provides DSL for steps definition and builds execution context.
36
+ class Builder
37
+ # @param klass [RSpec::Core::ExampleGroup]
38
+ def initialize(klass)
39
+ @klass = klass
40
+ @steps_context = Context.new(klass)
41
+ @fail_callbacks = []
42
+ end
43
+
44
+ # Defines new step in a series. Supports the same arguments as `RSpec::Core::ExampleGroup.it`.
45
+ # @see RSpec::Core::ExampleGroup.it
46
+ def step(*args, &block)
47
+ # `it` defines method within `klass`, so Builder's
48
+ # instance variable will not be visible there,
49
+ # so we use local var.
50
+ steps_context = @steps_context
51
+ fail_callbacks = @fail_callbacks
52
+ @klass.it(*args) do
53
+ if steps_context.previous_failed?
54
+ pending 'Previous step failed'
55
+ fail
56
+ else
57
+ begin
58
+ steps_context.run_step(&block)
59
+ rescue
60
+ fail_callbacks.each do |callback|
61
+ steps_context.run(&callback)
62
+ end
63
+ raise
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ # Runs if any step failed. Can be executed multiple times.
70
+ # Execution will happen in the same order as definition order.
71
+ #
72
+ # @example
73
+ # # Outputs API logs in case of failure.
74
+ # on_fail do
75
+ # puts api.execution_logs
76
+ # end
77
+ #
78
+ def on_fail(&block)
79
+ @fail_callbacks << block
80
+ end
81
+
82
+ # Runs after all steps finished.
83
+ #
84
+ # @example
85
+ # # Clears virtual mailbox after all steps.
86
+ # after do
87
+ # mailbox.clear
88
+ # end
89
+ #
90
+ def after(&block)
91
+ steps_context = @steps_context
92
+ @klass.after(:all) do
93
+ steps_context.run(&block)
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def method_missing(name, *args, &block)
100
+ if @klass.respond_to?(name)
101
+ @klass.public_send(name, *args, &block)
102
+ else
103
+ super
104
+ end
105
+ end
106
+
107
+ def respond_to_missing?(name, include_private = false)
108
+ @klass.respond_to?(name, include_private) || super
109
+ end
110
+ end
111
+
112
+ # @api private
113
+ class Context
114
+ def initialize(klass)
115
+ @context = klass.new
116
+ @previous_failed = false
117
+ end
118
+
119
+ def run_step(&block)
120
+ run(&block)
121
+ rescue
122
+ @previous_failed = true
123
+ raise
124
+ end
125
+
126
+ def run(&block)
127
+ @context.instance_eval(&block)
128
+ end
129
+
130
+ def previous_failed?
131
+ @previous_failed
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,22 @@
1
+ require_relative "lib/rspec/stepwise/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "rspec-stepwise"
5
+ spec.version = RSpec::Stepwise::VERSION
6
+ spec.authors = ["Nikita Afanasenko"]
7
+ spec.email = ["nikita@afanasenko.name"]
8
+
9
+ spec.summary = "Stepwise execution for RSpec."
10
+ spec.description = "Stepwise execution for RSpec."
11
+ spec.homepage = "https://github.com/nikitug/rspec-stepwise"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
15
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ end
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 2.0"
20
+ spec.add_development_dependency "rake", "~> 10.0"
21
+ spec.add_development_dependency "rspec", "~> 3.0"
22
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-stepwise
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nikita Afanasenko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-06-22 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: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
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: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: Stepwise execution for RSpec.
56
+ email:
57
+ - nikita@afanasenko.name
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - lib/rspec/stepwise.rb
70
+ - lib/rspec/stepwise/version.rb
71
+ - rspec-stepwise.gemspec
72
+ homepage: https://github.com/nikitug/rspec-stepwise
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubygems_version: 3.0.1
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Stepwise execution for RSpec.
95
+ test_files: []