transactional_capybara 0.1.0.pre.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/.ruby-version +1 -1
- data/.travis.yml +2 -1
- data/Gemfile.lock +113 -0
- data/README.md +56 -3
- data/Rakefile +16 -1
- data/lib/transactional_capybara/ajax_helpers.rb +14 -7
- data/lib/transactional_capybara/version.rb +1 -1
- data/spec/ajax_spec.rb +52 -5
- data/spec/spec_helper.rb +1 -0
- data/spec/support/server.rb +9 -3
- data/spec/support/vendor/angular.js +28604 -0
- data/spec/support/vendor/jquery.js +10346 -0
- data/spec/support/views/angular.erb +23 -0
- data/spec/support/views/jquery.erb +16 -0
- data/transactional_capybara.gemspec +1 -0
- metadata +28 -7
- data/spec/support/views/page_with_ajax.erb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b47fe9a7d758b60e2a61d02a9efc54683c04c958
|
4
|
+
data.tar.gz: 2fad7e2694272847292391264521c9edac1ec55b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 489e7e2d50f51dcb9d15fe8eb9198d2b09c71b394157e704ecbe9360e8070b63f8890f60834f9889ec560ced5fe84881610b7b35cf19a4be325d391272597672
|
7
|
+
data.tar.gz: d2fd46c45b0cc39fa8acfe71b538be2988cd9fa956571693378936e4a9a7f319462245122927b3eb074eea7296bbb25527743ca1cb46b31a21a129b880949c01
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.3.1
|
data/.travis.yml
CHANGED
@@ -4,6 +4,7 @@ rvm:
|
|
4
4
|
- "2.0"
|
5
5
|
- "2.1"
|
6
6
|
- "2.2"
|
7
|
+
- "2.3.1"
|
7
8
|
before_install:
|
8
9
|
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16"
|
9
10
|
- "export DISPLAY=:99.0"
|
@@ -12,4 +13,4 @@ before_script:
|
|
12
13
|
- psql -c 'create database transactional_capybara_test;' -U postgres
|
13
14
|
- "cp spec/{.travis.,}config.yml"
|
14
15
|
script: bundle exec rake test:all
|
15
|
-
|
16
|
+
cache: bundler
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
transactional_capybara (0.1.0.pre.3)
|
5
|
+
capybara
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activemodel (4.2.4)
|
11
|
+
activesupport (= 4.2.4)
|
12
|
+
builder (~> 3.1)
|
13
|
+
activerecord (4.2.4)
|
14
|
+
activemodel (= 4.2.4)
|
15
|
+
activesupport (= 4.2.4)
|
16
|
+
arel (~> 6.0)
|
17
|
+
activesupport (4.2.4)
|
18
|
+
i18n (~> 0.7)
|
19
|
+
json (~> 1.7, >= 1.7.7)
|
20
|
+
minitest (~> 5.1)
|
21
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
22
|
+
tzinfo (~> 1.1)
|
23
|
+
arel (6.0.3)
|
24
|
+
builder (3.2.2)
|
25
|
+
capybara (2.4.4)
|
26
|
+
mime-types (>= 1.16)
|
27
|
+
nokogiri (>= 1.3.3)
|
28
|
+
rack (>= 1.0.0)
|
29
|
+
rack-test (>= 0.5.4)
|
30
|
+
xpath (~> 2.0)
|
31
|
+
capybara-webkit (1.6.0)
|
32
|
+
capybara (>= 2.3.0, < 2.5.0)
|
33
|
+
json
|
34
|
+
childprocess (0.5.6)
|
35
|
+
ffi (~> 1.0, >= 1.0.11)
|
36
|
+
cliver (0.3.2)
|
37
|
+
diff-lcs (1.2.5)
|
38
|
+
ffi (1.9.10)
|
39
|
+
i18n (0.7.0)
|
40
|
+
json (1.8.3)
|
41
|
+
mime-types (2.6.1)
|
42
|
+
mini_portile (0.6.2)
|
43
|
+
minitest (5.8.0)
|
44
|
+
multi_json (1.11.2)
|
45
|
+
mysql2 (0.3.20)
|
46
|
+
nokogiri (1.6.6.2)
|
47
|
+
mini_portile (~> 0.6.0)
|
48
|
+
pg (0.18.2)
|
49
|
+
poltergeist (1.6.0)
|
50
|
+
capybara (~> 2.1)
|
51
|
+
cliver (~> 0.3.1)
|
52
|
+
multi_json (~> 1.0)
|
53
|
+
websocket-driver (>= 0.2.0)
|
54
|
+
rack (1.6.4)
|
55
|
+
rack-protection (1.5.3)
|
56
|
+
rack
|
57
|
+
rack-test (0.6.3)
|
58
|
+
rack (>= 1.0)
|
59
|
+
rake (10.4.2)
|
60
|
+
rspec (3.3.0)
|
61
|
+
rspec-core (~> 3.3.0)
|
62
|
+
rspec-expectations (~> 3.3.0)
|
63
|
+
rspec-mocks (~> 3.3.0)
|
64
|
+
rspec-core (3.3.1)
|
65
|
+
rspec-support (~> 3.3.0)
|
66
|
+
rspec-expectations (3.3.0)
|
67
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
68
|
+
rspec-support (~> 3.3.0)
|
69
|
+
rspec-mocks (3.3.1)
|
70
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
71
|
+
rspec-support (~> 3.3.0)
|
72
|
+
rspec-support (3.3.0)
|
73
|
+
rubyzip (1.1.7)
|
74
|
+
selenium-webdriver (2.47.1)
|
75
|
+
childprocess (~> 0.5)
|
76
|
+
multi_json (~> 1.0)
|
77
|
+
rubyzip (~> 1.0)
|
78
|
+
websocket (~> 1.0)
|
79
|
+
sinatra (1.4.6)
|
80
|
+
rack (~> 1.4)
|
81
|
+
rack-protection (~> 1.4)
|
82
|
+
tilt (>= 1.3, < 3)
|
83
|
+
sqlite3 (1.3.10)
|
84
|
+
thread_safe (0.3.5)
|
85
|
+
tilt (2.0.1)
|
86
|
+
tzinfo (1.2.2)
|
87
|
+
thread_safe (~> 0.1)
|
88
|
+
websocket (1.2.2)
|
89
|
+
websocket-driver (0.6.2)
|
90
|
+
websocket-extensions (>= 0.1.0)
|
91
|
+
websocket-extensions (0.1.2)
|
92
|
+
xpath (2.0.0)
|
93
|
+
nokogiri (~> 1.3)
|
94
|
+
|
95
|
+
PLATFORMS
|
96
|
+
ruby
|
97
|
+
|
98
|
+
DEPENDENCIES
|
99
|
+
activerecord
|
100
|
+
bundler (~> 1.3)
|
101
|
+
capybara-webkit
|
102
|
+
mysql2
|
103
|
+
pg
|
104
|
+
poltergeist
|
105
|
+
rake
|
106
|
+
rspec
|
107
|
+
selenium-webdriver
|
108
|
+
sinatra
|
109
|
+
sqlite3
|
110
|
+
transactional_capybara!
|
111
|
+
|
112
|
+
BUNDLED WITH
|
113
|
+
1.12.5
|
data/README.md
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
# Database Transactions 💜 Capybara
|
2
2
|
|
3
|
-
|
3
|
+
[![Build Status]](https://travis-ci.org/iangreenleaf/transactional_capybara)
|
4
4
|
|
5
|
-
|
5
|
+
You want your specs to use transactions for speed 🐎🐎🐎
|
6
|
+
|
7
|
+
But as soon as you try it with Capybara, things go wrong 💻💥
|
6
8
|
|
7
9
|
Don't flip tables.
|
8
10
|
Use this instead.
|
9
11
|
|
12
|
+
For a detailed explanation of how this works, refer to the [introductory blog post].
|
13
|
+
|
10
14
|
## Setup ##
|
11
15
|
|
12
16
|
Add it to your Gemfile, of course:
|
@@ -47,6 +51,50 @@ after :each do
|
|
47
51
|
end
|
48
52
|
```
|
49
53
|
|
54
|
+
## Manually waiting for AJAX ##
|
55
|
+
|
56
|
+
You might have situations where you need to wait for AJAX calls to complete at times other than teardown.
|
57
|
+
For example, you might have a pattern like this if you access models directly for either setup or verification of results:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
visit "/page-that-fires-ajax"
|
61
|
+
Model.where(whatever).first
|
62
|
+
```
|
63
|
+
|
64
|
+
This can still fail!
|
65
|
+
The ideal solution is to avoid direct database manipulation in integration tests.
|
66
|
+
However, if you insist on doing this, you can stay safe by waiting for AJAX to complete before continuing:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
visit "/page-that-fires-ajax"
|
70
|
+
TransactionalCapybara::AjaxHelpers.wait_for_ajax(page)
|
71
|
+
Model.where(whatever).first
|
72
|
+
```
|
73
|
+
|
74
|
+
If you'd like the helper more easily accessible, just mix the `AjaxHelpers` module into your test suite.
|
75
|
+
In RSpec, you can do this in the config block:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
RSpec.configure do |config|
|
79
|
+
config.include TransactionalCapybara::AjaxHelpers
|
80
|
+
end
|
81
|
+
```
|
82
|
+
Or in any example group:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
describe "awesome web stuff" do
|
86
|
+
include TransactionalCapybara::AjaxHelpers
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
90
|
+
Now the helper is easily available:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
visit "/page-that-fires-ajax"
|
94
|
+
wait_for_ajax
|
95
|
+
Model.where(whatever).first
|
96
|
+
```
|
97
|
+
|
50
98
|
## DatabaseCleaner ##
|
51
99
|
|
52
100
|
For this gem to be able to help with AJAX, it needs to be invoked *before* DatabaseCleaner rolls back the transaction.
|
@@ -99,6 +147,8 @@ Right now this gem automatically fixes the following things:
|
|
99
147
|
* jQuery
|
100
148
|
* Angular
|
101
149
|
|
150
|
+
Tested on Capybara 2.4.x, may not work on other major versions.
|
151
|
+
|
102
152
|
Don't see something you want?
|
103
153
|
I'd love a pull request, or even just a friendly inquiry!
|
104
154
|
|
@@ -106,9 +156,9 @@ I'd love a pull request, or even just a friendly inquiry!
|
|
106
156
|
|
107
157
|
1. Fork it
|
108
158
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
159
|
+
3. Make your changes. Don't forget to add a test!
|
109
160
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
110
161
|
4. Push to the branch (`git push origin my-new-feature`)
|
111
|
-
5. Think about how I'm a bad person for not writing any tests yet
|
112
162
|
6. Create new Pull Request
|
113
163
|
|
114
164
|
### Running the tests ###
|
@@ -119,3 +169,6 @@ DB=sqlite rspec spec
|
|
119
169
|
```
|
120
170
|
|
121
171
|
You can run the specs with other databases as well, but you will have to create the databases and users manually first.
|
172
|
+
|
173
|
+
[Build Status]: https://travis-ci.org/iangreenleaf/transactional_capybara.svg?branch=master
|
174
|
+
[introductory blog post]: http://technotes.iangreenleaf.com/posts/the-one-true-guide-to-database-transactions-with-capybara.html
|
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ namespace :test do
|
|
11
11
|
db_config = YAML.load_file(File.join(File.dirname(__FILE__), "spec/config.yml"))
|
12
12
|
db_config["database"].keys.each do |db_name|
|
13
13
|
ENV['DB'] = db_name
|
14
|
-
%w[selenium webkit].each do |driver|
|
14
|
+
%w[selenium webkit poltergeist].each do |driver|
|
15
15
|
ENV['DRIVER'] = driver
|
16
16
|
puts ENV.to_hash.slice 'DRIVER', 'DB'
|
17
17
|
Rake::Task['test:rspec'].reenable
|
@@ -19,4 +19,19 @@ namespace :test do
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
+
|
23
|
+
desc "Run the test server for manual debugging"
|
24
|
+
task :server do
|
25
|
+
db_type = ENV['DB'] || 'sqlite'
|
26
|
+
db_config = YAML.load_file(File.join(File.dirname(__FILE__), "spec/config.yml"))
|
27
|
+
db = db_config["database"][db_type]
|
28
|
+
require 'active_record'
|
29
|
+
ActiveRecord::Base.establish_connection(db)
|
30
|
+
load File.join(File.dirname(__FILE__), "spec/support/schema.rb")
|
31
|
+
require_relative './spec/support/server'
|
32
|
+
require_relative './spec/support/model'
|
33
|
+
TestValue.create! content: "This is a server response"
|
34
|
+
AjaxServer.should_return_from_ajax = true
|
35
|
+
AjaxServer.run!
|
36
|
+
end
|
22
37
|
end
|
@@ -20,14 +20,11 @@ module TransactionalCapybara
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def finished_ajax_requests?
|
23
|
-
(
|
24
|
-
angular_requests
|
25
|
-
+ jquery_requests
|
26
|
-
).zero?
|
23
|
+
( angular_requests + jquery_requests ).zero?
|
27
24
|
end
|
28
25
|
|
29
26
|
# TODO: timeout each individual session
|
30
|
-
def wait_until(timeout=
|
27
|
+
def wait_until(timeout=default_timeout)
|
31
28
|
Timeout.timeout(timeout) do
|
32
29
|
until yield
|
33
30
|
sleep(0.01)
|
@@ -44,6 +41,16 @@ module TransactionalCapybara
|
|
44
41
|
Capybara.send :session_pool
|
45
42
|
end
|
46
43
|
|
44
|
+
# Handle Capybara.default_wait_time deprecation
|
45
|
+
# https://github.com/jnicklas/capybara/pull/1502
|
46
|
+
def default_timeout
|
47
|
+
@default_timeout ||= begin
|
48
|
+
Capybara.respond_to?(:default_max_wait_time) ?
|
49
|
+
Capybara.default_max_wait_time :
|
50
|
+
Capybara.default_wait_time
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
47
54
|
# Another hack, to see if Capybara sessions have been used
|
48
55
|
def is_session_touched?(session)
|
49
56
|
session.instance_variable_get(:@touched)
|
@@ -54,12 +61,12 @@ module TransactionalCapybara
|
|
54
61
|
end
|
55
62
|
|
56
63
|
def angular?
|
57
|
-
run_js("!!window.angular") && run_js("
|
64
|
+
run_js("!!window.angular") && run_js("!!document.querySelector('[ng-app]')")
|
58
65
|
end
|
59
66
|
|
60
67
|
def angular_requests
|
61
68
|
if angular?
|
62
|
-
run_js("angular.element('[ng-app]').injector().get('$http').pendingRequests.length")
|
69
|
+
run_js("angular.element(document.querySelector('[ng-app]')).injector().get('$http').pendingRequests.length")
|
63
70
|
else
|
64
71
|
0
|
65
72
|
end
|
data/spec/ajax_spec.rb
CHANGED
@@ -9,9 +9,10 @@ RSpec.describe "server with AJAX", type: :feature, js: true do
|
|
9
9
|
TestValue.create! content: @expected_message
|
10
10
|
end
|
11
11
|
|
12
|
-
it "waits for AJAX" do
|
13
|
-
visit "/
|
12
|
+
it "waits for AJAX from jQuery" do
|
13
|
+
visit "/ajax/jquery"
|
14
14
|
expect(page).to have_content("Hello")
|
15
|
+
click_link "Do AJAX"
|
15
16
|
Thread.fork do
|
16
17
|
sleep 0.5
|
17
18
|
AjaxServer.should_return_from_ajax = true
|
@@ -21,10 +22,40 @@ RSpec.describe "server with AJAX", type: :feature, js: true do
|
|
21
22
|
expect(find(".message").text).to eq(@expected_message)
|
22
23
|
end
|
23
24
|
|
25
|
+
it "waits for AJAX from Angular" do
|
26
|
+
visit "/ajax/angular"
|
27
|
+
expect(page).to have_content("Hello")
|
28
|
+
click_link "Do AJAX"
|
29
|
+
Thread.fork do
|
30
|
+
sleep 0.5
|
31
|
+
AjaxServer.should_return_from_ajax = true
|
32
|
+
end
|
33
|
+
expect(find(".message").text).not_to eq(@expected_message)
|
34
|
+
TransactionalCapybara::AjaxHelpers.wait_for_ajax(page)
|
35
|
+
expect(find(".message").text).to eq(@expected_message)
|
36
|
+
end
|
37
|
+
|
38
|
+
context "mixed in" do
|
39
|
+
include TransactionalCapybara::AjaxHelpers
|
40
|
+
it "provides wait_for_ajax helper" do
|
41
|
+
visit "/ajax/jquery"
|
42
|
+
expect(page).to have_content("Hello")
|
43
|
+
click_link "Do AJAX"
|
44
|
+
Thread.fork do
|
45
|
+
sleep 0.5
|
46
|
+
AjaxServer.should_return_from_ajax = true
|
47
|
+
end
|
48
|
+
expect(find(".message").text).not_to eq(@expected_message)
|
49
|
+
wait_for_ajax
|
50
|
+
expect(find(".message").text).to eq(@expected_message)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
24
54
|
context "after hook", check_result_after: true do
|
25
55
|
it "automatically waits for AJAX" do
|
26
|
-
visit "/
|
56
|
+
visit "/ajax/jquery"
|
27
57
|
expect(page).to have_content("Hello")
|
58
|
+
click_link "Do AJAX"
|
28
59
|
Thread.fork do
|
29
60
|
sleep 0.5
|
30
61
|
AjaxServer.should_return_from_ajax = true
|
@@ -35,8 +66,9 @@ RSpec.describe "server with AJAX", type: :feature, js: true do
|
|
35
66
|
|
36
67
|
it "waits on all sessions" do
|
37
68
|
using_session :foo do
|
38
|
-
visit "/
|
69
|
+
visit "/ajax/jquery"
|
39
70
|
expect(page).to have_content("Hello")
|
71
|
+
click_link "Do AJAX"
|
40
72
|
end
|
41
73
|
|
42
74
|
using_session :bar do
|
@@ -57,8 +89,9 @@ RSpec.describe "server with AJAX", type: :feature, js: true do
|
|
57
89
|
AjaxServer.should_return_from_ajax = false
|
58
90
|
|
59
91
|
using_session :bar do
|
60
|
-
visit "/
|
92
|
+
visit "/ajax/jquery"
|
61
93
|
expect(page).to have_content("Hello")
|
94
|
+
click_link "Do AJAX"
|
62
95
|
end
|
63
96
|
|
64
97
|
Thread.fork do
|
@@ -71,4 +104,18 @@ RSpec.describe "server with AJAX", type: :feature, js: true do
|
|
71
104
|
expect(find(".message").text).to eq(@expected_message)
|
72
105
|
end
|
73
106
|
end
|
107
|
+
|
108
|
+
it "uses Capybara.default_max_wait_time if available" do
|
109
|
+
allow(Capybara).to receive(:default_max_wait_time).and_return(5)
|
110
|
+
expect(Capybara).to receive(:default_max_wait_time).at_least(:once)
|
111
|
+
|
112
|
+
TransactionalCapybara::AjaxHelpers.wait_for_ajax(page)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "fallbacks on deprecated Capybara.default_wait_time" do
|
116
|
+
allow(Capybara).to receive(:respond_to?).with(:default_max_wait_time).and_return(false)
|
117
|
+
expect(Capybara).to receive(:default_wait_time).at_least(:once)
|
118
|
+
|
119
|
+
TransactionalCapybara::AjaxHelpers.wait_for_ajax(page)
|
120
|
+
end
|
74
121
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/server.rb
CHANGED
@@ -3,17 +3,23 @@ require 'tilt/erb'
|
|
3
3
|
require_relative 'model'
|
4
4
|
|
5
5
|
class AjaxServer < Sinatra::Base
|
6
|
+
set :public_folder, File.dirname(__FILE__) + '/vendor'
|
7
|
+
|
6
8
|
cattr_accessor :should_return_from_ajax
|
7
9
|
|
8
10
|
get "/boring_page" do
|
9
11
|
erb "Hi", layout: :basic
|
10
12
|
end
|
11
13
|
|
12
|
-
get "/
|
13
|
-
erb :
|
14
|
+
get "/ajax/jquery" do
|
15
|
+
erb :jquery, layout: :basic
|
16
|
+
end
|
17
|
+
|
18
|
+
get "/ajax/angular" do
|
19
|
+
erb :angular, layout: :basic
|
14
20
|
end
|
15
21
|
|
16
|
-
get "/
|
22
|
+
get "/ajax/endpoint" do
|
17
23
|
until AjaxServer.should_return_from_ajax do
|
18
24
|
sleep 0.01
|
19
25
|
end
|