smart_rspec 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: 56204d08a3ee3d45091216ca50b197a4d9b08095
4
+ data.tar.gz: dd3431e077d7ef0a94d6df2e8df66779f14c1705
5
+ SHA512:
6
+ metadata.gz: b5a735e0e33fb63863c343ad17b3a5daeb0282cc759d7a1852cc2a7c734db2d69cb58cea1724548841abe331b1b1d9261eb38d0a8099a08f679c13b8c33d5be6
7
+ data.tar.gz: 3afea96381aeb7aed7dedf20eabd1814e07e9cb08731760deba0fd8b10aef4de2447f41f4244b45e35445264107a1377763584badc84cd5ad903247ed12db72b
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.sw*
13
+ *.o
14
+ *.a
15
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in smart_rspec.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Tiago Guedes
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,206 @@
1
+ # SmartRspec
2
+
3
+ It's time to make your specs even more awesome! SmartRspec adds useful macros and matchers into the RSpec's test suite, this way you can quickly define specs for your Rails app and get focused on making things turn into green.
4
+
5
+ ## Installation
6
+
7
+ Compatible with Ruby 1.9+
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'smart_rspec'
12
+
13
+ Execute:
14
+
15
+ $ bundle
16
+
17
+ Require the gem at the top of your `spec/rails_helper.rb` (or equivalent):
18
+ ``` ruby
19
+ require 'smart_rspec'
20
+ ```
21
+
22
+ Then include the SmartRspec module:
23
+
24
+ ``` ruby
25
+ RSpec.configure do |config|
26
+ config.include SmartRspec
27
+ end
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ * [Macros](#macros)
33
+ * [has_attributes](#has_attributes)
34
+ * [belongs_to, has_one, has_many](#belongs_to-has_one-has_many)
35
+ * [fails_validation_of](#fails_validation_of)
36
+ * [Matchers](#matchers)
37
+ * [be_ascending](#be_ascending)
38
+ * [be_descending](#be_descending)
39
+ * [be_boolean](#be_boolean)
40
+ * [be_email](#be_email)
41
+ * [be_url](#be_url)
42
+ * [be_image_url](#be_image_url)
43
+ * [have](#have)
44
+ * [have_at_least](#have_at_least)
45
+ * [have_at_most](#have_at_most)
46
+ * [have_error_on](#have_error_on)
47
+ * [include_items](#include_items)
48
+
49
+ ### Macros
50
+
51
+ You will just need to define a valid `subject` to start using SmartRspec's macros in your spec file.
52
+
53
+ #### has_attributes
54
+
55
+ It builds specs for model attributes and test its type, enumerated values and defaults:
56
+ ``` ruby
57
+ RSpec.describe User, type: :model do
58
+ subject { FactoryGirl.build(:user) }
59
+
60
+ has_attributes :email, type: :String
61
+ has_attributes :is_admin, type: :Boolean
62
+ has_attributes :score, type: :Integer, default: 0
63
+ has_attributes :locale, type: :String, enum: %i(en pt), default: 'en'
64
+ end
65
+ ```
66
+
67
+ #### belongs_to, has_one, has_many
68
+
69
+ It builds specs and test model associations like `belongs_to`, `has_one` and `has_many`.
70
+ ``` ruby
71
+ RSpec.describe User, type: :model do
72
+ subject { FactoryGirl.build(:user) }
73
+
74
+ belongs_to :business
75
+ has_one :project
76
+ has_many :tasks
77
+ end
78
+ ```
79
+
80
+ #### fails_validation_of
81
+
82
+ It builds specs forcing model validations to fail, it means that you will only turn its specs into green when you specify the corresponding validation in the model.
83
+
84
+ ``` ruby
85
+ RSpec.describe User, type: :model do
86
+ subject { FactoryGirl.build(:user) }
87
+
88
+ fails_validation_of :email, presence: true, email: true
89
+ fails_validation_of :name, length: { maximum: 80 }, uniqueness: true
90
+ fails_validation_of :username, length: { minimum: 10 }, exclusion: { in: %w(foo bar) }
91
+ # Other validations...
92
+ end
93
+ ```
94
+
95
+ The `fails_validation_of` implements specs for the following validations:
96
+
97
+ - `presence`
98
+ - `email`
99
+ - `length`
100
+ - `exclusion`
101
+ - `inclusion`
102
+ - `uniqueness`
103
+ - `format`
104
+
105
+ In two cases it will require a valid mock to be passed so SmartRspec can use it to force the validation to fail properly.
106
+
107
+ For uniqueness with scope:
108
+ ``` ruby
109
+ other_user = FactoryGirl.build(:other_valid_user)
110
+ fails_validation_of :username, uniqueness: { scope: :name, mock: other_user }
111
+ ```
112
+
113
+ For format:
114
+ ``` ruby
115
+ fails_validation_of :foo, format: { with: /foo/, mock: 'bar' }
116
+ ```
117
+
118
+ ### Matchers
119
+
120
+ SmartRspec gathers a collection of custom useful matchers:
121
+
122
+ #### be_ascending
123
+
124
+ ``` ruby
125
+ it { expect([1, 2, 3, 4]).to be_ascending }
126
+ it { expect([1, 4, 2, 3]).not_to be_ascending }
127
+ ```
128
+
129
+ #### be_descending
130
+ ``` ruby
131
+ it { expect([4, 3, 2, 1]).to be_descending }
132
+ it { expect([1, 2, 3, 4]).not_to be_descending }
133
+ ```
134
+
135
+ #### be_boolean
136
+ ``` ruby
137
+ it { expect(true).to be_boolean }
138
+ it { expect('true').not_to be_boolean }
139
+ ```
140
+
141
+ #### be_email
142
+ ``` ruby
143
+ it { expect('tiagopog@gmail.com').to be_email }
144
+ it { expect('tiagopog@gmail').not_to be_email }
145
+ ```
146
+
147
+ #### be_url
148
+ ``` ruby
149
+ it { expect('http://adtangerine.com').to be_url }
150
+ it { expect('adtangerine.com').not_to be_url }
151
+ ```
152
+
153
+ #### be_image_url
154
+ ``` ruby
155
+ it { expect('http://adtangerine.com/foobar.png').to be_image_url }
156
+ it { expect('http://adtangerine.com/foobar.jpg').not_to be_image_url(:gif) }
157
+ it { expect('http://adtangerine.com/foo/bar').not_to be_image_url }
158
+ ```
159
+
160
+ #### have(x).items
161
+ ``` ruby
162
+ it { expect([1]).to have(1).item }
163
+ it { expect(%w(foo bar)).to have(2).items }
164
+ it { expect(%w(foo bar)).not_to have(1).item }
165
+ ```
166
+
167
+ #### have_at_least
168
+ ``` ruby
169
+ it { expect(%w(foo bar foobar)).to have_at_least(3).items }
170
+ ```
171
+
172
+ #### have_at_most
173
+ ``` ruby
174
+ it { expect(%w(foo bar foobar)).to have_at_most(3).items }
175
+ ```
176
+ #### have_error_on
177
+ ``` ruby
178
+ subject(:user) { FactoryGirl.build(:user, email: nil) }
179
+
180
+ it 'has an invalid email' do
181
+ user.valid?
182
+ expect(user).to have_error_on(:email)
183
+ expect(user).not_to have_error_on(:email)
184
+ end
185
+ ```
186
+
187
+ #### include_items
188
+ ``` ruby
189
+ it { expect(%w(foo bar foobar)).to include_items(%w(foo bar foobar)) }
190
+ ```
191
+
192
+ # TODO
193
+
194
+ - Create macros for model scopes;
195
+ - Create macros for controllers and requests;
196
+ - Add more matchers.
197
+
198
+ ## Contributing
199
+
200
+ 1. Fork it;
201
+ 2. Create your feature branch (`git checkout -b my-new-feature`);
202
+ 3. Create your specs and make sure they are passing;
203
+ 4. Document your feature in the README.md;
204
+ 4. Commit your changes (`git commit -am 'Add some feature'`);
205
+ 5. Push to the branch (`git push origin my-new-feature`);
206
+ 6. Create new Pull Request.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,34 @@
1
+ require 'smart_rspec/support/assertions'
2
+
3
+ module SmartRspec::Macros
4
+ include SmartRspec::Support::Assertions
5
+
6
+ def belongs_to(*associations)
7
+ assert_association :belongs_to, associations
8
+ end
9
+
10
+ def has_attributes(*attrs)
11
+ options = attrs.last.is_a?(Hash) && attrs.last.has_key?(:type) ? attrs.pop : nil
12
+ assert_has_attributes(attrs, options)
13
+ end
14
+
15
+ def has_one(*associations)
16
+ assert_association :has_one, associations
17
+ end
18
+
19
+ def has_many(*associations)
20
+ assert_association :has_many, associations
21
+ end
22
+
23
+ def fails_validation_of(*attrs, validations)
24
+ attrs.each do |attr|
25
+ context attr do
26
+ validations.keys.each do |key|
27
+ validation = validations[key]
28
+ validation && send("validates_#{key}_of", attr, validation)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,45 @@
1
+ require 'rspec/matchers'
2
+ require 'rspec/expectations'
3
+ require 'rspec/collection_matchers'
4
+ require 'smart_rspec/support/regexes'
5
+
6
+ include SmartRspec::Support::Regexes
7
+
8
+ module SmartRspec
9
+ module Matchers
10
+ extend RSpec::Matchers::DSL
11
+
12
+ matcher :be_boolean do
13
+ match { |actual| [true, false].include?(actual) }
14
+ end
15
+
16
+ matcher :be_email do
17
+ match { |actual| actual =~ build_regex(:email) }
18
+ end
19
+
20
+ matcher :be_url do
21
+ match { |actual| actual =~ build_regex(:uri) }
22
+ end
23
+
24
+ matcher :be_image_url do |*types|
25
+ match { |actual| actual =~ build_regex(:image, types) }
26
+ end
27
+
28
+ matcher :have_error_on do |attr|
29
+ match { |actual| actual.errors.keys.include?(attr) }
30
+ end
31
+
32
+ matcher :include_items do |*items|
33
+ match { |actual| (items.flatten - [actual].flatten).empty? }
34
+ end
35
+
36
+ matcher :be_ascending do
37
+ match { |actual| actual == actual.sort }
38
+ end
39
+
40
+ matcher :be_descending do
41
+ match { |actual| actual.each_cons(2).all? { |i, j| i >= j } }
42
+ end
43
+ end
44
+ end
45
+
@@ -0,0 +1,125 @@
1
+ module SmartRspec
2
+ module Support
3
+ module Assertions
4
+ private_class_method
5
+
6
+ def validates_email_of(attr, validation)
7
+ it 'has an invalid format' do
8
+ %w(foobar foobar@ @foobar foo@bar).each do |e|
9
+ assert_validation(attr, e)
10
+ end
11
+ end
12
+ end
13
+
14
+ def validates_exclusion_of(attr, validation)
15
+ it 'has a reserved value' do
16
+ assert_validation(attr, validation[:in].sample)
17
+ end
18
+ end
19
+
20
+ def validates_format_of(attr, validation)
21
+ it 'does not match the required format' do
22
+ mock, with =
23
+ validation.values_at(:mock).first,
24
+ validation.values_at(:with).first
25
+
26
+ if mock && with && with !~ mock
27
+ assert_validation(attr, mock)
28
+ else
29
+ raise ArgumentError, ':with and :mock are required when using the :format validation'
30
+ end
31
+ end
32
+ end
33
+
34
+ def validates_inclusion_of(attr, validation)
35
+ it 'is out of the scope of possible values' do
36
+ begin
37
+ value = SecureRandom.hex
38
+ end while validation[:in].include?(value)
39
+ assert_validation(attr, value)
40
+ end
41
+ end
42
+
43
+ def validates_length_of(attr, validation)
44
+ validation.each do |key, value|
45
+ next unless %i(in is maximum minimum within).include?(key)
46
+ txt, n = build_length_validation(key, value)
47
+ it txt do
48
+ assert_validation(attr, 'x' * n)
49
+ end
50
+ end
51
+ end
52
+
53
+ def validates_presence_of(attr, validation)
54
+ it 'is blank' do
55
+ assert_validation(attr, nil)
56
+ end
57
+ end
58
+
59
+ def validates_uniqueness_of(attr, validation)
60
+ scoped = scoped_validation?(validation)
61
+ scope = scoped ? validation[:scope] : nil
62
+
63
+ it "is already in use#{" (scope: #{scope})" if scoped}" do
64
+ mock = (validation[:mock] rescue nil) || subject.dup
65
+ scoped && mock.send("#{scope}=", subject.send(scope))
66
+
67
+ assert_validation(attr, subject.send(attr), mock)
68
+ end
69
+ end
70
+
71
+ def assert_has_attributes(attrs, options)
72
+ type_str = build_type_str(options)
73
+ default, enum, type = options.values_at(:default, :enum, :type)
74
+
75
+ attrs.each do |attr|
76
+ it %Q(has an attribute named "#{attr}"#{type_str}) do
77
+ expect(subject).to respond_to(attr)
78
+ default && (expect(subject.send(attr)).to eq(default))
79
+ enum && (expect(enum).to include(subject.send(attr).to_sym))
80
+ type && assert_attr_type(attr, type, options)
81
+ end
82
+ end
83
+ end
84
+
85
+ def assert_association(assoc_type, associations)
86
+ associations.each do |association|
87
+ it "#{assoc_type.to_s.gsub('_', ' ')} #{association}" do
88
+ expect(subject).to respond_to(association)
89
+ case assoc_type
90
+ when :belongs_to
91
+ %W(#{association}= #{association}_id #{association}_id=).each do |method|
92
+ expect(subject).to respond_to(method)
93
+ end
94
+ when :has_many
95
+ expect(subject).to respond_to("#{association.to_s.singularize}_ids")
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ def build_length_validation(key, value)
102
+ case key
103
+ when :in, :within then ['is out of the length range', value.max + 1]
104
+ when :is, :minimum then ["is #{key == :is ? 'invalid' : 'too short'}", value - 1]
105
+ when :maximum then ['is too long', value + 1]
106
+ end
107
+ end
108
+
109
+ def build_type_str(options)
110
+ if !options.nil? && options[:type]
111
+ " (%s%s%s)" % [
112
+ ('Enumerated ' if options[:enum]),
113
+ options[:type],
114
+ (", default: #{options[:default]}" if options[:default])
115
+ ]
116
+ end
117
+ end
118
+
119
+ def scoped_validation?(validation)
120
+ validation.is_a?(Hash) && (%i(scope mock) - validation.keys).empty?
121
+ end
122
+ end
123
+ end
124
+ end
125
+
@@ -0,0 +1,19 @@
1
+ module SmartRspec
2
+ module Support
3
+ module Expectations
4
+ def assert_attr_type(attr, type, other)
5
+ assert_type = type == :Boolean ? be_boolean : be_kind_of(Kernel.const_get(type))
6
+ expect(subject.send(attr)).to assert_type
7
+ end
8
+
9
+ def assert_validation(attr, value = nil, mock = nil)
10
+ mock ||= subject
11
+ mock.send("#{attr}=", value)
12
+
13
+ expect(mock).not_to be_valid
14
+ expect(mock).to have_error_on(attr)
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,44 @@
1
+ module SmartRspec
2
+ module Support
3
+ module Regexes
4
+ def build_regex(type, *args)
5
+ type = type.to_sym unless type.is_a? Symbol
6
+ case type
7
+ when :email
8
+ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
9
+ when :image
10
+ build_img_regex(args.flatten)
11
+ else
12
+ build_uri_regex[type]
13
+ end
14
+ end
15
+
16
+ private_class_method
17
+
18
+ def build_img_regex(exts = [])
19
+ exts = [exts].flatten unless exts.is_a?(Array)
20
+ if exts.nil? || exts.empty?
21
+ exts = %w(jpg jpeg png gif)
22
+ elsif exts.include?(:jpg) && !exts.include?(:jpeg)
23
+ exts.push :jpeg
24
+ end
25
+ %r{(^http{1}[s]?://([w]{3}\.)?.+\.(#{exts.join('|')})(\?.+)?$)}i
26
+ end
27
+
28
+ def build_uri_regex
29
+ {
30
+ uri: %r{^(
31
+ (((ht|f)tp[s]?://)|([a-z0-9]+\.))+
32
+ (?<!@)
33
+ ([a-z0-9\_\-]+)
34
+ (\.[a-z]+)+
35
+ ([\?/\:][a-z0-9_=%&@\?\./\-\:\#\(\)]+)?
36
+ /?
37
+ )$}ix,
38
+ protocol: /((ht|f)tp[s]?)/i
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,3 @@
1
+ module SmartRspec
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,19 @@
1
+ require 'active_support/concern'
2
+ require 'smart_rspec/macros'
3
+ require 'smart_rspec/matchers'
4
+ require 'smart_rspec/support/expectations'
5
+
6
+ include SmartRspec::Matchers
7
+
8
+ module SmartRspec
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ include SmartRspec::Support::Expectations
13
+ end
14
+
15
+ module ClassMethods
16
+ include SmartRspec::Macros
17
+ end
18
+ end
19
+
@@ -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 'smart_rspec/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'smart_rspec'
8
+ spec.version = SmartRspec::VERSION
9
+ spec.authors = ['Tiago Guedes']
10
+ spec.email = ['tiagopog@gmail.com']
11
+ spec.summary = %q{Macros and matchers to make your RSpec tests even more amazing.}
12
+ spec.description = %q{Collection of useful macros and matchers for RSpec tests of models/controllers in Rails-based apps.}
13
+ spec.homepage = 'https://github.com/tiagopog/smart_rspec'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_runtime_dependency 'activesupport', '~> 4.1'
22
+ spec.add_runtime_dependency 'rspec-collection_matchers', '~> 1.1', '>= 1.1.2'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.7'
25
+ spec.add_development_dependency 'faker', '~> 1.4'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'rspec', '~> 3.2'
28
+ end
@@ -0,0 +1,88 @@
1
+ require 'smart_rspec/support/regexes'
2
+
3
+ module Factories
4
+ class User
5
+ include SmartRspec::Support::Regexes
6
+
7
+ @@last_id = 0
8
+ @@collection = []
9
+ @@error_message = {
10
+ blank: "can't be blank",
11
+ exclusion: "can't use a reserved value",
12
+ format: "doesn't match the required pattern",
13
+ inclusion: 'value not included',
14
+ too_big: "can't be greater than 80 chars",
15
+ uniqueness: 'must be unique within the given scope'
16
+ }
17
+
18
+ attr_accessor :email, :system, :system_id, :project, :project_id,
19
+ :name, :username, :is_admin, :score, :admin, :father,
20
+ :mother, :articles, :rates
21
+
22
+ attr_reader :id, :errors
23
+
24
+ def initialize(attrs = {})
25
+ attrs.each { |key, value| self.send("#{key}=", value) }
26
+ set_defaults
27
+ @@collection << self
28
+ end
29
+
30
+ class << self
31
+ attr_reader :collection
32
+ end
33
+
34
+ def locale
35
+ @locale.to_s unless @locale.nil?
36
+ end
37
+
38
+ def locale=(locale)
39
+ %i(en pt).include?(locale) && @locale = locale
40
+ end
41
+
42
+ def valid?
43
+ %w(email father locale name username).each { |e| send("check_#{e}") }
44
+ @errors.nil?
45
+ end
46
+
47
+ private
48
+
49
+ def check_email
50
+ if !email || (email && email !~ build_regex(:email))
51
+ @errors.merge!({ email: @@error_message[:blank] })
52
+ end
53
+ end
54
+
55
+ def check_father
56
+ if father && father !~ /foo/
57
+ @errors.merge!({ father: @@error_message[:format] })
58
+ end
59
+ end
60
+
61
+ def check_locale
62
+ unless %i(en pt).include?(locale)
63
+ @errors.merge!({ locale: @@error_message[:inclusion] })
64
+ end
65
+ end
66
+
67
+ def check_name
68
+ if !name || (name && name.length > 80)
69
+ @errors.merge!({ name: @@error_message[(name ? :too_big : :blank)] })
70
+ end
71
+ end
72
+
73
+ def check_username
74
+ other_user = @@collection.select { |e| e.name == name && e.username == username && e.id != id }.first
75
+ if username && (other_user || %w(foo bar).include?(username))
76
+ @errors.merge!({ username: @@error_message[other_user ? :uniqueness : :exclusion] })
77
+ end
78
+ end
79
+
80
+ def set_defaults
81
+ @@last_id = @id = @@last_id + 1
82
+ { errors: {}, is_admin: false, score: 0, locale: :en }.each do |key, value|
83
+ eval "@#{key} ||= #{value.inspect}"
84
+ end
85
+ end
86
+ end
87
+ end
88
+
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe SmartRspec::Macros do
4
+ include SmartRspec
5
+
6
+ before(:all) do
7
+ attrs = {
8
+ email: Faker::Internet.email,
9
+ name: Faker::Name.name,
10
+ username: Faker::Internet.user_name
11
+ }
12
+ @user = User.new(attrs)
13
+ end
14
+
15
+ subject { @user }
16
+
17
+ describe '#belongs_to' do
18
+ context 'when it receives a single arg' do
19
+ belongs_to :system
20
+ end
21
+
22
+ context 'when it receives multiple args' do
23
+ belongs_to :system, :project
24
+ end
25
+ end
26
+
27
+ describe '#has_attributes' do
28
+ context 'when it receives a single arg' do
29
+ has_attributes :email, :name, :username, type: :String
30
+ has_attributes :is_admin, type: :Boolean
31
+ has_attributes :score, type: :Integer, default: 0
32
+ has_attributes :locale, type: :String, enum: %i(en pt), default: 'en'
33
+ end
34
+
35
+ context 'when it receives multiple args' do
36
+ has_attributes :name, :username, type: :String
37
+ end
38
+ end
39
+
40
+ describe '#has_one' do
41
+ context 'when it receives a single arg' do
42
+ has_one :admin
43
+ end
44
+
45
+ context 'when it receives multiple args' do
46
+ has_one :admin, :father, :mother
47
+ end
48
+ end
49
+
50
+ describe '#has_many' do
51
+ context 'when it receives a single arg' do
52
+ has_one :articles
53
+ end
54
+
55
+ context 'when it receives multiple args' do
56
+ has_one :articles, :rates
57
+ end
58
+ end
59
+
60
+ describe '#fails_validation_of' do
61
+ context 'when it receives a single arg' do
62
+ user = User.new(email: Faker::Internet.email)
63
+
64
+ fails_validation_of :email, presence: true, email: true
65
+ fails_validation_of :name, length: { maximum: 80 }
66
+ fails_validation_of :username, uniqueness: { scope: :name, mock: user }, exclusion: { in: %w(foo bar) }
67
+ fails_validation_of :locale, inclusion: { in: %w(en pt) }
68
+ fails_validation_of :father, format: { with: /foo/, mock: 'bar' }
69
+ end
70
+
71
+ context 'when it receives multiple args' do
72
+ fails_validation_of :email, :name, presence: true
73
+ end
74
+ end
75
+ end
76
+
@@ -0,0 +1,144 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'SmartRspec Matchers' do
4
+ describe '#be_ascending' do
5
+ context 'when valid' do
6
+ it { expect([1, 2, 3, 4]).to be_ascending }
7
+ end
8
+
9
+ context 'when invalid' do
10
+ it { expect([1, 4, 2, 3]).not_to be_ascending }
11
+ end
12
+ end
13
+
14
+ describe '#be_boolean' do
15
+ context 'when valid' do
16
+ it { expect(true).to be_boolean }
17
+ it { expect(false).to be_boolean }
18
+ end
19
+
20
+ context 'when invalid' do
21
+ it { expect('true').not_to be_boolean }
22
+ it { expect(1).not_to be_boolean }
23
+ it { expect(%w(foo bar)).not_to be_boolean }
24
+ end
25
+ end
26
+
27
+ describe '#be_descending' do
28
+ context 'when valid' do
29
+ it { expect([4, 3, 2, 1]).to be_descending }
30
+ end
31
+
32
+ context 'when invalid' do
33
+ it { expect([1, 2, 3, 4]).not_to be_descending }
34
+ end
35
+ end
36
+
37
+ describe '#be_email' do
38
+ context 'when valid' do
39
+ it { expect(Faker::Internet.email).to be_email }
40
+ it { expect('tiagopog@gmail.com').to be_email }
41
+ it { expect('foo@bar.com.br').to be_email }
42
+ end
43
+
44
+ context 'when invalid' do
45
+ it { expect('foo@bar').not_to be_email }
46
+ it { expect('foo@').not_to be_email }
47
+ it { expect('@bar').not_to be_email }
48
+ it { expect('@bar.com').not_to be_email }
49
+ it { expect('foo bar@bar.com').not_to be_email }
50
+ end
51
+ end
52
+
53
+ describe '#be_url' do
54
+ context 'when valid' do
55
+ it { expect(Faker::Internet.url).to be_url }
56
+ it { expect('http://adtangerine.com').to be_url }
57
+ it { expect('http://www.facebook.com').to be_url }
58
+ it { expect('www.twitflink.com').to be_url }
59
+ it { expect('google.com.br').to be_url }
60
+ end
61
+
62
+ context 'when invalid' do
63
+ it { expect('foobar.bar').not_to be_url }
64
+ it { expect('foobar').not_to be_url }
65
+ it { expect('foo bar.com.br').not_to be_url }
66
+ end
67
+ end
68
+
69
+ describe '#be_image_url' do
70
+ context 'when valid' do
71
+ it { expect(Faker::Company.logo).to be_image_url }
72
+ it { expect('http://foobar.com/foo.jpg').to be_image_url }
73
+ it { expect('http://foobar.com/foo.jpg').to be_image_url(:jpg) }
74
+ it { expect('http://foobar.com/foo.gif').to be_image_url(:gif) }
75
+ it { expect('http://foobar.com/foo.png').to be_image_url(:png) }
76
+ it { expect('http://foobar.com/foo.png').to be_image_url(%i(jpg png)) }
77
+ it { expect('http://foobar.com/foo/bar?image=foo.jpg').to be_image_url }
78
+ end
79
+
80
+ context 'when invalid' do
81
+ it { expect('http://foobar.com').not_to be_image_url }
82
+ it { expect('http://foobar.com/foo.jpg').not_to be_image_url(:gif) }
83
+ it { expect('http://foobar.com/foo.gif').not_to be_image_url(:png) }
84
+ it { expect('http://foobar.com/foo.png').not_to be_image_url(:jpg) }
85
+ it { expect('http://foobar.com/foo.gif').not_to be_image_url(%i(jpg png)) }
86
+ end
87
+ end
88
+
89
+ describe '#have' do
90
+ context 'when valid' do
91
+ it { expect([1]).to have(1).item }
92
+ it { expect(%w(foo bar)).to have(2).items }
93
+ end
94
+
95
+ context 'when invalid' do
96
+ it { expect([1]).not_to have(2).items }
97
+ it { expect(%w(foo bar)).not_to have(1).item }
98
+ end
99
+ end
100
+
101
+ describe '#have_at_least' do
102
+ context 'when valid' do
103
+ it { expect(%w(foo bar foobar)).to have_at_least(3).items }
104
+ end
105
+ end
106
+
107
+ describe '#have_at_most' do
108
+ context 'when valid' do
109
+ it { expect(%w(foo bar foobar)).to have_at_most(3).items }
110
+ end
111
+ end
112
+
113
+ describe '#have_error_on' do
114
+ subject(:mock) { User.new(email: nil) }
115
+
116
+ context 'when valid' do
117
+ it do
118
+ mock.valid?
119
+ expect(mock).to have_error_on(:email)
120
+ end
121
+ end
122
+
123
+ context 'when invalid' do
124
+ it do
125
+ mock.email = Faker::Internet.email
126
+ mock.valid?
127
+
128
+ expect(mock).not_to have_error_on(:email)
129
+ end
130
+ end
131
+ end
132
+
133
+ describe '#include_items' do
134
+ context 'when valid' do
135
+ it { expect(%w(foo bar foobar)).to include_items(%w(foo bar foobar)) }
136
+ it { expect([1, 'foo', ['bar']]).to include_items([1, 'foo', ['bar']]) }
137
+ end
138
+
139
+ context 'when invalid' do
140
+ it { expect(%w(foo bar foobar)).not_to include_items(%w(lorem)) }
141
+ end
142
+ end
143
+ end
144
+
@@ -0,0 +1,8 @@
1
+ require 'bundler/setup'
2
+ require 'rubygems'
3
+ require 'smart_rspec'
4
+ require 'faker'
5
+ require 'factories/user'
6
+
7
+ include Factories
8
+
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smart_rspec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tiago Guedes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-collection_matchers
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 1.1.2
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '1.1'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.1.2
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.7'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.7'
61
+ - !ruby/object:Gem::Dependency
62
+ name: faker
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.4'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.4'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '10.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '10.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.2'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.2'
103
+ description: Collection of useful macros and matchers for RSpec tests of models/controllers
104
+ in Rails-based apps.
105
+ email:
106
+ - tiagopog@gmail.com
107
+ executables: []
108
+ extensions: []
109
+ extra_rdoc_files: []
110
+ files:
111
+ - ".gitignore"
112
+ - ".rspec"
113
+ - Gemfile
114
+ - LICENSE.txt
115
+ - README.md
116
+ - Rakefile
117
+ - lib/smart_rspec.rb
118
+ - lib/smart_rspec/macros.rb
119
+ - lib/smart_rspec/matchers.rb
120
+ - lib/smart_rspec/support/assertions.rb
121
+ - lib/smart_rspec/support/expectations.rb
122
+ - lib/smart_rspec/support/regexes.rb
123
+ - lib/smart_rspec/version.rb
124
+ - smart_rspec.gemspec
125
+ - spec/factories/user.rb
126
+ - spec/smart_rspec/macros_spec.rb
127
+ - spec/smart_rspec/matchers_spec.rb
128
+ - spec/spec_helper.rb
129
+ homepage: https://github.com/tiagopog/smart_rspec
130
+ licenses:
131
+ - MIT
132
+ metadata: {}
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 2.4.6
150
+ signing_key:
151
+ specification_version: 4
152
+ summary: Macros and matchers to make your RSpec tests even more amazing.
153
+ test_files:
154
+ - spec/factories/user.rb
155
+ - spec/smart_rspec/macros_spec.rb
156
+ - spec/smart_rspec/matchers_spec.rb
157
+ - spec/spec_helper.rb