smart_rspec 0.1.3 → 0.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2ff36ef01dd0d51c6bab2614a6613201973dd7c7
4
- data.tar.gz: cdf57909342d77f99b5ccf3b0fe3766343da5591
3
+ metadata.gz: 7b6913c78ea542aba3c5bb09a26bbb2b5aaa8767
4
+ data.tar.gz: 7a94b954a2e829efa220e487f94f3eb94894bdc1
5
5
  SHA512:
6
- metadata.gz: 8e1f3afcc473a3fb8b25a21da76bbc6a4cbfd09d7e93746f15b3e224f8b4f24f438f42266906e99e4389e9ffde7f07311790d16133d2e892117f11efc22f3e72
7
- data.tar.gz: ec5b1078402f12aa22cd125eceef70a1ea96ce4d639186c20505733dc7045d9a9e2be90b5f9abc4571c78ec54480a42bbd12e32994084596948835f13a4a7fbe
6
+ metadata.gz: 57e4f5b9b6cb2b9d55aa42c8d6e4cbdace08b94c0ae36cbcd311d74f8569dc0c88b842e42be6b362bcf087e2a9e486ab2b944d9b29bdda5ecb79774d7ada7c65
7
+ data.tar.gz: ebc06947e17c4c84aa5c0ba1f788dcc4f77ab6e3f09804b210694fda390f0667b627bd25ab47a130d458c5c6d58f727161ade7abeef039694d81ed8a121294f4
data/README.md CHANGED
@@ -51,7 +51,6 @@ end
51
51
  * [be_a_list_of](#be_a_list_of)
52
52
  * [be_ascending](#be_ascending)
53
53
  * [be_descending](#be_descending)
54
- * [be_a_bad_request](#be_a_bad_request)
55
54
  * ["Have" matchers](#have-matchers)
56
55
  * [have](#have)
57
56
  * [have_at_least](#have_at_least)
@@ -180,20 +179,6 @@ it { expect([4, 3, 2, 1]).to be_descending }
180
179
  it { expect([1, 2, 3, 4]).not_to be_descending }
181
180
  ```
182
181
 
183
- ##### be_a_bad_request
184
- ``` ruby
185
- context 'unauthenticated' do
186
- subject { get :profile }
187
- it { is_expected.to be_a_bad_request }
188
- end
189
-
190
- context 'authenticated' do
191
- before { sign_in user }
192
- subject { get :profile }
193
- it { is_expected.to_not be_a_bad_request }
194
- end
195
- ```
196
-
197
182
  #### Have matchers
198
183
 
199
184
  ##### have(x).items
@@ -1,7 +1,7 @@
1
- require 'smart_rspec/support/assertions'
1
+ require 'smart_rspec/support/model/assertions'
2
2
 
3
3
  module SmartRspec::Macros
4
- include SmartRspec::Support::Assertions
4
+ include SmartRspec::Support::Model::Assertions
5
5
 
6
6
  def belongs_to(*associations)
7
7
  assert_association :belongs_to, associations
@@ -31,4 +31,3 @@ module SmartRspec::Macros
31
31
  end
32
32
  end
33
33
  end
34
-
@@ -7,12 +7,6 @@ module SmartRspec
7
7
  match { |actual| actual == actual.sort }
8
8
  end
9
9
 
10
- matcher :be_a_bad_request do
11
- match do |response|
12
- response.code.to_s =~ /^4/
13
- end
14
- end
15
-
16
10
  matcher :be_a_list_of do |klass|
17
11
  match do |collection|
18
12
  collection.all? { |e| e.is_a?(klass) }
@@ -0,0 +1,43 @@
1
+ module SmartRspec
2
+ module Matchers
3
+ module JsonApiMatchers
4
+ extend RSpec::Matchers::DSL
5
+ include SmartRspec::Support::Controller::Response
6
+
7
+ matcher :have_primary_data do |expected|
8
+ match do |response|
9
+ json(response).collection.all? do |record|
10
+ !record['id'].to_s.empty? && record['type'] == expected
11
+ end
12
+ end
13
+ end
14
+
15
+ matcher :have_data_attributes do |fields|
16
+ match do |response|
17
+ json(response).check_keys_in('attributes', fields)
18
+ end
19
+ end
20
+
21
+ matcher :have_relationships do |relationships|
22
+ match do |response|
23
+ json(response).check_keys_in('relationships', relationships)
24
+ end
25
+ end
26
+
27
+ matcher :have_included_relationships do
28
+ match do |response|
29
+ json(response)
30
+ return false if included_data.empty? || relationship_data.empty?
31
+ included_data.size == relationship_data.size &&
32
+ (included_data - relationship_data).empty?
33
+ end
34
+ end
35
+
36
+ matcher :have_meta_record_count do |count|
37
+ match do |response|
38
+ json(response).meta_record_count == count
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -13,4 +13,3 @@ module SmartRspec
13
13
  end
14
14
  end
15
15
  end
16
-
@@ -1,12 +1,14 @@
1
1
  require 'smart_rspec/support/regexes'
2
+ require 'smart_rspec/support/controller/response'
2
3
  require 'smart_rspec/matchers/be_matchers'
4
+ require 'smart_rspec/matchers/json_api_matchers'
3
5
  require 'smart_rspec/matchers/other_matchers'
4
6
 
5
7
  module SmartRspec
6
8
  module Matchers
7
9
  include SmartRspec::Support::Regexes
8
10
  include SmartRspec::Matchers::BeMatchers
11
+ include SmartRspec::Matchers::JsonApiMatchers
9
12
  include SmartRspec::Matchers::OtherMatchers
10
13
  end
11
14
  end
12
-
@@ -0,0 +1,47 @@
1
+ require 'json'
2
+
3
+ module SmartRspec
4
+ module Support
5
+ module Controller
6
+ module Response
7
+ def json(response)
8
+ @json ||= JSON.parse(response.body)
9
+ self
10
+ end
11
+
12
+ def error
13
+ @error ||= @json['errors'].first
14
+ end
15
+
16
+ def collection
17
+ @collection ||= [@json['data']].flatten
18
+ end
19
+
20
+ def meta_record_count
21
+ @json['meta']['record_count']
22
+ end
23
+
24
+ def relationship_data
25
+ @relationship_data ||= collection.flat_map do |record|
26
+ record['relationships'].flat_map do |_, relation|
27
+ [relation['data']].flatten.map { |data| data.slice('type', 'id') }
28
+ end.compact
29
+ end
30
+ end
31
+
32
+ def included_data
33
+ return [] if @json['included'].nil?
34
+ @included_data ||= @json['included'].flat_map do |record|
35
+ record.slice('type', 'id')
36
+ end
37
+ end
38
+
39
+ def check_keys_in(member, keys)
40
+ collection.all? do |record|
41
+ record[member].keys.sort == keys.sort
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,112 @@
1
+ module SmartRspec
2
+ module Support
3
+ module Model
4
+ module Assertions
5
+ def validates_email_of(attr, validation)
6
+ it 'has an invalid format' do
7
+ %w(foobar foobar@ @foobar foo@bar).each do |e|
8
+ be_valid_expectation(attr, e, subject.dup)
9
+ end
10
+ end
11
+ end
12
+
13
+ def validates_exclusion_of(attr, validation)
14
+ it 'has a reserved value' do
15
+ be_valid_expectation(attr, validation[:in].sample)
16
+ end
17
+ end
18
+
19
+ def validates_format_of(attr, validation)
20
+ it 'does not match the required format' do
21
+ mock, with =
22
+ validation.values_at(:mock).first,
23
+ validation.values_at(:with).first
24
+
25
+ if mock && with && with !~ mock
26
+ be_valid_expectation(attr, mock)
27
+ else
28
+ raise ArgumentError, ':with and :mock are required when using the :format validation'
29
+ end
30
+ end
31
+ end
32
+
33
+ def validates_inclusion_of(attr, validation)
34
+ it 'is out of the scope of possible values' do
35
+ begin
36
+ value = SecureRandom.hex
37
+ end while validation[:in].include?(value)
38
+ be_valid_expectation(attr, value)
39
+ end
40
+ end
41
+
42
+ def validates_length_of(attr, validation)
43
+ validation.each do |key, value|
44
+ next unless [:in, :is, :maximum, :minimum, :within].include?(key)
45
+ txt, n = build_length_validation(key, value)
46
+ it txt do
47
+ be_valid_expectation(attr, 'x' * n)
48
+ end
49
+ end
50
+ end
51
+
52
+ def validates_presence_of(attr, validation)
53
+ it 'is blank' do
54
+ be_valid_expectation(attr, nil, subject.dup)
55
+ end
56
+ end
57
+
58
+ def validates_uniqueness_of(attr, validation)
59
+ it 'is already in use' do
60
+ if !validation.is_a?(Hash) || !validation.has_key?(:mock)
61
+ raise ArgumentError, 'A "mock" must be set when validating the uniqueness of a record'
62
+ elsif subject.persisted? || subject.save
63
+ mock, scope = validation.values_at(:mock, :scope)
64
+ mock.send("#{scope}=", subject.send(scope)) unless scope.to_s.empty?
65
+ be_valid_expectation(attr, subject.send(attr), mock)
66
+ end
67
+ end
68
+ end
69
+
70
+ def assert_has_attributes(attrs, options) type_str = build_type_str(options)
71
+ attrs.each do |attr|
72
+ it %Q(has an attribute named "#{attr}"#{type_str}) do
73
+ expect(subject).to respond_to(attr)
74
+ has_attributes_expectation(attr, options)
75
+ end
76
+ end
77
+ end
78
+
79
+ def assert_association(type, associations)
80
+ associations.each do |model|
81
+ it "#{type.to_s.gsub('_', ' ')} #{model}" do
82
+ expect(subject).to respond_to(model)
83
+ association_expectation(type, model)
84
+ end
85
+ end
86
+ end
87
+
88
+ def build_length_validation(key, value)
89
+ case key
90
+ when :in, :within then ['is out of the length range', value.max + 1]
91
+ when :is, :minimum then ["is #{key == :is ? 'invalid' : 'too short'}", value - 1]
92
+ when :maximum then ['is too long', value + 1]
93
+ end
94
+ end
95
+
96
+ def build_type_str(options)
97
+ if !options.nil? && options[:type]
98
+ " (%s%s%s)" % [
99
+ ('Enumerated ' if options[:enum]),
100
+ options[:type],
101
+ (", default: #{options[:default]}" if options[:default])
102
+ ]
103
+ end
104
+ end
105
+
106
+ # def scoped_validation?(validation)
107
+ # validation.is_a?(Hash) && ([:scope, :mock] - validation.keys).empty?
108
+ # end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,43 @@
1
+ module SmartRspec
2
+ module Support
3
+ module Model
4
+ module Expectations
5
+ def be_valid_expectation(attr, value = nil, mock = nil)
6
+ mock ||= subject
7
+ mock.send("#{attr}=", value)
8
+
9
+ expect(mock).not_to be_valid
10
+ expect(mock).to have_error_on(attr)
11
+ end
12
+
13
+ def default_expectation(attr, value)
14
+ expect(subject.send(attr)).to eq(value)
15
+ end
16
+
17
+ def enum_expectation(attr, value)
18
+ expect(value).to include(subject.send(attr).to_sym)
19
+ end
20
+
21
+ def type_expectation(attr, value)
22
+ assert_type = value != :Boolean ? be_kind_of(Kernel.const_get(value)) : be_boolean
23
+ expect(subject.send(attr)).to assert_type
24
+ end
25
+
26
+ def has_attributes_expectation(attr, options) options.each do |key, value|
27
+ send("#{key}_expectation", attr, value)
28
+ end
29
+ end
30
+
31
+ def association_expectation(type, model)
32
+ if type == :has_many
33
+ expect(subject).to respond_to("#{model.to_s.singularize}_ids")
34
+ elsif type == :belongs_to
35
+ %W(#{model}= #{model}_id #{model}_id=).each do |method|
36
+ expect(subject).to respond_to(method)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,3 +1,3 @@
1
1
  module SmartRspec
2
- VERSION = '0.1.3'
2
+ VERSION = '0.1.4'
3
3
  end
data/lib/smart_rspec.rb CHANGED
@@ -2,7 +2,7 @@ require 'active_support/concern'
2
2
  require 'rspec/collection_matchers'
3
3
  require 'rspec/matchers'
4
4
 
5
- %w(macros matchers support/expectations).each { |f| require "smart_rspec/#{f}" }
5
+ %w(macros matchers support/model/expectations).each { |f| require "smart_rspec/#{f}" }
6
6
 
7
7
  include SmartRspec::Matchers
8
8
 
@@ -10,11 +10,10 @@ module SmartRspec
10
10
  extend ActiveSupport::Concern
11
11
 
12
12
  included do
13
- include SmartRspec::Support::Expectations
13
+ include SmartRspec::Support::Model::Expectations
14
14
  end
15
15
 
16
16
  module ClassMethods
17
17
  include SmartRspec::Macros
18
18
  end
19
19
  end
20
-
@@ -0,0 +1,11 @@
1
+ module Fixtures
2
+ class Response
3
+ def initialize
4
+ @file = File.read('spec/fixtures/users.json')
5
+ end
6
+
7
+ def body
8
+ @file
9
+ end
10
+ end
11
+ end
@@ -1,6 +1,6 @@
1
1
  require 'smart_rspec/support/regexes'
2
2
 
3
- module Factories
3
+ module Fixtures
4
4
  class User
5
5
  include SmartRspec::Support::Regexes
6
6
 
@@ -17,30 +17,42 @@ module Factories
17
17
 
18
18
  attr_accessor :email, :system, :system_id, :project, :project_id,
19
19
  :name, :username, :is_admin, :score, :admin, :father,
20
- :mother, :articles, :rates
20
+ :mother, :articles, :rates, :errors
21
21
 
22
- attr_reader :id, :errors
22
+ attr_reader :id
23
+
24
+ attr_writer :locale
23
25
 
24
26
  def initialize(attrs = {})
25
27
  attrs.each { |key, value| self.send("#{key}=", value) }
26
28
  set_defaults
27
- @@collection << self
28
29
  end
29
30
 
30
31
  class << self
31
32
  attr_reader :collection
33
+
34
+ def create(attrs)
35
+ user = User.new(attrs)
36
+ @@collection << user && user
37
+ end
38
+
39
+ def find_by(key, value)
40
+ @@collection.find { |e| e.send(key) == value }
41
+ end
42
+ end
43
+
44
+ def save
45
+ @@collection << self
32
46
  end
33
47
 
34
48
  def locale
35
49
  @locale.to_s unless @locale.nil?
36
50
  end
37
51
 
38
- def locale=(locale)
39
- [:en, :pt].include?(locale) && @locale = locale
52
+ def persisted?
53
+ User.find_by(:id, id)
40
54
  end
41
55
 
42
- def persisted?; true end
43
-
44
56
  def valid?
45
57
  %w(email father locale name username).each { |e| send("check_#{e}") }
46
58
  @errors.nil?
@@ -51,6 +63,8 @@ module Factories
51
63
  def check_email
52
64
  if !email || (email && email !~ build_regex(:email))
53
65
  @errors.merge!({ email: @@error_message[:blank] })
66
+ elsif User.find_by(:email, email)
67
+ @errors.merge!({ email: @@error_message[:uniqueness] })
54
68
  end
55
69
  end
56
70
 
@@ -61,7 +75,7 @@ module Factories
61
75
  end
62
76
 
63
77
  def check_locale
64
- unless [:en, :pt].include?(locale)
78
+ unless %w(en pt).include?(locale)
65
79
  @errors.merge!({ locale: @@error_message[:inclusion] })
66
80
  end
67
81
  end
@@ -73,18 +87,19 @@ module Factories
73
87
  end
74
88
 
75
89
  def check_username
76
- other_user = @@collection.select { |e| e.name == name && e.username == username && e.id != id }.first
77
- if username && (other_user || %w(foo bar).include?(username))
78
- @errors.merge!({ username: @@error_message[other_user ? :uniqueness : :exclusion] })
90
+ if username.to_s.empty?
91
+ @errors.merge!({ username: @@error_message[:blank] })
92
+ elsif %w(foo bar).include?(username)
93
+ @errors.merge!({ username: @@error_message[:exclusion] })
94
+ elsif User.find_by(:username, username)
95
+ @errors.merge!({ username: @@error_message[:uniqueness] })
79
96
  end
80
97
  end
81
98
 
82
99
  def set_defaults
83
100
  @@last_id = @id = @@last_id + 1
84
- { errors: {}, is_admin: false, score: 0, locale: :en }.each do |key, value|
85
- eval "@#{key} ||= #{value.inspect}"
86
- end
101
+ attrs = { errors: {}, is_admin: false, score: 0, locale: :en }
102
+ attrs.each { |key, value| send("#{key}=", value) }
87
103
  end
88
104
  end
89
105
  end
90
-
@@ -0,0 +1,81 @@
1
+ {
2
+ "data": [
3
+ {
4
+ "id": "1",
5
+ "type": "users",
6
+ "links": {
7
+ "self": "http://api.myawesomesite.com/users/1"
8
+ },
9
+ "attributes": {
10
+ "first_name": "Tiago",
11
+ "last_name": "Guedes",
12
+ "full_name": "Tiago Guedes",
13
+ "birthday": "1988-22-12"
14
+ },
15
+ "relationships": {
16
+ "posts": {
17
+ "links": {
18
+ "self": "http://api.myawesomesite.com/users/1/relationships/posts",
19
+ "related": "http://api.myawesomesite.com/users/1/posts"
20
+ },
21
+ "data": [
22
+ {
23
+ "type": "posts",
24
+ "id": "1"
25
+ }
26
+ ]
27
+ }
28
+ }
29
+ },
30
+ {
31
+ "id": "2",
32
+ "type": "users",
33
+ "links": {
34
+ "self": "http://api.myawesomesite.com/users/2"
35
+ },
36
+ "attributes": {
37
+ "first_name": "Douglas",
38
+ "last_name": "André",
39
+ "full_name": "Douglas André",
40
+ "birthday": null
41
+ },
42
+ "relationships": {
43
+ "posts": {
44
+ "links": {
45
+ "self": "http://api.myawesomesite.com/users/2/relationships/posts",
46
+ "related": "http://api.myawesomesite.com/users/2/posts"
47
+ },
48
+ "data": []
49
+ }
50
+ }
51
+ }
52
+ ],
53
+ "included": [
54
+ {
55
+ "id": "1",
56
+ "type": "posts",
57
+ "links": {
58
+ "self": "http://api.myawesomesite.com/posts/1"
59
+ },
60
+ "attributes": {
61
+ "title": "An awesome post",
62
+ "body": "Lorem ipsum dolot sit amet"
63
+ },
64
+ "relationships": {
65
+ "author": {
66
+ "links": {
67
+ "self": "http://api.myawesomesite.com/posts/1/relationships/author",
68
+ "related": "http://api.myawesomesite.com/posts/1/author"
69
+ }
70
+ }
71
+ }
72
+ }
73
+ ],
74
+ "meta": {
75
+ "record_count": 2
76
+ },
77
+ "links": {
78
+ "first": "http://api.myawesomesite.com/users?include=posts&page%5Blimit%5D=2&page%5Boffset%5D=0",
79
+ "last": "http://api.myawesomesite.com/users?include=posts&page%5Blimit%5D=2&page%5Boffset%5D=0"
80
+ }
81
+ }
@@ -3,17 +3,14 @@ require 'spec_helper'
3
3
  describe SmartRspec::Macros do
4
4
  include SmartRspec
5
5
 
6
- before(:all) do
7
- attrs = {
8
- email: Faker::Internet.email,
9
- name: Faker::Name.name,
6
+ subject(:user) do
7
+ User.create({
8
+ email: Faker::Internet.email,
9
+ name: Faker::Name.name,
10
10
  username: Faker::Internet.user_name
11
- }
12
- @user = User.new(attrs)
11
+ })
13
12
  end
14
13
 
15
- subject { @user }
16
-
17
14
  describe '#belongs_to' do
18
15
  context 'when it receives a single arg' do
19
16
  belongs_to :system
@@ -59,11 +56,16 @@ describe SmartRspec::Macros do
59
56
 
60
57
  describe '#fails_validation_of' do
61
58
  context 'when it receives a single arg' do
62
- user = User.new(email: Faker::Internet.email)
59
+ new_user =
60
+ User.new({
61
+ email: Faker::Internet.email,
62
+ name: Faker::Name.name,
63
+ username: Faker::Internet.user_name
64
+ })
63
65
 
64
- fails_validation_of :email, presence: true, email: true, uniqueness: true
66
+ fails_validation_of :email, presence: true, email: true, uniqueness: { mock: new_user }
65
67
  fails_validation_of :name, length: { maximum: 80 }
66
- fails_validation_of :username, uniqueness: { scope: :name, mock: user }, exclusion: { in: %w(foo bar) }
68
+ fails_validation_of :username, uniqueness: { mock: new_user }, exclusion: { in: %w(foo bar) }
67
69
  fails_validation_of :locale, inclusion: { in: %w(en pt) }
68
70
  fails_validation_of :father, format: { with: /foo/, mock: 'bar' }
69
71
  end
@@ -73,4 +75,3 @@ describe SmartRspec::Macros do
73
75
  end
74
76
  end
75
77
  end
76
-
@@ -1,173 +1,234 @@
1
1
  require 'spec_helper'
2
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
3
+ describe SmartRspec::Matchers do
4
+ describe BeMatchers do
5
+ describe '#be_ascending' do
6
+ context 'positive assertion' do
7
+ it { expect([1, 2, 3, 4]).to be_ascending }
8
+ end
8
9
 
9
- context 'when invalid' do
10
- it { expect([1, 4, 2, 3]).not_to be_ascending }
10
+ context 'negative assertion' do
11
+ it { expect([1, 4, 2, 3]).not_to be_ascending }
12
+ end
11
13
  end
12
- end
13
14
 
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
15
+ describe '#be_boolean' do
16
+ context 'positive assertion' do
17
+ it { expect(true).to be_boolean }
18
+ it { expect(false).to be_boolean }
19
+ end
19
20
 
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 }
21
+ context 'negative assertion' do
22
+ it { expect('true').not_to be_boolean }
23
+ it { expect(1).not_to be_boolean }
24
+ it { expect(%w(foo bar)).not_to be_boolean }
25
+ end
24
26
  end
25
- end
26
27
 
27
- describe '#be_descending' do
28
- context 'when valid' do
29
- it { expect([4, 3, 2, 1]).to be_descending }
30
- end
28
+ describe '#be_descending' do
29
+ context 'positive assertion' do
30
+ it { expect([4, 3, 2, 1]).to be_descending }
31
+ end
31
32
 
32
- context 'when invalid' do
33
- it { expect([1, 2, 3, 4]).not_to be_descending }
33
+ context 'negative assertion' do
34
+ it { expect([1, 2, 3, 4]).not_to be_descending }
35
+ end
34
36
  end
35
- end
36
37
 
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
38
+ describe '#be_email' do
39
+ context 'positive assertion' do
40
+ it { expect(Faker::Internet.email).to be_email }
41
+ it { expect('tiagopog@gmail.com').to be_email }
42
+ it { expect('foo@bar.com.br').to be_email }
43
+ end
43
44
 
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 }
45
+ context 'negative assertion' do
46
+ it { expect('foo@bar').not_to be_email }
47
+ it { expect('foo@').not_to be_email }
48
+ it { expect('@bar').not_to be_email }
49
+ it { expect('@bar.com').not_to be_email }
50
+ it { expect('foo bar@bar.com').not_to be_email }
51
+ end
50
52
  end
51
- end
52
53
 
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
54
+ describe '#be_url' do
55
+ context 'positive assertion' do
56
+ it { expect(Faker::Internet.url).to be_url }
57
+ it { expect('http://adtangerine.com').to be_url }
58
+ it { expect('http://www.facebook.com').to be_url }
59
+ it { expect('www.twitflink.com').to be_url }
60
+ it { expect('google.com.br').to be_url }
61
+ end
61
62
 
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 }
63
+ context 'negative assertion' do
64
+ it { expect('foobar.bar').not_to be_url }
65
+ it { expect('foobar').not_to be_url }
66
+ it { expect('foo bar.com.br').not_to be_url }
67
+ end
66
68
  end
67
- end
68
69
 
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([:jpg, :png]) }
77
- it { expect('http://foobar.com/foo/bar?image=foo.jpg').to be_image_url }
78
- end
70
+ describe '#be_image_url' do
71
+ context 'positive assertion' do
72
+ it { expect(Faker::Company.logo).to be_image_url }
73
+ it { expect('http://foobar.com/foo.jpg').to be_image_url }
74
+ it { expect('http://foobar.com/foo.jpg').to be_image_url(:jpg) }
75
+ it { expect('http://foobar.com/foo.gif').to be_image_url(:gif) }
76
+ it { expect('http://foobar.com/foo.png').to be_image_url(:png) }
77
+ it { expect('http://foobar.com/foo.png').to be_image_url([:jpg, :png]) }
78
+ it { expect('http://foobar.com/foo/bar?image=foo.jpg').to be_image_url }
79
+ end
79
80
 
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([:jpg, :png]) }
81
+ context 'negative assertion' do
82
+ it { expect('http://foobar.com').not_to be_image_url }
83
+ it { expect('http://foobar.com/foo.jpg').not_to be_image_url(:gif) }
84
+ it { expect('http://foobar.com/foo.gif').not_to be_image_url(:png) }
85
+ it { expect('http://foobar.com/foo.png').not_to be_image_url(:jpg) }
86
+ it { expect('http://foobar.com/foo.gif').not_to be_image_url([:jpg, :png]) }
87
+ end
86
88
  end
87
- end
88
89
 
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
90
+ describe '#be_a_list_of' do
91
+ context 'positive assertion' do
92
+ subject { Array.new(3, User.new) }
93
+ it { is_expected.to be_a_list_of(User) }
94
+ end
94
95
 
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 }
96
+ context 'negative assertion' do
97
+ subject { Array.new(3, User.new) << nil }
98
+ it { is_expected.to_not be_a_list_of(User) }
99
+ end
98
100
  end
99
101
  end
100
102
 
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
103
+ describe JsonApiMatchers do
104
+ subject(:response) { Fixtures::Response.new }
105
+
106
+ describe '#have_primary_data' do
107
+ context 'positive assertion' do
108
+ it do
109
+ expect(response).to have_primary_data('users')
110
+ end
111
+ end
106
112
 
107
- describe '#have_at_most' do
108
- context 'when valid' do
109
- it { expect(%w(foo bar foobar)).to have_at_most(3).items }
113
+ context 'negative assertion' do
114
+ it do
115
+ expect(response).not_to have_primary_data('foobar')
116
+ end
117
+ end
110
118
  end
111
- end
112
119
 
113
- describe '#have_error_on' do
114
- subject { User.new(email: nil, name: Faker::Name.name) }
120
+ describe '#have_data_attributes' do
121
+ let(:fields) { %w(first_name last_name full_name birthday) }
122
+
123
+ context 'positive assertion' do
124
+ it do
125
+ expect(response).to have_data_attributes(fields)
126
+ end
127
+ end
115
128
 
116
- context 'when valid' do
117
- it do
118
- subject.valid?
119
- is_expected.to have_error_on(:email)
129
+ context 'negative assertion' do
130
+ it do
131
+ expect(response).not_to have_data_attributes(fields + %w(foobar))
132
+ end
120
133
  end
121
134
  end
122
135
 
123
- context 'when invalid' do
124
- it do
125
- subject.valid?
126
- is_expected.not_to have_error_on(:name)
136
+ describe '#have_relationships' do
137
+ let(:relationships) { %w(posts) }
138
+
139
+ context 'positive assertion' do
140
+ it do
141
+ expect(response).to have_relationships(relationships)
142
+ end
143
+ end
144
+
145
+ context 'negative assertion' do
146
+ it do
147
+ expect(response).not_to have_relationships(relationships + %w(foobar))
148
+ end
127
149
  end
128
150
  end
129
- end
130
151
 
131
- describe '#include_items' do
132
- context 'when valid' do
133
- it { expect(%w(foo bar foobar)).to include_items(%w(foo bar foobar)) }
134
- it { expect(%w(lorem ipsum)).to include_items('lorem', 'ipsum') }
135
- it { expect([1, 'foo', ['bar']]).to include_items([1, 'foo', ['bar']]) }
152
+ describe '#have_included_relationships' do
153
+ let(:relationships) { %w(posts) }
154
+
155
+ context 'positive assertion' do
156
+ it do
157
+ expect(response).to have_included_relationships
158
+ end
159
+ end
136
160
  end
137
161
 
138
- context 'when invalid' do
139
- it { expect(%w(foo bar foobar)).not_to include_items(%w(lorem)) }
162
+ describe '#have_meta_record_count' do
163
+ context 'positive assertion' do
164
+ it do
165
+ expect(response).to have_meta_record_count(2)
166
+ end
167
+ end
168
+
169
+ context 'negative assertion' do
170
+ it do
171
+ expect(response).not_to have_meta_record_count(3)
172
+ end
173
+ end
140
174
  end
141
175
  end
142
176
 
143
- describe '#be_a_list_of' do
144
- context 'when valid' do
145
- subject { Array.new(3, User.new) }
146
- it { is_expected.to be_a_list_of(User) }
177
+ describe OtherMatchers do
178
+ describe '#have_error_on' do
179
+ subject { User.new(email: nil, name: Faker::Name.name) }
180
+
181
+ context 'positive assertion' do
182
+ it do
183
+ subject.valid?
184
+ is_expected.to have_error_on(:email)
185
+ end
186
+ end
187
+
188
+ context 'negative assertion' do
189
+ it do
190
+ subject.valid?
191
+ is_expected.not_to have_error_on(:name)
192
+ end
193
+ end
147
194
  end
148
195
 
149
- context 'when invalid' do
150
- subject { Array.new(3, User.new) << nil }
151
- it { is_expected.to_not be_a_list_of(User) }
196
+ describe '#include_items' do
197
+ context 'positive assertion' do
198
+ it { expect(%w(foo bar foobar)).to include_items(%w(foo bar foobar)) }
199
+ it { expect(%w(lorem ipsum)).to include_items('lorem', 'ipsum') }
200
+ it { expect([1, 'foo', ['bar']]).to include_items([1, 'foo', ['bar']]) }
201
+ end
202
+
203
+ context 'negative assertion' do
204
+ it { expect(%w(foo bar foobar)).not_to include_items(%w(lorem)) }
205
+ end
152
206
  end
153
207
  end
154
208
 
155
- describe '#be_a_bad_request' do
156
- let(:response) { double('http response') }
209
+ describe ::RSpec::CollectionMatchers do
210
+ describe '#have' do
211
+ context 'positive assertion' do
212
+ it { expect([1]).to have(1).item }
213
+ it { expect(%w(foo bar)).to have(2).items }
214
+ end
157
215
 
158
- context 'ok' do
159
- before { allow(response).to receive(:code).and_return(200) }
160
- it { expect(response).to_not be_a_bad_request }
216
+ context 'negative assertion' do
217
+ it { expect([1]).not_to have(2).items }
218
+ it { expect(%w(foo bar)).not_to have(1).item }
219
+ end
161
220
  end
162
221
 
163
- context 'not found' do
164
- before { allow(response).to receive(:code).and_return(404) }
165
- it { expect(response).to be_a_bad_request }
222
+ describe '#have_at_least' do
223
+ context 'positive assertion' do
224
+ it { expect(%w(foo bar foobar)).to have_at_least(3).items }
225
+ end
166
226
  end
167
227
 
168
- context 'unauthorized' do
169
- before { allow(response).to receive(:code).and_return(401) }
170
- it { expect(response).to be_a_bad_request }
228
+ describe '#have_at_most' do
229
+ context 'positive assertion' do
230
+ it { expect(%w(foo bar foobar)).to have_at_most(3).items }
231
+ end
171
232
  end
172
233
  end
173
234
  end
data/spec/spec_helper.rb CHANGED
@@ -2,7 +2,7 @@ require 'bundler/setup'
2
2
  require 'rubygems'
3
3
  require 'smart_rspec'
4
4
  require 'faker'
5
- require 'factories/user'
6
-
7
- include Factories
5
+ require 'fixtures/user'
6
+ require 'fixtures/response'
8
7
 
8
+ include Fixtures
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Guedes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-13 00:00:00.000000000 Z
11
+ date: 2016-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -119,13 +119,17 @@ files:
119
119
  - lib/smart_rspec/macros.rb
120
120
  - lib/smart_rspec/matchers.rb
121
121
  - lib/smart_rspec/matchers/be_matchers.rb
122
+ - lib/smart_rspec/matchers/json_api_matchers.rb
122
123
  - lib/smart_rspec/matchers/other_matchers.rb
123
- - lib/smart_rspec/support/assertions.rb
124
- - lib/smart_rspec/support/expectations.rb
124
+ - lib/smart_rspec/support/controller/response.rb
125
+ - lib/smart_rspec/support/model/assertions.rb
126
+ - lib/smart_rspec/support/model/expectations.rb
125
127
  - lib/smart_rspec/support/regexes.rb
126
128
  - lib/smart_rspec/version.rb
127
129
  - smart_rspec.gemspec
128
- - spec/factories/user.rb
130
+ - spec/fixtures/response.rb
131
+ - spec/fixtures/user.rb
132
+ - spec/fixtures/users.json
129
133
  - spec/smart_rspec/macros_spec.rb
130
134
  - spec/smart_rspec/matchers_spec.rb
131
135
  - spec/spec_helper.rb
@@ -149,12 +153,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
153
  version: '0'
150
154
  requirements: []
151
155
  rubyforge_project:
152
- rubygems_version: 2.4.6
156
+ rubygems_version: 2.6.2
153
157
  signing_key:
154
158
  specification_version: 4
155
159
  summary: Macros and matchers to make your RSpec tests even more amazing.
156
160
  test_files:
157
- - spec/factories/user.rb
161
+ - spec/fixtures/response.rb
162
+ - spec/fixtures/user.rb
163
+ - spec/fixtures/users.json
158
164
  - spec/smart_rspec/macros_spec.rb
159
165
  - spec/smart_rspec/matchers_spec.rb
160
166
  - spec/spec_helper.rb
@@ -1,119 +0,0 @@
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
- validation_expectation(attr, e)
10
- end
11
- end
12
- end
13
-
14
- def validates_exclusion_of(attr, validation)
15
- it 'has a reserved value' do
16
- validation_expectation(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
- validation_expectation(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
- validation_expectation(attr, value)
40
- end
41
- end
42
-
43
- def validates_length_of(attr, validation)
44
- validation.each do |key, value|
45
- next unless [:in, :is, :maximum, :minimum, :within].include?(key)
46
- txt, n = build_length_validation(key, value)
47
- it txt do
48
- validation_expectation(attr, 'x' * n)
49
- end
50
- end
51
- end
52
-
53
- def validates_presence_of(attr, validation)
54
- it 'is blank' do
55
- validation_expectation(attr, nil)
56
- end
57
- end
58
-
59
- def validates_uniqueness_of(attr, validation)
60
- scoped = scoped_validation?(validation)
61
- it "is already in use#{" (scope: #{validation[:scope]})" if scoped}" do
62
- mock =
63
- if scoped
64
- copy = subject.send(validation[:scope])
65
- validation[:mock].send("#{validation[:scope]}=", copy)
66
- validation[:mock]
67
- else
68
- subject.dup
69
- end
70
- subject.save unless subject.persisted?
71
- validation_expectation(attr, subject.send(attr), mock)
72
- end
73
- end
74
-
75
- def assert_has_attributes(attrs, options)
76
- type_str = build_type_str(options)
77
-
78
- attrs.each do |attr|
79
- it %Q(has an attribute named "#{attr}"#{type_str}) do
80
- expect(subject).to respond_to(attr)
81
- has_attributes_expectation(attr, options)
82
- end
83
- end
84
- end
85
-
86
- def assert_association(type, associations)
87
- associations.each do |model|
88
- it "#{type.to_s.gsub('_', ' ')} #{model}" do
89
- expect(subject).to respond_to(model)
90
- association_expectation(type, model)
91
- end
92
- end
93
- end
94
-
95
- def build_length_validation(key, value)
96
- case key
97
- when :in, :within then ['is out of the length range', value.max + 1]
98
- when :is, :minimum then ["is #{key == :is ? 'invalid' : 'too short'}", value - 1]
99
- when :maximum then ['is too long', value + 1]
100
- end
101
- end
102
-
103
- def build_type_str(options)
104
- if !options.nil? && options[:type]
105
- " (%s%s%s)" % [
106
- ('Enumerated ' if options[:enum]),
107
- options[:type],
108
- (", default: #{options[:default]}" if options[:default])
109
- ]
110
- end
111
- end
112
-
113
- def scoped_validation?(validation)
114
- validation.is_a?(Hash) && ([:scope, :mock] - validation.keys).empty?
115
- end
116
- end
117
- end
118
- end
119
-
@@ -1,42 +0,0 @@
1
- module SmartRspec
2
- module Support
3
- module Expectations
4
- def validation_expectation(attr, value = nil, mock = nil)
5
- mock ||= subject
6
- mock.send("#{attr}=", value)
7
-
8
- expect(mock).not_to be_valid
9
- expect(mock).to have_error_on(attr)
10
- end
11
-
12
- def default_expectation(attr, value)
13
- expect(subject.send(attr)).to eq(value)
14
- end
15
-
16
- def enum_expectation(attr, value)
17
- expect(value).to include(subject.send(attr).to_sym)
18
- end
19
-
20
- def type_expectation(attr, value)
21
- assert_type = value != :Boolean ? be_kind_of(Kernel.const_get(value)) : be_boolean
22
- expect(subject.send(attr)).to assert_type
23
- end
24
-
25
- def has_attributes_expectation(attr, options) options.each do |key, value|
26
- send("#{key}_expectation", attr, value)
27
- end
28
- end
29
-
30
- def association_expectation(type, model)
31
- if type == :has_many
32
- expect(subject).to respond_to("#{model.to_s.singularize}_ids")
33
- elsif type == :belongs_to
34
- %W(#{model}= #{model}_id #{model}_id=).each do |method|
35
- expect(subject).to respond_to(method)
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
42
-