rails_api_kit 1.0.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.
@@ -0,0 +1,126 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe NotesController, type: :request do
4
+ describe "PUT /notes/:id" do
5
+ let(:note) { create_note }
6
+ let(:note_id) { note.id }
7
+ let(:user) { note.user }
8
+ let(:user_id) { user.id }
9
+ let(:note_params) do
10
+ {
11
+ note: {
12
+ title: FFaker::Company.name,
13
+ user_id: user_id
14
+ }
15
+ }
16
+ end
17
+ let(:params) { note_params }
18
+
19
+ before do
20
+ put(note_path(note_id), params: params.to_json, headers: api_headers)
21
+ end
22
+
23
+ it 'renders single' do
24
+ expect(response).to have_http_status(:ok)
25
+ expect(response_json["data"]["id"]).to eql(note.id)
26
+ expect(response_json["meta"]).to eq("single" => true)
27
+ end
28
+
29
+ context "with a missing parameter in the payload" do
30
+ let(:params) { {} }
31
+
32
+ it do
33
+ expect(response).to have_http_status(:unprocessable_content)
34
+ expect(response_json["errors"].size).to eq(1)
35
+ expect(response_json["errors"][0]["status"]).to eq("422")
36
+ expect(response_json["errors"][0]["title"]).to eq('Unprocessable Content')
37
+ expect(response_json["errors"][0]["detail"]).to eq("Required parameter missing or invalid")
38
+ end
39
+ end
40
+
41
+ context "with an invalid payload" do
42
+ let(:params) do
43
+ payload = note_params.dup
44
+ payload[:note][:user_id] = nil
45
+ payload
46
+ end
47
+
48
+ it 'with invalid user id' do
49
+ expect(response).to have_http_status(:unprocessable_content)
50
+ expect(response_json["errors"].size).to eq(1)
51
+ expect(response_json["errors"][0]["status"]).to eq("422")
52
+ expect(response_json["errors"][0]["code"]).to include("blank")
53
+ expect(response_json["errors"][0]["title"]).to eq('Error')
54
+ expect(response_json["errors"][0]["detail"]).to eq("User must exist")
55
+ expect(response_json["errors"][0]["attribute"]).to eq("user")
56
+ end
57
+
58
+ context "required by validations" do
59
+ let(:params) do
60
+ payload = note_params.dup
61
+ payload[:note][:title] = "BAD_TITLE"
62
+ payload[:note][:quantity] = 100 + rand(10)
63
+ payload
64
+ end
65
+
66
+ it 'multiple errors' do
67
+ expect(response).to have_http_status(:unprocessable_content)
68
+ expect(response_json["errors"].size).to eq(3)
69
+
70
+ expect(response_json["errors"][0]["status"]).to eq("422")
71
+ expect(response_json["errors"][0]["code"]).to include("invalid")
72
+ expect(response_json["errors"][0]["title"]).to eq('Error')
73
+ expect(response_json["errors"][0]["detail"]).to eq("Title is invalid")
74
+
75
+ expect(response_json["errors"][1]["status"]).to eq("422")
76
+ expect(response_json["errors"][1]["code"]).to eq("less_than")
77
+ expect(response_json["errors"][1]["title"]).to eq('Error')
78
+ expect(response_json["errors"][1]["detail"]).to eq("Quantity must be less than 100")
79
+
80
+ expect(response_json["errors"][2]["status"]).to eq("422")
81
+ expect(response_json["errors"][2]["code"]).to eq("invalid")
82
+ expect(response_json["errors"][2]["title"]).to eq('Error')
83
+ expect(response_json["errors"][2]["detail"]).to eq("Title has typos")
84
+ end
85
+ end
86
+
87
+ context "as a param attribute" do
88
+ let(:params) do
89
+ payload = note_params.dup
90
+ payload[:note].delete(:title)
91
+ payload
92
+ end
93
+
94
+ it do
95
+ expect(response).to have_http_status(:success)
96
+ end
97
+ end
98
+ end
99
+
100
+ context "with a bad note ID" do
101
+ let(:user_id) { nil }
102
+ let(:note_id) { rand(10) }
103
+
104
+ it do
105
+ expect(response).to have_http_status(:not_found)
106
+ expect(response_json["errors"].size).to eq(1)
107
+ expect(response_json["errors"][0]["status"]).to eq("404")
108
+ expect(response_json["errors"][0]["title"]).to eq(Rack::Utils::HTTP_STATUS_CODES[404])
109
+ expect(response_json["errors"][0]["detail"]).to eq("Resource not found")
110
+ end
111
+ end
112
+
113
+ context "with an exception" do
114
+ let(:user_id) { nil }
115
+ let(:note_id) { "tada" }
116
+
117
+ it do
118
+ expect(response).to have_http_status(:internal_server_error)
119
+ expect(response_json["errors"].size).to eq(1)
120
+ expect(response_json["errors"][0]["status"]).to eq("500")
121
+ expect(response_json["errors"][0]["title"]).to eq(Rack::Utils::HTTP_STATUS_CODES[500])
122
+ expect(response_json["errors"][0]["detail"]).to eql("tada")
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,171 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe UsersController, type: :request do
4
+ describe 'GET /users' do
5
+ let!(:user) { }
6
+ let(:params) { }
7
+
8
+ before do
9
+ get(users_path, params: params, headers: api_headers)
10
+ end
11
+
12
+ context 'with users' do
13
+ let(:first_user) { create_user }
14
+ let(:second_user) { create_user }
15
+ let(:third_user) { create_note.user }
16
+ let(:users) { [ first_user, second_user, third_user ] }
17
+ let(:user) { users.last }
18
+ let(:note) { third_user.notes.first }
19
+
20
+ context 'returns customers and dasherized first name' do
21
+ let(:params) do
22
+ { upcase: :yes, fields: [ :first_name ] }
23
+ end
24
+
25
+ it do
26
+ expect(response).to have_http_status(:ok)
27
+ expect(response_json['data'].size).to eq(users.size)
28
+
29
+ response_json['data'].each do |item|
30
+ user = users.detect { |u| u.id == item['id'].to_i }
31
+ expect(item['first_name']).to eql(user.first_name.upcase)
32
+ end
33
+ end
34
+ end
35
+
36
+ context 'returns customers and full name' do
37
+ let(:params) do
38
+ { fields: { user: 'id,full_name' } }
39
+ end
40
+
41
+ it do
42
+ expect(response).to have_http_status(:ok)
43
+ expect(response_json['data'].size).to eq(users.size)
44
+
45
+ response_json['data'].each do |item|
46
+ user = users.detect { |u| u.id == item['id'].to_i }
47
+ full_name = "#{user.first_name} #{user.last_name}"
48
+ expect(item['full_name']).to eql(full_name)
49
+ end
50
+ end
51
+ end
52
+
53
+ context 'returns customers included and sparse fields' do
54
+ let(:params) do
55
+ {
56
+ include: 'notes',
57
+ fields: { note: 'title,updated_at' }
58
+ }
59
+ end
60
+
61
+ it do
62
+ expect(response).to have_http_status(:ok)
63
+ expect(response_json['data'].last.keys).not_to include('custom_note')
64
+ expect(response_json['data'].last['notes'].size).to eql(1)
65
+ expect(response_json['data'].last['notes'][0]).to eql({
66
+ 'title' => note.title,
67
+ 'updated_at' => note.updated_at.as_json
68
+ })
69
+ end
70
+ end
71
+
72
+ context 'returns customers included runtime structs' do
73
+ let(:params) do
74
+ {
75
+ include: 'custom_note',
76
+ fields: { custom_note: 'title,updated_at' }
77
+ }
78
+ end
79
+
80
+ it do
81
+ expect(response).to have_http_status(:ok)
82
+ expect(response_json['data']).to all(include('custom_note'))
83
+ expect(response_json['data'].first['custom_note']).to include('title' => "My", 'quantity' => 1)
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ describe 'GET /users/:id' do
90
+ let(:note) { create_note }
91
+ let(:user) { note.user }
92
+ let(:params) { }
93
+
94
+ before do
95
+ get(user_path(user), params: params, headers: api_headers)
96
+ end
97
+
98
+ context 'with users' do
99
+ context 'returns user' do
100
+ it do
101
+ expect(response).to have_http_status(:ok)
102
+ expect(response_json['data']['id']).to eq(user.id)
103
+ expect(response_json['data']['first_name']).to eq(user.first_name)
104
+ expect(response_json['data']['last_name']).to eq(user.last_name)
105
+ expect(response_json['data'].keys).not_to include('notes')
106
+ end
107
+ end
108
+
109
+ context 'returns customers first name and notes id' do
110
+ let(:params) do
111
+ {
112
+ include: 'notes',
113
+ fields: { user: 'first_name', note: 'id' }
114
+ }
115
+ end
116
+
117
+ it do
118
+ expect(response).to have_http_status(:ok)
119
+ expect(response_json['data']).to eq({ "first_name" => user.first_name, "notes" => [ { "id" => note.id } ] })
120
+ end
121
+ end
122
+
123
+ context 'returns user attributes with and notes id' do
124
+ let(:params) do
125
+ {
126
+ include: 'notes',
127
+ fields: { note: 'id' }
128
+ }
129
+ end
130
+
131
+ it do
132
+ expect(response).to have_http_status(:ok)
133
+ expect(response_json.dig('data', 'id')).to eq(user.id)
134
+ expect(response_json.dig('data', 'first_name')).to eq(user.first_name)
135
+ expect(response_json.dig('data', 'last_name')).to eq(user.last_name)
136
+ expect(response_json.dig('data', 'notes', 0, 'id')).to eq(note.id)
137
+ end
138
+ end
139
+
140
+ context 'returns customers first name and notes id' do
141
+ let(:params) do
142
+ { fields: { user: 'first_name' } }
143
+ end
144
+
145
+ it do
146
+ expect(response).to have_http_status(:ok)
147
+ expect(response_json['data']).to eq({ "first_name" => user.first_name })
148
+ end
149
+ end
150
+
151
+ context 'returns customers included and sparse fields' do
152
+ let(:params) do
153
+ {
154
+ include: 'notes',
155
+ fields: { note: 'title,updated_at' }
156
+ }
157
+ end
158
+
159
+ it 'should render notes with user' do
160
+ expect(response).to have_http_status(:ok)
161
+ expect(response_json['data'].keys.size).to eql(7)
162
+ expect(response_json['data']['notes'].size).to eql(1)
163
+ expect(response_json['data']['notes'][0]).to eql({
164
+ 'title' => note.title,
165
+ 'updated_at' => note.updated_at.as_json
166
+ })
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe UsersController, type: :request do
4
+ describe '#extract_attributes_and_predicate' do
5
+ context 'mixed attributes (and/or)' do
6
+ it 'extracts ANDs' do
7
+ attributes, predicates = ApiKit::Filtering
8
+ .extract_attributes_and_predicates('attr1_and_attr2_eq')
9
+ expect(attributes).to eq([ 'attr1', 'attr2' ])
10
+ expect(predicates.size).to eq(1)
11
+ expect(predicates[0].name).to eq('eq')
12
+ end
13
+ end
14
+
15
+ context 'mixed predicates' do
16
+ it 'extracts in order' do
17
+ attributes, predicates = ApiKit::Filtering
18
+ .extract_attributes_and_predicates('attr1_sum_eq')
19
+ expect(attributes).to eq([ 'attr1' ])
20
+ expect(predicates.size).to eq(2)
21
+ expect(predicates[0].name).to eq('sum')
22
+ expect(predicates[1].name).to eq('eq')
23
+ end
24
+ end
25
+ end
26
+
27
+ describe 'GET /users' do
28
+ let!(:user) { }
29
+ let(:params) { }
30
+
31
+ before do
32
+ get(users_path, params: params, headers: api_headers)
33
+ end
34
+
35
+ context 'with users' do
36
+ let(:first_user) { create_user }
37
+ let(:second_user) { create_note.user }
38
+ let(:third_user) { create_user }
39
+ let(:users) { [ first_user, second_user, third_user ] }
40
+ let(:user) { users.last }
41
+
42
+ context 'returns filtered users' do
43
+ let(:params) do
44
+ {
45
+ filter: {
46
+ last_name_or_first_name_cont_any: (
47
+ "#{third_user.first_name[0..5]}%,#{self.class.name}"
48
+ )
49
+ }
50
+ }
51
+ end
52
+
53
+ it do
54
+ expect(response).to have_http_status(:ok)
55
+ expect(response_json['data'].size).to eq(1)
56
+ expect(response_json['data'][0]['id']).to eql(third_user.id)
57
+ end
58
+
59
+ context 'with a comma' do
60
+ let(:params) do
61
+ third_user.update(first_name: third_user.first_name + ',')
62
+
63
+ {
64
+ filter: { first_name_eq: third_user.first_name }
65
+ }
66
+ end
67
+
68
+ it do
69
+ expect(response).to have_http_status(:ok)
70
+ expect(response_json['data'].size).to eq(1)
71
+ expect(response_json['data'][0]['id']).to eql(third_user.id)
72
+ end
73
+ end
74
+ end
75
+
76
+ context 'returns sorted users by notes quantity sum' do
77
+ let(:params) do
78
+ { sort: '-notes_quantity_sum' }
79
+ end
80
+
81
+ it do
82
+ expect(response).to have_http_status(:ok)
83
+ expect(response_json['data'].size).to eq(3)
84
+ expect(response_json['data'][0]['id']).to eql(second_user.id)
85
+ end
86
+ end
87
+
88
+ context 'returns sorted users by notes' do
89
+ let(:params) do
90
+ { sort: '-notes_created_at' }
91
+ end
92
+
93
+ it do
94
+ expect(response).to have_http_status(:ok)
95
+ expect(response_json['data'].size).to eq(3)
96
+ expect(response_json['data'][0]['id']).to eql(second_user.id)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end