capybara-async_runner 1.0.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 +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +75 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/capybara-async_runner.gemspec +28 -0
- data/examples/indexeddb/commands/insert.rb +12 -0
- data/examples/indexeddb/commands/query.rb +11 -0
- data/examples/indexeddb/commands/wrapper_initializer.rb +10 -0
- data/examples/indexeddb/commands/wrapper_loader.rb +9 -0
- data/examples/indexeddb/indexdb.rb +139 -0
- data/examples/indexeddb/templates/commands/insert.js.erb +8 -0
- data/examples/indexeddb/templates/commands/query.js.erb +15 -0
- data/examples/indexeddb/templates/wrapper/initialize.js.erb +18 -0
- data/examples/indexeddb/templates/wrapper/inject.js.erb +29 -0
- data/examples/simple/command.rb +36 -0
- data/examples/simple/template.js.erb +4 -0
- data/lib/capybara/async_runner.rb +49 -0
- data/lib/capybara/async_runner/command.rb +59 -0
- data/lib/capybara/async_runner/commands/configuration.rb +74 -0
- data/lib/capybara/async_runner/commands/responders.rb +62 -0
- data/lib/capybara/async_runner/commands/templates.rb +11 -0
- data/lib/capybara/async_runner/configuration.rb +37 -0
- data/lib/capybara/async_runner/env.rb +78 -0
- data/lib/capybara/async_runner/js_builder.rb +80 -0
- data/lib/capybara/async_runner/registry.rb +32 -0
- data/lib/capybara/async_runner/version.rb +5 -0
- data/lib/capybara/async_runner/wait_helper.rb +40 -0
- metadata +173 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7e2d94d0d6867b6a67a5eb65b0436f8ad1e81cde
|
4
|
+
data.tar.gz: 7d47e6c4a489840d793272dfb23461f2a5f0d204
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2ba028e72e92957aebcba3509bbdc3d552937be71e1b954214ab2c0b03e9192a6922a7509b53807d9af1bc7de51b1f61d95a089ee3fb3805d44eaded7ca973aa
|
7
|
+
data.tar.gz: 26c9975d86b4e04c1c22034769f12cc1dce912bc179b0038b8497d3ebfc41c74c6fffc7143300fbebbe1603ce33722abf84a80da7d63965b5d44fe826f0c396b
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
before_install: gem install bundler -v 1.9.9
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Ilya Bylich
|
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,75 @@
|
|
1
|
+
# Capybara::AsyncRunner
|
2
|
+
|
3
|
+
[](https://travis-ci.org/iliabylich/capybara-async-runner)
|
4
|
+
[](https://codeclimate.com/github/iliabylich/capybara-async-runner)
|
5
|
+
[](http://inch-ci.org/github/iliabylich/capybara-async-runner)
|
6
|
+
|
7
|
+
This is a ruby gem for running asynchronous JavaScript code synchronously with Capybara.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'capybara-async_runner'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install capybara-async_runner
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
Read [this](http://ilyabylich.svbtle.com/capybara-and-asynchronous-stuff) blog post first.
|
28
|
+
Then check out `examples` dir.
|
29
|
+
|
30
|
+
## How to use
|
31
|
+
|
32
|
+
+ Setup a directory with command templates
|
33
|
+
|
34
|
+
``` ruby
|
35
|
+
Capybara::AsyncRunner.setup do |config|
|
36
|
+
config.commands_directory = Rails.root.join('directory/with/templates')
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
+ Create a command
|
41
|
+
|
42
|
+
``` ruby
|
43
|
+
class MyCommand < Capybara::AsyncRunner::Command
|
44
|
+
# specify the name
|
45
|
+
self.command_name = :my_command
|
46
|
+
# specify a path to template
|
47
|
+
self.template = 'template_name'
|
48
|
+
# specify a response
|
49
|
+
response :done
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
+ Create a template file
|
54
|
+
|
55
|
+
``` javascript
|
56
|
+
// directory/with/templates/template_name.js.erb
|
57
|
+
yourCode(function(data) {
|
58
|
+
<%= done(js[:data]) %>
|
59
|
+
})
|
60
|
+
```
|
61
|
+
|
62
|
+
+ Call the command
|
63
|
+
|
64
|
+
``` ruby
|
65
|
+
Capybara::AsyncRunner.run(:my_command)
|
66
|
+
# => data from your script
|
67
|
+
```
|
68
|
+
|
69
|
+
## Contributing
|
70
|
+
|
71
|
+
1. Fork it ( https://github.com/[my-github-username]/capybara-async_runner/fork )
|
72
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
73
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
74
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
75
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "capybara/async_runner"
|
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
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'capybara/async_runner/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "capybara-async_runner"
|
8
|
+
spec.version = Capybara::AsyncRunner::VERSION
|
9
|
+
spec.authors = ["Ilya Bylich"]
|
10
|
+
spec.email = ["ibylich@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Gem for running ascynrhonous jobs in Capybara.}
|
13
|
+
spec.homepage = "https://github.com/iliabylich/capybara-async-runner"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.9"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency 'rspec', '~> 3.2.0'
|
24
|
+
spec.add_development_dependency 'rspec-its', '~> 1.2.0'
|
25
|
+
spec.add_development_dependency 'capybara'
|
26
|
+
spec.add_development_dependency 'poltergeist'
|
27
|
+
spec.add_development_dependency 'pry'
|
28
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class IndexDB::Commands::Insert < Capybara::AsyncRunner::Command
|
2
|
+
FailedToInsertData = Class.new(StandardError)
|
3
|
+
|
4
|
+
self.command_name = 'indexeddb:insert'
|
5
|
+
self.file_to_run = 'commands/insert'
|
6
|
+
|
7
|
+
response :error do |response|
|
8
|
+
raise FailedToInsertData, response
|
9
|
+
end
|
10
|
+
|
11
|
+
response :success
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class IndexDB::Commands::Query < Capybara::AsyncRunner::Command
|
2
|
+
ErrorDuringQuerying = Class.new(StandardError)
|
3
|
+
|
4
|
+
self.command_name = 'indexeddb:query'
|
5
|
+
self.file_to_run = 'commands/query'
|
6
|
+
|
7
|
+
response :success
|
8
|
+
response :error do |response|
|
9
|
+
raise ErrorDuringQuerying, response
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class IndexDB::WrapperInitializer < Capybara::AsyncRunner::Command
|
2
|
+
self.command_name = 'indexeddb:wrapper:initialize'
|
3
|
+
self.file_to_run = 'wrapper/initialize'
|
4
|
+
|
5
|
+
response :error do |response|
|
6
|
+
raise "Client error: #{response}"
|
7
|
+
end
|
8
|
+
|
9
|
+
response :success
|
10
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
ROOT = Pathname.new(File.expand_path('../../..', __FILE__))
|
3
|
+
$: << ROOT.join('lib')
|
4
|
+
$: << EXAMPLE_ROOT = ROOT.join('examples/indexeddb')
|
5
|
+
|
6
|
+
require 'capybara'
|
7
|
+
require 'capybara/async_runner'
|
8
|
+
require 'capybara/poltergeist'
|
9
|
+
require 'pry'
|
10
|
+
|
11
|
+
Capybara.run_server = false
|
12
|
+
Capybara.default_driver = :poltergeist
|
13
|
+
|
14
|
+
Capybara::AsyncRunner.setup do |config|
|
15
|
+
config.commands_directory = EXAMPLE_ROOT.join('templates')
|
16
|
+
end
|
17
|
+
|
18
|
+
module IndexDB
|
19
|
+
URL = "https://raw.githubusercontent.com/dfahlander/Dexie.js/master/src/Dexie.js"
|
20
|
+
|
21
|
+
require 'commands/wrapper_loader'
|
22
|
+
require 'commands/wrapper_initializer'
|
23
|
+
|
24
|
+
module Commands
|
25
|
+
require 'commands/insert'
|
26
|
+
require 'commands/query'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# We can't run indexeddb-related code in about:blank
|
31
|
+
Capybara.current_session.visit('http://google.com')
|
32
|
+
|
33
|
+
# Inject the script
|
34
|
+
Capybara::AsyncRunner.run('indexeddb:wrapper:inject', url: IndexDB::URL)
|
35
|
+
|
36
|
+
# Run some initialization
|
37
|
+
Capybara::AsyncRunner.run('indexeddb:wrapper:initialize')
|
38
|
+
|
39
|
+
# And do some stuff
|
40
|
+
user_data = { name: 'Some Name' }
|
41
|
+
|
42
|
+
user_id = Capybara::AsyncRunner.run('indexeddb:insert', store: 'users', data: user_data)
|
43
|
+
p "User ID: #{user_id}"
|
44
|
+
|
45
|
+
methods = [
|
46
|
+
{ method: 'where', arguments: ['id']},
|
47
|
+
{ method: 'equals', arguments: [user_id] },
|
48
|
+
{ method: 'toArray', arguments: [] }
|
49
|
+
]
|
50
|
+
|
51
|
+
p Capybara::AsyncRunner.run('indexeddb:query', store: 'users', methods: methods)
|
52
|
+
|
53
|
+
# And even write some small wrapper
|
54
|
+
#
|
55
|
+
#
|
56
|
+
module IndexDB::DSL
|
57
|
+
def current_scope
|
58
|
+
@current_scope ||= []
|
59
|
+
end
|
60
|
+
|
61
|
+
IDB_METHODS = {
|
62
|
+
above: :above,
|
63
|
+
aboveOrEqual: :above_or_equal,
|
64
|
+
anyOf: :any_of,
|
65
|
+
below: :below,
|
66
|
+
belowOrEqual: :below_or_equal,
|
67
|
+
between: :between,
|
68
|
+
equals: :equals,
|
69
|
+
equalsIgnoreCase: :equals_ignore_case,
|
70
|
+
startsWith: :starts_with,
|
71
|
+
startsWithAnyOf: :starts_with_any_of,
|
72
|
+
startsWithIgnoreCase: :starts_with_ignore_case,
|
73
|
+
toArray: :to_a,
|
74
|
+
where: :where
|
75
|
+
}
|
76
|
+
|
77
|
+
IDB_METHODS.each do |js_method_name, ruby_method_name|
|
78
|
+
define_method ruby_method_name do |*arguments|
|
79
|
+
current_scope << { method: js_method_name, arguments: arguments }
|
80
|
+
self
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
module ModelSupport
|
85
|
+
IndexDB::DSL::IDB_METHODS.each do |_, method_name|
|
86
|
+
define_method method_name do |*arguments|
|
87
|
+
IndexDB::ChainedScope.new(self).send(method_name, *arguments)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class IndexDB::ChainedScope
|
94
|
+
include IndexDB::DSL
|
95
|
+
|
96
|
+
def initialize(model)
|
97
|
+
@model = model
|
98
|
+
end
|
99
|
+
|
100
|
+
def get
|
101
|
+
collection = Capybara::AsyncRunner.run('indexeddb:query', store: @model.store, methods: current_scope)
|
102
|
+
collection.map do |record|
|
103
|
+
@model.new(record)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class IndexDB::Model
|
109
|
+
extend IndexDB::DSL::ModelSupport
|
110
|
+
attr_accessor :data
|
111
|
+
|
112
|
+
def initialize(data)
|
113
|
+
@data = data
|
114
|
+
end
|
115
|
+
|
116
|
+
class << self
|
117
|
+
attr_accessor :store
|
118
|
+
|
119
|
+
def all
|
120
|
+
where('id').above(0).to_a.get
|
121
|
+
end
|
122
|
+
|
123
|
+
def find(record_id)
|
124
|
+
where('id').equals(record_id).to_a.get.first
|
125
|
+
end
|
126
|
+
|
127
|
+
def count
|
128
|
+
all.count
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class User < IndexDB::Model
|
134
|
+
self.store = :users
|
135
|
+
end
|
136
|
+
|
137
|
+
p User.all
|
138
|
+
p User.find(8)
|
139
|
+
p User.count
|
@@ -0,0 +1,15 @@
|
|
1
|
+
var store = window.db['<%= data[:store] %>'];
|
2
|
+
var methodsPayload = JSON.parse(<%= data[:methods].to_json.inspect %>);
|
3
|
+
|
4
|
+
methodsPayload.forEach(function(methodPayload) {
|
5
|
+
var method = methodPayload['method'];
|
6
|
+
var arguments = methodPayload['arguments'];
|
7
|
+
console.log("Executing", method, "with", arguments);
|
8
|
+
store = store[method].apply(store, arguments);
|
9
|
+
});
|
10
|
+
|
11
|
+
store.then(function(data) {
|
12
|
+
<%= success(js[:data]) %>
|
13
|
+
}).catch(function(err) {
|
14
|
+
<%= error(js[:err]) %>
|
15
|
+
})
|
@@ -0,0 +1,18 @@
|
|
1
|
+
window.errorHandler = function(err) {
|
2
|
+
<%= error(js[:err]) %>
|
3
|
+
}
|
4
|
+
|
5
|
+
if (typeof(Dexie) === 'undefined') {
|
6
|
+
errorHandler('No Dexie');
|
7
|
+
} else {
|
8
|
+
window.db = new Dexie('demo91');
|
9
|
+
window.db.version(1).stores({
|
10
|
+
users: '++id,name'
|
11
|
+
});
|
12
|
+
|
13
|
+
window.db.open().catch(function(err) {
|
14
|
+
errorHandler('failed to open indexedDB ' + err);
|
15
|
+
}).then(function() {
|
16
|
+
<%= success %>
|
17
|
+
});
|
18
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
function isWrapperReady() {
|
2
|
+
return (typeof(Dexie) !== 'undefined');
|
3
|
+
}
|
4
|
+
|
5
|
+
function injectScript(src) {
|
6
|
+
var fileref = document.createElement('script')
|
7
|
+
fileref.setAttribute("type","text/javascript")
|
8
|
+
fileref.setAttribute("src", src);
|
9
|
+
document.getElementsByTagName("head")[0].appendChild(fileref)
|
10
|
+
}
|
11
|
+
|
12
|
+
if (isWrapperReady()) {
|
13
|
+
<%= success %>
|
14
|
+
} else {
|
15
|
+
injectScript("<%= data[:url] %>");
|
16
|
+
|
17
|
+
setInterval(function() {
|
18
|
+
if (isWrapperReady()) {
|
19
|
+
<%= success %>
|
20
|
+
}
|
21
|
+
}, 100);
|
22
|
+
|
23
|
+
setTimeout(function () {
|
24
|
+
if (typeof(Dexie) === 'undefined') {
|
25
|
+
<%= error %>
|
26
|
+
}
|
27
|
+
}, 3000);
|
28
|
+
}
|
29
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Don't forget to run 'bundle install' before running this script
|
2
|
+
#
|
3
|
+
require 'pathname'
|
4
|
+
ROOT = Pathname.new(File.expand_path('../../..', __FILE__))
|
5
|
+
$: << ROOT.join('lib')
|
6
|
+
|
7
|
+
require 'capybara'
|
8
|
+
require 'capybara/async_runner'
|
9
|
+
|
10
|
+
# Base gem configuration
|
11
|
+
Capybara::AsyncRunner.setup do |config|
|
12
|
+
config.commands_directory = ROOT.join('examples/simple')
|
13
|
+
end
|
14
|
+
|
15
|
+
# Defining a command
|
16
|
+
class TestCommand < Capybara::AsyncRunner::Command
|
17
|
+
# global command name
|
18
|
+
self.command_name = :json_and_timeout
|
19
|
+
|
20
|
+
# .js.erb file in directory specified above
|
21
|
+
self.file_to_run = 'template'
|
22
|
+
|
23
|
+
response :parsed_json do |data|
|
24
|
+
JSON.parse(data)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# I'm using poltergeist as a webdriver here, but you can use whatever you want
|
29
|
+
require 'capybara/poltergeist'
|
30
|
+
|
31
|
+
# My command is totally abstract, so I'm running it in context of 'about:blank' page
|
32
|
+
Capybara.run_server = false
|
33
|
+
Capybara.default_driver = :poltergeist
|
34
|
+
|
35
|
+
p Capybara::AsyncRunner.run(:json_and_timeout)
|
36
|
+
# or TestCommand.new.invoke
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "capybara/async_runner/version"
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
module AsyncRunner
|
5
|
+
FailedToFetchResult = Class.new(StandardError)
|
6
|
+
|
7
|
+
autoload :Configuration, 'capybara/async_runner/configuration'
|
8
|
+
autoload :Command, 'capybara/async_runner/command'
|
9
|
+
autoload :Env, 'capybara/async_runner/env'
|
10
|
+
autoload :JsBuilder, 'capybara/async_runner/js_builder'
|
11
|
+
autoload :WaitHelper, 'capybara/async_runner/wait_helper'
|
12
|
+
autoload :Registry, 'capybara/async_runner/registry'
|
13
|
+
|
14
|
+
# Returns current gem configuration.
|
15
|
+
#
|
16
|
+
# @return [Capybara::AsyncRunner::Configuration]
|
17
|
+
#
|
18
|
+
def self.config
|
19
|
+
@config ||= Configuration.new
|
20
|
+
end
|
21
|
+
|
22
|
+
# Yields current configuration
|
23
|
+
#
|
24
|
+
# @yield [Capybara::AsyncRunner::Configuration]
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# Capybara::AsyncRunner.setup do |config|
|
28
|
+
# config.commands_directory = Rails.root.join('spec/support/async_runner')
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
def self.setup
|
32
|
+
yield config
|
33
|
+
end
|
34
|
+
|
35
|
+
# Runs command that has provided +command_name+ and passes provided +data+
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# class MyCoolCommand < Capybara::AsyncRunner::Command
|
39
|
+
# self.command_name = 'cool_command'
|
40
|
+
# self.file_to_run = 'path/to/cool/command'
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# Capybara::AsyncRunner.run(:cool_command)
|
44
|
+
#
|
45
|
+
def self.run(command_name, data = {})
|
46
|
+
Registry[command_name].new(data).invoke
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'capybara/async_runner/commands/configuration'
|
3
|
+
require 'capybara/async_runner/commands/responders'
|
4
|
+
require 'capybara/async_runner/commands/templates'
|
5
|
+
|
6
|
+
# A common class for defining your commands
|
7
|
+
#
|
8
|
+
# Every command MUST have a name and a .js.erb file
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # spec/support/async_runner/commands/some_command.rb
|
12
|
+
# #
|
13
|
+
# class SomeCommand < Capybara::AsyncRunner::Command
|
14
|
+
# self.command_name = :some_command_name
|
15
|
+
# self.file_to_run = 'your/path/to/file/without/extension'
|
16
|
+
#
|
17
|
+
# response :done
|
18
|
+
# response :fail do |data|
|
19
|
+
# JSON.parse(data)
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# SomeCommand.new({}).invoke
|
24
|
+
# # => result
|
25
|
+
#
|
26
|
+
class Capybara::AsyncRunner::Command
|
27
|
+
include Capybara::AsyncRunner::Commands::Configuration
|
28
|
+
include Capybara::AsyncRunner::Commands::Responders
|
29
|
+
include Capybara::AsyncRunner::Commands::Templates
|
30
|
+
|
31
|
+
# @param data [Hash] data is available in template through <%= data %>
|
32
|
+
#
|
33
|
+
def initialize(data = {})
|
34
|
+
@uuid = SecureRandom.uuid
|
35
|
+
@env = Capybara::AsyncRunner::Env.new(uuid, data, responders)
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :uuid, :env
|
39
|
+
|
40
|
+
# Invokes the command and returns its result
|
41
|
+
#
|
42
|
+
# @see Capybara::AsyncRunner::JsBuilder
|
43
|
+
# @see Capybara::AsyncRunner::Env
|
44
|
+
#
|
45
|
+
def invoke
|
46
|
+
js_builder.result
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def js_builder
|
52
|
+
@js_builder ||= Capybara::AsyncRunner::JsBuilder.new(@env, erb)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.inherited(klass)
|
56
|
+
super
|
57
|
+
Capybara::AsyncRunner::Registry << klass
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Module for confoiguring your commands
|
2
|
+
#
|
3
|
+
# @example
|
4
|
+
# class SomeCommand < Capybara::AsyncRunner::Command
|
5
|
+
# self.command_name = 'my_command_name'
|
6
|
+
# # (use underscores, your can later call them by passing symbols)
|
7
|
+
# self.file_to_run = 'path/to/your/file'
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
module Capybara::AsyncRunner::Commands
|
11
|
+
module Configuration
|
12
|
+
def self.included(base)
|
13
|
+
base.extend(ClassMethods)
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
# Returns configured command name or raises error
|
18
|
+
#
|
19
|
+
# @return [String, Symbol]
|
20
|
+
#
|
21
|
+
# @raise NotImplementedError
|
22
|
+
#
|
23
|
+
def command_name
|
24
|
+
store[:command_name] or
|
25
|
+
raise NotImplementedError, "You need to define self.command_name = ... in #{self}"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Saves provided +command_name+
|
29
|
+
#
|
30
|
+
# @param command_name [String]
|
31
|
+
#
|
32
|
+
def command_name=(command_name)
|
33
|
+
store[:command_name] = command_name
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns configured filepath or raises error
|
37
|
+
#
|
38
|
+
# @return [String, Symbol]
|
39
|
+
#
|
40
|
+
# @raise NotImplementedError
|
41
|
+
#
|
42
|
+
def file_to_run
|
43
|
+
store[:file_to_run] or
|
44
|
+
raise NotImplementedError, "You need to define self.file_to_run = ... in #{self}"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Stores provided relative +file_to_run+ (don't include directory and extension)
|
48
|
+
#
|
49
|
+
# @param file_to_run [String]
|
50
|
+
#
|
51
|
+
def file_to_run=(file_to_run)
|
52
|
+
store[:file_to_run] = file_to_run
|
53
|
+
end
|
54
|
+
|
55
|
+
# @private
|
56
|
+
#
|
57
|
+
# Inherits all configuration from parent
|
58
|
+
#
|
59
|
+
def inherited(klass)
|
60
|
+
super
|
61
|
+
return if self == Capybara::AsyncRunner::Command
|
62
|
+
klass.command_name = self.command_name
|
63
|
+
klass.file_to_run = self.file_to_run
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# @private
|
69
|
+
def store
|
70
|
+
@store ||= {}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Module for defining your responders
|
2
|
+
#
|
3
|
+
# Responder is a method that you should call in you .js code
|
4
|
+
#
|
5
|
+
# @example
|
6
|
+
# class MyCommand < Capybara::AsyncRunner::Commands
|
7
|
+
# response :done
|
8
|
+
# response :fail, as: :callback
|
9
|
+
# response :parsed_json do |data|
|
10
|
+
# JSON.parse(data)
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# # template
|
14
|
+
# if (done) {
|
15
|
+
# <%= done %>
|
16
|
+
# } else if (fail) {
|
17
|
+
# afterFail(<%= fail %>)
|
18
|
+
# } eles if (returnedJSON) {
|
19
|
+
# <%= parsed_json(js[:returnedJSON]) %>
|
20
|
+
# }
|
21
|
+
#
|
22
|
+
# Only one responder can be executed for 1 script during 1 invokation
|
23
|
+
#
|
24
|
+
module Capybara::AsyncRunner::Commands
|
25
|
+
module Responders
|
26
|
+
def self.included(base)
|
27
|
+
base.send(:include, InstanceMethods)
|
28
|
+
base.extend(ClassMethods)
|
29
|
+
end
|
30
|
+
|
31
|
+
module InstanceMethods
|
32
|
+
def responders
|
33
|
+
self.class.responders
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module ClassMethods
|
38
|
+
def responders
|
39
|
+
store[:responders] ||= {}
|
40
|
+
end
|
41
|
+
|
42
|
+
BLANK_PROXY = proc { |value| value }
|
43
|
+
|
44
|
+
# Defines a responder for script
|
45
|
+
#
|
46
|
+
# @param method_name [String, Symbols]
|
47
|
+
# @param options [Hash]
|
48
|
+
# @option options [Symbol] :as can be :callback
|
49
|
+
# @yield raw_data from script
|
50
|
+
#
|
51
|
+
# raw_data will be returned if no block provided
|
52
|
+
#
|
53
|
+
def response(method_name, options = {}, &block)
|
54
|
+
mapping = {
|
55
|
+
options: options,
|
56
|
+
processor: block || BLANK_PROXY
|
57
|
+
}
|
58
|
+
responders[method_name] = mapping
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Just a module for reading erb files
|
2
|
+
#
|
3
|
+
module Capybara::AsyncRunner::Commands
|
4
|
+
module Templates
|
5
|
+
def erb
|
6
|
+
fullname = self.class.file_to_run + '.js.erb'
|
7
|
+
filepath = Capybara::AsyncRunner.config.commands_directory.join(fullname)
|
8
|
+
File.read(filepath)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Class for configuring a gem
|
2
|
+
#
|
3
|
+
# @example
|
4
|
+
# config = Capybara::AsyncRunner::Configuration
|
5
|
+
# config.commands_directory = 'some/dir'
|
6
|
+
#
|
7
|
+
class Capybara::AsyncRunner::Configuration
|
8
|
+
def initialize
|
9
|
+
@data = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
# A DSL for defining accessors with default values
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# config_accessor :access_name # no default value
|
16
|
+
# config_accessor :timeout, 12
|
17
|
+
#
|
18
|
+
def self.config_accessor(attribute_name, default = nil)
|
19
|
+
define_method attribute_name do
|
20
|
+
@data[attribute_name] || default
|
21
|
+
end
|
22
|
+
|
23
|
+
define_method "#{attribute_name}=" do |value|
|
24
|
+
@data[attribute_name] = value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns directory that contains all command files
|
29
|
+
#
|
30
|
+
config_accessor :commands_directory
|
31
|
+
|
32
|
+
# Drops all configured values
|
33
|
+
#
|
34
|
+
def reset!
|
35
|
+
@data = {}
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Internal class for building environment for rendering .js.erb code
|
2
|
+
#
|
3
|
+
class Capybara::AsyncRunner::Env
|
4
|
+
# @param uuid [String] just a uuid of running command
|
5
|
+
# @param data [Hash] data that is available in .erb through <%= data[:something] %>
|
6
|
+
# @param responders [Hash<Symbol, Hash>] mapping method_name => options
|
7
|
+
#
|
8
|
+
# For responders:
|
9
|
+
# @see Capybara::AsyncRunner::Commands::Responders
|
10
|
+
#
|
11
|
+
def initialize(uuid, data, responders)
|
12
|
+
@uuid = uuid
|
13
|
+
@data = data
|
14
|
+
@responders = responders
|
15
|
+
end
|
16
|
+
attr_reader :data, :responders, :uuid
|
17
|
+
|
18
|
+
# Returns a js environment that can be used for fetching data from the code on-the-fly
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# # spec/support/async_runner/templates/command1.js.erb
|
22
|
+
# var jsLocal = 123;
|
23
|
+
# <%= done(js[:jsLocal] %>
|
24
|
+
#
|
25
|
+
def js_environment
|
26
|
+
Hash.new do |h, k|
|
27
|
+
k.to_s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
alias_method :js, :js_environment
|
31
|
+
|
32
|
+
# Delegates a method to responder
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# <%= responder1(js[:var1]) %>
|
36
|
+
#
|
37
|
+
# @see Capybara::AsyncRunner::Commands::Responders
|
38
|
+
#
|
39
|
+
def method_missing(method_name, *args)
|
40
|
+
if responders.include?(method_name)
|
41
|
+
response_method_for(method_name, *args)
|
42
|
+
else
|
43
|
+
super
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# @private
|
48
|
+
def respond_to_missing?(method_name, include_private = false)
|
49
|
+
super || responders.include?(method_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns local binding that is used for rendering (ERB.new(template).result(binding))
|
53
|
+
#
|
54
|
+
# @return [Binding]
|
55
|
+
#
|
56
|
+
def local_binding
|
57
|
+
binding
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :responders
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def response_method_for(method_name, *args)
|
65
|
+
options = responders[method_name][:options]
|
66
|
+
if options[:as] == :callback
|
67
|
+
<<-JS
|
68
|
+
function() {
|
69
|
+
var args = Array.prototype.slice.call(arguments, 0);
|
70
|
+
window.Capybara[#{uuid.inspect}] = { from: #{method_name.to_s.inspect}, data: args };
|
71
|
+
}
|
72
|
+
JS
|
73
|
+
else
|
74
|
+
formatted_args = "[#{args.join(', ')}]"
|
75
|
+
"window.Capybara[#{uuid.inspect}] = { from: #{method_name.to_s.inspect}, data: #{formatted_args} };"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
# Internal class for executing javascript code.
|
4
|
+
# Don't use directly
|
5
|
+
#
|
6
|
+
class Capybara::AsyncRunner::JsBuilder
|
7
|
+
# @param env [Capybara::AsyncRunner::Env] context of erb
|
8
|
+
# @param erb [String] erb template with js code
|
9
|
+
#
|
10
|
+
def initialize(env, erb)
|
11
|
+
@env = env
|
12
|
+
@erb = erb
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :env, :erb
|
16
|
+
|
17
|
+
# Executes provided code and returns its result
|
18
|
+
#
|
19
|
+
# @return [Object]
|
20
|
+
#
|
21
|
+
# @raise [Capybara::AsyncRunner::FailedToFetchResult] when javascript VM doesn't have any response after timeout
|
22
|
+
#
|
23
|
+
def result
|
24
|
+
Capybara.current_session.evaluate_script(calculation_code)
|
25
|
+
|
26
|
+
ResponseProcessor.new(raw_result, env.responders).result
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def raw_result
|
32
|
+
RawResult.new(env.uuid).fetch or
|
33
|
+
raise Capybara::AsyncRunner::FailedToFetchResult, "No response for command with uuid = #{env.uuid}"
|
34
|
+
end
|
35
|
+
|
36
|
+
RawResult = Struct.new(:uuid) do
|
37
|
+
def fetch
|
38
|
+
Capybara::AsyncRunner::WaitHelper.wait_until(2) do
|
39
|
+
Capybara.current_session.evaluate_script(result_code)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def result_code
|
44
|
+
"window.Capybara[#{uuid.inspect}]"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
ResponseProcessor = Struct.new(:raw_result, :responders) do
|
49
|
+
def method_name
|
50
|
+
raw_result['from'].to_sym
|
51
|
+
end
|
52
|
+
|
53
|
+
def data
|
54
|
+
raw_result['data'][0]
|
55
|
+
end
|
56
|
+
|
57
|
+
def responder
|
58
|
+
responders[method_name][:processor]
|
59
|
+
end
|
60
|
+
|
61
|
+
def result
|
62
|
+
responder.call(data)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def calculation_code
|
67
|
+
<<-JS
|
68
|
+
function() {
|
69
|
+
if (typeof(window.Capybara) === 'undefined') {
|
70
|
+
window.Capybara = {};
|
71
|
+
}
|
72
|
+
#{dynamic_code}
|
73
|
+
}()
|
74
|
+
JS
|
75
|
+
end
|
76
|
+
|
77
|
+
def dynamic_code
|
78
|
+
ERB.new(erb).result(env.local_binding)
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Module for storing all defined commands
|
2
|
+
#
|
3
|
+
# @example
|
4
|
+
# Capybara::AsyncRunner::Registry << SomeKlass
|
5
|
+
# Capybara::AsyncRunner::Registry[:some_name]
|
6
|
+
# # => SomeKlass
|
7
|
+
#
|
8
|
+
# You don't need to use this class directly, the gme does everything for you
|
9
|
+
#
|
10
|
+
module Capybara::AsyncRunner::Registry
|
11
|
+
# Stores provided +command_klass+ internally
|
12
|
+
#
|
13
|
+
# @param command_klass [Capybara::AsyncRunner::Command]
|
14
|
+
#
|
15
|
+
def self.<<(command_klass)
|
16
|
+
all << command_klass
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns first stored command that has provided +command_name+
|
20
|
+
#
|
21
|
+
# @paran command_name [String, Symbol]
|
22
|
+
#
|
23
|
+
def self.[](command_name)
|
24
|
+
all.detect { |klass| klass.command_name.to_s == command_name.to_s }
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def self.all
|
30
|
+
@all ||= []
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# This module allows to run a code periodically
|
2
|
+
# and check for its returning value
|
3
|
+
#
|
4
|
+
module Capybara::AsyncRunner::WaitHelper
|
5
|
+
extend self
|
6
|
+
|
7
|
+
# Calls provided +block+ every 100ms
|
8
|
+
# and stops when it returns false
|
9
|
+
#
|
10
|
+
# @param timeout [Fixnum]
|
11
|
+
# @yield block for execution
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# current_time = Time.now
|
15
|
+
# Capybara::AsyncRunner::WaitHelper.wait_until(3) do
|
16
|
+
# Time.now - current_time > 2
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # 2 seconds later ...
|
20
|
+
# # => true
|
21
|
+
#
|
22
|
+
# current_time = Time.now
|
23
|
+
# Capybara::AsyncRunner::WaitHelper.wait_until(3) do
|
24
|
+
# Time.now - current_time > 10
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # 3 seconds later (after timeout)
|
28
|
+
# # => false
|
29
|
+
#
|
30
|
+
def wait_until(timeout, &block)
|
31
|
+
begin
|
32
|
+
Timeout.timeout(timeout) do
|
33
|
+
sleep(0.1) until value = block.call
|
34
|
+
value
|
35
|
+
end
|
36
|
+
rescue TimeoutError
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capybara-async_runner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ilya Bylich
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-01 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.9'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.9'
|
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.2.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.2.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-its
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.2.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.2.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: capybara
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: poltergeist
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description:
|
112
|
+
email:
|
113
|
+
- ibylich@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".gitignore"
|
119
|
+
- ".travis.yml"
|
120
|
+
- Gemfile
|
121
|
+
- LICENSE.txt
|
122
|
+
- README.md
|
123
|
+
- Rakefile
|
124
|
+
- bin/console
|
125
|
+
- bin/setup
|
126
|
+
- capybara-async_runner.gemspec
|
127
|
+
- examples/indexeddb/commands/insert.rb
|
128
|
+
- examples/indexeddb/commands/query.rb
|
129
|
+
- examples/indexeddb/commands/wrapper_initializer.rb
|
130
|
+
- examples/indexeddb/commands/wrapper_loader.rb
|
131
|
+
- examples/indexeddb/indexdb.rb
|
132
|
+
- examples/indexeddb/templates/commands/insert.js.erb
|
133
|
+
- examples/indexeddb/templates/commands/query.js.erb
|
134
|
+
- examples/indexeddb/templates/wrapper/initialize.js.erb
|
135
|
+
- examples/indexeddb/templates/wrapper/inject.js.erb
|
136
|
+
- examples/simple/command.rb
|
137
|
+
- examples/simple/template.js.erb
|
138
|
+
- lib/capybara/async_runner.rb
|
139
|
+
- lib/capybara/async_runner/command.rb
|
140
|
+
- lib/capybara/async_runner/commands/configuration.rb
|
141
|
+
- lib/capybara/async_runner/commands/responders.rb
|
142
|
+
- lib/capybara/async_runner/commands/templates.rb
|
143
|
+
- lib/capybara/async_runner/configuration.rb
|
144
|
+
- lib/capybara/async_runner/env.rb
|
145
|
+
- lib/capybara/async_runner/js_builder.rb
|
146
|
+
- lib/capybara/async_runner/registry.rb
|
147
|
+
- lib/capybara/async_runner/version.rb
|
148
|
+
- lib/capybara/async_runner/wait_helper.rb
|
149
|
+
homepage: https://github.com/iliabylich/capybara-async-runner
|
150
|
+
licenses:
|
151
|
+
- MIT
|
152
|
+
metadata: {}
|
153
|
+
post_install_message:
|
154
|
+
rdoc_options: []
|
155
|
+
require_paths:
|
156
|
+
- lib
|
157
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
requirements: []
|
168
|
+
rubyforge_project:
|
169
|
+
rubygems_version: 2.4.7
|
170
|
+
signing_key:
|
171
|
+
specification_version: 4
|
172
|
+
summary: Gem for running ascynrhonous jobs in Capybara.
|
173
|
+
test_files: []
|