transactional_capybara 0.1.0.pre.3 → 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.
- 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
|