rspec-routes_coverage 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +81 -0
- data/Rakefile +2 -0
- data/lib/rspec-routes_coverage/dsl.rb +24 -0
- data/lib/rspec-routes_coverage/request_override.rb +16 -0
- data/lib/rspec-routes_coverage/version.rb +5 -0
- data/lib/rspec-routes_coverage.rb +115 -0
- data/lib/tasks/rspec-routes_coverage.rake +10 -0
- data/rspec-routes_coverage.gemspec +21 -0
- metadata +93 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Andrew Shaydurov
|
2
|
+
|
3
|
+
MIT License
|
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,81 @@
|
|
1
|
+
# Rspec::RoutesCoverage
|
2
|
+
|
3
|
+
Rails-RSpec plugin that will track the coverage of routes among your request specs. Intended for massive Rails JSON backends.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'rspec-routes_coverage'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
This gem allows tracking both – manual coverage and automatic coverage. Automatic coverage just works – as soon as any route got at least one request it will be considered auto-tested.
|
18
|
+
|
19
|
+
To allow manual coverage the gem defines `describe_request` helper. Being an extension of `describe`, this method requires route to be passed. Every route passed to `describe_request` will be considered manually-tested.
|
20
|
+
|
21
|
+
spec/requests/items_spec.rb:
|
22
|
+
```ruby
|
23
|
+
require 'spec_helper'
|
24
|
+
|
25
|
+
describe ItemsController do
|
26
|
+
|
27
|
+
describe_request :index, request_path: '/items', method: 'GET' do
|
28
|
+
it 'lists items' do
|
29
|
+
get '/items'
|
30
|
+
# ...
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# another style:
|
35
|
+
describe_request 'GET /items/:id' do
|
36
|
+
it 'shows item' do
|
37
|
+
get "/items/#{Item.first.id}"
|
38
|
+
# ...
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
Default gem output looks the following way:
|
46
|
+
|
47
|
+
Routes coverage stats:
|
48
|
+
Manually tested: 46/547
|
49
|
+
Auto tested: 34/547
|
50
|
+
Pending: 467/547
|
51
|
+
|
52
|
+
By default it contains no details. To get the complete listing of routes belonging to each category, you can use `LIST_ROUTES_COVERAGE=true` environment option:
|
53
|
+
|
54
|
+
$ LIST_ROUTES_COVERAGE=true rake spec
|
55
|
+
|
56
|
+
Alternatively you can run the following Rake task (ships with the gem):
|
57
|
+
|
58
|
+
$ rake spec:requests:coverage
|
59
|
+
|
60
|
+
## TODO
|
61
|
+
|
62
|
+
* Add the possibility to exclude some routes/namespaces from coverage analysis
|
63
|
+
|
64
|
+
## Contributing
|
65
|
+
|
66
|
+
1. Fork it
|
67
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
68
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
69
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
70
|
+
5. Create new Pull Request
|
71
|
+
|
72
|
+
## Credits
|
73
|
+
|
74
|
+
<img src="http://roundlake.ru/assets/logo.png" align="right" />
|
75
|
+
|
76
|
+
* Andrew Shaydurov ([@sandrew](https://github.com/sandrew))
|
77
|
+
* Boris Staal ([@_inossidabile](http://twitter.com/#!/_inossidabile))
|
78
|
+
|
79
|
+
## LICENSE
|
80
|
+
|
81
|
+
It is free software, and may be redistributed under the terms of MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module RSpec
|
2
|
+
module RoutesCoverage
|
3
|
+
module DSL
|
4
|
+
def describe_request(*args, &block)
|
5
|
+
verb, path = if args.last.is_a?(Hash) && args.last[:method] && args.last[:request_path]
|
6
|
+
[args.last[:method], args.last[:request_path]]
|
7
|
+
else
|
8
|
+
args[args[1].is_a?(String) ? 1 : 0].split ' '
|
9
|
+
end
|
10
|
+
|
11
|
+
describe *args do
|
12
|
+
before :all do
|
13
|
+
RSpec::RoutesCoverage.manually_remove_pending_route verb, path
|
14
|
+
end
|
15
|
+
|
16
|
+
instance_eval(&block) if block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
extend RSpec::RoutesCoverage::DSL
|
24
|
+
Module.send(:include, RSpec::RoutesCoverage::DSL)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'action_dispatch/testing/integration'
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module Integration
|
5
|
+
class Session
|
6
|
+
private
|
7
|
+
|
8
|
+
alias_method :_old_process_method, :process
|
9
|
+
|
10
|
+
def process(method, path, parameters = nil, rack_env = nil)
|
11
|
+
RSpec::RoutesCoverage.auto_remove_pending_route method, path
|
12
|
+
_old_process_method method, path, parameters, rack_env
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'colored'
|
2
|
+
require 'rspec/rails'
|
3
|
+
require 'rspec-routes_coverage/dsl'
|
4
|
+
require 'rspec-routes_coverage/request_override'
|
5
|
+
|
6
|
+
module RSpec
|
7
|
+
module RoutesCoverage
|
8
|
+
class Railtie < ::Rails::Railtie
|
9
|
+
railtie_name :'rspec-routes_coverage'
|
10
|
+
|
11
|
+
rake_tasks do
|
12
|
+
load "tasks/rspec-routes_coverage.rake"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
mattr_accessor :pending_routes
|
17
|
+
mattr_accessor :auto_tested_routes
|
18
|
+
mattr_accessor :manually_tested_routes
|
19
|
+
mattr_accessor :tested_routes_num
|
20
|
+
mattr_accessor :routes_num
|
21
|
+
|
22
|
+
def self.auto_remove_pending_route(verb, path)
|
23
|
+
recognize_route(verb, path) do |route|
|
24
|
+
auto_tested_routes << route unless auto_tested_routes.include?(route)
|
25
|
+
pending_routes.delete route
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.manually_remove_pending_route(verb, path)
|
30
|
+
recognize_route(verb, path) do |route|
|
31
|
+
manually_tested_routes << route unless manually_tested_routes.include?(route)
|
32
|
+
pending_routes.delete route
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.recognize_route(verb, path)
|
37
|
+
initialize_routes!
|
38
|
+
|
39
|
+
env = Rack::MockRequest.env_for path, method: verb.upcase
|
40
|
+
req = ::Rails.application.routes.request_class.new env
|
41
|
+
::Rails.application.routes.router.recognize(req) do |route|
|
42
|
+
yield route
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.initialize_routes!
|
47
|
+
return if self.pending_routes
|
48
|
+
|
49
|
+
::Rails.application.reload_routes!
|
50
|
+
self.pending_routes = ::Rails.application.routes.routes.routes.clone
|
51
|
+
|
52
|
+
selector = []
|
53
|
+
selector += RSpec.configuration.routes_coverage.exclude_namespaces.map do |n|
|
54
|
+
"^/#{n}/"
|
55
|
+
end
|
56
|
+
|
57
|
+
unless selector.blank?
|
58
|
+
selector = /(#{selector.join(')|(')})/
|
59
|
+
self.pending_routes.select!{|x| (x.path.spec.to_s =~ selector).nil?}
|
60
|
+
end
|
61
|
+
|
62
|
+
self.routes_num = ::Rails.application.routes.routes.routes.length
|
63
|
+
self.tested_routes_num = self.pending_routes.length
|
64
|
+
self.auto_tested_routes = []
|
65
|
+
self.manually_tested_routes = []
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
RSpec.configure do |config|
|
71
|
+
config.add_setting :routes_coverage
|
72
|
+
config.routes_coverage = OpenStruct.new
|
73
|
+
|
74
|
+
config.routes_coverage.exclude_namespaces = []
|
75
|
+
config.routes_coverage.exclude_routes = []
|
76
|
+
|
77
|
+
config.after(:suite) do
|
78
|
+
inspector = begin
|
79
|
+
require 'rails/application/route_inspector'
|
80
|
+
Rails::Application::RouteInspector
|
81
|
+
rescue
|
82
|
+
require 'action_dispatch/routing/inspector'
|
83
|
+
ActionDispatch::Routing::RoutesInspector
|
84
|
+
end.new
|
85
|
+
|
86
|
+
inspector.instance_eval do
|
87
|
+
def formatted_routes(routes)
|
88
|
+
verb_width = routes.map{ |r| r[:verb].length }.max
|
89
|
+
path_width = routes.map{ |r| r[:path].length }.max
|
90
|
+
|
91
|
+
routes.map do |r|
|
92
|
+
"#{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
if ENV['LIST_ROUTES_COVERAGE']
|
98
|
+
{ green: :manually_tested_routes, blue: :auto_tested_routes, yellow: :pending_routes }.each do |color, name|
|
99
|
+
puts "\n\n"
|
100
|
+
puts "#{name.to_s.humanize} (#{RSpec::RoutesCoverage.send(name).length}/#{RSpec::RoutesCoverage.routes_num})".send(color).bold
|
101
|
+
puts "\n"
|
102
|
+
inspector.format(RSpec::RoutesCoverage.send(name)).each do |route|
|
103
|
+
puts ' ' + route.send(color)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
else
|
107
|
+
puts "\n\n"
|
108
|
+
puts 'Routes coverage stats:'
|
109
|
+
puts " Routes to test: #{RSpec::RoutesCoverage.tested_routes_num}/#{RSpec::RoutesCoverage.routes_num}".magenta
|
110
|
+
puts " Manually tested: #{RSpec::RoutesCoverage.manually_tested_routes.length}/#{RSpec::RoutesCoverage.tested_routes_num}".green
|
111
|
+
puts " Auto tested: #{RSpec::RoutesCoverage.auto_tested_routes.length}/#{RSpec::RoutesCoverage.tested_routes_num}".blue
|
112
|
+
print " Pending: #{RSpec::RoutesCoverage.pending_routes.length}/#{RSpec::RoutesCoverage.tested_routes_num}".yellow
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
namespace :spec do
|
2
|
+
namespace :requests do
|
3
|
+
desc 'run requests specs with counting of untested routes'
|
4
|
+
task :coverage do
|
5
|
+
files = Dir["spec/requests/**/*_spec.rb"].map{|f| "./"+f}
|
6
|
+
ENV["LIST_ROUTES_COVERAGE"] = 'true'
|
7
|
+
exec "ruby -S rspec #{files.join ' '}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/rspec-routes_coverage/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Andrew Shaydurov", "Boris Staal"]
|
6
|
+
gem.email = ["a.shaydurov@roundlake.ru", "boris@roundlake.ru"]
|
7
|
+
gem.description = %q{Rails-RSpec plugin that will track the coverage of routes among your request specs}
|
8
|
+
gem.summary = %q{Rails-RSpec plugin that will track the coverage of routes among your request specs}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "rspec-routes_coverage"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = RSpec::RoutesCoverage::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'rspec-rails'
|
19
|
+
gem.add_dependency 'colored'
|
20
|
+
gem.add_dependency 'actionpack'
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rspec-routes_coverage
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Andrew Shaydurov
|
9
|
+
- Boris Staal
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-11-24 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec-rails
|
17
|
+
requirement: &70214687526240 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *70214687526240
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: colored
|
28
|
+
requirement: &70214687580880 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *70214687580880
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: actionpack
|
39
|
+
requirement: &70214687579620 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
type: :runtime
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *70214687579620
|
48
|
+
description: Rails-RSpec plugin that will track the coverage of routes among your
|
49
|
+
request specs
|
50
|
+
email:
|
51
|
+
- a.shaydurov@roundlake.ru
|
52
|
+
- boris@roundlake.ru
|
53
|
+
executables: []
|
54
|
+
extensions: []
|
55
|
+
extra_rdoc_files: []
|
56
|
+
files:
|
57
|
+
- .gitignore
|
58
|
+
- Gemfile
|
59
|
+
- LICENSE
|
60
|
+
- README.md
|
61
|
+
- Rakefile
|
62
|
+
- lib/rspec-routes_coverage.rb
|
63
|
+
- lib/rspec-routes_coverage/dsl.rb
|
64
|
+
- lib/rspec-routes_coverage/request_override.rb
|
65
|
+
- lib/rspec-routes_coverage/version.rb
|
66
|
+
- lib/tasks/rspec-routes_coverage.rake
|
67
|
+
- rspec-routes_coverage.gemspec
|
68
|
+
homepage: ''
|
69
|
+
licenses: []
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.8.15
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Rails-RSpec plugin that will track the coverage of routes among your request
|
92
|
+
specs
|
93
|
+
test_files: []
|