test_spec 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9de1b9a5b2ae221963420313565d64da5e982138
4
+ data.tar.gz: c3164a1dc1fedb62934d63a811beca414403bf1c
5
+ SHA512:
6
+ metadata.gz: 18702682dfd0d5ac8e69b35d7ebf65fdf86095fee1a1f80ce12608e119df6a01649745ed93fea92266365ffd92c99d71e039ab01d2eb548c9bfd3e23b63d0a33
7
+ data.tar.gz: f569b3d2d807ccd70f3fab61c486bb9dafab14674c2cedb275a9a7579f11e23001dee93f61a29a2864f7e09df5ce6529de4ad4d3854495ffcfa9ac6826b41514
@@ -0,0 +1,46 @@
1
+ # Ruby Generated
2
+
3
+ /Gemfile.lock
4
+ /.bundle/
5
+ /.yardoc
6
+ /_yardoc/
7
+ /coverage/
8
+ /doc/
9
+ /pkg/
10
+ /spec/reports/
11
+ /spec/coverage/
12
+ /tmp/
13
+
14
+ # Rspec Failure Tracking
15
+
16
+ .rspec_status
17
+
18
+ # IDE Files
19
+
20
+ .idea/
21
+ *.iml
22
+ *.iws
23
+ *.ipr
24
+ .vscode/
25
+ .settings/
26
+ .metadata
27
+ .classpath
28
+ .loadpath
29
+ .buildpath
30
+ .project
31
+
32
+ # OS Files
33
+
34
+ .DS_Store
35
+ .DS_Store?
36
+ ._*
37
+ .Spotlight-V100
38
+ .Trashes
39
+ ehthumbs.db
40
+ Thumbs.db
41
+ $RECYCLE.BIN/
42
+ Desktop.ini
43
+ *.tmp
44
+ *.bak
45
+ *.swp
46
+ *~.nib
@@ -0,0 +1,69 @@
1
+ AllCops:
2
+ Exclude:
3
+ - test_spec.gemspec
4
+ - spec/**/*
5
+
6
+ # Removing need for frozen string literal comment.
7
+ Style/FrozenStringLiteralComment:
8
+ Enabled: false
9
+
10
+ # Removing the preference for string single quotes.
11
+ Style/StringLiterals:
12
+ Enabled: false
13
+
14
+ # Missing top-level module documentation comment.
15
+ Style/Documentation:
16
+ Enabled: false
17
+
18
+ # Prefer reduce over inject.
19
+ Style/CollectionMethods:
20
+ PreferredMethods:
21
+ reduce: 'inject'
22
+
23
+ # Use each_with_object instead of inject.
24
+ Style/EachWithObject:
25
+ Enabled: false
26
+
27
+ # Prefer fail over raise.
28
+ Style/SignalException:
29
+ Enabled: false
30
+
31
+ # This never works for validations.
32
+ Layout/AlignHash:
33
+ EnforcedLastArgumentHashStyle: ignore_implicit
34
+
35
+ # Align multi-line params with previous line.
36
+ Layout/AlignParameters:
37
+ EnforcedStyle: with_fixed_indentation
38
+
39
+ # Indent `when` clause one step from `case`.
40
+ Layout/CaseIndentation:
41
+ IndentOneStep: true
42
+
43
+ # Don't force bad var names for reduce/inject loops.
44
+ Style/SingleLineBlockParams:
45
+ Enabled: false
46
+
47
+ # For method chains, keep the dot with the method name.
48
+ Layout/DotPosition:
49
+ EnforcedStyle: leading
50
+
51
+ # Stop nesting so hard.
52
+ Metrics/BlockNesting:
53
+ Max: 2
54
+
55
+ # Encourage short methods.
56
+ Metrics/MethodLength:
57
+ Max: 15
58
+
59
+ # Encourage short (as possible) modules.
60
+ Metrics/ModuleLength:
61
+ Max: 100
62
+
63
+ # Encourage fewer parameters.
64
+ Metrics/ParameterLists:
65
+ Max: 4
66
+
67
+ # Remove execute permissions check.
68
+ Lint/ScriptPermission:
69
+ Enabled: false
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format RSpec::TestSpec::Formatter
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,2 @@
1
+ inherit_from:
2
+ - .hound.yml
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at jeff.nyman@yello.co. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "coveralls", require: false
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Jeff Nyman
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,227 @@
1
+ # TestSpec
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/test_spec.svg)](http://badge.fury.io/rb/test_spec)
4
+ [![License](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jeffnyman/test_spec/blob/master/LICENSE.md)
5
+
6
+ > **The height of sophistication is simplicity.**<br>
7
+ > &nbsp;&nbsp;&nbsp;&nbsp;*Clare Boothe Brokaw*
8
+
9
+ ---
10
+
11
+ TestSpec is a tool for leveraging RSpec to create an expressive DSL for test and data conditions.
12
+
13
+ TestSpec provides an internal DSL, similar to the [RSpec Story Runner](https://github.com/dchelimsky/rspec-stories). This was the predecessor of the [Cucumber](http://cukes.info/) external DSL provided by [Gherkin](http://cukes.info/gherkin.html).
14
+
15
+ Behavior Driven Development, or even just good Test Driven Development, practices put emphasis on communication. Tools like Cucumber focus on allowing communication via a test description language, structured by Gherkin keywords. However, while the ideas of Gherkin are nice, tools like Cucumber abstract away the nuts and bolts of your tests.
16
+
17
+ Abstraction can be a good thing but Cucumber gives you no choice in the matter. It hides code blocks behind a "call by regular expression" invocation mechanism instead of making those code blocks readily available in the test description.
18
+
19
+ TestSpec lets you write as much logic beside your specifications as you want by leveraging the RSpec ecosystem with the addition of a Gherkin-like syntax as well as additions to that syntax.
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ gem 'test_spec'
27
+ ```
28
+
29
+ To get the latest code:
30
+
31
+ ```ruby
32
+ gem 'test_spec', git: 'https://github.com/jeffnyman/test_spec'
33
+ ```
34
+
35
+ After doing one of the above, execute the following command:
36
+
37
+ ```
38
+ $ bundle
39
+ ```
40
+
41
+ You can also install TestSpec just as you would any other gem:
42
+
43
+ ```
44
+ $ gem install test_spec
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ To use TestSpec you simply have to require it within your `spec_helper` file:
50
+
51
+ ```ruby
52
+ require 'test_spec'
53
+ ```
54
+
55
+ Then you simply run your `rspec` command as normal against your test suite.
56
+
57
+ Because TestSpec uses a custom formatter, you should have an `.rspec` file with the following line in it:
58
+
59
+ ```ruby
60
+ --format RSpec::TestSpec::Formatter
61
+ ```
62
+
63
+ You can use RSpec constructs within Specify constructs although there are some things to be aware of. Here is an example:
64
+
65
+ ```ruby
66
+ Feature 'Bank Accounts' do
67
+ let(:valid_account_number) { '1234567890' }
68
+ subject { Account.new(valid_account_number) }
69
+
70
+ Scenario 'starting a new account' do
71
+ Test 'will have a starting balance of 0' do
72
+ expect(subject.balance).to eq(0)
73
+ end
74
+
75
+ it 'will not allow an invalid account name' do
76
+ expect { Account.new('thx1138') }.to raise_error(InvalidAccountNumberError)
77
+ end
78
+ end
79
+ end
80
+ ```
81
+
82
+ You can see that within the Feature construct I have let and subject elements. Within the Scenario you can see I use a Specify method (Test) and an RSpec method (it).
83
+
84
+ ## Documentation
85
+
86
+ TestSpec provides an internal DSL that allows you to use a Gherkin-like structural syntax within traditional RSpec test suites.
87
+
88
+ Note that while TestSpec does provide a Gherkin-like syntax, there is no parsing of an actual Gherkin feature file. This means there are no regular expression matchers that exist as part of step definitions.
89
+
90
+ Here's a typical (if simplified) example of a traditional RSpec test:
91
+
92
+ ```ruby
93
+ describe 'The Nature of Truth' do
94
+ context 'logic tests are applied' do
95
+ it 'will realize that true is almost certainly not false' do
96
+ expect(true).to_not be false
97
+ end
98
+
99
+ it 'will realize that true is pretty definitely true' do
100
+ expect(true).to be true
101
+ end
102
+ end
103
+ end
104
+ ```
105
+
106
+ The following examples will show how the above example can be utilized in the context of TestSpec's DSL.
107
+
108
+ As with Gherkin, you can provide a high-level **Feature** keyword to describe the overall set of tests. Here is one example of what you can do:
109
+
110
+ ```ruby
111
+ Feature 'The Nature of Truth' do
112
+ tests 'logic tests are applied' do
113
+ test 'true is almost certainly not false' do
114
+ expect(true).to_not be false
115
+ end
116
+
117
+ test 'true is pretty definitely true' do
118
+ expect(true).to be true
119
+ end
120
+ end
121
+ end
122
+ ```
123
+
124
+ Notice here the **tests** keyword. This is an alias for elements like RSpec's `context`. Further notice that a **Test** keyword can be used. Some people think of tests in terms of steps and TestSpec can accommodate that as follows:
125
+
126
+ ```ruby
127
+ Feature 'The Nature of Truth' do
128
+ steps 'logic tests are applied' do
129
+ step 'true is almost certainly not false' do
130
+ expect(true).to_not be false
131
+ end
132
+
133
+ step 'true is pretty definitely true' do
134
+ expect(true).to be true
135
+ end
136
+ end
137
+ end
138
+ ```
139
+
140
+ This is similar to the previous example, with the changes being the use of the **steps** and **Step** keywords.
141
+
142
+ Do note that unlike Gherkin feature files, you can have multiple **Feature** blocks within the test file. So you could have both of the above blocks co-existing and running together.
143
+
144
+ If you want to adhere even more strictly to Gherkin syntax, TestSpec does allow that:
145
+
146
+ ```ruby
147
+ Feature 'The Nature of Truth' do
148
+ Scenario 'simple logic tests are applied' do
149
+ Then 'true is almost certainly not false' do
150
+ expect(true).to_not be false
151
+ end
152
+
153
+ Then 'true is pretty definitely true' do
154
+ expect(true).to be true
155
+ end
156
+ end
157
+ end
158
+ ```
159
+
160
+ Here you can see the use of the **Scenario** keyword, which is encapsulating two Then test steps.
161
+
162
+ Gherkin structures allow you to use the word "Ability" as an alias for "Feature". However TestSpec takes the viewpoint that a feature could be speaking to a high-level viewpoint, within which there are multiple abilities. Thus you can use both descriptors simultaneously:
163
+
164
+ ```ruby
165
+ Feature 'The Nature of Truth' do
166
+ Ability 'logic tests can be applied' do
167
+ Scenario 'true is not false' do
168
+ Then 'true is almost certainly not false' do
169
+ expect(true).to_not be false
170
+ end
171
+ end
172
+
173
+ Scenario 'true is true' do
174
+ Then 'true is pretty definitely true' do
175
+ expect(true).to be true
176
+ end
177
+ end
178
+ end
179
+ end
180
+ ```
181
+
182
+ You can also see here that multiple **Scenario** blocks can be included within a Feature or Ability.
183
+
184
+ This should give a rough idea of how TestSpec provides an internal DSL.
185
+
186
+ ## Development
187
+
188
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake spec:all` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
189
+
190
+ To experiment with the code, run `bin/console` for an interactive prompt. If you want to make changes and see how they work as a gem installed on your local machine, run `bundle exec rake install`.
191
+
192
+ The default `rake` command will run all tests as well as a Rubocop analysis.
193
+
194
+ If you have rights to deploy a new version, make sure to update the version number in `version.rb`, and then run `bundle exec rake release`. This will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
195
+
196
+ ## Contributing
197
+
198
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/jeffnyman/test_spec](https://github.com/jeffnyman/test_spec). The testing ecosystem of Ruby is very large and this project is intended to be a welcoming arena for collaboration on yet another test-supporting tool. As such, contributors are very much welcome but are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) which is provided as a [code of conduct](https://github.com/jeffnyman/test_spec/blob/master/CODE_OF_CONDUCT.md).
199
+
200
+ The TestSpec gems follows [semantic versioning](http://semver.org).
201
+
202
+ To contribute to TestSpec:
203
+
204
+ 1. [Fork the project](http://gun.io/blog/how-to-github-fork-branch-and-pull-request/).
205
+ 2. Create your feature branch. (`git checkout -b my-new-feature`)
206
+ 3. Commit your changes. (`git commit -am 'new feature'`)
207
+ 4. Push the branch. (`git push origin my-new-feature`)
208
+ 5. Create a new [pull request](https://help.github.com/articles/using-pull-requests).
209
+
210
+ ## Author
211
+
212
+ * [Jeff Nyman](http://testerstories.com)
213
+
214
+ ## License
215
+
216
+ TestSpec is distributed under the [MIT](http://www.opensource.org/licenses/MIT) license.
217
+ See the [LICENSE](https://github.com/jeffnyman/test_spec/blob/master/LICENSE.md) file for details.
218
+
219
+ ## Credits
220
+
221
+ TestSpec has been inspired by the following projects. Each provided me with ideas for what to do and, in some cases, for what not to do. All were invaluable as I better considered how to leverage RSpec's functionality.
222
+
223
+ * [maniok_bdd](https://github.com/21croissants/maniok_bdd)
224
+ * [rspec-gherkin](https://github.com/sheerun/rspec-gherkin)
225
+ * [rspec example steps](https://github.com/railsware/rspec-example_steps)
226
+ * [XSpec](https://github.com/xaviershay/xspec)
227
+ * [Mouse Melon](https://github.com/wojtha/mouse_melon)
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require "rdoc/task"
5
+ require "rubocop/rake_task"
6
+ require "rspec/core/rake_task"
7
+
8
+ RuboCop::RakeTask.new
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ namespace :spec do
13
+ desc 'Clean all generated reports'
14
+ task :clean do
15
+ system('rm -rf spec/reports')
16
+ system('rm -rf spec/coverage')
17
+ end
18
+
19
+ RSpec::Core::RakeTask.new(all: :clean) do |config|
20
+ options = %w[--color]
21
+ options += %w[--format documentation]
22
+ options += %w[--format html --out spec/reports/unit-test-report.html]
23
+
24
+ config.rspec_opts = options
25
+ end
26
+ end
27
+
28
+ Rake::RDocTask.new do |rdoc|
29
+ rdoc.rdoc_dir = 'doc'
30
+ rdoc.main = 'README.md'
31
+ rdoc.title = "TestSpec #{TestSpec::VERSION}"
32
+ rdoc.rdoc_files.include('README*', 'lib/**/*.rb')
33
+ end
34
+
35
+ task default: ['spec:all', :rubocop]
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "test_spec"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ require "pry"
10
+ Pry.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,38 @@
1
+ require "rspec/core"
2
+ require "rspec/core/world"
3
+ require "rspec/core/reporter"
4
+ require "rspec/core/formatters"
5
+ require "rspec/core/example_group"
6
+ require "rspec/core/formatters/console_codes"
7
+ require "rspec/core/formatters/documentation_formatter"
8
+
9
+ require "test_spec/spec"
10
+ require "test_spec/version"
11
+ require "test_spec/rspec/world"
12
+ require "test_spec/rspec/reporter"
13
+ require "test_spec/rspec/formatter"
14
+ require "test_spec/rspec/notification"
15
+ require "test_spec/rspec/example_group"
16
+
17
+ RSpec::Core::ExampleGroup.send :include, RSpec::TestSpec::ExampleGroup
18
+ RSpec::Core::Reporter.send :include, RSpec::TestSpec::Reporter
19
+ RSpec::Core::World.send :include, RSpec::TestSpec::World
20
+
21
+ RSpec::Core::ExampleGroup.define_example_method :Scenario, with_steps: true
22
+ RSpec::Core::ExampleGroup.define_example_method :Condition, with_steps: true
23
+ RSpec::Core::ExampleGroup.define_example_method :Behavior, with_steps: true
24
+
25
+ RSpec::Core::ExampleGroup.define_example_method :Step, with_steps: true
26
+ RSpec::Core::ExampleGroup.define_example_method :Test, with_steps: true
27
+ RSpec::Core::ExampleGroup.define_example_method :Rule, with_steps: true
28
+ RSpec::Core::ExampleGroup.define_example_method :Fact, with_steps: true
29
+
30
+ RSpec::Core::ExampleGroup.define_example_method :steps, with_steps: true
31
+ RSpec::Core::ExampleGroup.define_example_method :rules, with_steps: true
32
+ RSpec::Core::ExampleGroup.define_example_method :tests, with_steps: true
33
+ RSpec::Core::ExampleGroup.define_example_method :facts, with_steps: true
34
+
35
+ require "test_spec/rspec/shared_steps"
36
+ # rubocop:disable Style/MixinUsage
37
+ include RSpec::TestSpec::SharedSteps
38
+ # rubocop:enable Style/MixinUsage
@@ -0,0 +1,101 @@
1
+ module RSpec
2
+ module TestSpec
3
+ module ExampleGroup
4
+ # In Rspec, example group bodies are delimited by 'describe' and
5
+ # 'context' methods. These encapsulate examples, which are delimited
6
+ # by 'it' methods. Example groups are evaluated in the context of an
7
+ # ExampleGroup instance. Individual examples are evaluated in the
8
+ # context of an instance of the ExampleGroup to which they belong.
9
+ def include_steps(*args)
10
+ name = args.shift
11
+
12
+ shared_block = ::RSpec.world.shared_example_steps[name]
13
+ shared_block || raise(ArgumentError,
14
+ "Could not find shared steps #{name.inspect}")
15
+
16
+ instance_exec(*args, &shared_block)
17
+ end
18
+
19
+ # rubocop:disable Naming/MethodName
20
+ def Given(message, options = {}, &block)
21
+ action :given, message, options, &block
22
+ end
23
+
24
+ def When(message, options = {}, &block)
25
+ action :when, message, options, &block
26
+ end
27
+
28
+ def Then(message, options = {}, &block)
29
+ action :then, message, options, &block
30
+ end
31
+
32
+ def And(message, options = {}, &block)
33
+ action :and, message, options, &block
34
+ end
35
+
36
+ def But(message, options = {}, &block)
37
+ action :but, message, options, &block
38
+ end
39
+ # rubocop:enable Naming/MethodName
40
+
41
+ def rule(message, options = {}, &block)
42
+ action :rule, message, options, &block
43
+ end
44
+
45
+ def fact(message, options = {}, &block)
46
+ action :fact, message, options, &block
47
+ end
48
+
49
+ def test(message, options = {}, &block)
50
+ action :test, message, options, &block
51
+ end
52
+
53
+ def step(message, options = {}, &block)
54
+ action :step, message, options, &block
55
+ end
56
+
57
+ def it(message, options = {}, &block)
58
+ action :it, message, options, &block
59
+ end
60
+
61
+ def specify(message, options = {}, &block)
62
+ action :specify, message, options, &block
63
+ end
64
+
65
+ def example(message, options = {}, &block)
66
+ action :example, message, options, &block
67
+ end
68
+
69
+ private
70
+
71
+ # rubocop:disable Metrics/AbcSize
72
+ # rubocop:disable Metrics/MethodLength
73
+ def action(type, message, options = {}, &_block)
74
+ ::RSpec.world.reporter.example_step_started(
75
+ self, type, message, options
76
+ )
77
+ options = { pending: true } if options == :pending
78
+
79
+ if block_given? && !options[:pending]
80
+ begin
81
+ yield
82
+ rescue StandardError => e
83
+ ::RSpec.world.reporter.example_step_failed(
84
+ self, type, message, options
85
+ )
86
+ raise e
87
+ end
88
+ ::RSpec.world.reporter.example_step_passed(
89
+ self, type, message, options
90
+ )
91
+ else
92
+ ::RSpec.world.reporter.example_step_pending(
93
+ self, type, message, options
94
+ )
95
+ end
96
+ end
97
+ # rubocop:enable Metrics/AbcSize
98
+ # rubocop:enable Metrics/MethodLength
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,53 @@
1
+ require "rspec/core/formatters/documentation_formatter"
2
+
3
+ module RSpec
4
+ module TestSpec
5
+ class Formatter < ::RSpec::Core::Formatters::DocumentationFormatter
6
+ ::RSpec::Core::Formatters.register(
7
+ self,
8
+ :example_started, :example_passed, :example_step_passed,
9
+ :example_step_pending, :example_step_failed
10
+ )
11
+
12
+ # rubocop:disable Metrics/LineLength
13
+ def example_started(notification)
14
+ return unless notification.example.metadata[:with_steps]
15
+
16
+ full_message = "#{current_indentation}#{notification.example.description}"
17
+ output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :default)
18
+ end
19
+
20
+ def example_passed(notification)
21
+ super unless notification.example.metadata[:with_steps]
22
+ end
23
+
24
+ def example_step_passed(notification)
25
+ full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message}"
26
+ output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :success)
27
+ end
28
+
29
+ # rubocop:disable Metrics/AbcSize
30
+ # rubocop:disable Style/ConditionalAssignment
31
+ def example_step_pending(notification)
32
+ full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message}"
33
+
34
+ if notification.options[:pending] &&
35
+ notification.options[:pending] != true
36
+ full_message << " (PENDING: #{notification.options[:pending]})"
37
+ else
38
+ full_message << " (PENDING)"
39
+ end
40
+
41
+ output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :pending)
42
+ end
43
+ # rubocop:enable Metrics/AbcSize
44
+ # rubocop:enable Style/ConditionalAssignment
45
+
46
+ def example_step_failed(notification)
47
+ full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message} (FAILED)"
48
+ output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :failure)
49
+ end
50
+ # rubocop:enable Metrics/LineLength
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,12 @@
1
+ module RSpec
2
+ module TestSpec
3
+ # In RSpec, notifications are value objects that are passed to formatters
4
+ # to provide those formatters with information about a particular event.
5
+
6
+ Notification = Struct.new(:example, :type, :message, :options)
7
+
8
+ # Originally I did this:
9
+ # class Notification < Struct.new(:example, :type, :message, :options)
10
+ # end
11
+ end
12
+ end
@@ -0,0 +1,35 @@
1
+ module RSpec
2
+ module TestSpec
3
+ module Reporter
4
+ # An RSpec reporter sends notifications to listeners. The listeners
5
+ # are usually formatters for a specific test run.
6
+ def example_step_started(example, type, message, options)
7
+ notify :example_step_started,
8
+ Notification.new(example, type, message, options)
9
+ end
10
+
11
+ def example_step_passed(example, type, message, options)
12
+ notify :example_step_passed,
13
+ Notification.new(example, type, message, options)
14
+ end
15
+
16
+ def example_step_failed(example, type, message, options)
17
+ notify :example_step_failed,
18
+ Notification.new(example, type, message, options)
19
+ end
20
+
21
+ def example_step_pending(example, type, message, options)
22
+ notify :example_step_pending,
23
+ Notification.new(example, type, message, options)
24
+ end
25
+
26
+ def registered_formatters
27
+ @listeners.values.map(&:to_a).flatten.uniq
28
+ end
29
+
30
+ def find_registered_formatter(cls)
31
+ registered_formatters.detect { |formatter| formatter.class == cls }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ module RSpec
2
+ module TestSpec
3
+ module SharedSteps
4
+ def shared_steps(name, &block)
5
+ ensure_shared_example_steps_name_not_taken(name)
6
+ ::RSpec.world.shared_example_steps[name] = block
7
+ end
8
+
9
+ private
10
+
11
+ def ensure_shared_example_steps_name_not_taken(name)
12
+ return unless ::RSpec.world.shared_example_steps.key?(name)
13
+
14
+ raise(ArgumentError, "Shared step '#{name}' already exists")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ module RSpec
2
+ module TestSpec
3
+ module World
4
+ # RSpec's 'world' is an internal container that is used for
5
+ # holding global non-configuration data.
6
+ def shared_example_steps
7
+ @shared_example_steps ||= {}
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,41 @@
1
+ module TestSpec
2
+ module Spec
3
+ def self.included(base)
4
+ base.instance_eval do
5
+ alias :Feature :context
6
+ alias :Ability :context
7
+ alias :Story :context
8
+ alias :Component :context
9
+ alias :Workflow :context
10
+
11
+ alias :Background :before
12
+ alias :Setup :before
13
+ alias :Teardown :after
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ # rubocop:disable Naming/MethodName
20
+ def self.Feature(*args, &block)
21
+ RSpec.describe(*args, &block)
22
+ end
23
+
24
+ def self.Ability(*args, &block)
25
+ RSpec.describe(*args, &block)
26
+ end
27
+
28
+ def self.Story(*args, &block)
29
+ RSpec.describe(*args, &block)
30
+ end
31
+
32
+ def self.Component(*args, &block)
33
+ RSpec.describe(*args, &block)
34
+ end
35
+
36
+ def self.Workflow(*args, &block)
37
+ RSpec.describe(*args, &block)
38
+ end
39
+ # rubocop:enable Naming/MethodName
40
+
41
+ RSpec.configuration.include TestSpec::Spec
@@ -0,0 +1,3 @@
1
+ module TestSpec
2
+ VERSION = "0.1.0".freeze
3
+ end
@@ -0,0 +1,38 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "test_spec/version"
5
+ require "date"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "test_spec"
9
+ spec.version = TestSpec::VERSION
10
+ spec.date = Date.today.strftime("%Y-%m-%d")
11
+ spec.authors = ["Jeff Nyman"]
12
+ spec.email = ["jeffnyman@gmail.com"]
13
+
14
+ spec.summary = %q{Test and Data Condition DSL for RSpec}
15
+ spec.description = %q{Test and Data Condition DSL for RSpec}
16
+ spec.homepage = "https://github.com/jeffnyman/test_spec"
17
+ spec.license = "MIT"
18
+
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.17"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rspec", "~> 3.0"
29
+ spec.add_development_dependency "simplecov"
30
+ spec.add_development_dependency "rubocop"
31
+ spec.add_development_dependency "pry"
32
+
33
+ spec.post_install_message = %{
34
+ (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
35
+ TestSpec #{TestSpec::VERSION} has been installed.
36
+ (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
37
+ }
38
+ end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: test_spec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeff Nyman
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-11-21 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.17'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.17'
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
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Test and Data Condition DSL for RSpec
98
+ email:
99
+ - jeffnyman@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".hound.yml"
106
+ - ".rspec"
107
+ - ".rubocop.yml"
108
+ - CODE_OF_CONDUCT.md
109
+ - Gemfile
110
+ - LICENSE.md
111
+ - README.md
112
+ - Rakefile
113
+ - bin/console
114
+ - bin/setup
115
+ - lib/test_spec.rb
116
+ - lib/test_spec/rspec/example_group.rb
117
+ - lib/test_spec/rspec/formatter.rb
118
+ - lib/test_spec/rspec/notification.rb
119
+ - lib/test_spec/rspec/reporter.rb
120
+ - lib/test_spec/rspec/shared_steps.rb
121
+ - lib/test_spec/rspec/world.rb
122
+ - lib/test_spec/spec.rb
123
+ - lib/test_spec/version.rb
124
+ - test_spec.gemspec
125
+ homepage: https://github.com/jeffnyman/test_spec
126
+ licenses:
127
+ - MIT
128
+ metadata: {}
129
+ post_install_message: "\n(::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)\n
130
+ \ TestSpec 0.1.0 has been installed.\n(::) (::) (::) (::) (::) (::) (::) (::) (::)
131
+ (::) (::) (::)\n "
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.5.2.2
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: Test and Data Condition DSL for RSpec
151
+ test_files: []