bbq-core 0.3.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 +7 -0
- data/.gitignore +14 -0
- data/.travis.yml +4 -0
- data/CHANGELOG +47 -0
- data/Gemfile +5 -0
- data/MIT-LICENSE +20 -0
- data/README.md +318 -0
- data/Rakefile +10 -0
- data/bbq-core.gemspec +28 -0
- data/lib/bbq/core.rb +7 -0
- data/lib/bbq/core/roles.rb +14 -0
- data/lib/bbq/core/session.rb +64 -0
- data/lib/bbq/core/test_client.rb +97 -0
- data/lib/bbq/core/test_user.rb +33 -0
- data/lib/bbq/core/test_user/capybara_dsl.rb +17 -0
- data/lib/bbq/core/test_user/eyes.rb +15 -0
- data/lib/bbq/core/test_user/within.rb +35 -0
- data/lib/bbq/core/util.rb +21 -0
- data/lib/bbq/core/version.rb +5 -0
- data/lib/tasks/bbq.rake +15 -0
- data/test/session_pool_test.rb +44 -0
- data/test/test_client_test.rb +30 -0
- data/test/test_helper.rb +8 -0
- data/test/test_user_test.rb +112 -0
- data/test/util_test.rb +36 -0
- metadata +141 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4a48e0d7e2b08e20b007adafe0ead84e77bb54cc68bd4c8cdf7e5d68a1ae1fde
|
4
|
+
data.tar.gz: d8a944e766fb21bc119d771d28fcdee6e27a393e78ae4fded7bd403b420e613f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 69a88b57acf34e2ec33f347a86d82f8c45f275f2ed25852e4a313fa4196ba9f6fc2fab33758f9059b67fa7b318a18ba2efd87ef4cc88bbb7114df4a84a47f6a6
|
7
|
+
data.tar.gz: f90be21ff429c510175e37d08fa438734053b97260b9979bb04b53e2caf3bc8edcd17d4b2458cd4cb7e50be74ff7efcccba963e28b1553dc526c1d9afa29261c
|
data/.gitignore
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
*.gem
|
2
|
+
.bundle
|
3
|
+
Gemfile.lock
|
4
|
+
pkg/*
|
5
|
+
bin/*
|
6
|
+
tmp/*
|
7
|
+
test/dummy/db/*.sqlite3
|
8
|
+
test/dummy/log/*.log
|
9
|
+
test/dummy/tmp/
|
10
|
+
test/dummy/test/acceptance/*
|
11
|
+
test/dummy/spec/acceptance/*
|
12
|
+
test/dope/test/acceptance/*
|
13
|
+
test/dope/spec/acceptance/*
|
14
|
+
nbproject/
|
data/.travis.yml
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
0.2.1 / 2013-08-22
|
2
|
+
==================
|
3
|
+
|
4
|
+
* bugfix: Bbq::TestClient propagates NoMethodErrors from the controller of
|
5
|
+
tested app instead of rising unsupported method errors.
|
6
|
+
|
7
|
+
0.2.0 / 2013-01-06
|
8
|
+
==================
|
9
|
+
|
10
|
+
* Dropped support for Ruby 1.8.7
|
11
|
+
* Capybara 2.0 support
|
12
|
+
|
13
|
+
0.1.0 / 2013-01-06
|
14
|
+
==================
|
15
|
+
|
16
|
+
* Extracted Rails' URL helpers inclusion to separate module
|
17
|
+
* Include only Capybara::Session::DSL_METHODS in TestUser, not the whole Capybara::DSL
|
18
|
+
* Added Capybara sessions pool
|
19
|
+
* Moved Test::User default options to separate method
|
20
|
+
* Added Test::Client for testing REST APIs
|
21
|
+
* Renamed bbq/test.rb to bbq/test_unit.rb. You may want to fix your test_helper.
|
22
|
+
* Moved require bbq/test_user to generated test_user.rb. You may want to update your existing test_user.rb.
|
23
|
+
* Fixed Capybara 'within' scope for RSpec flavour
|
24
|
+
|
25
|
+
0.0.4 / 2011-10-19
|
26
|
+
==================
|
27
|
+
|
28
|
+
* Make Bbq work with Capybara 1.0 and 1.1
|
29
|
+
* Rails is development dependency
|
30
|
+
|
31
|
+
0.0.3 / 2011-07-14
|
32
|
+
==================
|
33
|
+
|
34
|
+
* Added support and tests for Sinatra
|
35
|
+
* Added Bbq.app and Bbq.app=
|
36
|
+
|
37
|
+
0.0.2 / 2011-07-01
|
38
|
+
==================
|
39
|
+
|
40
|
+
* Extracted Bbq::TestUser::Eyes module
|
41
|
+
* Added :within option to TestUser methods
|
42
|
+
* Fix tests for ree and ruby187
|
43
|
+
|
44
|
+
0.0.1 / 2011-04-20
|
45
|
+
==================
|
46
|
+
|
47
|
+
* Bbq introduced to the wild world!
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 DRUG, Dolnośląska Grupa Użytkowników Ruby
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,318 @@
|
|
1
|
+
# BBQ
|
2
|
+
|
3
|
+
[](http://travis-ci.org/drugpl/bbq-core) [](https://gemnasium.com/drugpl/bbq-core) [](https://codeclimate.com/github/drugpl/bbq-core) [](http://badge.fury.io/rb/bbq-core)
|
4
|
+
|
5
|
+
Object oriented acceptance testing using personas.
|
6
|
+
|
7
|
+
* Ruby (no Gherkin)
|
8
|
+
* Objects and methods instead of steps
|
9
|
+
* Test framework independent (RSpec and Test::Unit support)
|
10
|
+
* Thins based on Capybara.
|
11
|
+
* DCI (Data Context Interaction) for roles/personas
|
12
|
+
* Opinionated
|
13
|
+
|
14
|
+
## Setup
|
15
|
+
|
16
|
+
First, add BBQ to your apps `Gemfile`:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem "bbq", "0.2.1"
|
20
|
+
```
|
21
|
+
|
22
|
+
Run install generator:
|
23
|
+
|
24
|
+
```
|
25
|
+
bundle exec rails generate bbq:install
|
26
|
+
```
|
27
|
+
|
28
|
+
Require BBQ in test/test_helper.rb (in case of Test::Unit):
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require "bbq/test_unit"
|
32
|
+
```
|
33
|
+
|
34
|
+
Require BBQ in spec/spec_helper.rb (in case of RSpec):
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
require "bbq/rspec"
|
38
|
+
```
|
39
|
+
|
40
|
+
## Feature generator
|
41
|
+
|
42
|
+
```
|
43
|
+
bundle exec rails g bbq:test MyFeatureName
|
44
|
+
```
|
45
|
+
|
46
|
+
## Running features
|
47
|
+
|
48
|
+
For Test::Unit flavour:
|
49
|
+
|
50
|
+
```
|
51
|
+
bundle exec rake test:acceptance
|
52
|
+
```
|
53
|
+
|
54
|
+
For RSpec flavour:
|
55
|
+
|
56
|
+
```
|
57
|
+
bundle exec rake spec:acceptance
|
58
|
+
```
|
59
|
+
|
60
|
+
## Examples
|
61
|
+
|
62
|
+
### Roles and Devise integration
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
class TestUser < Bbq::TestUser
|
66
|
+
include Bbq::Devise
|
67
|
+
|
68
|
+
def update_ticket(summary, comment)
|
69
|
+
show_ticket(summary)
|
70
|
+
fill_in "Comment", :with => comment
|
71
|
+
click_on "Add update"
|
72
|
+
end
|
73
|
+
|
74
|
+
def open_application
|
75
|
+
visit '/'
|
76
|
+
end
|
77
|
+
|
78
|
+
module TicketReporter
|
79
|
+
def open_tickets_listing
|
80
|
+
open_application
|
81
|
+
click_link 'Tickets'
|
82
|
+
end
|
83
|
+
|
84
|
+
def open_ticket(summary, description)
|
85
|
+
open_tickets_listing
|
86
|
+
click_on "Open a new ticket"
|
87
|
+
fill_in "Summary", :with => summary
|
88
|
+
fill_in "Description", :with => description
|
89
|
+
click_on "Open ticket"
|
90
|
+
end
|
91
|
+
|
92
|
+
def show_ticket(summary)
|
93
|
+
open_tickets_listing
|
94
|
+
click_on summary
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
module TicketManager
|
99
|
+
def open_administration
|
100
|
+
visit '/admin'
|
101
|
+
end
|
102
|
+
|
103
|
+
def open_tickets_listing
|
104
|
+
open_administration
|
105
|
+
click_link 'Tickets'
|
106
|
+
end
|
107
|
+
|
108
|
+
def close_ticket(summary, comment = nil)
|
109
|
+
open_tickets_listing
|
110
|
+
click_on summary
|
111
|
+
fill_in "Comment", :with => comment if comment
|
112
|
+
click_on "Close ticket"
|
113
|
+
end
|
114
|
+
|
115
|
+
def show_ticket(summary)
|
116
|
+
open_tickets_listing
|
117
|
+
click_on summary
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
class AdminTicketsTest < Bbq::TestCase
|
125
|
+
background do
|
126
|
+
admin = Factory(:admin)
|
127
|
+
@email, @password = admin.email, admin.password
|
128
|
+
end
|
129
|
+
|
130
|
+
scenario "admin can browse all user tickets" do
|
131
|
+
summaries = ["Forgot my password", "Page is not displayed correctly"]
|
132
|
+
descriptions = ["I lost my yellow note with password under the table!",
|
133
|
+
"My IE renders crap instead of crispy fonts!"]
|
134
|
+
|
135
|
+
alice = TestUser.new
|
136
|
+
alice.roles(:ticket_reporter)
|
137
|
+
alice.register_and_login
|
138
|
+
alice.open_ticket(summaries.first, descriptions.first)
|
139
|
+
|
140
|
+
bob = TestUser.new
|
141
|
+
bob.roles(:ticket_reporter)
|
142
|
+
bob.register_and_login
|
143
|
+
bob.open_ticket(summaries.second, descriptions.second)
|
144
|
+
|
145
|
+
charlie = TestUser.new(:email => @email, :password => @password)
|
146
|
+
charlie.login # charlie was already "registered" in factory as admin
|
147
|
+
charlie.roles(:ticket_manager)
|
148
|
+
charlie.open_tickets_listing
|
149
|
+
charlie.see!(*summaries)
|
150
|
+
|
151
|
+
charlie.click_on(summaries.second)
|
152
|
+
charlie.see!(summaries.second, descriptions.second)
|
153
|
+
charlie.not_see!(summaries.first, descriptions.first)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
### RSpec integration
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
class TestUser < Bbq::TestUser
|
162
|
+
def email
|
163
|
+
@options[:email] || "buyer@example.com"
|
164
|
+
end
|
165
|
+
|
166
|
+
module Buyer
|
167
|
+
def ask_question(question)
|
168
|
+
fill_in "question", :with => question
|
169
|
+
fill_in "email", :with => email
|
170
|
+
click_on("Ask")
|
171
|
+
end
|
172
|
+
|
173
|
+
def go_to_page_and_open_widget(page_url, &block)
|
174
|
+
go_to_page(page_url)
|
175
|
+
open_widget &block
|
176
|
+
end
|
177
|
+
|
178
|
+
def go_to_page(page_url)
|
179
|
+
visit page_url
|
180
|
+
wait_until { page.find("iframe") }
|
181
|
+
end
|
182
|
+
|
183
|
+
def open_widget
|
184
|
+
within_widget do
|
185
|
+
page.find("#widget h3").click
|
186
|
+
yield if block_given?
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
ef within_widget(&block)
|
191
|
+
within_frame(widget_frame, &block)
|
192
|
+
end
|
193
|
+
|
194
|
+
def widget_frame
|
195
|
+
page.evaluate_script("document.getElementsByTagName('iframe')[0].id")
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
```
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
feature "ask question widget" do
|
203
|
+
let(:user) {
|
204
|
+
user = TestUser.new(:driver => :webkit)
|
205
|
+
user.roles('buyer')
|
206
|
+
user
|
207
|
+
}
|
208
|
+
|
209
|
+
scenario "as a guest user, I should be able to ask a question" do
|
210
|
+
user.go_to_page_and_open_widget("/widget") do
|
211
|
+
user.ask_question "my question"
|
212
|
+
user.see!("Thanks!")
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
```
|
217
|
+
|
218
|
+
## Testing REST APIs
|
219
|
+
|
220
|
+
Bbq provides `Bbq::TestClient`, similar to `Bbq::TestUser`, but intended for testing APIs.
|
221
|
+
It's a thin wrapper around `Rack::Test` which allows you to send requests and run assertions
|
222
|
+
against responses.
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
class ApiTest < Bbq::TestCase
|
226
|
+
background do
|
227
|
+
headers = {'HTTP_ACCEPT' => 'application/json'}
|
228
|
+
@client = TestClient.new(:headers => headers)
|
229
|
+
end
|
230
|
+
|
231
|
+
scenario "admin can browse all user tickets" do
|
232
|
+
@client.get "/unicorn" do |response|
|
233
|
+
assert_equal 200, response.status
|
234
|
+
assert_equal "pink", response.body["unicorn"]["color"]
|
235
|
+
end
|
236
|
+
@client.post "/ponies", { :name => "Miracle" } do |response|
|
237
|
+
assert_equal 200, response.status
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
```
|
242
|
+
|
243
|
+
## Rails URL Helpers
|
244
|
+
|
245
|
+
Using url helpers from Rails in integration tests is not recommended.
|
246
|
+
Testing routes is part of integration test, so you should actually use only
|
247
|
+
|
248
|
+
```ruby
|
249
|
+
visit '/'
|
250
|
+
```
|
251
|
+
|
252
|
+
in your integration test. Use links and buttons in order to get to other pages in your app.
|
253
|
+
|
254
|
+
If you really need url helpers in your test user, just include them in your TestUser class:
|
255
|
+
|
256
|
+
```ruby
|
257
|
+
require 'bbq/rails/routes'
|
258
|
+
|
259
|
+
class TestUser < Bbq::TestUser
|
260
|
+
include Bbq::Rails::Routes
|
261
|
+
end
|
262
|
+
```
|
263
|
+
or just
|
264
|
+
|
265
|
+
```ruby
|
266
|
+
class TestUser < Bbq::TestUser
|
267
|
+
include ::ActionDispatch::Routing::UrlFor
|
268
|
+
include ::Rails.application.routes.url_helpers
|
269
|
+
include ::ActionDispatch::Routing::RouteSet::MountedHelpers unless ::Rails.version < "3.1"
|
270
|
+
end
|
271
|
+
```
|
272
|
+
|
273
|
+
## Devise support
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
require "bbq/test_user"
|
277
|
+
require "bbq/devise"
|
278
|
+
|
279
|
+
class TestUser < Bbq::TestUser
|
280
|
+
include Bbq::Devise
|
281
|
+
end
|
282
|
+
```
|
283
|
+
|
284
|
+
After that TestUser have *login*, *logout*, *register*, *register_and_login* methods.
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
test "user register with devise" do
|
288
|
+
user = TestUser.new # or TestUser.new(:email => "email@example.com", :password => "secret")
|
289
|
+
user.register_and_login
|
290
|
+
user.see!("Stuff after auth")
|
291
|
+
end
|
292
|
+
```
|
293
|
+
|
294
|
+
## Caveats
|
295
|
+
|
296
|
+
### Timeout::Error
|
297
|
+
|
298
|
+
If you simulate multiple users in your tests and spawn multiple browsers with selenium it might
|
299
|
+
be a good idea to use Thin instead of Webrick to create application server.
|
300
|
+
We have experienced some problems with Webrick that lead to `Timeout::Error` exception
|
301
|
+
when user/browser that was inactive for some time (due to other users/browsers
|
302
|
+
activities) was requested to execute an action.
|
303
|
+
|
304
|
+
Capybara will use Thin instead of Webrick when it's available, so you only need to add Thin to you Gemfile:
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
# In test group if you want it to
|
308
|
+
# be used only in tests and not in your development mode
|
309
|
+
# ex. when running 'rails s'
|
310
|
+
|
311
|
+
gem 'thin', :require => false
|
312
|
+
```
|
313
|
+
|
314
|
+
## Additional information
|
315
|
+
|
316
|
+
* [2 problems with Cucumber](http://andrzejonsoftware.blogspot.com/2011/03/2-problems-with-cucumber.html)
|
317
|
+
* [Object oriented acceptance testing](http://andrzejonsoftware.blogspot.com/2011/04/object-oriented-acceptance-testing.html)
|
318
|
+
|
data/Rakefile
ADDED
data/bbq-core.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "bbq/core/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "bbq-core"
|
7
|
+
s.version = Bbq::Core::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["DRUG - Dolnośląska Grupa Użytkowników Ruby"]
|
10
|
+
s.email = ["bbq@drug.org.pl"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.description = %q{Objected oriented acceptance testing for Rails, using personas.}
|
13
|
+
s.summary = %q{Objected oriented acceptance testing for Rails, using personas.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "bbq-core"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency "capybara", ">= 2.0"
|
23
|
+
s.add_dependency "activesupport", ">= 2.0"
|
24
|
+
|
25
|
+
s.add_development_dependency "rake"
|
26
|
+
s.add_development_dependency "rdoc", "~> 3.7"
|
27
|
+
s.add_development_dependency "minitest", "~> 5.0"
|
28
|
+
end
|
data/lib/bbq/core.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'bbq/core'
|
2
|
+
|
3
|
+
module Bbq
|
4
|
+
module Core
|
5
|
+
module Session
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def next(options = {})
|
9
|
+
driver = options.delete(:driver)
|
10
|
+
pool = options.delete(:pool)
|
11
|
+
|
12
|
+
if pool
|
13
|
+
pool.next(driver)
|
14
|
+
else
|
15
|
+
create(driver)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def create(driver)
|
20
|
+
Capybara::Session.new(driver, Bbq::Core.app)
|
21
|
+
end
|
22
|
+
|
23
|
+
def pool
|
24
|
+
@pool ||= Pool.new
|
25
|
+
end
|
26
|
+
|
27
|
+
class Pool
|
28
|
+
attr_accessor :idle, :taken
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
@idle = []
|
32
|
+
@taken = []
|
33
|
+
end
|
34
|
+
|
35
|
+
def next(driver)
|
36
|
+
take_idle(driver) || create(driver)
|
37
|
+
end
|
38
|
+
|
39
|
+
def release
|
40
|
+
taken.each(&:reset!)
|
41
|
+
idle.concat(taken)
|
42
|
+
taken.clear
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def take_idle(driver)
|
48
|
+
idle.find { |s| s.mode == driver }.tap do |session|
|
49
|
+
if session
|
50
|
+
idle.delete(session)
|
51
|
+
taken.push(session)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def create(driver)
|
57
|
+
Bbq::Core::Session.create(driver).tap do |session|
|
58
|
+
taken.push(session)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'bbq/core/roles'
|
2
|
+
|
3
|
+
module Bbq
|
4
|
+
module Core
|
5
|
+
class TestClient
|
6
|
+
class UnsupportedMethodError < StandardError; end
|
7
|
+
|
8
|
+
include Bbq::Core::Roles
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
HTTP_METHODS = %w(get post put delete head options patch)
|
15
|
+
|
16
|
+
HTTP_METHODS.each do |method|
|
17
|
+
class_eval <<-RUBY
|
18
|
+
def #{method}(path, params = {}, headers = {})
|
19
|
+
unless driver.respond_to? :#{method}
|
20
|
+
raise UnsupportedMethodError, "Your driver does not support #{method.upcase} method"
|
21
|
+
end
|
22
|
+
|
23
|
+
response = driver.#{method}(path, params, default_headers.merge(headers))
|
24
|
+
parsed_response = parse_response(response)
|
25
|
+
yield parsed_response if block_given?
|
26
|
+
parsed_response
|
27
|
+
end
|
28
|
+
RUBY
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
def app
|
33
|
+
@options[:app] || Bbq::Core.app
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_headers
|
37
|
+
@options[:headers] || {}
|
38
|
+
end
|
39
|
+
|
40
|
+
def driver
|
41
|
+
@driver ||= RackTest.new(app)
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse_response(response)
|
45
|
+
case response.headers["Content-Type"]
|
46
|
+
when /^application\/(.*\+)?json/
|
47
|
+
response.extend(JsonBody)
|
48
|
+
when /^application\/(.*\+)?x-yaml/
|
49
|
+
response.extend(YamlBody)
|
50
|
+
else
|
51
|
+
response
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class RackTest
|
56
|
+
attr_accessor :app
|
57
|
+
|
58
|
+
def initialize(app)
|
59
|
+
self.app = app
|
60
|
+
end
|
61
|
+
|
62
|
+
module ConvertHeaders
|
63
|
+
HTTP_METHODS.each do |method|
|
64
|
+
class_eval <<-RUBY
|
65
|
+
def #{method}(path, params = {}, headers = {})
|
66
|
+
super(path, params, to_env_headers(headers))
|
67
|
+
end
|
68
|
+
RUBY
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_env_headers(http_headers)
|
72
|
+
http_headers.map do |k, v|
|
73
|
+
k = k.upcase.gsub("-", "_")
|
74
|
+
k = "HTTP_#{k}" unless ["CONTENT_TYPE", "CONTENT_LENGTH"].include?(k)
|
75
|
+
{ k => v }
|
76
|
+
end.inject({}, :merge)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
include Rack::Test::Methods
|
81
|
+
include ConvertHeaders
|
82
|
+
end
|
83
|
+
|
84
|
+
module JsonBody
|
85
|
+
def body
|
86
|
+
@parsed_body ||= super.empty?? super : JSON.parse(super)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
module YamlBody
|
91
|
+
def body
|
92
|
+
@parsed_body ||= YAML.load(super)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'bbq/core/session'
|
2
|
+
require 'bbq/core/roles'
|
3
|
+
require 'bbq/core/test_user/capybara_dsl'
|
4
|
+
require 'bbq/core/test_user/eyes'
|
5
|
+
require 'bbq/core/test_user/within'
|
6
|
+
|
7
|
+
module Bbq
|
8
|
+
module Core
|
9
|
+
class TestUser
|
10
|
+
include Bbq::Core::TestUser::CapybaraDsl
|
11
|
+
include Bbq::Core::TestUser::Eyes
|
12
|
+
include Bbq::Core::TestUser::Within
|
13
|
+
include Bbq::Core::Roles
|
14
|
+
|
15
|
+
attr_reader :options
|
16
|
+
|
17
|
+
def initialize(options = {})
|
18
|
+
@options = default_options.merge(options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_options
|
22
|
+
{
|
23
|
+
:pool => Bbq::Core::Session.pool,
|
24
|
+
:driver => ::Capybara.default_driver
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def page
|
29
|
+
@page ||= options[:session] || Bbq::Core::Session.next(:driver => options[:driver], :pool => options[:pool])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'capybara/dsl'
|
2
|
+
|
3
|
+
module Bbq
|
4
|
+
module Core
|
5
|
+
class TestUser
|
6
|
+
module CapybaraDsl
|
7
|
+
::Capybara::Session::DSL_METHODS.each do |method|
|
8
|
+
class_eval <<-RUBY, __FILE__, __LINE__+1
|
9
|
+
def #{method}(*args, &block)
|
10
|
+
page.#{method}(*args, &block)
|
11
|
+
end
|
12
|
+
RUBY
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'active_support/core_ext/array/extract_options'
|
2
|
+
|
3
|
+
module Bbq
|
4
|
+
module Core
|
5
|
+
class TestUser
|
6
|
+
module Within
|
7
|
+
METHODS_USING_WITHIN = [
|
8
|
+
:see?, :not_see?,
|
9
|
+
:attach_file, :check, :choose, :click_link_or_button, :click_button,
|
10
|
+
:click_link, :click_on, :fill_in, :select, :uncheck, :unselect
|
11
|
+
]
|
12
|
+
|
13
|
+
METHODS_USING_WITHIN.each do |method_name|
|
14
|
+
class_eval <<-RUBY
|
15
|
+
def #{method_name}(*args)
|
16
|
+
using_within(args) { super }
|
17
|
+
end
|
18
|
+
RUBY
|
19
|
+
end
|
20
|
+
|
21
|
+
def using_within(args)
|
22
|
+
options = args.extract_options!
|
23
|
+
locator = options.delete(:within)
|
24
|
+
args.push(options) unless options.empty?
|
25
|
+
|
26
|
+
if locator
|
27
|
+
within(locator) { yield }
|
28
|
+
else
|
29
|
+
yield
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'active_support/core_ext/string/inflections'
|
2
|
+
|
3
|
+
module Bbq
|
4
|
+
module Core
|
5
|
+
class Util
|
6
|
+
def self.find_module(name, scope = nil)
|
7
|
+
namespace = case scope
|
8
|
+
when String, Symbol
|
9
|
+
"::#{scope.to_s.camelize}"
|
10
|
+
when Class
|
11
|
+
"::#{scope.name}"
|
12
|
+
when NilClass
|
13
|
+
nil
|
14
|
+
else
|
15
|
+
"::#{scope.class.name}"
|
16
|
+
end
|
17
|
+
"#{namespace}::#{name.to_s.camelize}".constantize
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/tasks/bbq.rake
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
Rake::TestTask.new("test:acceptance") do |t|
|
4
|
+
t.libs << 'test'
|
5
|
+
t.pattern = 'test/acceptance/**/*_test.rb'
|
6
|
+
t.verbose = false
|
7
|
+
end if File.exists?('test/acceptance')
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'rspec/core/rake_task'
|
11
|
+
RSpec::Core::RakeTask.new('spec:acceptance') do |spec|
|
12
|
+
spec.pattern = FileList['spec/acceptance/**/*_spec.rb']
|
13
|
+
end if File.exists?('spec/acceptance')
|
14
|
+
rescue LoadError
|
15
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'bbq/core/test_user'
|
3
|
+
|
4
|
+
class SessionPoolTest < Minitest::Test
|
5
|
+
|
6
|
+
def setup
|
7
|
+
Bbq::Core::Session.instance_variable_set(:@pool, nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_reuses_sessions
|
11
|
+
pool = Bbq::Core::Session::Pool.new
|
12
|
+
user1 = Bbq::Core::TestUser.new(:pool => pool).tap { |u| u.page }
|
13
|
+
pool.release
|
14
|
+
user2 = Bbq::Core::TestUser.new(:pool => pool).tap { |u| u.page }
|
15
|
+
|
16
|
+
assert_same user1.page, user2.page
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_has_default_pool
|
20
|
+
user1 = Bbq::Core::TestUser.new.tap { |u| u.page }
|
21
|
+
Bbq::Core::Session::pool.release
|
22
|
+
user2 = Bbq::Core::TestUser.new.tap { |u| u.page }
|
23
|
+
|
24
|
+
assert_same user1.page, user2.page
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_without_pool
|
28
|
+
user1 = Bbq::Core::TestUser.new(:pool => false).tap { |u| u.page }
|
29
|
+
Bbq::Core::Session::pool.release
|
30
|
+
user2 = Bbq::Core::TestUser.new(:pool => false).tap { |u| u.page }
|
31
|
+
|
32
|
+
refute_same user1.page, user2.page
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_pool_returns_correct_driver
|
36
|
+
pool = Bbq::Core::Session::Pool.new
|
37
|
+
pool.next(:rack_test)
|
38
|
+
pool.next(:rack_test_the_other)
|
39
|
+
pool.release
|
40
|
+
|
41
|
+
assert_equal :rack_test, pool.next(:rack_test).mode
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'bbq/core/test_client'
|
3
|
+
|
4
|
+
class TestClientTest < Minitest::Test
|
5
|
+
|
6
|
+
def test_rack_test_to_env_headers_for_empty_hash
|
7
|
+
test_client = Bbq::Core::TestClient::RackTest.new(:app)
|
8
|
+
assert_equal({}, test_client.to_env_headers({}))
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_rack_test_to_env_headers_for_content_type_or_content_length
|
12
|
+
test_client = Bbq::Core::TestClient::RackTest.new(:app)
|
13
|
+
result = test_client.to_env_headers({
|
14
|
+
"content-type" => "text/plain",
|
15
|
+
"content-length" => "40"
|
16
|
+
})
|
17
|
+
assert_includes(result.keys, "CONTENT_TYPE")
|
18
|
+
assert_includes(result.keys, "CONTENT_LENGTH")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_rack_test_to_env_headers_for_other_headers
|
22
|
+
test_client = Bbq::Core::TestClient::RackTest.new(:app)
|
23
|
+
result = test_client.to_env_headers({
|
24
|
+
"silly-header" => "silly-value"
|
25
|
+
})
|
26
|
+
assert_includes(result.keys, "HTTP_SILLY_HEADER")
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'bbq/core/test_user'
|
3
|
+
|
4
|
+
|
5
|
+
def text(output)
|
6
|
+
end
|
7
|
+
|
8
|
+
def html(output)
|
9
|
+
->{ ['200', {'Content-Type' => 'text/html'}, [output]] }
|
10
|
+
end
|
11
|
+
|
12
|
+
TestApp = Rack::Builder.new do
|
13
|
+
map '/' do
|
14
|
+
run ->(env) { ['200', {'Content-Type' => 'text/plain'}, ['BBQ']] }
|
15
|
+
end
|
16
|
+
|
17
|
+
map '/miracle' do
|
18
|
+
run ->(env) { ['200', {'Content-Type' => 'text/plain'}, ['MIRACLE']] }
|
19
|
+
end
|
20
|
+
|
21
|
+
map '/ponycorns' do
|
22
|
+
run ->(env) { ['200', {'Content-Type' => 'text/html'}, [<<HTML
|
23
|
+
<ul id="unicorns">
|
24
|
+
<li>Pink</li>
|
25
|
+
</ul>
|
26
|
+
<ul id="ponies">
|
27
|
+
<li>Violet</li>
|
28
|
+
</ul>
|
29
|
+
<div id="new_pony">
|
30
|
+
<input type="text" name="color" value="" />
|
31
|
+
</div>
|
32
|
+
<a href="#">More ponycorns</a>
|
33
|
+
HTML
|
34
|
+
]] }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
class TestUser < Bbq::Core::TestUser
|
40
|
+
module Commenter
|
41
|
+
def comment
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module VideoUploader
|
46
|
+
def upload
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module CommentModerator
|
51
|
+
def moderate
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class TestUserTest < Minitest::Test
|
57
|
+
|
58
|
+
def setup
|
59
|
+
Bbq::Core.app = TestApp
|
60
|
+
end
|
61
|
+
|
62
|
+
def teardown
|
63
|
+
Bbq::Core.app = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_capybara_dsl_methods
|
67
|
+
user = TestUser.new
|
68
|
+
Capybara::Session::DSL_METHODS.each do |m|
|
69
|
+
assert user.respond_to?(m)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_driver_option
|
74
|
+
user = TestUser.new(:driver => :rack_test_the_other)
|
75
|
+
assert_equal :rack_test_the_other, user.page.mode
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_roles
|
79
|
+
user = TestUser.new
|
80
|
+
%w(comment upload moderate).each { |m| assert !user.respond_to?(m) }
|
81
|
+
|
82
|
+
user.roles(:commenter, "comment_moderator")
|
83
|
+
%w(comment moderate).each { |m| assert user.respond_to?(m) }
|
84
|
+
assert !user.respond_to?(:upload)
|
85
|
+
|
86
|
+
user.roles(:video_uploader)
|
87
|
+
%w(comment upload moderate).each { |m| assert user.respond_to?(m) }
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_explicit_user_eyes
|
91
|
+
@user = TestUser.new
|
92
|
+
@user.visit "/miracle"
|
93
|
+
assert @user.not_see?("BBQ")
|
94
|
+
assert @user.see?("MIRACLE")
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_user_eyes_within_scope
|
98
|
+
@user = TestUser.new
|
99
|
+
@user.visit "/ponycorns"
|
100
|
+
assert @user.see?("Pink", :within => "#unicorns")
|
101
|
+
assert ! @user.see?("Violet", :within => "#unicorns")
|
102
|
+
assert @user.not_see?("Violet", :within => "#unicorns")
|
103
|
+
assert ! @user.not_see?("Pink", :within => "#unicorns")
|
104
|
+
|
105
|
+
@user.fill_in "color", :with => "red", :within => "#new_pony"
|
106
|
+
assert_raises Capybara::ElementNotFound do
|
107
|
+
@user.fill_in "color", :with => "red", :within => "#new_unicorn"
|
108
|
+
end
|
109
|
+
@user.click_link "More ponycorns"
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
data/test/util_test.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'bbq/core/util'
|
3
|
+
|
4
|
+
class User
|
5
|
+
module Commenter
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Commenter
|
10
|
+
end
|
11
|
+
|
12
|
+
class UtilTest < Minitest::Test
|
13
|
+
|
14
|
+
def test_find_module_in_object_namespace
|
15
|
+
assert_commenter(User.new, User::Commenter)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_find_module_in_class_namespace
|
19
|
+
assert_commenter(User, User::Commenter)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_find_module_in_string_namespace
|
23
|
+
assert_commenter("User", User::Commenter)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_find_global_module
|
27
|
+
assert_commenter(nil, ::Commenter)
|
28
|
+
end
|
29
|
+
|
30
|
+
def assert_commenter(namespace, result)
|
31
|
+
[:commenter, "commenter"].each do |name|
|
32
|
+
assert_equal Bbq::Core::Util.find_module(name, namespace), result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bbq-core
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- DRUG - Dolnośląska Grupa Użytkowników Ruby
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-03-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: capybara
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
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: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
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: rdoc
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '5.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.0'
|
83
|
+
description: Objected oriented acceptance testing for Rails, using personas.
|
84
|
+
email:
|
85
|
+
- bbq@drug.org.pl
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".travis.yml"
|
92
|
+
- CHANGELOG
|
93
|
+
- Gemfile
|
94
|
+
- MIT-LICENSE
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- bbq-core.gemspec
|
98
|
+
- lib/bbq/core.rb
|
99
|
+
- lib/bbq/core/roles.rb
|
100
|
+
- lib/bbq/core/session.rb
|
101
|
+
- lib/bbq/core/test_client.rb
|
102
|
+
- lib/bbq/core/test_user.rb
|
103
|
+
- lib/bbq/core/test_user/capybara_dsl.rb
|
104
|
+
- lib/bbq/core/test_user/eyes.rb
|
105
|
+
- lib/bbq/core/test_user/within.rb
|
106
|
+
- lib/bbq/core/util.rb
|
107
|
+
- lib/bbq/core/version.rb
|
108
|
+
- lib/tasks/bbq.rake
|
109
|
+
- test/session_pool_test.rb
|
110
|
+
- test/test_client_test.rb
|
111
|
+
- test/test_helper.rb
|
112
|
+
- test/test_user_test.rb
|
113
|
+
- test/util_test.rb
|
114
|
+
homepage: ''
|
115
|
+
licenses: []
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubygems_version: 3.0.3
|
133
|
+
signing_key:
|
134
|
+
specification_version: 4
|
135
|
+
summary: Objected oriented acceptance testing for Rails, using personas.
|
136
|
+
test_files:
|
137
|
+
- test/session_pool_test.rb
|
138
|
+
- test/test_client_test.rb
|
139
|
+
- test/test_helper.rb
|
140
|
+
- test/test_user_test.rb
|
141
|
+
- test/util_test.rb
|