integration-tests-rails 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 +7 -0
- data/MIT-LICENSE +22 -0
- data/README.md +211 -0
- data/lib/generators/integration_tests_rails/install_generator.rb +50 -0
- data/lib/generators/integration_tests_rails/templates/tests_controller.rb +36 -0
- data/lib/integration_tests_rails/capybara/helpers.rb +26 -0
- data/lib/integration_tests_rails/capybara/local.rb +41 -0
- data/lib/integration_tests_rails/capybara/remote.rb +49 -0
- data/lib/integration_tests_rails/capybara/util.rb +54 -0
- data/lib/integration_tests_rails/capybara.rb +28 -0
- data/lib/integration_tests_rails/configuration.rb +46 -0
- data/lib/integration_tests_rails/istanbul/collector.rb +172 -0
- data/lib/integration_tests_rails/istanbul/instrumenter.rb +65 -0
- data/lib/integration_tests_rails/istanbul/util.rb +35 -0
- data/lib/integration_tests_rails/istanbul.rb +24 -0
- data/lib/integration_tests_rails/version.rb +5 -0
- data/lib/integration_tests_rails.rb +31 -0
- metadata +129 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 30f959f27b2ebdf182bc6a8107f851baeb5f77805e02bfff5bf2dc591faecb5c
|
|
4
|
+
data.tar.gz: 4b5dbdb852a9aecef5346044bf3b6ddb2f3349fa92e62411d39af6bd6c8a1b05
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: f52d395e2dd5ab6fe1726e050f28c9dd34b8153a6d6e7b45dabd61ac15b0a1bac9f5aa15d49e1bc5247d0a2c42e84b9ee9ec0c98bb831ec6a535d526a77c5cb0
|
|
7
|
+
data.tar.gz: f370d6841dfc1a179f8cf20aee07ff137f6f38f45eceeabb1838e0a5cde9902d9d04c5df8b7e5e498ce5c9fdb43d3db1de03f27bb5069359bc5d46f099fc614c
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Integration Tests Rails
|
|
2
|
+
|
|
3
|
+
This gem is designed to facilitate integration testing in Ruby on Rails applications. It provides a streamlined way to configure and run integration tests while capturing coverage data for JavaScript files.
|
|
4
|
+
|
|
5
|
+
## Tech Stack
|
|
6
|
+
|
|
7
|
+
- **Ruby on Rails** - The primary framework for building web applications.
|
|
8
|
+
- **RSpec** - A testing tool for Ruby, used for writing and executing test cases.
|
|
9
|
+
- **Capybara** - A library that helps you test web applications by simulating how a real user would interact with your app.
|
|
10
|
+
- **Cuprite** - A Capybara driver that uses Chrome DevTools Protocol.
|
|
11
|
+
- **Istanbul** - A JavaScript code coverage tool.
|
|
12
|
+
- **Puma** - A concurrent web server.
|
|
13
|
+
|
|
14
|
+
## Getting Started
|
|
15
|
+
|
|
16
|
+
### Installation
|
|
17
|
+
|
|
18
|
+
Add this line to your Rails application's Gemfile:
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
group :development, :test do
|
|
22
|
+
gem 'integration_tests_rails', require: false
|
|
23
|
+
end
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Test environment is needed to run integration tests. Development environment is needed to be able to use terminal commands provided by the gem.
|
|
27
|
+
|
|
28
|
+
After adding the gem, run the following command to install it:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
bundle install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
After installation, run:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
rails generate integration_tests_rails:install
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If you do not have `Yarn` installed, the above command will prompt you to install it. Follow the instructions to complete the installation. Re-run the command after installing `Yarn`.
|
|
41
|
+
|
|
42
|
+
The generator will do the following:
|
|
43
|
+
- Install Instanbul using Yarn.
|
|
44
|
+
- Create a controller that can be used to *unit test JavaScript code*.
|
|
45
|
+
- Add a line in `routes.rb` to route requests to the above controller.
|
|
46
|
+
- Add an entry in `.gitignore` to ignore coverage reports and locally installed Istanbul packages.
|
|
47
|
+
|
|
48
|
+
### Configuration
|
|
49
|
+
|
|
50
|
+
Since test suites can vary greatly between applications, manual setup of the configuration may vary. It is recommended to create a separate helper file alongside `spec_helper.rb` and `rails_helper.rb`.
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
# spec/capybara_helper.rb
|
|
54
|
+
|
|
55
|
+
require 'integration_tests_rails'
|
|
56
|
+
|
|
57
|
+
IntegrationTestsRails.setup
|
|
58
|
+
|
|
59
|
+
require_relative 'features/tests_controller' # Loads the controller for unit testing JavaScript.
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The `IntegrationTestsRails.setup` method accepts an optional block for further customization. Below is an example how to use and contains the default values:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
IntegrationTestsRails.setup do |config|
|
|
66
|
+
config.chrome_url = nil # Used for remote Chrome instances. Needs remote to be true.
|
|
67
|
+
config.max_server_retries = 1000 # Before running the tests, Cuprite starts a server to communicate with Chrome. This sets the maximum number of retries to connect to that server.
|
|
68
|
+
config.puma_threads = '1:1' # Number of threads for the Puma server used by Cuprite.
|
|
69
|
+
config.remote = false # Whether to use a remote Chrome instance.
|
|
70
|
+
config.server_host = '0.0.0.0' # Host for the Puma server used by Cuprite.
|
|
71
|
+
config.server_port = nil # Port for the Puma server used by Cuprite.
|
|
72
|
+
config.source_dir = 'app/javascript' # Directory containing the JavaScript files to be instrumented.
|
|
73
|
+
config.verbose = false # Whether to enable verbose logging.
|
|
74
|
+
config.wait_time = 5 # Max time in seconds to wait after each request by Capybara to load content.
|
|
75
|
+
config.window_size = [1920, 1080] # Size of the browser window used by Cuprite.
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Unit Testing JavaScript Code
|
|
80
|
+
|
|
81
|
+
### Usage
|
|
82
|
+
|
|
83
|
+
To unit test JavaScript code, the provided `TestsController (spec/support/features/tests_controller)` can be modified. By default, it only renders a complete HTML page that also loads importmap-supporting JavaScript code to set up the environment for testing.
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
class TestsController < ActionController::Base
|
|
87
|
+
def index
|
|
88
|
+
render inline: <<~HTML.squish
|
|
89
|
+
<!DOCTYPE html>
|
|
90
|
+
<html lang="en">
|
|
91
|
+
<head>
|
|
92
|
+
<meta charset="UTF-8">
|
|
93
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
94
|
+
<meta name="turbo-visit-control" content="reload">
|
|
95
|
+
<%%= csrf_meta_tags %>
|
|
96
|
+
<%%= csp_meta_tag %>
|
|
97
|
+
<%%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
|
|
98
|
+
<%%= stylesheet_link_tag 'custom', "data-turbo-track": "reload" %>
|
|
99
|
+
<%%= javascript_importmap_tags %>
|
|
100
|
+
</head>
|
|
101
|
+
<body>
|
|
102
|
+
</body>
|
|
103
|
+
</html>
|
|
104
|
+
HTML
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Since vendored JavaScript are not included by default, additional tags may be required to load them. For example, if there exists a `custom_code.js` file in `app/javascript`:
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
<<~HTML.squish
|
|
113
|
+
<!DOCTYPE html>
|
|
114
|
+
<html lang="en">
|
|
115
|
+
<head>
|
|
116
|
+
<meta charset="UTF-8">
|
|
117
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
118
|
+
<meta name="turbo-visit-control" content="reload">
|
|
119
|
+
<%%= csrf_meta_tags %>
|
|
120
|
+
<%%= csp_meta_tag %>
|
|
121
|
+
<%%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
|
|
122
|
+
<%%= stylesheet_link_tag 'custom', "data-turbo-track": "reload" %>
|
|
123
|
+
<%%= javascript_importmap_tags %>
|
|
124
|
+
|
|
125
|
+
<script type="module">
|
|
126
|
+
import CustomCode from 'custom_code';
|
|
127
|
+
window.CustomCode = CustomCode;
|
|
128
|
+
</script>
|
|
129
|
+
</head>
|
|
130
|
+
<body>
|
|
131
|
+
</body>
|
|
132
|
+
</html>
|
|
133
|
+
HTML
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Writing Tests
|
|
137
|
+
|
|
138
|
+
Tests can be written using RSpec and Capybara as follows:
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
require 'capybara_helper'
|
|
142
|
+
|
|
143
|
+
RSpec.describe 'Custom Code Unit Test', type: :feature, unit: true do
|
|
144
|
+
describe '#doSomething' do
|
|
145
|
+
let(:script) do
|
|
146
|
+
'CustomCode.doSomething();'
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'does something' do
|
|
150
|
+
expect(result).to eq('Did something!')
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The `script` component is the JavaScript code that will be executed for the test. The `result` component will contain the return value of the evaluated script. The `script` can accept string or heredoc formats:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
let(:script) do
|
|
160
|
+
<<~JS
|
|
161
|
+
CustomCode.doSomething();
|
|
162
|
+
JS
|
|
163
|
+
end
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Do note that **the `script` component can execute one statement only**. If multiple statements are needed, consider wrapping them in a function and invoking that function in the `script` component.
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
let(:script) do
|
|
170
|
+
<<~JS
|
|
171
|
+
(() => {
|
|
172
|
+
const value1 = CustomCode.getValue1();
|
|
173
|
+
const value2 = CustomCode.getValue2();
|
|
174
|
+
return CustomCode.combineValues(value1, value2);
|
|
175
|
+
})();
|
|
176
|
+
JS
|
|
177
|
+
end
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The above will successfully execute the three statements and return the value in `result`. However, this can become a problem if the JavaScript code being tested relies on waiting for each statement to complete. In such cases, it is recommended to use an array instead in `script`:
|
|
181
|
+
|
|
182
|
+
```ruby
|
|
183
|
+
let(:script) do
|
|
184
|
+
[
|
|
185
|
+
<<~JS,
|
|
186
|
+
CustomCode.initialize();
|
|
187
|
+
CustomCode.doSomething();
|
|
188
|
+
JS
|
|
189
|
+
'CustomCode.openModal()',
|
|
190
|
+
'CustomCode.closeModal()'
|
|
191
|
+
]
|
|
192
|
+
end
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
In such cases where `script` is an array, the `result` component will contain the return value of the **last statement only**.
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
## Integration Testing
|
|
199
|
+
|
|
200
|
+
Refer to [Cuprite](https://github.com/rubycdp/cuprite) and [Capybara](https://github.com/teamcapybara/capybara). Use them as normally in integration tests.
|
|
201
|
+
|
|
202
|
+
## JavaScript Coverage Reports
|
|
203
|
+
|
|
204
|
+
After the tests (successful, failed or cancelled), coverage reports will be generated in `coverage/javascript` by default.
|
|
205
|
+
|
|
206
|
+
## Contributing
|
|
207
|
+
|
|
208
|
+
1. Fork the repository.
|
|
209
|
+
2. Create a new branch for your feature or bugfix.
|
|
210
|
+
3. Make your changes.
|
|
211
|
+
5. Submit a pull request describing your changes.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
|
|
5
|
+
module IntegrationTestsRails
|
|
6
|
+
module Generators
|
|
7
|
+
# Generator responsible for setting up the Rails project with necessary tools to make integration testing possible.
|
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
|
9
|
+
source_root File.expand_path('templates', __dir__)
|
|
10
|
+
|
|
11
|
+
desc 'Initialize project for integration testing.'
|
|
12
|
+
|
|
13
|
+
def install_node_dependencies
|
|
14
|
+
unless system('which yarn > /dev/null 2>&1')
|
|
15
|
+
say 'Yarn is not installed. Please install Yarn first: https://yarnpkg.com/getting-started/install', :red
|
|
16
|
+
exit 1
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
say 'Installing Istanbul...', :green
|
|
20
|
+
run 'yarn add --dev istanbul-lib-instrument istanbul-lib-coverage istanbul-lib-report istanbul-reports'
|
|
21
|
+
run 'yarn install'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def copy_tests_controller
|
|
25
|
+
template 'tests_controller.rb', 'spec/support/features/tests_controller.rb'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def add_route
|
|
29
|
+
route 'resources(:tests, only: :index) if Rails.env.test?'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def update_gitignore
|
|
33
|
+
gitignore_path = '.gitignore'
|
|
34
|
+
lines_to_add = ['node_modules/', 'coverage/']
|
|
35
|
+
|
|
36
|
+
return unless File.exist?(gitignore_path)
|
|
37
|
+
|
|
38
|
+
content = File.read(gitignore_path)
|
|
39
|
+
lines_to_add.each do |line|
|
|
40
|
+
if content.include?(line)
|
|
41
|
+
say "'#{line}' already exists in .gitignore", :blue
|
|
42
|
+
else
|
|
43
|
+
append_to_file gitignore_path, "\n#{line}\n"
|
|
44
|
+
say "Added '#{line}' to .gitignore", :green
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This provides a minimal page that loads your JavaScript
|
|
4
|
+
class TestsController < ActionController::Base
|
|
5
|
+
def index
|
|
6
|
+
render inline: <<~HTML.squish
|
|
7
|
+
<!DOCTYPE html>
|
|
8
|
+
<html lang="en">
|
|
9
|
+
<head>
|
|
10
|
+
<meta charset="UTF-8">
|
|
11
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
12
|
+
<meta name="turbo-visit-control" content="reload">
|
|
13
|
+
<%%= csrf_meta_tags %>
|
|
14
|
+
<%%= csp_meta_tag %>
|
|
15
|
+
<%%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
|
|
16
|
+
<%%= stylesheet_link_tag 'custom', "data-turbo-track": "reload" %>
|
|
17
|
+
<%%= javascript_importmap_tags %>
|
|
18
|
+
<!-- If there are JavaScript libraries not globally available, include them here for testing.-->
|
|
19
|
+
<!-- E.g. The block below shows how to import a JavaScript module and attach it to the window object. -->
|
|
20
|
+
<!-- The file is located in app/javascripts/libs/my_library.js -->
|
|
21
|
+
<!--
|
|
22
|
+
<script type="module">
|
|
23
|
+
import MyLibrary from 'libs/my_library';
|
|
24
|
+
window.MyLibrary = MyLibrary;
|
|
25
|
+
</script>
|
|
26
|
+
-->
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<!-- Include JavaScript libraries here instead if they need to be loaded much later. -->
|
|
30
|
+
<!-- E.g. The line below loads a JavaScript file located in app/assets/javascripts/plugins/vendor.min.js -->
|
|
31
|
+
<%%#= javascript_include_tag 'plugins/vendor.min' %>
|
|
32
|
+
</body>
|
|
33
|
+
</html>
|
|
34
|
+
HTML
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IntegrationTestsRails
|
|
4
|
+
module Capybara
|
|
5
|
+
# Adds helpers to enable unit testing.
|
|
6
|
+
module Helper
|
|
7
|
+
extend RSpec::SharedContext
|
|
8
|
+
|
|
9
|
+
let(:result) do
|
|
10
|
+
case script
|
|
11
|
+
when Array
|
|
12
|
+
script.map { |cmd| page.evaluate_script(cmd) }.last
|
|
13
|
+
when String
|
|
14
|
+
page.evaluate_script(script)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
let(:script) { nil }
|
|
19
|
+
|
|
20
|
+
before do
|
|
21
|
+
visit tests_path
|
|
22
|
+
result
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IntegrationTestsRails
|
|
4
|
+
module Capybara
|
|
5
|
+
# Configure Capybara to use local Chrome browser via Cuprite.
|
|
6
|
+
module Local
|
|
7
|
+
class << self
|
|
8
|
+
def setup
|
|
9
|
+
config = IntegrationTestsRails.configuration
|
|
10
|
+
|
|
11
|
+
::Capybara.default_max_wait_time = config.wait_time
|
|
12
|
+
::Capybara.server = :puma, { Silent: !Util.verbose? }
|
|
13
|
+
|
|
14
|
+
register_driver
|
|
15
|
+
Util.log 'Local Chrome Mode: Server is running locally'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def register_driver
|
|
21
|
+
config = IntegrationTestsRails.configuration
|
|
22
|
+
|
|
23
|
+
::Capybara.register_driver(:cuprite) do |app|
|
|
24
|
+
options = {
|
|
25
|
+
window_size: config.window_size,
|
|
26
|
+
browser_options: {
|
|
27
|
+
'no-sandbox' => nil,
|
|
28
|
+
'disable-dev-shm-usage' => nil,
|
|
29
|
+
'disable-web-security' => nil,
|
|
30
|
+
'disable-gpu' => nil
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Util.log 'Registered Cuprite driver using local configuration'
|
|
35
|
+
::Capybara::Cuprite::Driver.new(app, options)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IntegrationTestsRails
|
|
4
|
+
module Capybara
|
|
5
|
+
# Configure Capybara to use remote Chrome browser via Cuprite.
|
|
6
|
+
module Remote
|
|
7
|
+
class << self
|
|
8
|
+
def setup
|
|
9
|
+
config = IntegrationTestsRails.configuration
|
|
10
|
+
server_host = config.server_host
|
|
11
|
+
server_port = config.server_port
|
|
12
|
+
|
|
13
|
+
::Capybara.server_host = server_host
|
|
14
|
+
::Capybara.server_port = server_port
|
|
15
|
+
::Capybara.default_max_wait_time = config.wait_time
|
|
16
|
+
::Capybara.app_host = "http://localhost:#{server_port}"
|
|
17
|
+
::Capybara.server = :puma, {
|
|
18
|
+
Silent: !Util.verbose?,
|
|
19
|
+
Host: server_host,
|
|
20
|
+
Port: server_port,
|
|
21
|
+
Threads: config.puma_threads
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
register_driver
|
|
25
|
+
Util.log "Remote Chrome Mode: Test server bound to #{server_host}:#{server_port}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def register_driver
|
|
31
|
+
config = IntegrationTestsRails.configuration
|
|
32
|
+
|
|
33
|
+
::Capybara.register_driver(:cuprite) do |app|
|
|
34
|
+
timeout = config.timeout
|
|
35
|
+
options = {
|
|
36
|
+
window_size: config.window_size,
|
|
37
|
+
url: config.chrome_url,
|
|
38
|
+
timeout: timeout,
|
|
39
|
+
process_timeout: timeout
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
Util.log 'Registered Cuprite driver using remote configuration'
|
|
43
|
+
::Capybara::Cuprite::Driver.new(app, options)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'helpers'
|
|
4
|
+
|
|
5
|
+
module IntegrationTestsRails
|
|
6
|
+
module Capybara
|
|
7
|
+
# Utilities for Capybara setup and configuration are found here.
|
|
8
|
+
module Util
|
|
9
|
+
class << self
|
|
10
|
+
def configure_webmock
|
|
11
|
+
WebMock.disable_net_connect!(allow_localhost: true)
|
|
12
|
+
log 'WebMock configured to allow localhost connections'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ensure_server_ready(context)
|
|
16
|
+
return if @server_ready
|
|
17
|
+
|
|
18
|
+
config = IntegrationTestsRails.configuration
|
|
19
|
+
log "Waiting for server on #{::Capybara.app_host.presence || 'localhost'} to start..."
|
|
20
|
+
|
|
21
|
+
server_retries = config.max_server_retries
|
|
22
|
+
server_retries.times do |attempt|
|
|
23
|
+
context.visit('/400')
|
|
24
|
+
@server_ready = true
|
|
25
|
+
log 'Server is ready!'
|
|
26
|
+
break
|
|
27
|
+
rescue StandardError
|
|
28
|
+
log "Server not ready (attempt #{attempt + 1}/#{server_retries})."
|
|
29
|
+
end
|
|
30
|
+
log "Server did not start after #{server_retries} attempts..." unless @server_ready
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def configure_rspec
|
|
34
|
+
RSpec.configure do |config|
|
|
35
|
+
config.before(:each, type: :feature) do
|
|
36
|
+
::Capybara.current_driver = ::Capybara.javascript_driver
|
|
37
|
+
IntegrationTestsRails::Capybara::Util.ensure_server_ready(self)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
config.include(Helper, type: :feature, unit: true)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def verbose?
|
|
45
|
+
IntegrationTestsRails.configuration.verbose
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def log(message)
|
|
49
|
+
puts "[CAPYBARA] #{message}" if verbose?
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'capybara/cuprite'
|
|
4
|
+
require_relative 'capybara/util'
|
|
5
|
+
require_relative 'capybara/remote'
|
|
6
|
+
require_relative 'capybara/local'
|
|
7
|
+
|
|
8
|
+
module IntegrationTestsRails
|
|
9
|
+
# This contains the Capybara setup and configuration.
|
|
10
|
+
module Capybara
|
|
11
|
+
class << self
|
|
12
|
+
def setup
|
|
13
|
+
config = IntegrationTestsRails.configuration
|
|
14
|
+
|
|
15
|
+
::Capybara.javascript_driver = :cuprite
|
|
16
|
+
|
|
17
|
+
if config.remote
|
|
18
|
+
Remote.setup
|
|
19
|
+
else
|
|
20
|
+
Local.setup
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Util.configure_rspec
|
|
24
|
+
Util.configure_webmock
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IntegrationTestsRails
|
|
4
|
+
# Configuration class for this gem to modify adjustable settings for Capybara, Cuprite and Istanbul.
|
|
5
|
+
class Configuration
|
|
6
|
+
attr_accessor :source_dir, :output_dir, :backup_dir, :coverage_path, :wait_time, :remote, :chrome_url,
|
|
7
|
+
:verbose, :timeout, :server_host, :server_port, :puma_threads, :window_size, :max_server_retries
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@backup_dir = 'tmp/js_backup'
|
|
11
|
+
@chrome_url = nil
|
|
12
|
+
@coverage_path = 'coverage/nyc'
|
|
13
|
+
@max_server_retries = 1000
|
|
14
|
+
@output_dir = 'tmp/instrumented_js'
|
|
15
|
+
@puma_threads = '1:1'
|
|
16
|
+
@remote = false
|
|
17
|
+
@server_host = '0.0.0.0' # rubocop:disable Style/IpAddresses
|
|
18
|
+
@server_port = nil
|
|
19
|
+
@source_dir = 'app/javascript'
|
|
20
|
+
@timeout = 30
|
|
21
|
+
@verbose = false
|
|
22
|
+
@wait_time = 5
|
|
23
|
+
@window_size = [1920, 1080]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def source_path
|
|
27
|
+
Rails.root.join(source_dir)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def output_path
|
|
31
|
+
Rails.root.join(output_dir)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def backup_path
|
|
35
|
+
Rails.root.join(backup_dir)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def coverage_dir
|
|
39
|
+
Rails.root.join(coverage_path)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def coverage_file
|
|
43
|
+
coverage_dir.join('coverage.json')
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'pathname'
|
|
6
|
+
require 'shellwords'
|
|
7
|
+
|
|
8
|
+
module IntegrationTestsRails
|
|
9
|
+
module Istanbul
|
|
10
|
+
# Collects reports and manages instrumented files.
|
|
11
|
+
module Collector
|
|
12
|
+
class << self
|
|
13
|
+
def setup
|
|
14
|
+
config = IntegrationTestsRails.configuration
|
|
15
|
+
|
|
16
|
+
# Instrument files
|
|
17
|
+
Instrumenter.instrument_all
|
|
18
|
+
|
|
19
|
+
# Backup and replace original files
|
|
20
|
+
backup_and_replace_files
|
|
21
|
+
|
|
22
|
+
# Clean previous coverage data
|
|
23
|
+
coverage_dir = config.coverage_dir
|
|
24
|
+
FileUtils.rm_rf(coverage_dir)
|
|
25
|
+
FileUtils.mkdir_p(coverage_dir)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def collect(page)
|
|
29
|
+
coverage_data = page.evaluate_script('window.__coverage__')
|
|
30
|
+
save_coverage_snapshot(coverage_data) if coverage_data.present?
|
|
31
|
+
rescue StandardError => e
|
|
32
|
+
Util.log "Coverage collection failed: #{e.message}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def generate_report
|
|
36
|
+
# Generate report using Node.js (will merge all snapshot files)
|
|
37
|
+
report_script = build_report_script
|
|
38
|
+
output = `node -e #{Shellwords.escape(report_script)} 2>&1`.strip
|
|
39
|
+
|
|
40
|
+
# Parse and display coverage summary
|
|
41
|
+
return if output.blank?
|
|
42
|
+
|
|
43
|
+
begin
|
|
44
|
+
data = JSON.parse(output)
|
|
45
|
+
puts "\nJavaScript Coverage: #{data['covered']} / #{data['total']} LOC (#{data['pct']}%) covered."
|
|
46
|
+
puts "Coverage report: coverage/javascript/index.html\n"
|
|
47
|
+
rescue JSON::ParserError
|
|
48
|
+
puts output
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def restore_original_files
|
|
53
|
+
config = IntegrationTestsRails.configuration
|
|
54
|
+
|
|
55
|
+
backup_dir = config.backup_path
|
|
56
|
+
source_dir = config.source_path
|
|
57
|
+
|
|
58
|
+
return unless Dir.exist?(backup_dir)
|
|
59
|
+
|
|
60
|
+
FileUtils.rm_rf(source_dir)
|
|
61
|
+
FileUtils.cp_r(backup_dir, source_dir)
|
|
62
|
+
Util.log '✓ Restored original JavaScript files'
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def backup_and_replace_files
|
|
68
|
+
config = IntegrationTestsRails.configuration
|
|
69
|
+
source_path = config.source_path
|
|
70
|
+
backup_path = config.backup_path
|
|
71
|
+
output_path = config.output_path
|
|
72
|
+
|
|
73
|
+
# Backup originals
|
|
74
|
+
FileUtils.rm_rf(backup_path)
|
|
75
|
+
FileUtils.cp_r(source_path, backup_path)
|
|
76
|
+
|
|
77
|
+
# Replace with instrumented
|
|
78
|
+
Dir.glob(output_path.join('**/*.js')).each do |instrumented_file|
|
|
79
|
+
relative_path = Pathname.new(instrumented_file).relative_path_from(output_path)
|
|
80
|
+
target_file = source_path.join(relative_path)
|
|
81
|
+
FileUtils.cp(instrumented_file, target_file)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def save_coverage_snapshot(coverage_data)
|
|
86
|
+
config = IntegrationTestsRails.configuration
|
|
87
|
+
|
|
88
|
+
snapshot_file = config.coverage_dir.join("js-#{Time.now.to_f.to_s.tr('.', '-')}.json")
|
|
89
|
+
File.write(snapshot_file, JSON.pretty_generate(coverage_data))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def build_report_script
|
|
93
|
+
config = IntegrationTestsRails.configuration
|
|
94
|
+
|
|
95
|
+
<<~JS
|
|
96
|
+
const libCoverage = require('istanbul-lib-coverage');
|
|
97
|
+
const libReport = require('istanbul-lib-report');
|
|
98
|
+
const reports = require('istanbul-reports');
|
|
99
|
+
const fs = require('fs');
|
|
100
|
+
const path = require('path');
|
|
101
|
+
|
|
102
|
+
const coverageDir = '#{config.coverage_dir}';
|
|
103
|
+
const files = fs.readdirSync(coverageDir).filter(f => f.startsWith('js-') && f.endsWith('.json'));
|
|
104
|
+
|
|
105
|
+
const coverageMap = libCoverage.createCoverageMap();
|
|
106
|
+
|
|
107
|
+
files.forEach(file => {
|
|
108
|
+
const filePath = path.join(coverageDir, file);
|
|
109
|
+
const coverage = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
110
|
+
coverageMap.merge(coverage);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Add all instrumented files (even those with 0% coverage)
|
|
114
|
+
function findJsFiles(dir, fileList = []) {
|
|
115
|
+
const items = fs.readdirSync(dir);
|
|
116
|
+
items.forEach(item => {
|
|
117
|
+
const fullPath = path.join(dir, item);
|
|
118
|
+
const stat = fs.statSync(fullPath);
|
|
119
|
+
if (stat.isDirectory()) {
|
|
120
|
+
findJsFiles(fullPath, fileList);
|
|
121
|
+
} else if (item.endsWith('.js')) {
|
|
122
|
+
fileList.push(fullPath);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
return fileList;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const instrumentedDir = '#{config.output_path}';
|
|
129
|
+
const instrumentedFiles = findJsFiles(instrumentedDir);
|
|
130
|
+
|
|
131
|
+
instrumentedFiles.forEach(instrumentedFile => {
|
|
132
|
+
const relativePath = path.relative(instrumentedDir, instrumentedFile);
|
|
133
|
+
const originalFile = path.join('#{config.source_path}', relativePath);
|
|
134
|
+
|
|
135
|
+
if (coverageMap.data[originalFile]) return;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const code = fs.readFileSync(instrumentedFile, 'utf8');
|
|
139
|
+
const match = code.match(/var coverageData = (\\{[\\s\\S]+?\\});/);
|
|
140
|
+
|
|
141
|
+
if (match && match[1]) {
|
|
142
|
+
const coverageData = eval('(' + match[1] + ')');
|
|
143
|
+
coverageData.path = originalFile;
|
|
144
|
+
coverageMap.addFileCoverage(coverageData);
|
|
145
|
+
}
|
|
146
|
+
} catch(e) {
|
|
147
|
+
// Skip files that can't be parsed
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const context = libReport.createContext({
|
|
152
|
+
dir: 'coverage/javascript',
|
|
153
|
+
coverageMap: coverageMap
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
['html', 'lcov', 'cobertura'].forEach(reportType => {
|
|
157
|
+
const report = reports.create(reportType, {});
|
|
158
|
+
report.execute(context);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const summary = coverageMap.getCoverageSummary();
|
|
162
|
+
console.log(JSON.stringify({
|
|
163
|
+
covered: summary.lines.covered,
|
|
164
|
+
total: summary.lines.total,
|
|
165
|
+
pct: summary.lines.pct.toFixed(2)
|
|
166
|
+
}));
|
|
167
|
+
JS
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'pathname'
|
|
6
|
+
require 'shellwords'
|
|
7
|
+
|
|
8
|
+
module IntegrationTestsRails
|
|
9
|
+
module Istanbul
|
|
10
|
+
# Instruments JavaScript files for code coverage using Istanbul.
|
|
11
|
+
module Instrumenter
|
|
12
|
+
class << self
|
|
13
|
+
def instrument_all
|
|
14
|
+
config = IntegrationTestsRails.configuration
|
|
15
|
+
output_path = config.output_path
|
|
16
|
+
|
|
17
|
+
# Clean output directory
|
|
18
|
+
FileUtils.rm_rf(output_path)
|
|
19
|
+
FileUtils.mkdir_p(output_path)
|
|
20
|
+
|
|
21
|
+
# Find all JS files
|
|
22
|
+
js_files = Dir.glob(config.source_path.join('**/*.js'))
|
|
23
|
+
Util.log "Instrumenting #{js_files.length} JavaScript files..."
|
|
24
|
+
|
|
25
|
+
js_files.each do |file|
|
|
26
|
+
instrument_file(file)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
Util.log '✓ Instrumented files created'
|
|
30
|
+
Util.log '=== Istanbul Instrumentation Complete ==='
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def instrument_file(file)
|
|
34
|
+
config = IntegrationTestsRails.configuration
|
|
35
|
+
|
|
36
|
+
relative_path = Pathname.new(file).relative_path_from(config.source_path)
|
|
37
|
+
output_file = config.output_path.join(relative_path)
|
|
38
|
+
|
|
39
|
+
FileUtils.mkdir_p(output_file.dirname)
|
|
40
|
+
|
|
41
|
+
# Use Node.js to instrument the file
|
|
42
|
+
code = File.read(file)
|
|
43
|
+
escaped_code = JSON.generate(code)
|
|
44
|
+
escaped_file = JSON.generate(file.to_s)
|
|
45
|
+
|
|
46
|
+
js_command = <<~JS
|
|
47
|
+
const { createInstrumenter } = require('istanbul-lib-instrument');
|
|
48
|
+
const instrumenter = createInstrumenter({ esModules: true, compact: false });
|
|
49
|
+
const code = #{escaped_code};
|
|
50
|
+
const filename = #{escaped_file};
|
|
51
|
+
console.log(instrumenter.instrumentSync(code, filename));
|
|
52
|
+
JS
|
|
53
|
+
|
|
54
|
+
instrumented = `node -e #{Shellwords.escape(js_command)}`.strip
|
|
55
|
+
|
|
56
|
+
if $CHILD_STATUS.success?
|
|
57
|
+
File.write(output_file, instrumented)
|
|
58
|
+
else
|
|
59
|
+
warn "Failed to instrument #{relative_path}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IntegrationTestsRails
|
|
4
|
+
module Istanbul
|
|
5
|
+
# Utilities for Istanbul setup and configuration are found here.
|
|
6
|
+
module Util
|
|
7
|
+
class << self
|
|
8
|
+
def configure_rspec
|
|
9
|
+
RSpec.configure do |config|
|
|
10
|
+
config.before(:suite) do
|
|
11
|
+
Instrumenter.instrument_all
|
|
12
|
+
Collector.setup
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
config.after(:each, type: :feature) do
|
|
16
|
+
Collector.collect(page)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def log(message)
|
|
22
|
+
return unless verbose?
|
|
23
|
+
|
|
24
|
+
puts "[ISTANBUL] #{message}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def verbose?
|
|
30
|
+
IntegrationTestsRails.configuration&.verbose
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'istanbul/instrumenter'
|
|
4
|
+
require_relative 'istanbul/collector'
|
|
5
|
+
require_relative 'istanbul/util'
|
|
6
|
+
|
|
7
|
+
module IntegrationTestsRails
|
|
8
|
+
# This contains the Istanbul setup and configuration.
|
|
9
|
+
module Istanbul
|
|
10
|
+
class << self
|
|
11
|
+
def setup
|
|
12
|
+
Util.configure_rspec
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Ensure cleanup at exit, either success, failure or cancellation.
|
|
17
|
+
at_exit do
|
|
18
|
+
Collector.generate_report
|
|
19
|
+
Collector.restore_original_files
|
|
20
|
+
rescue StandardError => e
|
|
21
|
+
warn "Istanbul cleanup failed: #{e.message}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'integration_tests_rails/version'
|
|
4
|
+
require_relative 'integration_tests_rails/configuration'
|
|
5
|
+
require_relative 'integration_tests_rails/istanbul'
|
|
6
|
+
require_relative 'integration_tests_rails/capybara'
|
|
7
|
+
|
|
8
|
+
# The main module for the IntegrationTestsRails gem.
|
|
9
|
+
module IntegrationTestsRails
|
|
10
|
+
class << self
|
|
11
|
+
def configuration
|
|
12
|
+
@configuration ||= Configuration.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def configure
|
|
16
|
+
yield(configuration)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def reset_configuration!
|
|
20
|
+
@configuration = Configuration.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Convenience method to set up everything at once
|
|
24
|
+
def setup
|
|
25
|
+
yield(configuration) if block_given?
|
|
26
|
+
|
|
27
|
+
Capybara.setup
|
|
28
|
+
Istanbul.setup
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: integration-tests-rails
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Tien
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: capybara
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: cuprite
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: rails
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rspec-rails
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: webmock
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
email:
|
|
83
|
+
- tieeeeen1994@gmail.com
|
|
84
|
+
executables: []
|
|
85
|
+
extensions: []
|
|
86
|
+
extra_rdoc_files: []
|
|
87
|
+
files:
|
|
88
|
+
- MIT-LICENSE
|
|
89
|
+
- README.md
|
|
90
|
+
- lib/generators/integration_tests_rails/install_generator.rb
|
|
91
|
+
- lib/generators/integration_tests_rails/templates/tests_controller.rb
|
|
92
|
+
- lib/integration_tests_rails.rb
|
|
93
|
+
- lib/integration_tests_rails/capybara.rb
|
|
94
|
+
- lib/integration_tests_rails/capybara/helpers.rb
|
|
95
|
+
- lib/integration_tests_rails/capybara/local.rb
|
|
96
|
+
- lib/integration_tests_rails/capybara/remote.rb
|
|
97
|
+
- lib/integration_tests_rails/capybara/util.rb
|
|
98
|
+
- lib/integration_tests_rails/configuration.rb
|
|
99
|
+
- lib/integration_tests_rails/istanbul.rb
|
|
100
|
+
- lib/integration_tests_rails/istanbul/collector.rb
|
|
101
|
+
- lib/integration_tests_rails/istanbul/instrumenter.rb
|
|
102
|
+
- lib/integration_tests_rails/istanbul/util.rb
|
|
103
|
+
- lib/integration_tests_rails/version.rb
|
|
104
|
+
homepage: https://github.com/tieeeeen1994/integration-tests-rails
|
|
105
|
+
licenses:
|
|
106
|
+
- MIT
|
|
107
|
+
metadata:
|
|
108
|
+
homepage_uri: https://github.com/tieeeeen1994/integration-tests-rails
|
|
109
|
+
source_code_uri: https://github.com/tieeeeen1994/integration-tests-rails
|
|
110
|
+
rubygems_mfa_required: 'true'
|
|
111
|
+
rdoc_options: []
|
|
112
|
+
require_paths:
|
|
113
|
+
- lib
|
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
115
|
+
requirements:
|
|
116
|
+
- - ">="
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: 3.4.0
|
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
124
|
+
requirements: []
|
|
125
|
+
rubygems_version: 3.6.9
|
|
126
|
+
specification_version: 4
|
|
127
|
+
summary: Integration Testing for Rails applications using Istanbul, Cuprite, Capybara
|
|
128
|
+
and RSpec specifically.
|
|
129
|
+
test_files: []
|