test_workflow 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +40 -0
- data/.hound.yml +62 -0
- data/.rspec +3 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +260 -0
- data/Rakefile +31 -0
- data/bin/console +10 -0
- data/bin/setup +8 -0
- data/lib/test_workflow.rb +108 -0
- data/lib/test_workflow/version.rb +3 -0
- data/test_workflow.gemspec +35 -0
- metadata +131 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c53489fbc2c38d6b23e5862bf693db730ebcec33
|
4
|
+
data.tar.gz: c7c6408cf7d834de2c0695d1976d76f1361ca456
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ad82e427ba320539336819fe7f3da69b975559c306168f4d22bb21b41c39306e3a9b8899973d0fd23fed92fe3993b5330fe98ce56494aa0b86121e3c4ddfda79
|
7
|
+
data.tar.gz: 1ca5acf697fd1c5ca8b44a2ff7a77abeedc491e8c555173def6fffc071d8947cec2b6cd0182f5ffda9a242c8f5789e46d958f73bad35499a61eb8305d3a58da5
|
data/.gitignore
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Ruby-Specific
|
2
|
+
|
3
|
+
/.bundle/
|
4
|
+
/.yardoc
|
5
|
+
/Gemfile.lock
|
6
|
+
/_yardoc/
|
7
|
+
|
8
|
+
# Ouput-Specific
|
9
|
+
|
10
|
+
/coverage/
|
11
|
+
/doc/
|
12
|
+
/pkg/
|
13
|
+
/spec/reports/
|
14
|
+
/tmp/
|
15
|
+
*.log
|
16
|
+
*.tmp
|
17
|
+
*.swp
|
18
|
+
*.bak
|
19
|
+
|
20
|
+
# IDE-Specific
|
21
|
+
|
22
|
+
.idea
|
23
|
+
.settings
|
24
|
+
.project
|
25
|
+
.classpath
|
26
|
+
*.iws
|
27
|
+
|
28
|
+
# Windows-Specific
|
29
|
+
|
30
|
+
Thumbs.db
|
31
|
+
|
32
|
+
# Mac OS-Specific
|
33
|
+
|
34
|
+
*.DS_Store
|
35
|
+
._*
|
36
|
+
|
37
|
+
# Linux-Specific
|
38
|
+
|
39
|
+
.directory
|
40
|
+
.Trash-*
|
data/.hound.yml
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- test_workflow.gemspec
|
4
|
+
- test/*.rb
|
5
|
+
- spec/**/*
|
6
|
+
|
7
|
+
# Removing need for frozen string literal comment.
|
8
|
+
Style/FrozenStringLiteralComment:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
# Removing the preference for string single quotes.
|
12
|
+
Style/StringLiterals:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
# Missing top-level module documentation comment.
|
16
|
+
Style/Documentation:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
# Prefer reduce over inject.
|
20
|
+
Style/CollectionMethods:
|
21
|
+
PreferredMethods:
|
22
|
+
reduce: 'inject'
|
23
|
+
|
24
|
+
# Use each_with_object instead of inject.
|
25
|
+
Style/EachWithObject:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
# Prefer fail over raise.
|
29
|
+
Style/SignalException:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
# This never works for validations.
|
33
|
+
Style/AlignHash:
|
34
|
+
EnforcedLastArgumentHashStyle: ignore_implicit
|
35
|
+
|
36
|
+
# Align multi-line params with previous line.
|
37
|
+
Style/AlignParameters:
|
38
|
+
EnforcedStyle: with_fixed_indentation
|
39
|
+
|
40
|
+
# Indent `when` clause one step from `case`.
|
41
|
+
Style/CaseIndentation:
|
42
|
+
IndentOneStep: true
|
43
|
+
|
44
|
+
# Don't force bad var names for reduce/inject loops.
|
45
|
+
Style/SingleLineBlockParams:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
# For method chains, keep the dot with the method name.
|
49
|
+
Style/DotPosition:
|
50
|
+
EnforcedStyle: leading
|
51
|
+
|
52
|
+
# Stop nesting so hard.
|
53
|
+
Metrics/BlockNesting:
|
54
|
+
Max: 2
|
55
|
+
|
56
|
+
# Encourage short methods.
|
57
|
+
Metrics/MethodLength:
|
58
|
+
Max: 10
|
59
|
+
|
60
|
+
# Encourage fewer parameters.
|
61
|
+
Metrics/ParameterLists:
|
62
|
+
Max: 4
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -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 jeffnyman@gmail.com. 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
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 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.
|
data/README.md
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
# TestWorkflow
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/test_workflow.svg)](http://badge.fury.io/rb/test_workflow)
|
4
|
+
[![License](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jnyman/test_workflow/blob/master/LICENSE.txt)
|
5
|
+
|
6
|
+
TestWorkflow implements the idea of traversing a set of activities in the context of a user workflow.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
To get the latest stable release, add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'test_workflow'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then include it in your bundle:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
You can also install TestWorkflow just as you would any other gem:
|
21
|
+
|
22
|
+
$ gem install test_workflow
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
The core operation of the TestWorkflow is a path. A workflow can have different paths. A path is an array of actions. These actions consist of a class a method on that class. Parameters can also be passed to the methods. The idea here is that the class is acting as context object for test execution. That class may be a page object, a screen object, a service object, and so on.
|
27
|
+
|
28
|
+
### Paths
|
29
|
+
|
30
|
+
Here's an example of a workflow class with a path:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
PurchaseFromAmazon.paths = {
|
34
|
+
:default => [
|
35
|
+
[AmazonSearch, :search_for, "Star Wars"],
|
36
|
+
[AmazonProduct, :add_to_cart, "Vector Prime"],
|
37
|
+
[AmazonCart, :checkout]
|
38
|
+
]
|
39
|
+
}
|
40
|
+
```
|
41
|
+
|
42
|
+
Notice how some of the paths are passing arguments to the methods.
|
43
|
+
|
44
|
+
Now to run that workflow up to the last point, you could do this:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
path_to(AmazonCart)
|
48
|
+
```
|
49
|
+
|
50
|
+
This would run the workflow _up to_ the AmazonCart, starting with AmazonSearch and moving on down the list. Note that the first argument is a context definition (i.e., AmazonSearch), the second is a method on that context definition (i.e., :search_for) and the the third item is an optional argument to pass to that method.
|
51
|
+
|
52
|
+
Symbiote will always assume there is a default path, and will complain if there is not one. But you can have a different workflow as such:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
PurchaseFromAmazon.paths = {
|
56
|
+
:default => [
|
57
|
+
[AmazonSearch, :search_for, "Star Wars"],
|
58
|
+
[AmazonProduct, :add_to_cart, "Vector Prime"],
|
59
|
+
[AmazonCart, :checkout]
|
60
|
+
],
|
61
|
+
|
62
|
+
:trekking => [
|
63
|
+
[AmazonSearch, :search_for, "Star Trek"],
|
64
|
+
[AmazonProduct, :add_to_cart, "Engines of Destiny"],
|
65
|
+
[AmazonCart, :checkout]
|
66
|
+
]
|
67
|
+
}
|
68
|
+
```
|
69
|
+
|
70
|
+
Now you can specify that you want to use that different path:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
path_to(AmazonCart, using: :trekking)
|
74
|
+
```
|
75
|
+
|
76
|
+
So what you can see here is that you can navigate to a particiular context traversing through all other contexts along the way. The use of the term "context" is deliberate because the workflow could be the traversal of a series of pages. Thus the contexts would be page objects. But the workflow could also be a series of API calls, which means the contexts might be service objects.
|
77
|
+
|
78
|
+
### Examples
|
79
|
+
|
80
|
+
Consider the following setup:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
require "test_workflow"
|
84
|
+
|
85
|
+
class AmazonSearch
|
86
|
+
def search_for(product)
|
87
|
+
puts "AmazonSearch - search_for: #{product}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class AmazonProduct
|
92
|
+
def add_to_cart(product)
|
93
|
+
puts "AmazonProduct - add_to_cart: #{product}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class AmazonCart
|
98
|
+
def checkout
|
99
|
+
puts "AmazonCart - checkout"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class PurchaseFromAmazon
|
104
|
+
include TestWorkflow
|
105
|
+
|
106
|
+
def on(caller)
|
107
|
+
caller.new
|
108
|
+
end
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
The `on` method here is critical. This is a part of the API that is exposed by TestWorkflow. What this means is that you should implement this method so that context calls can be made.
|
113
|
+
|
114
|
+
You can then do the following:
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
PurchaseFromAmazon.paths = {
|
118
|
+
:default => [
|
119
|
+
[AmazonSearch, :search_for, "Star Wars"],
|
120
|
+
[AmazonProduct, :add_to_cart, "Vector Prime"],
|
121
|
+
[AmazonCart, :checkout]
|
122
|
+
]
|
123
|
+
}
|
124
|
+
|
125
|
+
testing = PurchaseFromAmazon.new
|
126
|
+
testing.path_to(AmazonCart)
|
127
|
+
```
|
128
|
+
|
129
|
+
That would lead to output like this:
|
130
|
+
|
131
|
+
AmazonSearch - search_for: Star Wars
|
132
|
+
AmazonProduct - add_to_cart: Vector Prime
|
133
|
+
|
134
|
+
You can see the logic is running up to the AmazonCart part of the path. That is by design. You could change that last line to this:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
testing.path_to(AmazonCart, from: AmazonProduct)
|
138
|
+
```
|
139
|
+
|
140
|
+
That would lead to this output:
|
141
|
+
|
142
|
+
AmazonProduct - add_to_cart: Vector Prime
|
143
|
+
|
144
|
+
Here you are saying you want to run the path starting from a particular point in the path.
|
145
|
+
|
146
|
+
Let's add a second path to the workflow:
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
PurchaseFromAmazon.paths = {
|
150
|
+
:default => [
|
151
|
+
[AmazonSearch, :search_for, "Star Wars"],
|
152
|
+
[AmazonProduct, :add_to_cart, "Vector Prime"],
|
153
|
+
[AmazonCart, :checkout]
|
154
|
+
],
|
155
|
+
:trekking => [
|
156
|
+
[AmazonSearch, :search_for, "Star Trek"],
|
157
|
+
[AmazonProduct, :add_to_cart, "Engines of Destiny"],
|
158
|
+
[AmazonCart, :checkout]
|
159
|
+
]
|
160
|
+
}
|
161
|
+
|
162
|
+
testing = PurchaseFromAmazon.new
|
163
|
+
testing.path_to(AmazonCart, from: AmazonProduct, using: :trekking)
|
164
|
+
```
|
165
|
+
|
166
|
+
The output from this would be:
|
167
|
+
|
168
|
+
AmazonProduct - add_to_cart: Engines of Destiny
|
169
|
+
|
170
|
+
Here I'm not only running from a particular point on the path but I'm using a specific path as well.
|
171
|
+
|
172
|
+
You can also override the method call. For example, try this:
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
testing.path_to(AmazonProduct).add_to_cart('testing')
|
176
|
+
```
|
177
|
+
|
178
|
+
This would lead to this output:
|
179
|
+
|
180
|
+
AmazonSearch - search_for: Star Wars
|
181
|
+
AmazonProduct - add_to_cart: testing
|
182
|
+
|
183
|
+
Notice here how the argument passed in is not the default one from the path but the one you specified.
|
184
|
+
|
185
|
+
You can also run the entire path by doing this:
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
testing.entire_path
|
189
|
+
```
|
190
|
+
|
191
|
+
You'll note here that I've defined the paths outside of the workflow class, but you can easily do otherwise, as such:
|
192
|
+
|
193
|
+
You can also continue executing a path that you previously started. Consider this logic:
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
testing = PurchaseFromAmazon.new
|
197
|
+
|
198
|
+
testing.path_to(AmazonProduct)
|
199
|
+
testing.current_context = AmazonProduct.new
|
200
|
+
|
201
|
+
# Do some other logic here.
|
202
|
+
puts "Other Logic Happens Here."
|
203
|
+
|
204
|
+
testing.continue_path_to(AmazonCart)
|
205
|
+
```
|
206
|
+
|
207
|
+
The output would be:
|
208
|
+
|
209
|
+
AmazonSearch - search_for: Star Wars
|
210
|
+
Other Logic Happens Here.
|
211
|
+
AmazonProduct - add_to_cart: Vector Prime
|
212
|
+
|
213
|
+
What this is showing you is that a path can be started, then other work can be done, and then the path can be re-entered at a particular starting point. Key to this is the use of `current_context` which you would want to define on any of your classes that include TestWorkflow. For example, with the above logic you would have:
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
class PurchaseFromAmazon
|
217
|
+
include TestWorkflow
|
218
|
+
|
219
|
+
attr_accessor :current_context
|
220
|
+
# ...
|
221
|
+
end
|
222
|
+
```
|
223
|
+
|
224
|
+
You have to maintain the `@current_context` instance variable which should always point to the current object in the workflow path. This gives you a minimal way to control the execution of paths by executing them up to a point, interleaving other activities you might want to perform, and then continuing on from where you left off.
|
225
|
+
|
226
|
+
### Code Considerations
|
227
|
+
|
228
|
+
From a code perspecive, `path_to` is a key method. It takes in a context as well as a path. That path will be a hash that contains two elements. One of the elements is the key :using. This is what is used to lookup the path to traverse. You can see that in the example above. This key will have a default value of :default. The second key that can be specified is :visit. This specifies whether the execution context should be specifically set up, as opposed to assuming that the context already exists. The default value of :visit is false.
|
229
|
+
|
230
|
+
Another method to be aware of is `entire_path`, which was covered above. This is used to traverse through a complete workflow based on the paths, executing any methods specified.
|
231
|
+
|
232
|
+
## Development
|
233
|
+
|
234
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec:all` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`.
|
235
|
+
|
236
|
+
## Contributing
|
237
|
+
|
238
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/jnyman/test_workflow](https://github.com/jnyman/test_workflow). The testing ecosystem of Ruby is very large and this project is intended to be a welcoming arena for collaboration on yet another testing tool. As such, contributors are very much welcome but are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
239
|
+
|
240
|
+
To contribute to TestWorkflow:
|
241
|
+
|
242
|
+
1. [Fork the project](http://gun.io/blog/how-to-github-fork-branch-and-pull-request/).
|
243
|
+
2. Create your feature branch. (`git checkout -b my-new-feature`)
|
244
|
+
3. Commit your changes. (`git commit -am 'new feature'`)
|
245
|
+
4. Push the branch. (`git push origin my-new-feature`)
|
246
|
+
5. Create a new [pull request](https://help.github.com/articles/using-pull-requests).
|
247
|
+
|
248
|
+
## Author
|
249
|
+
|
250
|
+
* [Jeff Nyman](http://testerstories.com)
|
251
|
+
|
252
|
+
## Credits
|
253
|
+
|
254
|
+
This code is loosely based upon the [PageNavigation](https://github.com/cheezy/page_navigation) gem. The rationale for a new version is that tying the project to "page navigation" in particular is limiting, particularly since workflow-based patterns (like journey and screenplay) are often much more effective from a testing standpoint.
|
255
|
+
|
256
|
+
## License
|
257
|
+
|
258
|
+
TestWorkflow is distributed under the [MIT](http://www.opensource.org/licenses/MIT) license.
|
259
|
+
See the [LICENSE](https://github.com/jnyman/test_workflow/blob/master/LICENSE.txt) file for details.
|
260
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require "rdoc/task"
|
4
|
+
require "rubocop/rake_task"
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
|
7
|
+
RuboCop::RakeTask.new
|
8
|
+
|
9
|
+
namespace :spec do
|
10
|
+
desc 'Clean all generated reports'
|
11
|
+
task :clean do
|
12
|
+
system('rm -rf spec/reports')
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec::Core::RakeTask.new(all: :clean) do |config|
|
16
|
+
options = %w(--color)
|
17
|
+
options += %w(--format documentation)
|
18
|
+
options += %w(--format html --out spec/reports/unit-test-report.html)
|
19
|
+
|
20
|
+
config.rspec_opts = options
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Rake::RDocTask.new do |rdoc|
|
25
|
+
rdoc.rdoc_dir = 'doc'
|
26
|
+
rdoc.main = 'README.md'
|
27
|
+
rdoc.title = "TestWorkflow #{TestWorkflow::VERSION}"
|
28
|
+
rdoc.rdoc_files.include('README*', 'lib/**/*.rb')
|
29
|
+
end
|
30
|
+
|
31
|
+
task default: ['spec:all', :rubocop]
|
data/bin/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "test_workflow"
|
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
|
data/bin/setup
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require "test_workflow/version"
|
2
|
+
|
3
|
+
require "data_builder"
|
4
|
+
|
5
|
+
module TestWorkflow
|
6
|
+
module Paths
|
7
|
+
def paths
|
8
|
+
@paths
|
9
|
+
end
|
10
|
+
|
11
|
+
def paths=(path)
|
12
|
+
@paths = path
|
13
|
+
raise("You must provide a default workflow path") unless paths[:default]
|
14
|
+
@paths
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.included(caller)
|
19
|
+
caller.extend Paths
|
20
|
+
@caller = caller
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.caller
|
24
|
+
@caller
|
25
|
+
end
|
26
|
+
|
27
|
+
# Provides an execution path for a given workflow path, using a specific
|
28
|
+
# definition that is part of that workflow path.
|
29
|
+
def path_to(context, keys = { using: :default, visit: false }, &block)
|
30
|
+
keys[:using] = :default unless keys[:using]
|
31
|
+
keys[:visit] = false unless keys[:visit]
|
32
|
+
|
33
|
+
path, path_goal = path_trail(keys, context)
|
34
|
+
|
35
|
+
return on(context, &block) if path_goal == -1
|
36
|
+
|
37
|
+
path_start = keys[:from] ? path_start_point(path, keys) : 0
|
38
|
+
execute_path(path[path_start..path_goal], keys[:visit])
|
39
|
+
|
40
|
+
on(context, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
alias path_up_to path_to
|
44
|
+
alias workflow_to path_to
|
45
|
+
alias workflow_up_to path_to
|
46
|
+
|
47
|
+
# Provides an execution path that starts execution of a given path
|
48
|
+
# from the standpoint of the "current context", which is something
|
49
|
+
# that must be set as part of execution logic.
|
50
|
+
def continue_path_to(context, keys = { using: :default }, &block)
|
51
|
+
path = workflow_path_for(keys)
|
52
|
+
path_start = find_index_for(path, @current_context.class)
|
53
|
+
path_end = find_index_for(path, context) - 1
|
54
|
+
|
55
|
+
if path_start == path_end
|
56
|
+
execute_path([path[path_start]], false)
|
57
|
+
else
|
58
|
+
execute_path(path[path_start..path_end], false)
|
59
|
+
end
|
60
|
+
|
61
|
+
on(context, &block)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Provides an execution path for an entire workflow path.
|
65
|
+
def entire_path(keys = { using: :default, visit: false })
|
66
|
+
path_workflow = workflow_path_for(keys)
|
67
|
+
execute_path(path_workflow[0..-1], keys[:visit])
|
68
|
+
end
|
69
|
+
|
70
|
+
alias run_entire_path entire_path
|
71
|
+
alias run_full_path entire_path
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def path_trail(keys, context)
|
76
|
+
path = workflow_path_for(keys)
|
77
|
+
goal = find_index_for(path, context) - 1
|
78
|
+
[path, goal]
|
79
|
+
end
|
80
|
+
|
81
|
+
def path_start_point(path, keys)
|
82
|
+
path.find_index { |item| item[0] == keys[:from] }
|
83
|
+
end
|
84
|
+
|
85
|
+
def workflow_path_for(keys)
|
86
|
+
path = TestWorkflow.caller.paths[keys[:using]]
|
87
|
+
raise("The path named '#{keys[:using]}' was not found.") unless path
|
88
|
+
path
|
89
|
+
end
|
90
|
+
|
91
|
+
def execute_path(path, visit)
|
92
|
+
path.each do |definition, action, *args|
|
93
|
+
context = visit ? visit(definition) : on(definition)
|
94
|
+
visit = false
|
95
|
+
|
96
|
+
unless context.respond_to?(action)
|
97
|
+
raise("Path action '#{action}' not defined on '#{definition}'.")
|
98
|
+
end
|
99
|
+
|
100
|
+
context.__send__ action unless args
|
101
|
+
context.__send__ action, *args if args
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def find_index_for(path, context)
|
106
|
+
path.find_index { |item| item[0] == context }
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'test_workflow/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "test_workflow"
|
8
|
+
spec.version = TestWorkflow::VERSION
|
9
|
+
spec.authors = ["Jeff Nyman"]
|
10
|
+
spec.email = ["jeffnyman@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Chains classes and methods as a path to execute in a workflow.}
|
13
|
+
spec.description = %q{Chains classes and methods as a path to execute in a workflow.}
|
14
|
+
spec.homepage = "https://github.com/jnyman/test_workflow"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
spec.add_development_dependency "rubocop"
|
28
|
+
spec.add_development_dependency "pry"
|
29
|
+
|
30
|
+
spec.post_install_message = %{
|
31
|
+
(::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
|
32
|
+
TestWorkflow #{TestWorkflow::VERSION} has been installed.
|
33
|
+
(::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)
|
34
|
+
}
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: test_workflow
|
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: 2016-10-19 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.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
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: rubocop
|
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: pry
|
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
|
+
description: Chains classes and methods as a path to execute in a workflow.
|
84
|
+
email:
|
85
|
+
- jeffnyman@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".hound.yml"
|
92
|
+
- ".rspec"
|
93
|
+
- ".rubocop.yml"
|
94
|
+
- ".travis.yml"
|
95
|
+
- CODE_OF_CONDUCT.md
|
96
|
+
- Gemfile
|
97
|
+
- LICENSE.txt
|
98
|
+
- README.md
|
99
|
+
- Rakefile
|
100
|
+
- bin/console
|
101
|
+
- bin/setup
|
102
|
+
- lib/test_workflow.rb
|
103
|
+
- lib/test_workflow/version.rb
|
104
|
+
- test_workflow.gemspec
|
105
|
+
homepage: https://github.com/jnyman/test_workflow
|
106
|
+
licenses:
|
107
|
+
- MIT
|
108
|
+
metadata: {}
|
109
|
+
post_install_message: "\n(::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::) (::)\n
|
110
|
+
\ TestWorkflow 0.1.0 has been installed.\n(::) (::) (::) (::) (::) (::) (::) (::)
|
111
|
+
(::) (::) (::) (::)\n "
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 2.5.1
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: Chains classes and methods as a path to execute in a workflow.
|
131
|
+
test_files: []
|