rspec-stepwise 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []