dmc_kanye 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8221b03c8ffdc2903f174bdf1e1a2c52634d4546
4
+ data.tar.gz: 4c776783243f78b3d149af99cd99affd4160bee4
5
+ SHA512:
6
+ metadata.gz: 3e96f9ec2901df52ad84db94536150545cab9115ce3f07c3fb95b0ad935e9fe4e5ed1947faa0d2cd0ec0cb95dc5b34a766e626c494846ccea8bb1e6a10fd5795
7
+ data.tar.gz: b7cdc5e08ec2ca3dc166415924f1aa73a1c9d226cd14d511fde51b5444a5bfb5a373a5d7fd207570ea51df288e72571d304852e537c54c6e60621ead7fc69de6
data/.gitignore ADDED
@@ -0,0 +1,35 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /vendor/bundle
26
+ /lib/bundler/man/
27
+
28
+ # for a library or gem, you might want to ignore these files since the code is
29
+ # intended to run in multiple environments; otherwise, check them in:
30
+ # Gemfile.lock
31
+ # .ruby-version
32
+ # .ruby-gemset
33
+
34
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
35
+ .rvmrc
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,10 @@
1
+ # Contributing
2
+
3
+ If you want to contribute to Dmc_Kanye, the usual steps apply:
4
+
5
+ * Fork the repo
6
+ * Start a new branch (we favor branch names with your name or initials, e.g. `pjm/my_feature_branch`)
7
+ * Make your changes (tested changes are much appreciated)
8
+ * Open a pull request
9
+
10
+ Regular contributors may be given "commit bit".
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dmc_kanye.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,17 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dmc_kanye (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ rake (10.4.2)
10
+
11
+ PLATFORMS
12
+ ruby
13
+
14
+ DEPENDENCIES
15
+ bundler (~> 1.9)
16
+ dmc_kanye!
17
+ rake (~> 10.0)
data/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # Kanye
2
+
3
+ Kanye improves Capybara's synchronization algorithm by letting the browser finish before the test keeps going. By doing this, Kanye also helps you tailor the swiftness of your feature specs.
4
+
5
+
6
+
7
+ ## How Kanye Works
8
+
9
+ When a Capybara test is run with a JavaScript driver, the two processes can easily get out of sync which causes intermittent, difficult-to-reproduce test failures.
10
+
11
+ ### How Timing Failures Happen
12
+
13
+ For example, imagine a feature where a user clicks a "details" button, which causes a pane to slide down containing the extra information. The Capybara test may want to:
14
+
15
+ * click the details button
16
+ * expect that "foo bar baz" is showing in the details pane
17
+
18
+ The Ruby process will apply the expectation immediately after clicking the button; however, the browser may need some time to:
19
+
20
+ * send an ajax request to the server to fetch the details
21
+ * do a fancy slide-down animation
22
+
23
+ Since the details wouldn't be visible yet, the Cabybara test will fail.
24
+
25
+ ### A Stupid Way to Solve Timing Failures
26
+
27
+ You could simply `sleep 20` after every single command you send to the browser, which should give it plenty of time to finish whatever it is doing and catch up to the Ruby process.
28
+
29
+ Obviously, this would make the tests unbearably slow, so a good solution to timing failures should balance speed and robustness well.
30
+
31
+ ### Capybara's Approach to Timing Issues
32
+
33
+ Capybara's way of solving timing issues, [which can be found here in its code](https://github.com/jnicklas/capybara/blob/2.4.4/lib/capybara/node/base.rb#L43), is basically this:
34
+
35
+ * Just do everything as if timing issues don't exist.
36
+ * If we do X and get a `Capybara::ElementNotFound` error, it could be because the browser has not caught up to the Ruby process. In this case, wait for the browser to catch up like so:
37
+ * Sleep for 0.05 seconds.
38
+ * Do X again.
39
+ * If X succeeds you are done.
40
+ * If X fails, try again.
41
+ * Repeat until `Capybara.default_wait_time` seconds have passed.
42
+
43
+ ### Some Problems with Capybara's Approach
44
+
45
+ **The "Does Not Exist" Gotcha** -- `!page.has_css?('.error-notice')`, while intuitive to write, will lead to an incorrectly written test. [Read more here.](https://github.com/jnicklas/capybara#asynchronous-javascript-ajax-and-friends)
46
+
47
+ **JavaScript Bleeding** -- it's possible that the browser is still executing some leftover ajax or other JavaScript after one test example has ended and during the execution of a new test example. While this rarely happens, when it does, it is very hard to troubleshoot the cause.
48
+
49
+ **Slower Specs** -- every time we have an example that expects an element to *not* be present, it is forced to wait the entire `Capybara.default_wait_time`. As the number of spec examples grow, this adds up. You can't simply choose a very small `Capybara.default_wait_time`, because this will lead to instability of test results.
50
+
51
+ ### Kanye's Approach to Timing Issues
52
+
53
+ Kanye's strategy is, instead of sleeping and waiting for things to happen, to take more control. This will lead to tests that are *both* faster and more robust.
54
+
55
+ It's easiest to think of Kanye as a wrapper. Every single time the browser is asked to do X, it is wrapped like this:
56
+
57
+ * Imma let you finish
58
+ * now do X
59
+ * Imma let you finish
60
+
61
+ "Imma let you finish" means that Kanye closely watches the browser for indications that it is busy, waiting until it is finished before allowing the Capybara process to continue.
62
+
63
+ More specifically, Kanye does the following:
64
+
65
+ * waits for all ajax to complete
66
+ * if the browser URL has changed, triggers some JavaScript code that disables all transitions on the page
67
+
68
+ That last point is important to note. Transitions (CSS transitions, jQuery transitions, etc.) take time, which causes the Capybara process to get ahead of the browser process. There is no reliable way to know whether the browser is currently running any transitions, so the strategy is to disable them. Take note of two things:
69
+
70
+ * you have to supply the JavaScript code snippet that disables transitions
71
+ * this means the test is not totally "pure" since it is disabling some production code (transitions)
72
+
73
+
74
+
75
+ ## Basic Usage
76
+
77
+ ### Setup
78
+
79
+ Kanye requires poltergeist and jQuery.
80
+
81
+ Add Kanye to your gemfile (if you have a test group, you can put it there):
82
+
83
+ gem 'dmc_kanye'
84
+
85
+ Require Kanye in your spec_helper.rb:
86
+
87
+ require 'dmc_kanye'
88
+
89
+ Configure Kanye with JavaScript that will disable transitions:
90
+
91
+ DmcKanye::Config.script_to_disable_transitions = "(typeof jQuery === 'undefined') ? false : jQuery('.fade').removeClass('fade')"
92
+
93
+ Kanye can't predict which kind of transitions you will use or how to disable them, so you have to supply the JavaScript that will disable transitions. This transition-disabling JavaScript is executed on the browser every time the browser URL changes.
94
+
95
+ Set Capybara's wait time lower to speed up your specs:
96
+
97
+ Capybara.default_wait_time = 0.5
98
+
99
+ Configure Kanye's default wait time:
100
+
101
+ DmcKanye::Config.default_wait_time = 0.5
102
+
103
+ The Kanye default wait time will be used when poltergeist is active (meaning :js => true for that spec). Otherwise, you will be using the Rack::Test driver which will use the Capybara default wait time. Because Kanye keeps a more controlled watch on what the browser is doing, there is less guess-work and so Kanye's default wait time can be lower than Capybara's.
104
+
105
+ ### Usage in Specs
106
+
107
+ You generally don't have to think about timing issues as you write your specs. Even if you are writing a spec that makes sure an error message does not appear, Kanye will be waiting for the ajax to finish so you don't have to do anything special in your spec.
108
+
109
+ However, there are a couple of situations that may confuse Kanye:
110
+
111
+ * you have a complex JavaScript chain of events started by an ajax completion event (for example, ajax that reloads the current page when completing)
112
+ * anytime the browser is busy for longer than `Capybara.default_wait_time` and the page has already finished loading and all ajax has completed (for example, you have a JavaScript function that walks the dom and does something very time-consuming to each element)
113
+
114
+ In those (hopefully rare) situations, it is recommended that you write your own code into that test to deal with the timing issue, even if it ends up being a dumb `sleep` statement. Kanye provides some [helper methods](driver_helpers.rb) to make your job easier and help you avoid those `sleep` statements.
115
+
116
+ ## A note about the name
117
+
118
+ There are more than a few "Kanye" gems in the world already, but the name was just too good to pass up. For open-source release, Kanye has been "namespaced" with the company where it was originally developed, [The District Management Council][1].
119
+
120
+ [1]: http://dmcouncil.org/
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/TODO.md ADDED
@@ -0,0 +1,4 @@
1
+ # DMC-Kanye TODO
2
+
3
+ * [ ] Tests! (How meta...)
4
+ * [ ] Publish to Rubygems
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "dmc_kanye"
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,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/dmc_kanye.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dmc_kanye/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dmc_kanye"
8
+ spec.version = DmcKanye::VERSION
9
+ spec.authors = ["Wyatt Greene", "Parker Morse"]
10
+ spec.email = ["pmorse@dmcouncil.org"]
11
+ spec.licenses = ['MIT']
12
+ spec.homepage = 'https://github.com/dmcouncil/dmc_kanye'
13
+
14
+ spec.summary = %q{Imma let your AJAX finish, but these are the best feature tests of ALL TIME.}
15
+ spec.description = %q{Kanye improves Capybara's synchronization algorithm by letting the browser finish before the test keeps going. By doing this, Kanye also helps you tailor the swiftness of your feature specs.}
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.9"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ end
@@ -0,0 +1,6 @@
1
+ module DmcKanye
2
+ class Config
3
+ class_attribute :script_to_disable_transitions
4
+ class_attribute :default_wait_time
5
+ end
6
+ end
@@ -0,0 +1,79 @@
1
+ module DmcKanye
2
+
3
+ class TimeoutException < RuntimeError; end
4
+
5
+ module DriverHelpers
6
+
7
+ # If the browser is waiting for ajax or loading a page, Kanye is smart
8
+ # enough to deal with this. However, if the browser is busy doing something
9
+ # else for a significant period of time (such as long-running JavaScript),
10
+ # Kanye is not smart enough to know that there is something that needs
11
+ # finishing.
12
+ #
13
+ # So basically, in the very rare cases that Kanye cannot detect that something
14
+ # needs to be waited for, you can explicitly wait for a DOM element to
15
+ # appear, for example:
16
+ #
17
+ # wait_to_appear(:css, '.ui-autocomplete.ui-menu')
18
+ #
19
+ # This will wait up to the poltergeist timeout value (which is probably
20
+ # 30 seconds) for this DOM element to appear before moving on. If the
21
+ # DOM element does not appear, an error is thrown.
22
+ #
23
+ def wait_to_appear(method, selector)
24
+ seconds = 0
25
+ while find(method, selector).nil?
26
+ seconds += 0.2
27
+ raise TimeoutException if seconds > timeout
28
+ sleep 0.2
29
+ end
30
+ end
31
+
32
+ def open_ajax_requests?
33
+ !evaluate_script("(typeof jQuery === 'undefined') ? 0 : jQuery.active").zero?
34
+ rescue Capybara::NotSupportedByDriverError
35
+ false
36
+ end
37
+
38
+ def page_loaded?
39
+ evaluate_script("document.readyState") == "complete"
40
+ rescue Capybara::NotSupportedByDriverError
41
+ true
42
+ end
43
+
44
+ def wait_for_page_to_finish_loading
45
+ seconds = 0
46
+ while !page_loaded?
47
+ seconds += 0.02
48
+ raise TimeoutException if seconds > timeout
49
+ sleep 0.02
50
+ end
51
+ end
52
+
53
+ def wait_for_in_progress_ajax_to_finish
54
+ seconds = 0
55
+ while open_ajax_requests?
56
+ seconds += 0.05
57
+ raise TimeoutException if seconds > timeout
58
+ sleep 0.05
59
+ end
60
+ end
61
+
62
+ def wait_for_page_to_settle
63
+ if !page_loaded?
64
+ wait_for_page_to_finish_loading
65
+ wait_for_page_to_settle
66
+ end
67
+ if open_ajax_requests?
68
+ wait_for_in_progress_ajax_to_finish
69
+ wait_for_page_to_settle
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ module Capybara::Poltergeist
76
+ class Driver < Capybara::Driver::Base
77
+ include DmcKanye::DriverHelpers
78
+ end
79
+ end
@@ -0,0 +1,15 @@
1
+ require 'capybara'
2
+ require 'capybara/poltergeist'
3
+ require 'capybara/poltergeist/version'
4
+
5
+ unless Capybara::VERSION == "2.4.4"
6
+ raise "Kanye specifically monkey-patched version 2.4.4 of Capybara. "\
7
+ "You have version #{Capybara::VERSION}. "\
8
+ "Please upgrade the monkey patches along with the gem."
9
+ end
10
+
11
+ unless Capybara::Poltergeist::VERSION == "1.5.1"
12
+ raise "Kanye specifically monkey-patched version 1.5.1 of Poltergeist. "\
13
+ "You have version #{Capybara::Poltergeist::VERSION}. "\
14
+ "Please upgrade the monkey patches along with the gem."
15
+ end
@@ -0,0 +1,101 @@
1
+ module Capybara::Poltergeist
2
+ class Driver < Capybara::Driver::Base
3
+
4
+ # allows Capybara to have different behaviors depending on whether
5
+ # the current driver includes Kanye's algorithm
6
+ def kanye_invited?
7
+ true
8
+ end
9
+
10
+ private
11
+
12
+ def imma_let_you_finish
13
+ wait_for_in_progress_ajax_to_finish
14
+ disable_transitions_if_new_page
15
+ end
16
+
17
+ def remove_transitions
18
+ if DmcKanye::Config.script_to_disable_transitions.present?
19
+ evaluate_script DmcKanye::Config.script_to_disable_transitions
20
+ end
21
+ rescue Capybara::NotSupportedByDriverError
22
+ false
23
+ end
24
+
25
+ # if we are on a new page, run some JavaScript that attempts to disable
26
+ # any JS/CSS transitions that would cause the browser process to get out of
27
+ # sync with the Capbyara test process
28
+ def disable_transitions_if_new_page
29
+ @__current_url = current_url
30
+ if @__current_url != @__previous_url
31
+ wait_for_page_to_finish_loading
32
+ remove_transitions
33
+ end
34
+ @__previous_url = @__current_url
35
+ end
36
+
37
+ end
38
+ end
39
+
40
+ ##### VIOLENT DUCK PUNCHING AHEAD
41
+ #
42
+ # Here we have overridden the behavior of a method in Capybara. The part
43
+ # that we added is highlighted below to make it easier when upgrading
44
+ # to a future version of Capybara.
45
+
46
+ ##### THIS CODE IS ORIGINAL
47
+ module Capybara
48
+ module Node
49
+ class Base
50
+ ##### START PUNCHING DUCKS
51
+ # orig code:
52
+ # def synchronize(seconds=Capybara.default_wait_time, options = {})
53
+ # new code:
54
+ def synchronize(seconds = nil, options = {})
55
+ kanye_in_the_house = session.driver.respond_to?(:kanye_invited?) && session.driver.kanye_invited?
56
+ if seconds
57
+ seconds_to_wait = seconds
58
+ elsif kanye_in_the_house
59
+ seconds_to_wait = DmcKanye::Config.default_wait_time || Capybara.default_wait_time
60
+ else
61
+ seconds_to_wait = Capybara.default_wait_time
62
+ end
63
+ ##### STOP PUNCHING DUCKS, BACK TO ORIGINAL CODE
64
+ start_time = Time.now
65
+
66
+ if session.synchronized
67
+ yield
68
+ else
69
+ session.synchronized = true
70
+ begin
71
+ ##### START PUNCHING DUCKS
72
+ # orig code:
73
+ # yield
74
+ # new code:
75
+ session.driver.send(:imma_let_you_finish) if kanye_in_the_house
76
+ result = yield
77
+ session.driver.send(:imma_let_you_finish) if kanye_in_the_house
78
+ result
79
+ ##### STOP PUNCHING DUCKS, BACK TO ORIGINAL CODE
80
+ rescue => e
81
+ session.raise_server_error!
82
+ raise e unless driver.wait?
83
+ raise e unless catch_error?(e, options[:errors])
84
+ ##### START PUNCHING DUCKS
85
+ # orig code:
86
+ # raise e if (Time.now - start_time) >= seconds
87
+ # new code:
88
+ raise e if (Time.now - start_time) >= seconds_to_wait
89
+ ##### STOP PUNCHING DUCKS, BACK TO ORIGINAL CODE
90
+ sleep(0.05)
91
+ raise Capybara::FrozenInTime, "time appears to be frozen, Capybara does not work with libraries which freeze time, consider using time travelling instead" if Time.now == start_time
92
+ reload if Capybara.automatic_reload
93
+ retry
94
+ ensure
95
+ session.synchronized = false
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,3 @@
1
+ module DmcKanye
2
+ VERSION = "0.0.1"
3
+ end
data/lib/dmc_kanye.rb ADDED
@@ -0,0 +1,8 @@
1
+ raise "Kanye is not allowed in this environment." unless Rails.env.test?
2
+
3
+ require "dmc_kanye/version"
4
+
5
+ require_relative 'dmc_kanye/duck_punching_insurance'
6
+ require_relative 'dmc_kanye/config'
7
+ require_relative 'dmc_kanye/driver_helpers'
8
+ require_relative 'dmc_kanye/imma_let_you_finish'
data/license.txt ADDED
@@ -0,0 +1,8 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2016 The District Management Council
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dmc_kanye
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Wyatt Greene
8
+ - Parker Morse
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2016-01-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.9'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.9'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ description: Kanye improves Capybara's synchronization algorithm by letting the browser
43
+ finish before the test keeps going. By doing this, Kanye also helps you tailor the
44
+ swiftness of your feature specs.
45
+ email:
46
+ - pmorse@dmcouncil.org
47
+ executables: []
48
+ extensions: []
49
+ extra_rdoc_files: []
50
+ files:
51
+ - ".gitignore"
52
+ - CONTRIBUTING.md
53
+ - Gemfile
54
+ - Gemfile.lock
55
+ - README.md
56
+ - Rakefile
57
+ - TODO.md
58
+ - bin/console
59
+ - bin/setup
60
+ - dmc_kanye.gemspec
61
+ - lib/dmc_kanye.rb
62
+ - lib/dmc_kanye/config.rb
63
+ - lib/dmc_kanye/driver_helpers.rb
64
+ - lib/dmc_kanye/duck_punching_insurance.rb
65
+ - lib/dmc_kanye/imma_let_you_finish.rb
66
+ - lib/dmc_kanye/version.rb
67
+ - license.txt
68
+ homepage: https://github.com/dmcouncil/dmc_kanye
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 2.2.2
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Imma let your AJAX finish, but these are the best feature tests of ALL TIME.
92
+ test_files: []