jsonapi-resources 0.7.1.beta1 → 0.7.1.beta2

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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +248 -74
  3. data/lib/jsonapi-resources.rb +5 -3
  4. data/lib/jsonapi/acts_as_resource_controller.rb +77 -14
  5. data/lib/jsonapi/configuration.rb +77 -16
  6. data/lib/jsonapi/error.rb +12 -0
  7. data/lib/jsonapi/error_codes.rb +2 -0
  8. data/lib/jsonapi/exceptions.rb +29 -9
  9. data/lib/jsonapi/formatter.rb +29 -4
  10. data/lib/jsonapi/link_builder.rb +18 -18
  11. data/lib/jsonapi/mime_types.rb +25 -6
  12. data/lib/jsonapi/naive_cache.rb +30 -0
  13. data/lib/jsonapi/operation.rb +10 -342
  14. data/lib/jsonapi/operation_dispatcher.rb +87 -0
  15. data/lib/jsonapi/operation_result.rb +2 -1
  16. data/lib/jsonapi/paginator.rb +6 -2
  17. data/lib/jsonapi/processor.rb +283 -0
  18. data/lib/jsonapi/relationship.rb +6 -4
  19. data/lib/jsonapi/{request.rb → request_parser.rb} +46 -35
  20. data/lib/jsonapi/resource.rb +88 -13
  21. data/lib/jsonapi/resource_controller.rb +2 -14
  22. data/lib/jsonapi/resource_controller_metal.rb +17 -0
  23. data/lib/jsonapi/resource_serializer.rb +62 -47
  24. data/lib/jsonapi/resources/version.rb +1 -1
  25. data/lib/jsonapi/response_document.rb +13 -2
  26. data/lib/jsonapi/routing_ext.rb +49 -11
  27. metadata +37 -129
  28. data/.gitignore +0 -22
  29. data/.travis.yml +0 -9
  30. data/Gemfile +0 -23
  31. data/Rakefile +0 -20
  32. data/jsonapi-resources.gemspec +0 -29
  33. data/lib/jsonapi/active_record_operations_processor.rb +0 -35
  34. data/lib/jsonapi/operations_processor.rb +0 -120
  35. data/locales/en.yml +0 -80
  36. data/test/config/database.yml +0 -5
  37. data/test/controllers/controller_test.rb +0 -3312
  38. data/test/fixtures/active_record.rb +0 -1486
  39. data/test/fixtures/author_details.yml +0 -9
  40. data/test/fixtures/book_authors.yml +0 -3
  41. data/test/fixtures/book_comments.yml +0 -12
  42. data/test/fixtures/books.yml +0 -7
  43. data/test/fixtures/categories.yml +0 -35
  44. data/test/fixtures/comments.yml +0 -21
  45. data/test/fixtures/comments_tags.yml +0 -20
  46. data/test/fixtures/companies.yml +0 -4
  47. data/test/fixtures/craters.yml +0 -9
  48. data/test/fixtures/customers.yml +0 -11
  49. data/test/fixtures/documents.yml +0 -3
  50. data/test/fixtures/expense_entries.yml +0 -13
  51. data/test/fixtures/facts.yml +0 -11
  52. data/test/fixtures/hair_cuts.yml +0 -3
  53. data/test/fixtures/iso_currencies.yml +0 -17
  54. data/test/fixtures/line_items.yml +0 -37
  55. data/test/fixtures/makes.yml +0 -2
  56. data/test/fixtures/moons.yml +0 -6
  57. data/test/fixtures/numeros_telefone.yml +0 -3
  58. data/test/fixtures/order_flags.yml +0 -7
  59. data/test/fixtures/people.yml +0 -31
  60. data/test/fixtures/pictures.yml +0 -15
  61. data/test/fixtures/planet_types.yml +0 -19
  62. data/test/fixtures/planets.yml +0 -47
  63. data/test/fixtures/posts.yml +0 -102
  64. data/test/fixtures/posts_tags.yml +0 -59
  65. data/test/fixtures/preferences.yml +0 -14
  66. data/test/fixtures/products.yml +0 -3
  67. data/test/fixtures/purchase_orders.yml +0 -23
  68. data/test/fixtures/sections.yml +0 -8
  69. data/test/fixtures/tags.yml +0 -39
  70. data/test/fixtures/vehicles.yml +0 -17
  71. data/test/fixtures/web_pages.yml +0 -3
  72. data/test/helpers/assertions.rb +0 -13
  73. data/test/helpers/functional_helpers.rb +0 -59
  74. data/test/helpers/value_matchers.rb +0 -60
  75. data/test/helpers/value_matchers_test.rb +0 -40
  76. data/test/integration/requests/namespaced_model_test.rb +0 -13
  77. data/test/integration/requests/request_test.rb +0 -932
  78. data/test/integration/routes/routes_test.rb +0 -218
  79. data/test/integration/sti_fields_test.rb +0 -18
  80. data/test/lib/generators/jsonapi/controller_generator_test.rb +0 -25
  81. data/test/lib/generators/jsonapi/resource_generator_test.rb +0 -30
  82. data/test/test_helper.rb +0 -342
  83. data/test/unit/formatters/dasherized_key_formatter_test.rb +0 -8
  84. data/test/unit/jsonapi_request/jsonapi_request_test.rb +0 -199
  85. data/test/unit/operation/operations_processor_test.rb +0 -528
  86. data/test/unit/pagination/offset_paginator_test.rb +0 -245
  87. data/test/unit/pagination/paged_paginator_test.rb +0 -242
  88. data/test/unit/resource/resource_test.rb +0 -560
  89. data/test/unit/serializer/include_directives_test.rb +0 -113
  90. data/test/unit/serializer/link_builder_test.rb +0 -244
  91. data/test/unit/serializer/polymorphic_serializer_test.rb +0 -383
  92. data/test/unit/serializer/response_document_test.rb +0 -61
  93. data/test/unit/serializer/serializer_test.rb +0 -1939
@@ -1,35 +0,0 @@
1
- class ActiveRecordOperationsProcessor < JSONAPI::OperationsProcessor
2
- private
3
-
4
- def transaction
5
- if @transactional
6
- ActiveRecord::Base.transaction do
7
- yield
8
- end
9
- else
10
- yield
11
- end
12
- end
13
-
14
- def rollback
15
- fail ActiveRecord::Rollback if @transactional
16
- end
17
-
18
- # Catch errors that should be handled before JSONAPI::Exceptions::Error
19
- # and other unprocessed exceptions
20
- def process_operation(operation)
21
- with_default_handling do
22
- begin
23
- operation.apply
24
- rescue ActiveRecord::DeleteRestrictionError => e
25
- record_locked_error = JSONAPI::Exceptions::RecordLocked.new(e.message)
26
- return JSONAPI::ErrorsOperationResult.new(record_locked_error.errors[0].code, record_locked_error.errors)
27
-
28
- rescue ActiveRecord::RecordNotFound
29
- key = operation.respond_to?(:associated_key) ? operation.associated_key : :unavailable
30
- record_not_found = JSONAPI::Exceptions::RecordNotFound.new(key)
31
- return JSONAPI::ErrorsOperationResult.new(record_not_found.errors[0].code, record_not_found.errors)
32
- end
33
- end
34
- end
35
- end
@@ -1,120 +0,0 @@
1
- module JSONAPI
2
- class OperationsProcessor
3
- include Callbacks
4
- define_jsonapi_resources_callbacks :operation,
5
- :operations,
6
- :find_operation,
7
- :show_operation,
8
- :show_relationship_operation,
9
- :show_related_resource_operation,
10
- :show_related_resources_operation,
11
- :create_resource_operation,
12
- :remove_resource_operation,
13
- :replace_fields_operation,
14
- :replace_to_one_relationship_operation,
15
- :replace_polymorphic_to_one_relationship_operation,
16
- :create_to_many_relationship_operation,
17
- :replace_to_many_relationship_operation,
18
- :remove_to_many_relationship_operation,
19
- :remove_to_one_relationship_operation
20
-
21
- class << self
22
- def operations_processor_for(operations_processor)
23
- operations_processor_class_name = "#{operations_processor.to_s.camelize}OperationsProcessor"
24
- operations_processor_class_name.safe_constantize
25
- end
26
- end
27
-
28
- def process(request)
29
- @results = JSONAPI::OperationResults.new
30
- @request = request
31
- @operations = request.operations
32
-
33
- # Use transactions if more than one operation and if one of the operations can be transactional
34
- # Even if transactional transactions won't be used unless the derived OperationsProcessor supports them.
35
- @transactional = false
36
- @operations.each do |operation|
37
- @transactional |= operation.transactional
38
- end
39
-
40
- run_callbacks :operations do
41
- transaction do
42
- # Links and meta data global to the set of operations
43
- @operations_meta = {}
44
- @operations_links = {}
45
- @operations.each do |operation|
46
- @operation = operation
47
- # Links and meta data for each operation
48
- @operation_meta = {}
49
- @operation_links = {}
50
- run_callbacks :operation do
51
- @result = nil
52
- run_callbacks @operation.class.name.demodulize.underscore.to_sym do
53
- @result = process_operation(@operation)
54
- end
55
- @result.meta.merge!(@operation_meta)
56
- @result.links.merge!(@operation_links)
57
- @results.add_result(@result)
58
- rollback if @results.has_errors?
59
- end
60
- end
61
- @results.meta = @operations_meta
62
- @results.links = @operations_links
63
- end
64
- end
65
- @results
66
- end
67
-
68
- private
69
-
70
- # The base OperationsProcessor provides no transaction support
71
- # Override the transaction and rollback methods to provide transaction support.
72
- # For ActiveRecord transactions you can use the ActiveRecordOperationsProcessor
73
- def transaction
74
- yield
75
- end
76
-
77
- def rollback
78
- end
79
-
80
- # If overriding in child operation processors, call operation.apply and
81
- # catch errors that should be handled before JSONAPI::Exceptions::Error
82
- # and other unprocessed exceptions
83
- def process_operation(operation)
84
- with_default_handling do
85
- operation.apply
86
- end
87
- end
88
-
89
- def with_default_handling(&block)
90
- yield
91
- rescue JSONAPI::Exceptions::Error => e
92
- raise e
93
-
94
- rescue => e
95
- if JSONAPI.configuration.exception_class_whitelist.any? { |k| e.class.ancestors.include?(k) }
96
- raise e
97
- else
98
- @request.server_error_callbacks.each { |callback| safe_run_callback(callback, e) }
99
-
100
- internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e)
101
- Rails.logger.error { "Internal Server Error: #{e.message} #{e.backtrace.join("\n")}" }
102
- return JSONAPI::ErrorsOperationResult.new(internal_server_error.errors[0].code, internal_server_error.errors)
103
- end
104
- end
105
-
106
- def safe_run_callback(callback, error)
107
- begin
108
- callback.call(error)
109
- rescue => e
110
- Rails.logger.error { "Error in error handling callback: #{e.message} #{e.backtrace.join("\n")}" }
111
- internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e)
112
- return JSONAPI::ErrorsOperationResult.new(internal_server_error.errors[0].code, internal_server_error.errors)
113
- end
114
- end
115
-
116
- end
117
- end
118
-
119
- class BasicOperationsProcessor < JSONAPI::OperationsProcessor
120
- end
@@ -1,80 +0,0 @@
1
- en:
2
- jsonapi-resources:
3
- exceptions:
4
- internal_server_error:
5
- title: 'Internal Server Error'
6
- detail: 'Internal Server Error'
7
- invalid_resource:
8
- title: 'Invalid resource'
9
- detail: "%{resource} is not a valid resource."
10
- record_not_found:
11
- title: 'Record not found'
12
- detail: "The record identified by %{id} could not be found."
13
- unsupported_media_type:
14
- title: 'Unsupported media type'
15
- detail: "All requests that create or update must use the '%{needed_media_type}' Content-Type. This request specified '%{media_type}.'"
16
- has_many_relation:
17
- title: 'Relation exists'
18
- detail: "The relation to %{id} already exists."
19
- to_many_set_replacement_forbidden:
20
- title: 'Complete replacement forbidden'
21
- detail: 'Complete replacement forbidden for this relationship'
22
- invalid_filter_syntax:
23
- title: 'Invalid filters syntax'
24
- detail: "%{filters} is not a valid syntax for filtering."
25
- filter_not_allowed:
26
- title: "Filter not allowed"
27
- detail: "%{filter} is not allowed."
28
- invalid_filter_value:
29
- title: 'Invalid filter value'
30
- detail: "%{value} is not a valid value for %{filter}."
31
- invalid_field_value:
32
- title: 'Invalid field value'
33
- detail: "%{value} is not a valid value for %{field}."
34
- invalid_field_format:
35
- title: 'Invalid field format'
36
- detail: 'Fields must specify a type.'
37
- invalid_links_object:
38
- title: 'Invalid Links Object'
39
- detail: 'Data is not a valid Links Object.'
40
- type_mismatch:
41
- title: 'Type Mismatch'
42
- detail: "%{type} is not a valid type for this operation."
43
- invalid_field:
44
- title: 'Invalid field'
45
- detail: "%{field} is not a valid field for %{type}."
46
- invalid_include:
47
- title: 'Invalid field'
48
- detail: "%{relationship} is not a valid relationship of %{resource}"
49
- invalid_sort_criteria:
50
- title: 'Invalid sort criteria'
51
- detail: "%{sort_criteria} is not a valid sort criteria for %{resource}"
52
- parameters_not_allowed:
53
- title: 'Param not allowed'
54
- detail: "%{param} is not allowed."
55
- parameter_missing:
56
- title: 'Missing Parameter'
57
- detail: "The required parameter, %{param}, is missing."
58
- count_mismatch:
59
- title: 'Count to key mismatch'
60
- detail: 'The resource collection does not contain the same number of objects as the number of keys.'
61
- key_not_included_in_url:
62
- title: 'Key is not included in URL'
63
- detail: "The URL does not support the key %{key}"
64
- missing_key:
65
- title: 'A key is required'
66
- detail: 'The resource object does not contain a key.'
67
- record_locked:
68
- title: 'Locked resource'
69
- save_failed:
70
- title: 'Save failed or was cancelled'
71
- detail: 'Save failed or was cancelled'
72
- invalid_page_object:
73
- title: 'Invalid Page Object'
74
- detail: 'Invalid Page Object.'
75
- page_parameters_not_allowed:
76
- title: 'Page parameter not allowed'
77
- detail: "%{param} is not an allowed page parameter."
78
- invalid_page_value:
79
- title: 'Invalid page value'
80
- detail: "%{value} is not a valid value for %{page} page parameter."
@@ -1,5 +0,0 @@
1
- test:
2
- adapter: sqlite3
3
- database: test_db
4
- pool: 5
5
- timeout: 5000
@@ -1,3312 +0,0 @@
1
- require File.expand_path('../../test_helper', __FILE__)
2
-
3
- def set_content_type_header!
4
- @request.headers['Content-Type'] = JSONAPI::MEDIA_TYPE
5
- end
6
-
7
- class PostsControllerTest < ActionController::TestCase
8
- def setup
9
- JSONAPI.configuration.raise_if_parameters_not_allowed = true
10
- end
11
-
12
- def test_index
13
- get :index
14
- assert_response :success
15
- assert json_response['data'].is_a?(Array)
16
- end
17
-
18
- def test_exception_class_whitelist
19
- original_config = JSONAPI.configuration.dup
20
- JSONAPI.configuration.operations_processor = :error_raising
21
- # test that the operations processor rescues the error when it
22
- # has not been added to the exception_class_whitelist
23
- get :index
24
- assert_response 500
25
- # test that the operations processor does not rescue the error when it
26
- # has been added to the exception_class_whitelist
27
- JSONAPI.configuration.exception_class_whitelist << PostsController::SpecialError
28
- get :index
29
- assert_response 403
30
- ensure
31
- JSONAPI.configuration = original_config
32
- end
33
-
34
- def test_on_server_error_block_callback_with_exception
35
- original_config = JSONAPI.configuration.dup
36
- JSONAPI.configuration.operations_processor = :error_raising
37
- JSONAPI.configuration.exception_class_whitelist = []
38
-
39
- @controller.class.instance_variable_set(:@callback_message, "none")
40
- BaseController.on_server_error do
41
- @controller.class.instance_variable_set(:@callback_message, "Sent from block")
42
- end
43
-
44
- get :index
45
- assert_equal @controller.class.instance_variable_get(:@callback_message), "Sent from block"
46
-
47
- # test that it renders the default server error response
48
- assert_equal "Internal Server Error", json_response['errors'][0]['title']
49
- assert_equal "Internal Server Error", json_response['errors'][0]['detail']
50
- ensure
51
- JSONAPI.configuration = original_config
52
- end
53
-
54
- def test_on_server_error_method_callback_with_exception
55
- original_config = JSONAPI.configuration.dup
56
- JSONAPI.configuration.operations_processor = :error_raising
57
- JSONAPI.configuration.exception_class_whitelist = []
58
-
59
- #ignores methods that don't exist
60
- @controller.class.on_server_error :set_callback_message, :a_bogus_method
61
- @controller.class.instance_variable_set(:@callback_message, "none")
62
-
63
- get :index
64
- assert_equal @controller.class.instance_variable_get(:@callback_message), "Sent from method"
65
-
66
- # test that it renders the default server error response
67
- assert_equal "Internal Server Error", json_response['errors'][0]['title']
68
- ensure
69
- JSONAPI.configuration = original_config
70
- end
71
-
72
- def test_on_server_error_callback_without_exception
73
-
74
- callback = Proc.new { @controller.class.instance_variable_set(:@callback_message, "Sent from block") }
75
- @controller.class.on_server_error callback
76
- @controller.class.instance_variable_set(:@callback_message, "none")
77
-
78
- get :index
79
- assert_equal @controller.class.instance_variable_get(:@callback_message), "none"
80
-
81
- # test that it does not render error
82
- assert json_response.key?('data')
83
- end
84
-
85
- def test_index_filter_with_empty_result
86
- get :index, {filter: {title: 'post that does not exist'}}
87
- assert_response :success
88
- assert json_response['data'].is_a?(Array)
89
- assert_equal 0, json_response['data'].size
90
- end
91
-
92
- def test_index_filter_by_id
93
- get :index, {filter: {id: '1'}}
94
- assert_response :success
95
- assert json_response['data'].is_a?(Array)
96
- assert_equal 1, json_response['data'].size
97
- end
98
-
99
- def test_index_filter_by_title
100
- get :index, {filter: {title: 'New post'}}
101
- assert_response :success
102
- assert json_response['data'].is_a?(Array)
103
- assert_equal 1, json_response['data'].size
104
- end
105
-
106
- def test_index_filter_by_ids
107
- get :index, {filter: {ids: '1,2'}}
108
- assert_response :success
109
- assert json_response['data'].is_a?(Array)
110
- assert_equal 2, json_response['data'].size
111
- end
112
-
113
- def test_index_filter_by_ids_and_include_related
114
- get :index, {filter: {id: '2'}, include: 'comments'}
115
- assert_response :success
116
- assert_equal 1, json_response['data'].size
117
- assert_equal 1, json_response['included'].size
118
- end
119
-
120
- def test_index_filter_by_ids_and_include_related_different_type
121
- get :index, {filter: {id: '1,2'}, include: 'author'}
122
- assert_response :success
123
- assert_equal 2, json_response['data'].size
124
- assert_equal 1, json_response['included'].size
125
- end
126
-
127
- def test_index_filter_not_allowed
128
- JSONAPI.configuration.allow_filter = false
129
- get :index, {filter: {id: '1'}}
130
- assert_response :bad_request
131
- ensure
132
- JSONAPI.configuration.allow_filter = true
133
- end
134
-
135
- def test_index_include_one_level_query_count
136
- count_queries do
137
- get :index, {include: 'author'}
138
- end
139
- assert_response :success
140
- assert_query_count(2)
141
- end
142
-
143
- def test_index_include_two_levels_query_count
144
- count_queries do
145
- get :index, {include: 'author,author.comments'}
146
- end
147
- assert_response :success
148
- assert_query_count(3)
149
- end
150
-
151
- def test_index_filter_by_ids_and_fields
152
- get :index, {filter: {id: '1,2'}, fields: {posts: 'id,title,author'}}
153
- assert_response :success
154
- assert_equal 2, json_response['data'].size
155
-
156
- # type, id, links, attributes, relationships
157
- assert_equal 5, json_response['data'][0].size
158
- assert json_response['data'][0].key?('type')
159
- assert json_response['data'][0].key?('id')
160
- assert json_response['data'][0]['attributes'].key?('title')
161
- assert json_response['data'][0].key?('links')
162
- end
163
-
164
- def test_index_filter_by_ids_and_fields_specify_type
165
- get :index, {filter: {id: '1,2'}, 'fields' => {'posts' => 'id,title,author'}}
166
- assert_response :success
167
- assert_equal 2, json_response['data'].size
168
-
169
- # type, id, links, attributes, relationships
170
- assert_equal 5, json_response['data'][0].size
171
- assert json_response['data'][0].key?('type')
172
- assert json_response['data'][0].key?('id')
173
- assert json_response['data'][0]['attributes'].key?('title')
174
- assert json_response['data'][0].key?('links')
175
- end
176
-
177
- def test_index_filter_by_ids_and_fields_specify_unrelated_type
178
- get :index, {filter: {id: '1,2'}, 'fields' => {'currencies' => 'code'}}
179
- assert_response :bad_request
180
- assert_match /currencies is not a valid resource./, json_response['errors'][0]['detail']
181
- end
182
-
183
- def test_index_filter_by_ids_and_fields_2
184
- get :index, {filter: {id: '1,2'}, fields: {posts: 'author'}}
185
- assert_response :success
186
- assert_equal 2, json_response['data'].size
187
-
188
- # type, id, links, relationships
189
- assert_equal 4, json_response['data'][0].size
190
- assert json_response['data'][0].key?('type')
191
- assert json_response['data'][0].key?('id')
192
- assert json_response['data'][0]['relationships'].key?('author')
193
- end
194
-
195
- def test_filter_relationship_single
196
- count_queries do
197
- get :index, {filter: {tags: '5,1'}}
198
- end
199
- assert_query_count(1)
200
- assert_response :success
201
- assert_equal 3, json_response['data'].size
202
- assert_match /New post/, response.body
203
- assert_match /JR Solves your serialization woes!/, response.body
204
- assert_match /JR How To/, response.body
205
- end
206
-
207
- def test_filter_relationships_multiple
208
- count_queries do
209
- get :index, {filter: {tags: '5,1', comments: '3'}}
210
- end
211
- assert_query_count(1)
212
- assert_response :success
213
- assert_equal 1, json_response['data'].size
214
- assert_match /JR Solves your serialization woes!/, response.body
215
- end
216
-
217
- def test_filter_relationships_multiple_not_found
218
- get :index, {filter: {tags: '1', comments: '3'}}
219
- assert_response :success
220
- assert_equal 0, json_response['data'].size
221
- end
222
-
223
- def test_bad_filter
224
- get :index, {filter: {post_ids: '1,2'}}
225
- assert_response :bad_request
226
- assert_match /post_ids is not allowed/, response.body
227
- end
228
-
229
- def test_bad_filter_value_not_integer_array
230
- get :index, {filter: {id: 'asdfg'}}
231
- assert_response :bad_request
232
- assert_match /asdfg is not a valid value for id/, response.body
233
- end
234
-
235
- def test_bad_filter_value_not_integer
236
- get :index, {filter: {id: 'asdfg'}}
237
- assert_response :bad_request
238
- assert_match /asdfg is not a valid value for id/, response.body
239
- end
240
-
241
- def test_bad_filter_value_not_found_array
242
- get :index, {filter: {id: '5412333'}}
243
- assert_response :not_found
244
- assert_match /5412333 could not be found/, response.body
245
- end
246
-
247
- def test_bad_filter_value_not_found
248
- get :index, {filter: {id: '5412333'}}
249
- assert_response :not_found
250
- assert_match /5412333 could not be found/, json_response['errors'][0]['detail']
251
- end
252
-
253
- def test_field_not_supported
254
- get :index, {filter: {id: '1,2'}, 'fields' => {'posts' => 'id,title,rank,author'}}
255
- assert_response :bad_request
256
- assert_match /rank is not a valid field for posts./, json_response['errors'][0]['detail']
257
- end
258
-
259
- def test_resource_not_supported
260
- get :index, {filter: {id: '1,2'}, 'fields' => {'posters' => 'id,title'}}
261
- assert_response :bad_request
262
- assert_match /posters is not a valid resource./, json_response['errors'][0]['detail']
263
- end
264
-
265
- def test_index_filter_on_relationship
266
- get :index, {filter: {author: '1'}}
267
- assert_response :success
268
- assert_equal 3, json_response['data'].size
269
- end
270
-
271
- def test_sorting_blank
272
- get :index, {sort: ''}
273
-
274
- assert_response :success
275
- end
276
-
277
- def test_sorting_asc
278
- get :index, {sort: 'title'}
279
-
280
- assert_response :success
281
- assert_equal "A First Post", json_response['data'][0]['attributes']['title']
282
- end
283
-
284
- def test_sorting_desc
285
- get :index, {sort: '-title'}
286
-
287
- assert_response :success
288
- assert_equal "Update This Later - Multiple", json_response['data'][0]['attributes']['title']
289
- end
290
-
291
- def test_sorting_by_multiple_fields
292
- get :index, {sort: 'title,body'}
293
-
294
- assert_response :success
295
- assert_equal '14', json_response['data'][0]['id']
296
- end
297
-
298
- def test_invalid_sort_param
299
- get :index, {sort: 'asdfg'}
300
-
301
- assert_response :bad_request
302
- assert_match /asdfg is not a valid sort criteria for post/, response.body
303
- end
304
-
305
- def test_show_single_with_sort_disallowed
306
- JSONAPI.configuration.allow_sort = false
307
- get :index, {sort: 'title,body'}
308
- assert_response :bad_request
309
- ensure
310
- JSONAPI.configuration.allow_sort = true
311
- end
312
-
313
- def test_excluded_sort_param
314
- get :index, {sort: 'id'}
315
-
316
- assert_response :bad_request
317
- assert_match /id is not a valid sort criteria for post/, response.body
318
- end
319
-
320
- def test_show_single
321
- get :show, {id: '1'}
322
- assert_response :success
323
- assert json_response['data'].is_a?(Hash)
324
- assert_equal 'New post', json_response['data']['attributes']['title']
325
- assert_equal 'A body!!!', json_response['data']['attributes']['body']
326
- assert_nil json_response['included']
327
- end
328
-
329
- def test_show_does_not_include_records_count_in_meta
330
- JSONAPI.configuration.top_level_meta_include_record_count = true
331
- get :show, { id: Post.first.id }
332
- assert_response :success
333
- assert_equal json_response['meta'], nil
334
- ensure
335
- JSONAPI.configuration.top_level_meta_include_record_count = false
336
- end
337
-
338
- def test_show_single_with_includes
339
- get :show, {id: '1', include: 'comments'}
340
- assert_response :success
341
- assert json_response['data'].is_a?(Hash)
342
- assert_equal 'New post', json_response['data']['attributes']['title']
343
- assert_equal 'A body!!!', json_response['data']['attributes']['body']
344
- assert_nil json_response['data']['relationships']['tags']['data']
345
- assert matches_array?([{'type' => 'comments', 'id' => '1'}, {'type' => 'comments', 'id' => '2'}],
346
- json_response['data']['relationships']['comments']['data'])
347
- assert_equal 2, json_response['included'].size
348
- end
349
-
350
- def test_show_single_with_include_disallowed
351
- JSONAPI.configuration.allow_include = false
352
- get :show, {id: '1', include: 'comments'}
353
- assert_response :bad_request
354
- ensure
355
- JSONAPI.configuration.allow_include = true
356
- end
357
-
358
- def test_show_single_with_fields
359
- get :show, {id: '1', fields: {posts: 'author'}}
360
- assert_response :success
361
- assert json_response['data'].is_a?(Hash)
362
- assert_nil json_response['data']['attributes']
363
- end
364
-
365
- def test_show_single_with_fields_string
366
- get :show, {id: '1', fields: 'author'}
367
- assert_response :bad_request
368
- assert_match /Fields must specify a type./, json_response['errors'][0]['detail']
369
- end
370
-
371
- def test_show_single_invalid_id_format
372
- get :show, {id: 'asdfg'}
373
- assert_response :bad_request
374
- assert_match /asdfg is not a valid value for id/, response.body
375
- end
376
-
377
- def test_show_single_missing_record
378
- get :show, {id: '5412333'}
379
- assert_response :not_found
380
- assert_match /record identified by 5412333 could not be found/, response.body
381
- end
382
-
383
- def test_show_malformed_fields_not_list
384
- get :show, {id: '1', 'fields' => ''}
385
- assert_response :bad_request
386
- assert_match /Fields must specify a type./, json_response['errors'][0]['detail']
387
- end
388
-
389
- def test_show_malformed_fields_type_not_list
390
- get :show, {id: '1', 'fields' => {'posts' => ''}}
391
- assert_response :bad_request
392
- assert_match /nil is not a valid field for posts./, json_response['errors'][0]['detail']
393
- end
394
-
395
- def test_create_simple
396
- set_content_type_header!
397
- post :create,
398
- {
399
- data: {
400
- type: 'posts',
401
- attributes: {
402
- title: 'JR is Great',
403
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
404
- },
405
- relationships: {
406
- author: {data: {type: 'people', id: '3'}}
407
- }
408
- }
409
- }
410
-
411
- assert_response :created
412
- assert json_response['data'].is_a?(Hash)
413
- assert_equal 'JR is Great', json_response['data']['attributes']['title']
414
- assert_equal 'JSONAPIResources is the greatest thing since unsliced bread.', json_response['data']['attributes']['body']
415
- end
416
-
417
- def test_create_link_to_missing_object
418
- set_content_type_header!
419
- post :create,
420
- {
421
- data: {
422
- type: 'posts',
423
- attributes: {
424
- title: 'JR is Great',
425
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
426
- },
427
- relationships: {
428
- author: {data: {type: 'people', id: '304567'}}
429
- }
430
- }
431
- }
432
-
433
- assert_response :unprocessable_entity
434
- # TODO: check if this validation is working
435
- assert_match /author - can't be blank/, response.body
436
- end
437
-
438
- def test_create_extra_param
439
- set_content_type_header!
440
- post :create,
441
- {
442
- data: {
443
- type: 'posts',
444
- attributes: {
445
- asdfg: 'aaaa',
446
- title: 'JR is Great',
447
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
448
- },
449
- relationships: {
450
- author: {data: {type: 'people', id: '3'}}
451
- }
452
- }
453
- }
454
-
455
- assert_response :bad_request
456
- assert_match /asdfg is not allowed/, response.body
457
- end
458
-
459
- def test_create_extra_param_allow_extra_params
460
- JSONAPI.configuration.raise_if_parameters_not_allowed = false
461
-
462
- set_content_type_header!
463
- post :create,
464
- {
465
- data: {
466
- type: 'posts',
467
- attributes: {
468
- asdfg: 'aaaa',
469
- title: 'JR is Great',
470
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
471
- },
472
- relationships: {
473
- author: {data: {type: 'people', id: '3'}}
474
- }
475
- },
476
- include: 'author'
477
- }
478
-
479
- assert_response :created
480
- assert json_response['data'].is_a?(Hash)
481
- assert_equal '3', json_response['data']['relationships']['author']['data']['id']
482
- assert_equal 'JR is Great', json_response['data']['attributes']['title']
483
- assert_equal 'JSONAPIResources is the greatest thing since unsliced bread.', json_response['data']['attributes']['body']
484
-
485
- assert_equal 1, json_response['meta']["warnings"].count
486
- assert_equal "Param not allowed", json_response['meta']["warnings"][0]["title"]
487
- assert_equal "asdfg is not allowed.", json_response['meta']["warnings"][0]["detail"]
488
- assert_equal '105', json_response['meta']["warnings"][0]["code"]
489
- ensure
490
- JSONAPI.configuration.raise_if_parameters_not_allowed = true
491
- end
492
-
493
- def test_create_with_invalid_data
494
- set_content_type_header!
495
- post :create,
496
- {
497
- data: {
498
- type: 'posts',
499
- attributes: {
500
- title: 'JSONAPIResources is the greatest thing...',
501
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
502
- },
503
- relationships: {
504
- author: nil
505
- }
506
- }
507
- }
508
-
509
- assert_response :unprocessable_entity
510
-
511
- assert_equal "/data/relationships/author", json_response['errors'][0]['source']['pointer']
512
- assert_equal "can't be blank", json_response['errors'][0]['title']
513
- assert_equal "author - can't be blank", json_response['errors'][0]['detail']
514
-
515
- assert_equal "/data/attributes/title", json_response['errors'][1]['source']['pointer']
516
- assert_equal "is too long (maximum is 35 characters)", json_response['errors'][1]['title']
517
- assert_equal "title - is too long (maximum is 35 characters)", json_response['errors'][1]['detail']
518
- end
519
-
520
- def test_create_multiple
521
- set_content_type_header!
522
- post :create,
523
- {
524
- data: [
525
- {
526
- type: 'posts',
527
- attributes: {
528
- title: 'JR is Great',
529
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
530
- },
531
- relationships: {
532
- author: {data: {type: 'people', id: '3'}}
533
- }
534
- },
535
- {
536
- type: 'posts',
537
- attributes: {
538
- title: 'Ember is Great',
539
- body: 'Ember is the greatest thing since unsliced bread.'
540
- },
541
- relationships: {
542
- author: {data: {type: 'people', id: '3'}}
543
- }
544
- }
545
- ]
546
- }
547
-
548
- assert_response :created
549
- assert json_response['data'].is_a?(Array)
550
- assert_equal json_response['data'].size, 2
551
- assert_nil json_response['data'][0]['relationships']['author']['data']
552
- assert_match /JR is Great/, response.body
553
- assert_match /Ember is Great/, response.body
554
- end
555
-
556
- def test_create_multiple_wrong_case
557
- set_content_type_header!
558
- post :create,
559
- {
560
- data: [
561
- {
562
- type: 'posts',
563
- attributes: {
564
- Title: 'JR is Great',
565
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
566
- },
567
- relationships: {
568
- author: {data: {type: 'people', id: '3'}}
569
- }
570
- },
571
- {
572
- type: 'posts',
573
- attributes: {
574
- title: 'Ember is Great',
575
- BODY: 'Ember is the greatest thing since unsliced bread.'
576
- },
577
- relationships: {
578
- author: {data: {type: 'people', id: '3'}}
579
- }
580
- }
581
- ]
582
- }
583
-
584
- assert_response :bad_request
585
- assert_match /Title/, json_response['errors'][0]['detail']
586
- end
587
-
588
- def test_create_simple_missing_posts
589
- set_content_type_header!
590
- post :create,
591
- {
592
- data_spelled_wrong: {
593
- type: 'posts',
594
- attributes: {
595
- title: 'JR is Great',
596
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
597
- },
598
- relationships: {
599
- author: {data: {type: 'people', id: '3'}}
600
- }
601
- }
602
- }
603
-
604
- assert_response :bad_request
605
- assert_match /The required parameter, data, is missing./, json_response['errors'][0]['detail']
606
- end
607
-
608
- def test_create_simple_wrong_type
609
- set_content_type_header!
610
- post :create,
611
- {
612
- data: {
613
- type: 'posts_spelled_wrong',
614
- attributes: {
615
- title: 'JR is Great',
616
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
617
- },
618
- relationships: {
619
- author: {data: {type: 'people', id: '3'}}
620
- }
621
- }
622
- }
623
-
624
- assert_response :bad_request
625
- assert_match /posts_spelled_wrong is not a valid resource./, json_response['errors'][0]['detail']
626
- end
627
-
628
- def test_create_simple_missing_type
629
- set_content_type_header!
630
- post :create,
631
- {
632
- data: {
633
- attributes: {
634
- title: 'JR is Great',
635
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
636
- },
637
- relationships: {
638
- author: {data: {type: 'people', id: '3'}}
639
- }
640
- }
641
- }
642
-
643
- assert_response :bad_request
644
- assert_match /The required parameter, type, is missing./, json_response['errors'][0]['detail']
645
- end
646
-
647
- def test_create_simple_unpermitted_attributes
648
- set_content_type_header!
649
- post :create,
650
- {
651
- data: {
652
- type: 'posts',
653
- attributes: {
654
- subject: 'JR is Great',
655
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
656
- },
657
- relationships: {
658
- author: {data: {type: 'people', id: '3'}}
659
- }
660
- }
661
- }
662
-
663
- assert_response :bad_request
664
- assert_match /subject/, json_response['errors'][0]['detail']
665
- end
666
-
667
- def test_create_simple_unpermitted_attributes_allow_extra_params
668
- JSONAPI.configuration.raise_if_parameters_not_allowed = false
669
-
670
- set_content_type_header!
671
- post :create,
672
- {
673
- data: {
674
- type: 'posts',
675
- attributes: {
676
- title: 'JR is Great',
677
- subject: 'JR is SUPER Great',
678
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
679
- },
680
- relationships: {
681
- author: {data: {type: 'people', id: '3'}}
682
- }
683
- },
684
- include: 'author'
685
- }
686
-
687
- assert_response :created
688
- assert json_response['data'].is_a?(Hash)
689
- assert_equal '3', json_response['data']['relationships']['author']['data']['id']
690
- assert_equal 'JR is Great', json_response['data']['attributes']['title']
691
- assert_equal 'JR is Great', json_response['data']['attributes']['subject']
692
- assert_equal 'JSONAPIResources is the greatest thing since unsliced bread.', json_response['data']['attributes']['body']
693
-
694
-
695
- assert_equal 1, json_response['meta']["warnings"].count
696
- assert_equal "Param not allowed", json_response['meta']["warnings"][0]["title"]
697
- assert_equal "subject is not allowed.", json_response['meta']["warnings"][0]["detail"]
698
- assert_equal '105', json_response['meta']["warnings"][0]["code"]
699
- ensure
700
- JSONAPI.configuration.raise_if_parameters_not_allowed = true
701
- end
702
-
703
- def test_create_with_links_to_many_type_ids
704
- set_content_type_header!
705
- post :create,
706
- {
707
- data: {
708
- type: 'posts',
709
- attributes: {
710
- title: 'JR is Great',
711
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
712
- },
713
- relationships: {
714
- author: {data: {type: 'people', id: '3'}},
715
- tags: {data: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]}
716
- }
717
- },
718
- include: 'author'
719
- }
720
-
721
- assert_response :created
722
- assert json_response['data'].is_a?(Hash)
723
- assert_equal '3', json_response['data']['relationships']['author']['data']['id']
724
- assert_equal 'JR is Great', json_response['data']['attributes']['title']
725
- assert_equal 'JSONAPIResources is the greatest thing since unsliced bread.', json_response['data']['attributes']['body']
726
- end
727
-
728
- def test_create_with_links_to_many_array
729
- set_content_type_header!
730
- post :create,
731
- {
732
- data: {
733
- type: 'posts',
734
- attributes: {
735
- title: 'JR is Great',
736
- body: 'JSONAPIResources is the greatest thing since unsliced bread.'
737
- },
738
- relationships: {
739
- author: {data: {type: 'people', id: '3'}},
740
- tags: {data: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]}
741
- }
742
- },
743
- include: 'author'
744
- }
745
-
746
- assert_response :created
747
- assert json_response['data'].is_a?(Hash)
748
- assert_equal '3', json_response['data']['relationships']['author']['data']['id']
749
- assert_equal 'JR is Great', json_response['data']['attributes']['title']
750
- assert_equal 'JSONAPIResources is the greatest thing since unsliced bread.', json_response['data']['attributes']['body']
751
- end
752
-
753
- def test_create_with_links_include_and_fields
754
- set_content_type_header!
755
- post :create,
756
- {
757
- data: {
758
- type: 'posts',
759
- attributes: {
760
- title: 'JR is Great!',
761
- body: 'JSONAPIResources is the greatest thing since unsliced bread!'
762
- },
763
- relationships: {
764
- author: {data: {type: 'people', id: '3'}},
765
- tags: {data: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]}
766
- }
767
- },
768
- include: 'author,author.posts',
769
- fields: {posts: 'id,title,author'}
770
- }
771
-
772
- assert_response :created
773
- assert json_response['data'].is_a?(Hash)
774
- assert_equal '3', json_response['data']['relationships']['author']['data']['id']
775
- assert_equal 'JR is Great!', json_response['data']['attributes']['title']
776
- assert_not_nil json_response['included'].size
777
- end
778
-
779
- def test_update_with_links
780
- set_content_type_header!
781
- javascript = Section.find_by(name: 'javascript')
782
-
783
- put :update,
784
- {
785
- id: 3,
786
- data: {
787
- id: '3',
788
- type: 'posts',
789
- attributes: {
790
- title: 'A great new Post'
791
- },
792
- relationships: {
793
- section: {data: {type: 'sections', id: "#{javascript.id}"}},
794
- tags: {data: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]}
795
- }
796
- },
797
- include: 'tags,author,section'
798
- }
799
-
800
- assert_response :success
801
- assert json_response['data'].is_a?(Hash)
802
- assert_equal '3', json_response['data']['relationships']['author']['data']['id']
803
- assert_equal javascript.id.to_s, json_response['data']['relationships']['section']['data']['id']
804
- assert_equal 'A great new Post', json_response['data']['attributes']['title']
805
- assert_equal 'AAAA', json_response['data']['attributes']['body']
806
- assert matches_array?([{'type' => 'tags', 'id' => '3'}, {'type' => 'tags', 'id' => '4'}],
807
- json_response['data']['relationships']['tags']['data'])
808
- end
809
-
810
- def test_update_with_internal_server_error
811
- set_content_type_header!
812
- post_object = Post.find(3)
813
- title = post_object.title
814
-
815
- put :update,
816
- {
817
- id: 3,
818
- data: {
819
- id: '3',
820
- type: 'posts',
821
- attributes: {
822
- title: 'BOOM'
823
- }
824
- }
825
- }
826
-
827
- assert_response 500
828
- post_object = Post.find(3)
829
- assert_equal title, post_object.title
830
- end
831
-
832
- def test_update_with_links_allow_extra_params
833
- JSONAPI.configuration.raise_if_parameters_not_allowed = false
834
-
835
- set_content_type_header!
836
- javascript = Section.find_by(name: 'javascript')
837
-
838
- put :update,
839
- {
840
- id: 3,
841
- data: {
842
- id: '3',
843
- type: 'posts',
844
- attributes: {
845
- title: 'A great new Post',
846
- subject: 'A great new Post',
847
- },
848
- relationships: {
849
- section: {data: {type: 'sections', id: "#{javascript.id}"}},
850
- tags: {data: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]}
851
- }
852
- },
853
- include: 'tags,author,section'
854
- }
855
-
856
- assert_response :success
857
- assert json_response['data'].is_a?(Hash)
858
- assert_equal '3', json_response['data']['relationships']['author']['data']['id']
859
- assert_equal javascript.id.to_s, json_response['data']['relationships']['section']['data']['id']
860
- assert_equal 'A great new Post', json_response['data']['attributes']['title']
861
- assert_equal 'AAAA', json_response['data']['attributes']['body']
862
- assert matches_array?([{'type' => 'tags', 'id' => '3'}, {'type' => 'tags', 'id' => '4'}],
863
- json_response['data']['relationships']['tags']['data'])
864
-
865
-
866
- assert_equal 1, json_response['meta']["warnings"].count
867
- assert_equal "Param not allowed", json_response['meta']["warnings"][0]["title"]
868
- assert_equal "subject is not allowed.", json_response['meta']["warnings"][0]["detail"]
869
- assert_equal '105', json_response['meta']["warnings"][0]["code"]
870
- ensure
871
- JSONAPI.configuration.raise_if_parameters_not_allowed = true
872
- end
873
-
874
- def test_update_remove_links
875
- set_content_type_header!
876
- put :update,
877
- {
878
- id: 3,
879
- data: {
880
- id: '3',
881
- type: 'posts',
882
- attributes: {
883
- title: 'A great new Post'
884
- },
885
- relationships: {
886
- section: {data: {type: 'sections', id: 1}},
887
- tags: {data: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]}
888
- }
889
- },
890
- include: 'tags'
891
- }
892
-
893
- assert_response :success
894
-
895
- put :update,
896
- {
897
- id: 3,
898
- data: {
899
- type: 'posts',
900
- id: 3,
901
- attributes: {
902
- title: 'A great new Post'
903
- },
904
- relationships: {
905
- section: nil,
906
- tags: []
907
- }
908
- },
909
- include: 'tags,author,section'
910
- }
911
-
912
- assert_response :success
913
- assert json_response['data'].is_a?(Hash)
914
- assert_equal '3', json_response['data']['relationships']['author']['data']['id']
915
- assert_equal nil, json_response['data']['relationships']['section']['data']
916
- assert_equal 'A great new Post', json_response['data']['attributes']['title']
917
- assert_equal 'AAAA', json_response['data']['attributes']['body']
918
- assert matches_array?([],
919
- json_response['data']['relationships']['tags']['data'])
920
- end
921
-
922
- def test_update_relationship_to_one
923
- set_content_type_header!
924
- ruby = Section.find_by(name: 'ruby')
925
- post_object = Post.find(4)
926
- assert_not_equal ruby.id, post_object.section_id
927
-
928
- put :update_relationship, {post_id: 4, relationship: 'section', data: {type: 'sections', id: "#{ruby.id}"}}
929
-
930
- assert_response :no_content
931
- post_object = Post.find(4)
932
- assert_equal ruby.id, post_object.section_id
933
- end
934
-
935
- def test_update_relationship_to_one_invalid_links_hash_keys_ids
936
- set_content_type_header!
937
- put :update_relationship, {post_id: 3, relationship: 'section', data: {type: 'sections', ids: 'foo'}}
938
-
939
- assert_response :bad_request
940
- assert_match /Invalid Links Object/, response.body
941
- end
942
-
943
- def test_update_relationship_to_one_invalid_links_hash_count
944
- set_content_type_header!
945
- put :update_relationship, {post_id: 3, relationship: 'section', data: {type: 'sections'}}
946
-
947
- assert_response :bad_request
948
- assert_match /Invalid Links Object/, response.body
949
- end
950
-
951
- def test_update_relationship_to_many_not_array
952
- set_content_type_header!
953
- put :update_relationship, {post_id: 3, relationship: 'tags', data: {type: 'tags', id: 2}}
954
-
955
- assert_response :bad_request
956
- assert_match /Invalid Links Object/, response.body
957
- end
958
-
959
- def test_update_relationship_to_one_invalid_links_hash_keys_type_mismatch
960
- set_content_type_header!
961
- put :update_relationship, {post_id: 3, relationship: 'section', data: {type: 'comment', id: '3'}}
962
-
963
- assert_response :bad_request
964
- assert_match /Type Mismatch/, response.body
965
- end
966
-
967
- def test_update_nil_to_many_links
968
- set_content_type_header!
969
- put :update,
970
- {
971
- id: 3,
972
- data: {
973
- type: 'posts',
974
- id: 3,
975
- relationships: {
976
- tags: nil
977
- }
978
- }
979
- }
980
-
981
- assert_response :bad_request
982
- assert_match /Invalid Links Object/, response.body
983
- end
984
-
985
- def test_update_bad_hash_to_many_links
986
- set_content_type_header!
987
- put :update,
988
- {
989
- id: 3,
990
- data: {
991
- type: 'posts',
992
- id: 3,
993
- relationships: {
994
- tags: {data: {typ: 'bad link', idd: 'as'}}
995
- }
996
- }
997
- }
998
-
999
- assert_response :bad_request
1000
- assert_match /Invalid Links Object/, response.body
1001
- end
1002
-
1003
- def test_update_other_to_many_links
1004
- set_content_type_header!
1005
- put :update,
1006
- {
1007
- id: 3,
1008
- data: {
1009
- type: 'posts',
1010
- id: 3,
1011
- relationships: {
1012
- tags: 'bad link'
1013
- }
1014
- }
1015
- }
1016
-
1017
- assert_response :bad_request
1018
- assert_match /Invalid Links Object/, response.body
1019
- end
1020
-
1021
- def test_update_other_to_many_links_data_nil
1022
- set_content_type_header!
1023
- put :update,
1024
- {
1025
- id: 3,
1026
- data: {
1027
- type: 'posts',
1028
- id: 3,
1029
- relationships: {
1030
- tags: {data: nil}
1031
- }
1032
- }
1033
- }
1034
-
1035
- assert_response :bad_request
1036
- assert_match /Invalid Links Object/, response.body
1037
- end
1038
-
1039
- def test_update_relationship_to_one_singular_param_id_nil
1040
- set_content_type_header!
1041
- ruby = Section.find_by(name: 'ruby')
1042
- post_object = Post.find(3)
1043
- post_object.section = ruby
1044
- post_object.save!
1045
-
1046
- put :update_relationship, {post_id: 3, relationship: 'section', data: {type: 'sections', id: nil}}
1047
-
1048
- assert_response :no_content
1049
- assert_equal nil, post_object.reload.section_id
1050
- end
1051
-
1052
- def test_update_relationship_to_one_data_nil
1053
- set_content_type_header!
1054
- ruby = Section.find_by(name: 'ruby')
1055
- post_object = Post.find(3)
1056
- post_object.section = ruby
1057
- post_object.save!
1058
-
1059
- put :update_relationship, {post_id: 3, relationship: 'section', data: nil}
1060
-
1061
- assert_response :no_content
1062
- assert_equal nil, post_object.reload.section_id
1063
- end
1064
-
1065
- def test_remove_relationship_to_one
1066
- set_content_type_header!
1067
- ruby = Section.find_by(name: 'ruby')
1068
- post_object = Post.find(3)
1069
- post_object.section_id = ruby.id
1070
- post_object.save!
1071
-
1072
- put :destroy_relationship, {post_id: 3, relationship: 'section'}
1073
-
1074
- assert_response :no_content
1075
- post_object = Post.find(3)
1076
- assert_equal nil, post_object.section_id
1077
- end
1078
-
1079
- def test_update_relationship_to_one_singular_param
1080
- set_content_type_header!
1081
- ruby = Section.find_by(name: 'ruby')
1082
- post_object = Post.find(3)
1083
- post_object.section_id = nil
1084
- post_object.save!
1085
-
1086
- put :update_relationship, {post_id: 3, relationship: 'section', data: {type: 'sections', id: "#{ruby.id}"}}
1087
-
1088
- assert_response :no_content
1089
- post_object = Post.find(3)
1090
- assert_equal ruby.id, post_object.section_id
1091
- end
1092
-
1093
- def test_update_relationship_to_many_join_table_single
1094
- set_content_type_header!
1095
- put :update_relationship, {post_id: 3, relationship: 'tags', data: []}
1096
- assert_response :no_content
1097
-
1098
- post_object = Post.find(3)
1099
- assert_equal 0, post_object.tags.length
1100
-
1101
- put :update_relationship, {post_id: 3, relationship: 'tags', data: [{type: 'tags', id: 2}]}
1102
-
1103
- assert_response :no_content
1104
- post_object = Post.find(3)
1105
- assert_equal 1, post_object.tags.length
1106
-
1107
- put :update_relationship, {post_id: 3, relationship: 'tags', data: [{type: 'tags', id: 5}]}
1108
-
1109
- assert_response :no_content
1110
- post_object = Post.find(3)
1111
- tags = post_object.tags.collect { |tag| tag.id }
1112
- assert_equal 1, tags.length
1113
- assert matches_array? [5], tags
1114
- end
1115
-
1116
- def test_update_relationship_to_many
1117
- set_content_type_header!
1118
- put :update_relationship, {post_id: 3, relationship: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]}
1119
-
1120
- assert_response :no_content
1121
- post_object = Post.find(3)
1122
- assert_equal 2, post_object.tags.collect { |tag| tag.id }.length
1123
- assert matches_array? [2, 3], post_object.tags.collect { |tag| tag.id }
1124
- end
1125
-
1126
- def test_create_relationship_to_many_join_table
1127
- set_content_type_header!
1128
- put :update_relationship, {post_id: 3, relationship: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]}
1129
-
1130
- assert_response :no_content
1131
- post_object = Post.find(3)
1132
- assert_equal 2, post_object.tags.collect { |tag| tag.id }.length
1133
- assert matches_array? [2, 3], post_object.tags.collect { |tag| tag.id }
1134
-
1135
- post :create_relationship, {post_id: 3, relationship: 'tags', data: [{type: 'tags', id: 5}]}
1136
-
1137
- assert_response :no_content
1138
- post_object = Post.find(3)
1139
- assert_equal 3, post_object.tags.collect { |tag| tag.id }.length
1140
- assert matches_array? [2, 3, 5], post_object.tags.collect { |tag| tag.id }
1141
- end
1142
-
1143
- def test_create_relationship_to_many_mismatched_type
1144
- set_content_type_header!
1145
- post :create_relationship, {post_id: 3, relationship: 'tags', data: [{type: 'comments', id: 5}]}
1146
-
1147
- assert_response :bad_request
1148
- assert_match /Type Mismatch/, response.body
1149
- end
1150
-
1151
- def test_create_relationship_to_many_missing_id
1152
- set_content_type_header!
1153
- post :create_relationship, {post_id: 3, relationship: 'tags', data: [{type: 'tags', idd: 5}]}
1154
-
1155
- assert_response :bad_request
1156
- assert_match /Data is not a valid Links Object./, response.body
1157
- end
1158
-
1159
- def test_create_relationship_to_many_not_array
1160
- set_content_type_header!
1161
- post :create_relationship, {post_id: 3, relationship: 'tags', data: {type: 'tags', id: 5}}
1162
-
1163
- assert_response :bad_request
1164
- assert_match /Data is not a valid Links Object./, response.body
1165
- end
1166
-
1167
- def test_create_relationship_to_many_missing_data
1168
- set_content_type_header!
1169
- post :create_relationship, {post_id: 3, relationship: 'tags'}
1170
-
1171
- assert_response :bad_request
1172
- assert_match /The required parameter, data, is missing./, response.body
1173
- end
1174
-
1175
- def test_create_relationship_to_many_join
1176
- set_content_type_header!
1177
- post :create_relationship, {post_id: 4, relationship: 'tags', data: [{type: 'tags', id: 1}, {type: 'tags', id: 2}, {type: 'tags', id: 3}]}
1178
- assert_response :no_content
1179
- end
1180
-
1181
- def test_create_relationship_to_many_join_table_record_exists
1182
- set_content_type_header!
1183
- put :update_relationship, {post_id: 3, relationship: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]}
1184
-
1185
- assert_response :no_content
1186
- post_object = Post.find(3)
1187
- assert_equal 2, post_object.tags.collect { |tag| tag.id }.length
1188
- assert matches_array? [2, 3], post_object.tags.collect { |tag| tag.id }
1189
-
1190
- post :create_relationship, {post_id: 3, relationship: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 5}]}
1191
-
1192
- assert_response :bad_request
1193
- assert_match /The relation to 2 already exists./, response.body
1194
- end
1195
-
1196
- def test_update_relationship_to_many_missing_tags
1197
- set_content_type_header!
1198
- put :update_relationship, {post_id: 3, relationship: 'tags'}
1199
-
1200
- assert_response :bad_request
1201
- assert_match /The required parameter, data, is missing./, response.body
1202
- end
1203
-
1204
- def test_delete_relationship_to_many
1205
- set_content_type_header!
1206
- put :update_relationship, {post_id: 14, relationship: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]}
1207
- assert_response :no_content
1208
- p = Post.find(14)
1209
- assert_equal [2, 3], p.tag_ids
1210
-
1211
- delete :destroy_relationship, {post_id: 14, relationship: 'tags', data: [{type: 'tags', id: 3}]}
1212
-
1213
- p.reload
1214
- assert_response :no_content
1215
- assert_equal [2], p.tag_ids
1216
- end
1217
-
1218
- def test_delete_relationship_to_many_with_relationship_url_not_matching_type
1219
- set_content_type_header!
1220
- PostResource.has_many :special_tags, relation_name: :special_tags, class_name: "Tag"
1221
- post :create_relationship, {post_id: 14, relationship: 'special_tags', data: [{type: 'tags', id: 2}]}
1222
-
1223
- #check the relationship was created successfully
1224
- assert_equal 1, Post.find(14).special_tags.count
1225
- before_tags = Post.find(14).tags.count
1226
-
1227
- delete :destroy_relationship, {post_id: 14, relationship: 'special_tags', data: [{type: 'tags', id: 2}]}
1228
- assert_equal 0, Post.find(14).special_tags.count, "Relationship that matches URL relationship not destroyed"
1229
-
1230
- #check that the tag association is not affected
1231
- assert_equal Post.find(14).tags.count, before_tags
1232
- ensure
1233
- PostResource.instance_variable_get(:@_relationships).delete(:special_tags)
1234
- end
1235
-
1236
- def test_delete_relationship_to_many_does_not_exist
1237
- set_content_type_header!
1238
- put :update_relationship, {post_id: 14, relationship: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]}
1239
- assert_response :no_content
1240
- p = Post.find(14)
1241
- assert_equal [2, 3], p.tag_ids
1242
-
1243
- delete :destroy_relationship, {post_id: 14, relationship: 'tags', data: [{type: 'tags', id: 4}]}
1244
-
1245
- p.reload
1246
- assert_response :not_found
1247
- assert_equal [2, 3], p.tag_ids
1248
- end
1249
-
1250
- def test_delete_relationship_to_many_with_empty_data
1251
- set_content_type_header!
1252
- put :update_relationship, {post_id: 14, relationship: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]}
1253
- assert_response :no_content
1254
- p = Post.find(14)
1255
- assert_equal [2, 3], p.tag_ids
1256
-
1257
- put :update_relationship, {post_id: 14, relationship: 'tags', data: [] }
1258
-
1259
- p.reload
1260
- assert_response :no_content
1261
- assert_equal [], p.tag_ids
1262
- end
1263
-
1264
- def test_update_mismatched_keys
1265
- set_content_type_header!
1266
- javascript = Section.find_by(name: 'javascript')
1267
-
1268
- put :update,
1269
- {
1270
- id: 3,
1271
- data: {
1272
- type: 'posts',
1273
- id: 2,
1274
- attributes: {
1275
- title: 'A great new Post'
1276
- },
1277
- relationships: {
1278
- section: {type: 'sections', id: "#{javascript.id}"},
1279
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1280
- }
1281
- }
1282
- }
1283
-
1284
- assert_response :bad_request
1285
- assert_match /The URL does not support the key 2/, response.body
1286
- end
1287
-
1288
- def test_update_extra_param
1289
- set_content_type_header!
1290
- javascript = Section.find_by(name: 'javascript')
1291
-
1292
- put :update,
1293
- {
1294
- id: 3,
1295
- data: {
1296
- type: 'posts',
1297
- id: '3',
1298
- attributes: {
1299
- asdfg: 'aaaa',
1300
- title: 'A great new Post'
1301
- },
1302
- relationships: {
1303
- section: {type: 'sections', id: "#{javascript.id}"},
1304
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1305
- }
1306
- }
1307
- }
1308
-
1309
- assert_response :bad_request
1310
- assert_match /asdfg is not allowed/, response.body
1311
- end
1312
-
1313
- def test_update_extra_param_in_links
1314
- set_content_type_header!
1315
- javascript = Section.find_by(name: 'javascript')
1316
-
1317
- put :update,
1318
- {
1319
- id: 3,
1320
- data: {
1321
- type: 'posts',
1322
- id: '3',
1323
- attributes: {
1324
- title: 'A great new Post'
1325
- },
1326
- relationships: {
1327
- asdfg: 'aaaa',
1328
- section: {type: 'sections', id: "#{javascript.id}"},
1329
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1330
- }
1331
- }
1332
- }
1333
-
1334
- assert_response :bad_request
1335
- assert_match /asdfg is not allowed/, response.body
1336
- end
1337
-
1338
- def test_update_extra_param_in_links_allow_extra_params
1339
- JSONAPI.configuration.raise_if_parameters_not_allowed = false
1340
- JSONAPI.configuration.use_text_errors = true
1341
-
1342
- set_content_type_header!
1343
- javascript = Section.find_by(name: 'javascript')
1344
-
1345
- put :update,
1346
- {
1347
- id: 3,
1348
- data: {
1349
- type: 'posts',
1350
- id: '3',
1351
- attributes: {
1352
- title: 'A great new Post'
1353
- },
1354
- relationships: {
1355
- asdfg: 'aaaa'
1356
- }
1357
- }
1358
- }
1359
-
1360
- assert_response :success
1361
- assert_equal "A great new Post", json_response["data"]["attributes"]["title"]
1362
- assert_equal "Param not allowed", json_response["meta"]["warnings"][0]["title"]
1363
- assert_equal "asdfg is not allowed.", json_response["meta"]["warnings"][0]["detail"]
1364
- assert_equal "PARAM_NOT_ALLOWED", json_response["meta"]["warnings"][0]["code"]
1365
- ensure
1366
- JSONAPI.configuration.raise_if_parameters_not_allowed = true
1367
- JSONAPI.configuration.use_text_errors = false
1368
- end
1369
-
1370
- def test_update_missing_param
1371
- set_content_type_header!
1372
- javascript = Section.find_by(name: 'javascript')
1373
-
1374
- put :update,
1375
- {
1376
- id: 3,
1377
- data_spelled_wrong: {
1378
- type: 'posts',
1379
- attributes: {
1380
- title: 'A great new Post'
1381
- },
1382
- relationships: {
1383
- section: {type: 'sections', id: "#{javascript.id}"},
1384
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1385
- }
1386
- }
1387
- }
1388
-
1389
- assert_response :bad_request
1390
- assert_match /The required parameter, data, is missing./, response.body
1391
- end
1392
-
1393
- def test_update_missing_key
1394
- set_content_type_header!
1395
-
1396
- put :update,
1397
- {
1398
- id: 3,
1399
- data: {
1400
- type: 'posts',
1401
- attributes: {
1402
- title: 'A great new Post'
1403
- }
1404
- }
1405
- }
1406
-
1407
- assert_response :bad_request
1408
- assert_match /The resource object does not contain a key/, response.body
1409
- end
1410
-
1411
- def test_update_missing_type
1412
- set_content_type_header!
1413
- javascript = Section.find_by(name: 'javascript')
1414
-
1415
- put :update,
1416
- {
1417
- id: 3,
1418
- data: {
1419
- id: '3',
1420
- type_spelled_wrong: 'posts',
1421
- attributes: {
1422
- title: 'A great new Post'
1423
- },
1424
- relationships: {
1425
- section: {type: 'sections', id: "#{javascript.id}"},
1426
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1427
- }
1428
- }
1429
- }
1430
-
1431
- assert_response :bad_request
1432
- assert_match /The required parameter, type, is missing./, response.body
1433
- end
1434
-
1435
- def test_update_unknown_key
1436
- set_content_type_header!
1437
- javascript = Section.find_by(name: 'javascript')
1438
-
1439
- put :update,
1440
- {
1441
- id: 3,
1442
- data: {
1443
- id: '3',
1444
- type: 'posts',
1445
- body: 'asdfg',
1446
- attributes: {
1447
- title: 'A great new Post'
1448
- },
1449
- relationships: {
1450
- section: {type: 'sections', id: "#{javascript.id}"},
1451
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1452
- }
1453
- }
1454
- }
1455
-
1456
- assert_response :bad_request
1457
- assert_match /body is not allowed/, response.body
1458
- end
1459
-
1460
- def test_update_multiple
1461
- set_content_type_header!
1462
- javascript = Section.find_by(name: 'javascript')
1463
-
1464
- put :update,
1465
- {
1466
- id: [3, 16],
1467
- data: [
1468
- {
1469
- type: 'posts',
1470
- id: 3,
1471
- attributes: {
1472
- title: 'A great new Post QWERTY'
1473
- },
1474
- relationships: {
1475
- section: {data: {type: 'sections', id: "#{javascript.id}"}},
1476
- tags: {data: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]}
1477
- }
1478
- },
1479
- {
1480
- type: 'posts',
1481
- id: 16,
1482
- attributes: {
1483
- title: 'A great new Post ASDFG'
1484
- },
1485
- relationships: {
1486
- section: {data: {type: 'sections', id: "#{javascript.id}"}},
1487
- tags: {data: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]}
1488
- }
1489
- }
1490
- ],
1491
- include: 'tags'
1492
- }
1493
-
1494
- assert_response :success
1495
- assert_equal json_response['data'].size, 2
1496
- assert_equal json_response['data'][0]['attributes']['title'], 'A great new Post QWERTY'
1497
- assert_equal json_response['data'][0]['attributes']['body'], 'AAAA'
1498
- assert matches_array?([{'type' => 'tags', 'id' => '3'}, {'type' => 'tags', 'id' => '4'}],
1499
- json_response['data'][0]['relationships']['tags']['data'])
1500
-
1501
- assert_equal json_response['data'][1]['attributes']['title'], 'A great new Post ASDFG'
1502
- assert_equal json_response['data'][1]['attributes']['body'], 'Not First!!!!'
1503
- assert matches_array?([{'type' => 'tags', 'id' => '3'}, {'type' => 'tags', 'id' => '4'}],
1504
- json_response['data'][1]['relationships']['tags']['data'])
1505
- end
1506
-
1507
- def test_update_multiple_missing_keys
1508
- set_content_type_header!
1509
- javascript = Section.find_by(name: 'javascript')
1510
-
1511
- put :update,
1512
- {
1513
- id: [3, 9],
1514
- data: [
1515
- {
1516
- type: 'posts',
1517
- attributes: {
1518
- title: 'A great new Post ASDFG'
1519
- },
1520
- relationships: {
1521
- section: {type: 'sections', id: "#{javascript.id}"},
1522
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1523
- }
1524
- },
1525
- {
1526
- type: 'posts',
1527
- attributes: {
1528
- title: 'A great new Post QWERTY'
1529
- },
1530
- relationships: {
1531
- section: {type: 'sections', id: "#{javascript.id}"},
1532
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1533
- }
1534
- }
1535
- ]}
1536
-
1537
- assert_response :bad_request
1538
- assert_match /A key is required/, response.body
1539
- end
1540
-
1541
- def test_update_mismatch_keys
1542
- set_content_type_header!
1543
- javascript = Section.find_by(name: 'javascript')
1544
-
1545
- put :update,
1546
- {
1547
- id: [3, 9],
1548
- data: [
1549
- {
1550
- type: 'posts',
1551
- id: 3,
1552
- attributes: {
1553
- title: 'A great new Post ASDFG'
1554
- },
1555
- relationships: {
1556
- section: {data: {type: 'sections', id: "#{javascript.id}"}},
1557
- tags: {data: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]}
1558
- }
1559
- },
1560
- {
1561
- type: 'posts',
1562
- id: 8,
1563
- attributes: {
1564
- title: 'A great new Post QWERTY'
1565
- },
1566
- relationships: {
1567
- section: {data: {type: 'sections', id: "#{javascript.id}"}},
1568
- tags: {data: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]}
1569
- }
1570
- }
1571
- ]}
1572
-
1573
- assert_response :bad_request
1574
- assert_match /The URL does not support the key 8/, response.body
1575
- end
1576
-
1577
- def test_update_multiple_count_mismatch
1578
- set_content_type_header!
1579
- javascript = Section.find_by(name: 'javascript')
1580
-
1581
- put :update,
1582
- {
1583
- id: [3, 9, 2],
1584
- data: [
1585
- {
1586
- type: 'posts',
1587
- id: 3,
1588
- attributes: {
1589
- title: 'A great new Post QWERTY'
1590
- },
1591
- relationships: {
1592
- section: {type: 'sections', id: "#{javascript.id}"},
1593
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1594
- }
1595
- },
1596
- {
1597
- type: 'posts',
1598
- id: 9,
1599
- attributes: {
1600
- title: 'A great new Post ASDFG'
1601
- },
1602
- relationships: {
1603
- section: {type: 'sections', id: "#{javascript.id}"},
1604
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1605
- }
1606
- }
1607
- ]}
1608
-
1609
- assert_response :bad_request
1610
- assert_match /Count to key mismatch/, response.body
1611
- end
1612
-
1613
- def test_update_unpermitted_attributes
1614
- set_content_type_header!
1615
- put :update,
1616
- {
1617
- id: 3,
1618
- data: {
1619
- type: 'posts',
1620
- id: '3',
1621
- attributes: {
1622
- subject: 'A great new Post'
1623
- },
1624
- relationships: {
1625
- author: {type: 'people', id: '1'},
1626
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1627
- }
1628
- }
1629
- }
1630
-
1631
- assert_response :bad_request
1632
- assert_match /author is not allowed./, response.body
1633
- assert_match /subject is not allowed./, response.body
1634
- end
1635
-
1636
- def test_update_bad_attributes
1637
- set_content_type_header!
1638
- put :update,
1639
- {
1640
- id: 3,
1641
- data: {
1642
- type: 'posts',
1643
- attributes: {
1644
- subject: 'A great new Post'
1645
- },
1646
- linked_objects: {
1647
- author: {type: 'people', id: '1'},
1648
- tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}]
1649
- }
1650
- }
1651
- }
1652
-
1653
- assert_response :bad_request
1654
- end
1655
-
1656
- def test_delete_with_validation_error
1657
- post = Post.create!(title: "can't destroy me", author: Person.first)
1658
- delete :destroy, { id: post.id }
1659
-
1660
- assert_equal "can't destroy me", json_response['errors'][0]['title']
1661
- assert_response :unprocessable_entity
1662
- end
1663
-
1664
- def test_delete_single
1665
- initial_count = Post.count
1666
- delete :destroy, {id: '4'}
1667
- assert_response :no_content
1668
- assert_equal initial_count - 1, Post.count
1669
- end
1670
-
1671
- def test_delete_multiple
1672
- initial_count = Post.count
1673
- delete :destroy, {id: '5,6'}
1674
- assert_response :no_content
1675
- assert_equal initial_count - 2, Post.count
1676
- end
1677
-
1678
- def test_delete_multiple_one_does_not_exist
1679
- initial_count = Post.count
1680
- delete :destroy, {id: '5,6,99999'}
1681
- assert_response :not_found
1682
- assert_equal initial_count, Post.count
1683
- end
1684
-
1685
- def test_show_to_one_relationship
1686
- get :show_relationship, {post_id: '1', relationship: 'author'}
1687
- assert_response :success
1688
- assert_hash_equals json_response,
1689
- {data: {
1690
- type: 'people',
1691
- id: '1'
1692
- },
1693
- links: {
1694
- self: 'http://test.host/posts/1/relationships/author',
1695
- related: 'http://test.host/posts/1/author'
1696
- }
1697
- }
1698
- end
1699
-
1700
- def test_show_to_many_relationship
1701
- get :show_relationship, {post_id: '2', relationship: 'tags'}
1702
- assert_response :success
1703
- assert_hash_equals json_response,
1704
- {
1705
- data: [
1706
- {type: 'tags', id: '5'}
1707
- ],
1708
- links: {
1709
- self: 'http://test.host/posts/2/relationships/tags',
1710
- related: 'http://test.host/posts/2/tags'
1711
- }
1712
- }
1713
- end
1714
-
1715
- def test_show_to_many_relationship_invalid_id
1716
- get :show_relationship, {post_id: '2,1', relationship: 'tags'}
1717
- assert_response :bad_request
1718
- assert_match /2,1 is not a valid value for id/, response.body
1719
- end
1720
-
1721
- def test_show_to_one_relationship_nil
1722
- get :show_relationship, {post_id: '17', relationship: 'author'}
1723
- assert_response :success
1724
- assert_hash_equals json_response,
1725
- {
1726
- data: nil,
1727
- links: {
1728
- self: 'http://test.host/posts/17/relationships/author',
1729
- related: 'http://test.host/posts/17/author'
1730
- }
1731
- }
1732
- end
1733
- end
1734
-
1735
- class TagsControllerTest < ActionController::TestCase
1736
- def test_tags_index
1737
- get :index, {filter: {id: '6,7,8,9'}, include: 'posts.tags,posts.author.posts'}
1738
- assert_response :success
1739
- assert_equal 4, json_response['data'].size
1740
- assert_equal 3, json_response['included'].size
1741
- end
1742
-
1743
- def test_tags_show_multiple
1744
- get :show, {id: '6,7,8,9'}
1745
- assert_response :bad_request
1746
- assert_match /6,7,8,9 is not a valid value for id/, response.body
1747
- end
1748
-
1749
- def test_tags_show_multiple_with_include
1750
- get :show, {id: '6,7,8,9', include: 'posts.tags,posts.author.posts'}
1751
- assert_response :bad_request
1752
- assert_match /6,7,8,9 is not a valid value for id/, response.body
1753
- end
1754
-
1755
- def test_tags_show_multiple_with_nonexistent_ids
1756
- get :show, {id: '6,99,9,100'}
1757
- assert_response :bad_request
1758
- assert_match /6,99,9,100 is not a valid value for id/, response.body
1759
- end
1760
-
1761
- def test_tags_show_multiple_with_nonexistent_ids_at_the_beginning
1762
- get :show, {id: '99,9,100'}
1763
- assert_response :bad_request
1764
- assert_match /99,9,100 is not a valid value for id/, response.body
1765
- end
1766
- end
1767
-
1768
- class ExpenseEntriesControllerTest < ActionController::TestCase
1769
- def setup
1770
- JSONAPI.configuration.json_key_format = :camelized_key
1771
- end
1772
-
1773
- def test_text_error
1774
- JSONAPI.configuration.use_text_errors = true
1775
- get :index, {sort: 'not_in_record'}
1776
- assert_response 400
1777
- assert_equal 'INVALID_SORT_CRITERIA', json_response['errors'][0]['code']
1778
- ensure
1779
- JSONAPI.configuration.use_text_errors = false
1780
- end
1781
-
1782
- def test_expense_entries_index
1783
- get :index
1784
- assert_response :success
1785
- assert json_response['data'].is_a?(Array)
1786
- assert_equal 2, json_response['data'].size
1787
- end
1788
-
1789
- def test_expense_entries_show
1790
- get :show, {id: 1}
1791
- assert_response :success
1792
- assert json_response['data'].is_a?(Hash)
1793
- end
1794
-
1795
- def test_expense_entries_show_include
1796
- get :show, {id: 1, include: 'isoCurrency,employee'}
1797
- assert_response :success
1798
- assert json_response['data'].is_a?(Hash)
1799
- assert_equal 2, json_response['included'].size
1800
- end
1801
-
1802
- def test_expense_entries_show_bad_include_missing_relationship
1803
- get :show, {id: 1, include: 'isoCurrencies,employees'}
1804
- assert_response :bad_request
1805
- assert_match /isoCurrencies is not a valid relationship of expenseEntries/, json_response['errors'][0]['detail']
1806
- assert_match /employees is not a valid relationship of expenseEntries/, json_response['errors'][1]['detail']
1807
- end
1808
-
1809
- def test_expense_entries_show_bad_include_missing_sub_relationship
1810
- get :show, {id: 1, include: 'isoCurrency,employee.post'}
1811
- assert_response :bad_request
1812
- assert_match /post is not a valid relationship of people/, json_response['errors'][0]['detail']
1813
- end
1814
-
1815
- def test_expense_entries_show_fields
1816
- get :show, {id: 1, include: 'isoCurrency,employee', 'fields' => {'expenseEntries' => 'transactionDate'}}
1817
- assert_response :success
1818
- assert json_response['data'].is_a?(Hash)
1819
- assert json_response['data']['attributes'].key?('transactionDate')
1820
- assert_equal 2, json_response['included'].size
1821
- end
1822
-
1823
- def test_expense_entries_show_fields_type_many
1824
- get :show, {id: 1, include: 'isoCurrency,employee', 'fields' => {'expenseEntries' => 'transactionDate',
1825
- 'isoCurrencies' => 'id,name'}}
1826
- assert_response :success
1827
- assert json_response['data'].is_a?(Hash)
1828
- assert json_response['data']['attributes'].key?('transactionDate')
1829
- assert_equal 2, json_response['included'].size
1830
- end
1831
-
1832
- def test_create_expense_entries_underscored
1833
- set_content_type_header!
1834
- original_config = JSONAPI.configuration.dup
1835
- JSONAPI.configuration.json_key_format = :underscored_key
1836
-
1837
- post :create,
1838
- {
1839
- data: {
1840
- type: 'expense_entries',
1841
- attributes: {
1842
- transaction_date: '2014/04/15',
1843
- cost: 50.58
1844
- },
1845
- relationships: {
1846
- employee: {data: {type: 'people', id: '3'}},
1847
- iso_currency: {data: {type: 'iso_currencies', id: 'USD'}}
1848
- }
1849
- },
1850
- include: 'iso_currency,employee',
1851
- fields: {expense_entries: 'id,transaction_date,iso_currency,cost,employee'}
1852
- }
1853
-
1854
- assert_response :created
1855
- assert json_response['data'].is_a?(Hash)
1856
- assert_equal '3', json_response['data']['relationships']['employee']['data']['id']
1857
- assert_equal 'USD', json_response['data']['relationships']['iso_currency']['data']['id']
1858
- assert_equal '50.58', json_response['data']['attributes']['cost']
1859
-
1860
- delete :destroy, {id: json_response['data']['id']}
1861
- assert_response :no_content
1862
- ensure
1863
- JSONAPI.configuration = original_config
1864
- end
1865
-
1866
- def test_create_expense_entries_camelized_key
1867
- set_content_type_header!
1868
- original_config = JSONAPI.configuration.dup
1869
- JSONAPI.configuration.json_key_format = :camelized_key
1870
-
1871
- post :create,
1872
- {
1873
- data: {
1874
- type: 'expense_entries',
1875
- attributes: {
1876
- transactionDate: '2014/04/15',
1877
- cost: 50.58
1878
- },
1879
- relationships: {
1880
- employee: {data: {type: 'people', id: '3'}},
1881
- isoCurrency: {data: {type: 'iso_currencies', id: 'USD'}}
1882
- }
1883
- },
1884
- include: 'isoCurrency,employee',
1885
- fields: {expenseEntries: 'id,transactionDate,isoCurrency,cost,employee'}
1886
- }
1887
-
1888
- assert_response :created
1889
- assert json_response['data'].is_a?(Hash)
1890
- assert_equal '3', json_response['data']['relationships']['employee']['data']['id']
1891
- assert_equal 'USD', json_response['data']['relationships']['isoCurrency']['data']['id']
1892
- assert_equal '50.58', json_response['data']['attributes']['cost']
1893
-
1894
- delete :destroy, {id: json_response['data']['id']}
1895
- assert_response :no_content
1896
- ensure
1897
- JSONAPI.configuration = original_config
1898
- end
1899
-
1900
- def test_create_expense_entries_dasherized_key
1901
- set_content_type_header!
1902
- original_config = JSONAPI.configuration.dup
1903
- JSONAPI.configuration.json_key_format = :dasherized_key
1904
-
1905
- post :create,
1906
- {
1907
- data: {
1908
- type: 'expense_entries',
1909
- attributes: {
1910
- 'transaction-date' => '2014/04/15',
1911
- cost: 50.58
1912
- },
1913
- relationships: {
1914
- employee: {data: {type: 'people', id: '3'}},
1915
- 'iso-currency' => {data: {type: 'iso_currencies', id: 'USD'}}
1916
- }
1917
- },
1918
- include: 'iso-currency,employee',
1919
- fields: {'expense-entries' => 'id,transaction-date,iso-currency,cost,employee'}
1920
- }
1921
-
1922
- assert_response :created
1923
- assert json_response['data'].is_a?(Hash)
1924
- assert_equal '3', json_response['data']['relationships']['employee']['data']['id']
1925
- assert_equal 'USD', json_response['data']['relationships']['iso-currency']['data']['id']
1926
- assert_equal '50.58', json_response['data']['attributes']['cost']
1927
-
1928
- delete :destroy, {id: json_response['data']['id']}
1929
- assert_response :no_content
1930
- ensure
1931
- JSONAPI.configuration = original_config
1932
- end
1933
- end
1934
-
1935
- class IsoCurrenciesControllerTest < ActionController::TestCase
1936
- def after_teardown
1937
- JSONAPI.configuration.json_key_format = :camelized_key
1938
- end
1939
-
1940
- def test_currencies_show
1941
- get :show, {id: 'USD'}
1942
- assert_response :success
1943
- assert json_response['data'].is_a?(Hash)
1944
- end
1945
-
1946
- def test_create_currencies_client_generated_id
1947
- set_content_type_header!
1948
- original_config = JSONAPI.configuration.dup
1949
- JSONAPI.configuration.json_key_format = :underscored_route
1950
-
1951
- post :create,
1952
- {
1953
- data: {
1954
- type: 'iso_currencies',
1955
- id: 'BTC',
1956
- attributes: {
1957
- name: 'Bit Coin',
1958
- 'country_name' => 'global',
1959
- 'minor_unit' => 'satoshi'
1960
- }
1961
- }
1962
- }
1963
-
1964
- assert_response :created
1965
- assert_equal 'BTC', json_response['data']['id']
1966
- assert_equal 'Bit Coin', json_response['data']['attributes']['name']
1967
- assert_equal 'global', json_response['data']['attributes']['country_name']
1968
- assert_equal 'satoshi', json_response['data']['attributes']['minor_unit']
1969
-
1970
- delete :destroy, {id: json_response['data']['id']}
1971
- assert_response :no_content
1972
- ensure
1973
- JSONAPI.configuration = original_config
1974
- end
1975
-
1976
- def test_currencies_primary_key_sort
1977
- get :index, {sort: 'id'}
1978
- assert_response :success
1979
- assert_equal 3, json_response['data'].size
1980
- assert_equal 'CAD', json_response['data'][0]['id']
1981
- assert_equal 'EUR', json_response['data'][1]['id']
1982
- assert_equal 'USD', json_response['data'][2]['id']
1983
- end
1984
-
1985
- def test_currencies_code_sort
1986
- get :index, {sort: 'code'}
1987
- assert_response :bad_request
1988
- end
1989
-
1990
- def test_currencies_json_key_underscored_sort
1991
- original_config = JSONAPI.configuration.dup
1992
- JSONAPI.configuration.json_key_format = :underscored_key
1993
- get :index, {sort: 'country_name'}
1994
- assert_response :success
1995
- assert_equal 3, json_response['data'].size
1996
- assert_equal 'Canada', json_response['data'][0]['attributes']['country_name']
1997
- assert_equal 'Euro Member Countries', json_response['data'][1]['attributes']['country_name']
1998
- assert_equal 'United States', json_response['data'][2]['attributes']['country_name']
1999
-
2000
- # reverse sort
2001
- get :index, {sort: '-country_name'}
2002
- assert_response :success
2003
- assert_equal 3, json_response['data'].size
2004
- assert_equal 'United States', json_response['data'][0]['attributes']['country_name']
2005
- assert_equal 'Euro Member Countries', json_response['data'][1]['attributes']['country_name']
2006
- assert_equal 'Canada', json_response['data'][2]['attributes']['country_name']
2007
- ensure
2008
- JSONAPI.configuration = original_config
2009
- end
2010
-
2011
- def test_currencies_json_key_dasherized_sort
2012
- original_config = JSONAPI.configuration.dup
2013
- JSONAPI.configuration.json_key_format = :dasherized_key
2014
- get :index, {sort: 'country-name'}
2015
- assert_response :success
2016
- assert_equal 3, json_response['data'].size
2017
- assert_equal 'Canada', json_response['data'][0]['attributes']['country-name']
2018
- assert_equal 'Euro Member Countries', json_response['data'][1]['attributes']['country-name']
2019
- assert_equal 'United States', json_response['data'][2]['attributes']['country-name']
2020
-
2021
- # reverse sort
2022
- get :index, {sort: '-country-name'}
2023
- assert_response :success
2024
- assert_equal 3, json_response['data'].size
2025
- assert_equal 'United States', json_response['data'][0]['attributes']['country-name']
2026
- assert_equal 'Euro Member Countries', json_response['data'][1]['attributes']['country-name']
2027
- assert_equal 'Canada', json_response['data'][2]['attributes']['country-name']
2028
- ensure
2029
- JSONAPI.configuration = original_config
2030
- end
2031
-
2032
- def test_currencies_json_key_custom_json_key_sort
2033
- original_config = JSONAPI.configuration.dup
2034
- JSONAPI.configuration.json_key_format = :upper_camelized_key
2035
- get :index, {sort: 'CountryName'}
2036
- assert_response :success
2037
- assert_equal 3, json_response['data'].size
2038
- assert_equal 'Canada', json_response['data'][0]['attributes']['CountryName']
2039
- assert_equal 'Euro Member Countries', json_response['data'][1]['attributes']['CountryName']
2040
- assert_equal 'United States', json_response['data'][2]['attributes']['CountryName']
2041
-
2042
- # reverse sort
2043
- get :index, {sort: '-CountryName'}
2044
- assert_response :success
2045
- assert_equal 3, json_response['data'].size
2046
- assert_equal 'United States', json_response['data'][0]['attributes']['CountryName']
2047
- assert_equal 'Euro Member Countries', json_response['data'][1]['attributes']['CountryName']
2048
- assert_equal 'Canada', json_response['data'][2]['attributes']['CountryName']
2049
- ensure
2050
- JSONAPI.configuration = original_config
2051
- end
2052
-
2053
- def test_currencies_json_key_underscored_filter
2054
- original_config = JSONAPI.configuration.dup
2055
- JSONAPI.configuration.json_key_format = :underscored_key
2056
- get :index, {filter: {country_name: 'Canada'}}
2057
- assert_response :success
2058
- assert_equal 1, json_response['data'].size
2059
- assert_equal 'Canada', json_response['data'][0]['attributes']['country_name']
2060
- ensure
2061
- JSONAPI.configuration = original_config
2062
- end
2063
-
2064
- def test_currencies_json_key_camelized_key_filter
2065
- original_config = JSONAPI.configuration.dup
2066
- JSONAPI.configuration.json_key_format = :camelized_key
2067
- get :index, {filter: {'countryName' => 'Canada'}}
2068
- assert_response :success
2069
- assert_equal 1, json_response['data'].size
2070
- assert_equal 'Canada', json_response['data'][0]['attributes']['countryName']
2071
- ensure
2072
- JSONAPI.configuration = original_config
2073
- end
2074
-
2075
- def test_currencies_json_key_custom_json_key_filter
2076
- original_config = JSONAPI.configuration.dup
2077
- JSONAPI.configuration.json_key_format = :upper_camelized_key
2078
- get :index, {filter: {'CountryName' => 'Canada'}}
2079
- assert_response :success
2080
- assert_equal 1, json_response['data'].size
2081
- assert_equal 'Canada', json_response['data'][0]['attributes']['CountryName']
2082
- ensure
2083
- JSONAPI.configuration = original_config
2084
- end
2085
- end
2086
-
2087
- class PeopleControllerTest < ActionController::TestCase
2088
- def setup
2089
- JSONAPI.configuration.json_key_format = :camelized_key
2090
- end
2091
-
2092
- def test_create_validations
2093
- set_content_type_header!
2094
- post :create,
2095
- {
2096
- data: {
2097
- type: 'people',
2098
- attributes: {
2099
- name: 'Steve Jobs',
2100
- email: 'sj@email.zzz',
2101
- dateJoined: DateTime.parse('2014-1-30 4:20:00 UTC +00:00')
2102
- }
2103
- }
2104
- }
2105
-
2106
- assert_response :success
2107
- end
2108
-
2109
- def test_update_link_with_dasherized_type
2110
- original_config = JSONAPI.configuration.dup
2111
- JSONAPI.configuration.json_key_format = :dasherized_key
2112
- set_content_type_header!
2113
- put :update,
2114
- {
2115
- id: 3,
2116
- data: {
2117
- id: '3',
2118
- type: 'people',
2119
- relationships: {
2120
- 'hair-cut' => {
2121
- data: {
2122
- type: 'hair-cuts',
2123
- id: '1'
2124
- }
2125
- }
2126
- }
2127
- }
2128
- }
2129
- assert_response :success
2130
- ensure
2131
- JSONAPI.configuration = original_config
2132
- end
2133
-
2134
- def test_create_validations_missing_attribute
2135
- set_content_type_header!
2136
- post :create,
2137
- {
2138
- data: {
2139
- type: 'people',
2140
- attributes: {
2141
- email: 'sj@email.zzz'
2142
- }
2143
- }
2144
- }
2145
-
2146
- assert_response :unprocessable_entity
2147
- assert_equal 2, json_response['errors'].size
2148
- assert_equal JSONAPI::VALIDATION_ERROR, json_response['errors'][0]['code']
2149
- assert_equal JSONAPI::VALIDATION_ERROR, json_response['errors'][1]['code']
2150
- assert_match /dateJoined - can't be blank/, response.body
2151
- assert_match /name - can't be blank/, response.body
2152
- end
2153
-
2154
- def test_update_validations_missing_attribute
2155
- set_content_type_header!
2156
- put :update,
2157
- {
2158
- id: 3,
2159
- data: {
2160
- id: '3',
2161
- type: 'people',
2162
- attributes: {
2163
- name: ''
2164
- }
2165
- }
2166
- }
2167
-
2168
- assert_response :unprocessable_entity
2169
- assert_equal 1, json_response['errors'].size
2170
- assert_equal JSONAPI::VALIDATION_ERROR, json_response['errors'][0]['code']
2171
- assert_match /name - can't be blank/, response.body
2172
- end
2173
-
2174
- def test_delete_locked
2175
- initial_count = Person.count
2176
- delete :destroy, {id: '3'}
2177
- assert_response :locked
2178
- assert_equal initial_count, Person.count
2179
- end
2180
-
2181
- def test_invalid_filter_value
2182
- get :index, {filter: {name: 'L'}}
2183
- assert_response :bad_request
2184
- end
2185
-
2186
- def test_valid_filter_value
2187
- get :index, {filter: {name: 'Joe Author'}}
2188
- assert_response :success
2189
- assert_equal json_response['data'].size, 1
2190
- assert_equal json_response['data'][0]['id'], '1'
2191
- assert_equal json_response['data'][0]['attributes']['name'], 'Joe Author'
2192
- end
2193
-
2194
- def test_get_related_resource_no_namespace
2195
- original_config = JSONAPI.configuration.dup
2196
- JSONAPI.configuration.json_key_format = :dasherized_key
2197
- JSONAPI.configuration.route_format = :underscored_key
2198
- get :get_related_resource, {post_id: '2', relationship: 'author', source:'posts'}
2199
- assert_response :success
2200
- assert_hash_equals(
2201
- {
2202
- data: {
2203
- id: '1',
2204
- type: 'people',
2205
- attributes: {
2206
- name: 'Joe Author',
2207
- email: 'joe@xyz.fake',
2208
- "date-joined" => '2013-08-07 16:25:00 -0400'
2209
- },
2210
- links: {
2211
- self: 'http://test.host/people/1'
2212
- },
2213
- relationships: {
2214
- comments: {
2215
- links: {
2216
- self: 'http://test.host/people/1/relationships/comments',
2217
- related: 'http://test.host/people/1/comments'
2218
- }
2219
- },
2220
- posts: {
2221
- links: {
2222
- self: 'http://test.host/people/1/relationships/posts',
2223
- related: 'http://test.host/people/1/posts'
2224
- }
2225
- },
2226
- preferences: {
2227
- links: {
2228
- self: 'http://test.host/people/1/relationships/preferences',
2229
- related: 'http://test.host/people/1/preferences'
2230
- }
2231
- },
2232
- "hair-cut" => {
2233
- "links" => {
2234
- "self" => "http://test.host/people/1/relationships/hair_cut",
2235
- "related" => "http://test.host/people/1/hair_cut"
2236
- }
2237
- },
2238
- vehicles: {
2239
- links: {
2240
- self: "http://test.host/people/1/relationships/vehicles",
2241
- related: "http://test.host/people/1/vehicles"
2242
- }
2243
- }
2244
- }
2245
- }
2246
- },
2247
- json_response
2248
- )
2249
- ensure
2250
- JSONAPI.configuration = original_config
2251
- end
2252
-
2253
- def test_get_related_resource_nil
2254
- get :get_related_resource, {post_id: '17', relationship: 'author', source:'posts'}
2255
- assert_response :success
2256
- assert_hash_equals json_response,
2257
- {
2258
- data: nil
2259
- }
2260
-
2261
- end
2262
- end
2263
-
2264
- class BooksControllerTest < ActionController::TestCase
2265
- def test_books_include_correct_type
2266
- $test_user = Person.find(1)
2267
- get :index, {filter: {id: '1'}, include: 'authors'}
2268
- assert_response :success
2269
- assert_equal 'authors', json_response['included'][0]['type']
2270
- end
2271
- end
2272
-
2273
- class Api::V5::AuthorsControllerTest < ActionController::TestCase
2274
- def test_get_person_as_author
2275
- get :index, {filter: {id: '1'}}
2276
- assert_response :success
2277
- assert_equal 1, json_response['data'].size
2278
- assert_equal '1', json_response['data'][0]['id']
2279
- assert_equal 'authors', json_response['data'][0]['type']
2280
- assert_equal 'Joe Author', json_response['data'][0]['attributes']['name']
2281
- assert_equal nil, json_response['data'][0]['attributes']['email']
2282
- end
2283
-
2284
- def test_show_person_as_author
2285
- get :show, {id: '1'}
2286
- assert_response :success
2287
- assert_equal '1', json_response['data']['id']
2288
- assert_equal 'authors', json_response['data']['type']
2289
- assert_equal 'Joe Author', json_response['data']['attributes']['name']
2290
- assert_equal nil, json_response['data']['attributes']['email']
2291
- end
2292
-
2293
- def test_get_person_as_author_by_name_filter
2294
- get :index, {filter: {name: 'thor'}}
2295
- assert_response :success
2296
- assert_equal 3, json_response['data'].size
2297
- assert_equal '1', json_response['data'][0]['id']
2298
- assert_equal 'Joe Author', json_response['data'][0]['attributes']['name']
2299
- end
2300
-
2301
- def test_meta_serializer_options
2302
- JSONAPI.configuration.json_key_format = :camelized_key
2303
-
2304
- Api::V5::AuthorResource.class_eval do
2305
- def meta(options)
2306
- {
2307
- fixed: 'Hardcoded value',
2308
- computed: "#{self.class._type.to_s}: #{options[:serializer].link_builder.self_link(self)}",
2309
- computed_foo: options[:serialization_options][:foo],
2310
- options[:serializer].format_key('test_key') => 'test value'
2311
- }
2312
- end
2313
- end
2314
-
2315
- get :show, {id: '1'}
2316
- assert_response :success
2317
- assert_equal '1', json_response['data']['id']
2318
- assert_equal 'Hardcoded value', json_response['data']['meta']['fixed']
2319
- assert_equal 'authors: http://test.host/api/v5/authors/1', json_response['data']['meta']['computed']
2320
- assert_equal 'bar', json_response['data']['meta']['computed_foo']
2321
- assert_equal 'test value', json_response['data']['meta']['testKey']
2322
-
2323
- ensure
2324
- JSONAPI.configuration.json_key_format = :dasherized_key
2325
- Api::V5::AuthorResource.class_eval do
2326
- def meta(options)
2327
- # :nocov:
2328
- { }
2329
- # :nocov:
2330
- end
2331
- end
2332
- end
2333
-
2334
- def test_meta_serializer_hash_data
2335
- JSONAPI.configuration.json_key_format = :camelized_key
2336
-
2337
- Api::V5::AuthorResource.class_eval do
2338
- def meta(options)
2339
- {
2340
- custom_hash: {
2341
- fixed: 'Hardcoded value',
2342
- computed: "#{self.class._type.to_s}: #{options[:serializer].link_builder.self_link(self)}",
2343
- computed_foo: options[:serialization_options][:foo],
2344
- options[:serializer].format_key('test_key') => 'test value'
2345
- }
2346
- }
2347
- end
2348
- end
2349
-
2350
- get :show, {id: '1'}
2351
- assert_response :success
2352
- assert_equal '1', json_response['data']['id']
2353
- assert_equal 'Hardcoded value', json_response['data']['meta']['custom_hash']['fixed']
2354
- assert_equal 'authors: http://test.host/api/v5/authors/1', json_response['data']['meta']['custom_hash']['computed']
2355
- assert_equal 'bar', json_response['data']['meta']['custom_hash']['computed_foo']
2356
- assert_equal 'test value', json_response['data']['meta']['custom_hash']['testKey']
2357
-
2358
- ensure
2359
- JSONAPI.configuration.json_key_format = :dasherized_key
2360
- Api::V5::AuthorResource.class_eval do
2361
- def meta(options)
2362
- # :nocov:
2363
- { }
2364
- # :nocov:
2365
- end
2366
- end
2367
- end
2368
- end
2369
-
2370
- class BreedsControllerTest < ActionController::TestCase
2371
- # Note: Breed names go through the TitleValueFormatter
2372
-
2373
- def test_poro_index
2374
- get :index
2375
- assert_response :success
2376
- assert_equal '0', json_response['data'][0]['id']
2377
- assert_equal 'Persian', json_response['data'][0]['attributes']['name']
2378
- end
2379
-
2380
- def test_poro_show
2381
- get :show, {id: '0'}
2382
- assert_response :success
2383
- assert json_response['data'].is_a?(Hash)
2384
- assert_equal '0', json_response['data']['id']
2385
- assert_equal 'Persian', json_response['data']['attributes']['name']
2386
- end
2387
-
2388
- def test_poro_show_multiple
2389
- get :show, {id: '0,2'}
2390
-
2391
- assert_response :bad_request
2392
- assert_match /0,2 is not a valid value for id/, response.body
2393
- end
2394
-
2395
- def test_poro_create_simple
2396
- set_content_type_header!
2397
- post :create,
2398
- {
2399
- data: {
2400
- type: 'breeds',
2401
- attributes: {
2402
- name: 'tabby'
2403
- }
2404
- }
2405
- }
2406
-
2407
- assert_response :accepted
2408
- assert json_response['data'].is_a?(Hash)
2409
- assert_equal 'Tabby', json_response['data']['attributes']['name']
2410
- end
2411
-
2412
- def test_poro_create_validation_error
2413
- set_content_type_header!
2414
- post :create,
2415
- {
2416
- data: {
2417
- type: 'breeds',
2418
- attributes: {
2419
- name: ''
2420
- }
2421
- }
2422
- }
2423
-
2424
- assert_equal 1, json_response['errors'].size
2425
- assert_equal JSONAPI::VALIDATION_ERROR, json_response['errors'][0]['code']
2426
- assert_match /name - can't be blank/, response.body
2427
- end
2428
-
2429
- def test_poro_create_update
2430
- set_content_type_header!
2431
- post :create,
2432
- {
2433
- data: {
2434
- type: 'breeds',
2435
- attributes: {
2436
- name: 'CALIC'
2437
- }
2438
- }
2439
- }
2440
-
2441
- assert_response :accepted
2442
- assert json_response['data'].is_a?(Hash)
2443
- assert_equal 'Calic', json_response['data']['attributes']['name']
2444
-
2445
- put :update,
2446
- {
2447
- id: json_response['data']['id'],
2448
- data: {
2449
- id: json_response['data']['id'],
2450
- type: 'breeds',
2451
- attributes: {
2452
- name: 'calico'
2453
- }
2454
- }
2455
- }
2456
- assert_response :success
2457
- assert json_response['data'].is_a?(Hash)
2458
- assert_equal 'Calico', json_response['data']['attributes']['name']
2459
- end
2460
-
2461
- def test_poro_delete
2462
- initial_count = $breed_data.breeds.keys.count
2463
- delete :destroy, {id: '3'}
2464
- assert_response :no_content
2465
- assert_equal initial_count - 1, $breed_data.breeds.keys.count
2466
- end
2467
-
2468
- end
2469
-
2470
- class Api::V2::PreferencesControllerTest < ActionController::TestCase
2471
- def test_show_singleton_resource_without_id
2472
- get :show
2473
- assert_response :success
2474
- end
2475
-
2476
- def test_update_singleton_resource_without_id
2477
- set_content_type_header!
2478
- patch :update,
2479
- data: {
2480
- id: "1",
2481
- type: "preferences",
2482
- attributes: {
2483
- }
2484
- }
2485
- assert_response :success
2486
- end
2487
- end
2488
-
2489
- class Api::V1::PostsControllerTest < ActionController::TestCase
2490
- def test_show_post_namespaced
2491
- get :show, {id: '1'}
2492
- assert_response :success
2493
- assert_equal 'http://test.host/api/v1/posts/1/relationships/writer', json_response['data']['relationships']['writer']['links']['self']
2494
- end
2495
-
2496
- def test_show_post_namespaced_include
2497
- get :show, {id: '1', include: 'writer'}
2498
- assert_response :success
2499
- assert_equal '1', json_response['data']['relationships']['writer']['data']['id']
2500
- assert_nil json_response['data']['relationships']['tags']
2501
- assert_equal '1', json_response['included'][0]['id']
2502
- assert_equal 'writers', json_response['included'][0]['type']
2503
- assert_equal 'joe@xyz.fake', json_response['included'][0]['attributes']['email']
2504
- end
2505
-
2506
- def test_index_filter_on_relationship_namespaced
2507
- get :index, {filter: {writer: '1'}}
2508
- assert_response :success
2509
- assert_equal 3, json_response['data'].size
2510
- end
2511
-
2512
- def test_sorting_desc_namespaced
2513
- get :index, {sort: '-title'}
2514
-
2515
- assert_response :success
2516
- assert_equal "Update This Later - Multiple", json_response['data'][0]['attributes']['title']
2517
- end
2518
-
2519
- def test_create_simple_namespaced
2520
- set_content_type_header!
2521
- post :create,
2522
- {
2523
- data: {
2524
- type: 'posts',
2525
- attributes: {
2526
- title: 'JR - now with Namespacing',
2527
- body: 'JSONAPIResources is the greatest thing since unsliced bread now that it has namespaced resources.'
2528
- },
2529
- relationships: {
2530
- writer: { data: {type: 'writers', id: '3'}}
2531
- }
2532
- }
2533
- }
2534
-
2535
- assert_response :created
2536
- assert json_response['data'].is_a?(Hash)
2537
- assert_equal 'JR - now with Namespacing', json_response['data']['attributes']['title']
2538
- assert_equal 'JSONAPIResources is the greatest thing since unsliced bread now that it has namespaced resources.',
2539
- json_response['data']['attributes']['body']
2540
- end
2541
-
2542
- end
2543
-
2544
- class FactsControllerTest < ActionController::TestCase
2545
- def test_type_formatting
2546
- original_config = JSONAPI.configuration.dup
2547
- JSONAPI.configuration.json_key_format = :camelized_key
2548
- get :show, {id: '1'}
2549
- assert_response :success
2550
- assert json_response['data'].is_a?(Hash)
2551
- assert_equal 'Jane Author', json_response['data']['attributes']['spouseName']
2552
- assert_equal 'First man to run across Antartica.', json_response['data']['attributes']['bio']
2553
- assert_equal 23.89/45.6, json_response['data']['attributes']['qualityRating']
2554
- assert_equal '47000.56', json_response['data']['attributes']['salary']
2555
- assert_equal '2013-08-07T20:25:00Z', json_response['data']['attributes']['dateTimeJoined']
2556
- assert_equal '1965-06-30', json_response['data']['attributes']['birthday']
2557
- assert_equal '2000-01-01T20:00:00Z', json_response['data']['attributes']['bedtime']
2558
- assert_equal 'abc', json_response['data']['attributes']['photo']
2559
- assert_equal false, json_response['data']['attributes']['cool']
2560
- ensure
2561
- JSONAPI.configuration = original_config
2562
- end
2563
-
2564
- def test_create_with_invalid_data
2565
- original_config = JSONAPI.configuration.dup
2566
- JSONAPI.configuration.json_key_format = :dasherized_key
2567
- set_content_type_header!
2568
- post :create,
2569
- {
2570
- data: {
2571
- type: 'facts',
2572
- attributes: {
2573
- bio: '',
2574
- :"quality-rating" => '',
2575
- :"spouse-name" => '',
2576
- salary: 100000,
2577
- :"date-time-joined" => '',
2578
- birthday: '',
2579
- bedtime: '',
2580
- photo: 'abc',
2581
- cool: false
2582
- },
2583
- relationships: {
2584
- }
2585
- }
2586
- }
2587
-
2588
- assert_response :unprocessable_entity
2589
-
2590
- assert_equal "/data/attributes/spouse-name", json_response['errors'][0]['source']['pointer']
2591
- assert_equal "can't be blank", json_response['errors'][0]['title']
2592
- assert_equal "spouse-name - can't be blank", json_response['errors'][0]['detail']
2593
-
2594
- assert_equal "/data/attributes/bio", json_response['errors'][1]['source']['pointer']
2595
- assert_equal "can't be blank", json_response['errors'][1]['title']
2596
- assert_equal "bio - can't be blank", json_response['errors'][1]['detail']
2597
- ensure
2598
- JSONAPI.configuration = original_config
2599
- end
2600
- end
2601
-
2602
- class Api::V2::BooksControllerTest < ActionController::TestCase
2603
- def setup
2604
- JSONAPI.configuration.json_key_format = :dasherized_key
2605
- $test_user = Person.find(1)
2606
- end
2607
-
2608
- def after_teardown
2609
- Api::V2::BookResource.paginator :offset
2610
- end
2611
-
2612
- def test_books_offset_pagination_no_params
2613
- Api::V2::BookResource.paginator :offset
2614
-
2615
- get :index
2616
- assert_response :success
2617
- assert_equal 10, json_response['data'].size
2618
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2619
- end
2620
-
2621
- def test_books_record_count_in_meta
2622
- Api::V2::BookResource.paginator :offset
2623
- JSONAPI.configuration.top_level_meta_include_record_count = true
2624
- get :index, {include: 'book-comments'}
2625
- JSONAPI.configuration.top_level_meta_include_record_count = false
2626
-
2627
- assert_response :success
2628
- assert_equal 901, json_response['meta']['record-count']
2629
- assert_equal 10, json_response['data'].size
2630
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2631
- end
2632
-
2633
- def test_books_record_count_in_meta_custom_name
2634
- Api::V2::BookResource.paginator :offset
2635
- JSONAPI.configuration.top_level_meta_include_record_count = true
2636
- JSONAPI.configuration.top_level_meta_record_count_key = 'total_records'
2637
-
2638
- get :index, {include: 'book-comments'}
2639
- JSONAPI.configuration.top_level_meta_include_record_count = false
2640
- JSONAPI.configuration.top_level_meta_record_count_key = :record_count
2641
-
2642
- assert_response :success
2643
- assert_equal 901, json_response['meta']['total-records']
2644
- assert_equal 10, json_response['data'].size
2645
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2646
- end
2647
-
2648
- def test_books_offset_pagination_no_params_includes_query_count_one_level
2649
- Api::V2::BookResource.paginator :offset
2650
-
2651
- count_queries do
2652
- get :index, {include: 'book-comments'}
2653
- end
2654
- assert_response :success
2655
- assert_equal 10, json_response['data'].size
2656
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2657
- assert_query_count(3)
2658
- end
2659
-
2660
- def test_books_offset_pagination_no_params_includes_query_count_two_levels
2661
- Api::V2::BookResource.paginator :offset
2662
-
2663
- count_queries do
2664
- get :index, {include: 'book-comments,book-comments.author'}
2665
- end
2666
- assert_response :success
2667
- assert_equal 10, json_response['data'].size
2668
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2669
- assert_query_count(4)
2670
- end
2671
-
2672
- def test_books_offset_pagination
2673
- Api::V2::BookResource.paginator :offset
2674
-
2675
- get :index, {page: {offset: 50, limit: 12}}
2676
- assert_response :success
2677
- assert_equal 12, json_response['data'].size
2678
- assert_equal 'Book 50', json_response['data'][0]['attributes']['title']
2679
- end
2680
-
2681
- def test_books_offset_pagination_bad_page_param
2682
- Api::V2::BookResource.paginator :offset
2683
-
2684
- get :index, {page: {offset_bad: 50, limit: 12}}
2685
- assert_response :bad_request
2686
- assert_match /offset_bad is not an allowed page parameter./, json_response['errors'][0]['detail']
2687
- end
2688
-
2689
- def test_books_offset_pagination_bad_param_value_limit_to_large
2690
- Api::V2::BookResource.paginator :offset
2691
-
2692
- get :index, {page: {offset: 50, limit: 1000}}
2693
- assert_response :bad_request
2694
- assert_match /Limit exceeds maximum page size of 20./, json_response['errors'][0]['detail']
2695
- end
2696
-
2697
- def test_books_offset_pagination_bad_param_value_limit_too_small
2698
- Api::V2::BookResource.paginator :offset
2699
-
2700
- get :index, {page: {offset: 50, limit: -1}}
2701
- assert_response :bad_request
2702
- assert_match /-1 is not a valid value for limit page parameter./, json_response['errors'][0]['detail']
2703
- end
2704
-
2705
- def test_books_offset_pagination_bad_param_offset_less_than_zero
2706
- Api::V2::BookResource.paginator :offset
2707
-
2708
- get :index, {page: {offset: -1, limit: 20}}
2709
- assert_response :bad_request
2710
- assert_match /-1 is not a valid value for offset page parameter./, json_response['errors'][0]['detail']
2711
- end
2712
-
2713
- def test_books_offset_pagination_invalid_page_format
2714
- Api::V2::BookResource.paginator :offset
2715
-
2716
- get :index, {page: 50}
2717
- assert_response :bad_request
2718
- assert_match /Invalid Page Object./, json_response['errors'][0]['detail']
2719
- end
2720
-
2721
- def test_books_paged_pagination_no_params
2722
- Api::V2::BookResource.paginator :paged
2723
-
2724
- get :index
2725
- assert_response :success
2726
- assert_equal 10, json_response['data'].size
2727
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2728
- end
2729
-
2730
- def test_books_paged_pagination_no_page
2731
- Api::V2::BookResource.paginator :paged
2732
-
2733
- get :index, {page: {size: 12}}
2734
- assert_response :success
2735
- assert_equal 12, json_response['data'].size
2736
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2737
- end
2738
-
2739
- def test_books_paged_pagination
2740
- Api::V2::BookResource.paginator :paged
2741
-
2742
- get :index, {page: {number: 3, size: 12}}
2743
- assert_response :success
2744
- assert_equal 12, json_response['data'].size
2745
- assert_equal 'Book 24', json_response['data'][0]['attributes']['title']
2746
- end
2747
-
2748
- def test_books_paged_pagination_bad_page_param
2749
- Api::V2::BookResource.paginator :paged
2750
-
2751
- get :index, {page: {number_bad: 50, size: 12}}
2752
- assert_response :bad_request
2753
- assert_match /number_bad is not an allowed page parameter./, json_response['errors'][0]['detail']
2754
- end
2755
-
2756
- def test_books_paged_pagination_bad_param_value_limit_to_large
2757
- Api::V2::BookResource.paginator :paged
2758
-
2759
- get :index, {page: {number: 50, size: 1000}}
2760
- assert_response :bad_request
2761
- assert_match /size exceeds maximum page size of 20./, json_response['errors'][0]['detail']
2762
- end
2763
-
2764
- def test_books_paged_pagination_bad_param_value_limit_too_small
2765
- Api::V2::BookResource.paginator :paged
2766
-
2767
- get :index, {page: {number: 50, size: -1}}
2768
- assert_response :bad_request
2769
- assert_match /-1 is not a valid value for size page parameter./, json_response['errors'][0]['detail']
2770
- end
2771
-
2772
- def test_books_paged_pagination_invalid_page_format_incorrect
2773
- Api::V2::BookResource.paginator :paged
2774
-
2775
- get :index, {page: 'qwerty'}
2776
- assert_response :bad_request
2777
- assert_match /0 is not a valid value for number page parameter./, json_response['errors'][0]['detail']
2778
- end
2779
-
2780
- def test_books_paged_pagination_invalid_page_format_interpret_int
2781
- Api::V2::BookResource.paginator :paged
2782
-
2783
- get :index, {page: 3}
2784
- assert_response :success
2785
- assert_equal 10, json_response['data'].size
2786
- assert_equal 'Book 20', json_response['data'][0]['attributes']['title']
2787
- end
2788
-
2789
- def test_books_included_paged
2790
- Api::V2::BookResource.paginator :offset
2791
-
2792
- count_queries do
2793
- get :index, {filter: {id: '0'}, include: 'book-comments'}
2794
- end
2795
- assert_response :success
2796
- assert_equal 1, json_response['data'].size
2797
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2798
- assert_query_count(3)
2799
- end
2800
-
2801
- def test_books_banned_non_book_admin
2802
- $test_user = Person.find(1)
2803
- Api::V2::BookResource.paginator :offset
2804
- JSONAPI.configuration.top_level_meta_include_record_count = true
2805
- count_queries do
2806
- get :index, {page: {offset: 50, limit: 12}}
2807
- end
2808
- assert_response :success
2809
- assert_equal 12, json_response['data'].size
2810
- assert_equal 'Book 50', json_response['data'][0]['attributes']['title']
2811
- assert_equal 901, json_response['meta']['record-count']
2812
- assert_query_count(2)
2813
- ensure
2814
- JSONAPI.configuration.top_level_meta_include_record_count = false
2815
- end
2816
-
2817
- def test_books_banned_non_book_admin_includes_switched
2818
- $test_user = Person.find(1)
2819
- Api::V2::BookResource.paginator :offset
2820
- JSONAPI.configuration.top_level_meta_include_record_count = true
2821
- count_queries do
2822
- get :index, {page: {offset: 0, limit: 12}, include: 'book-comments'}
2823
- end
2824
-
2825
- assert_response :success
2826
- assert_equal 12, json_response['data'].size
2827
- assert_equal 130, json_response['included'].size
2828
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2829
- assert_equal 26, json_response['data'][0]['relationships']['book-comments']['data'].size
2830
- assert_equal 'book-comments', json_response['included'][0]['type']
2831
- assert_equal 901, json_response['meta']['record-count']
2832
- assert_query_count(3)
2833
- ensure
2834
- JSONAPI.configuration.top_level_meta_include_record_count = false
2835
- end
2836
-
2837
- def test_books_banned_non_book_admin_includes_nested_includes
2838
- $test_user = Person.find(1)
2839
- JSONAPI.configuration.top_level_meta_include_record_count = true
2840
- Api::V2::BookResource.paginator :offset
2841
- count_queries do
2842
- get :index, {page: {offset: 0, limit: 12}, include: 'book-comments.author'}
2843
- end
2844
- assert_response :success
2845
- assert_equal 12, json_response['data'].size
2846
- assert_equal 131, json_response['included'].size
2847
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2848
- assert_equal 901, json_response['meta']['record-count']
2849
- assert_query_count(4)
2850
- ensure
2851
- JSONAPI.configuration.top_level_meta_include_record_count = false
2852
- end
2853
-
2854
- def test_books_banned_admin
2855
- $test_user = Person.find(5)
2856
- Api::V2::BookResource.paginator :offset
2857
- JSONAPI.configuration.top_level_meta_include_record_count = true
2858
- count_queries do
2859
- get :index, {page: {offset: 50, limit: 12}, filter: {banned: 'true'}}
2860
- end
2861
- assert_response :success
2862
- assert_equal 12, json_response['data'].size
2863
- assert_equal 'Book 651', json_response['data'][0]['attributes']['title']
2864
- assert_equal 99, json_response['meta']['record-count']
2865
- assert_query_count(2)
2866
- ensure
2867
- JSONAPI.configuration.top_level_meta_include_record_count = false
2868
- end
2869
-
2870
- def test_books_not_banned_admin
2871
- $test_user = Person.find(5)
2872
- Api::V2::BookResource.paginator :offset
2873
- JSONAPI.configuration.top_level_meta_include_record_count = true
2874
- count_queries do
2875
- get :index, {page: {offset: 50, limit: 12}, filter: {banned: 'false'}}
2876
- end
2877
- assert_response :success
2878
- assert_equal 12, json_response['data'].size
2879
- assert_equal 'Book 50', json_response['data'][0]['attributes']['title']
2880
- assert_equal 901, json_response['meta']['record-count']
2881
- assert_query_count(2)
2882
- ensure
2883
- JSONAPI.configuration.top_level_meta_include_record_count = false
2884
- end
2885
-
2886
- def test_books_banned_non_book_admin_overlapped
2887
- $test_user = Person.find(1)
2888
- Api::V2::BookResource.paginator :offset
2889
- JSONAPI.configuration.top_level_meta_include_record_count = true
2890
- count_queries do
2891
- get :index, {page: {offset: 590, limit: 20}}
2892
- end
2893
- assert_response :success
2894
- assert_equal 20, json_response['data'].size
2895
- assert_equal 'Book 590', json_response['data'][0]['attributes']['title']
2896
- assert_equal 901, json_response['meta']['record-count']
2897
- assert_query_count(2)
2898
- ensure
2899
- JSONAPI.configuration.top_level_meta_include_record_count = false
2900
- end
2901
-
2902
- def test_books_included_exclude_unapproved
2903
- $test_user = Person.find(1)
2904
- Api::V2::BookResource.paginator :none
2905
-
2906
- count_queries do
2907
- get :index, {filter: {id: '0,1,2,3,4'}, include: 'book-comments'}
2908
- end
2909
- assert_response :success
2910
- assert_equal 5, json_response['data'].size
2911
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2912
- assert_equal 130, json_response['included'].size
2913
- assert_equal 26, json_response['data'][0]['relationships']['book-comments']['data'].size
2914
- assert_query_count(2)
2915
- end
2916
-
2917
- def test_books_included_all_comments_for_admin
2918
- $test_user = Person.find(5)
2919
- Api::V2::BookResource.paginator :none
2920
-
2921
- get :index, {filter: {id: '0,1,2,3,4'}, include: 'book-comments'}
2922
- assert_response :success
2923
- assert_equal 5, json_response['data'].size
2924
- assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
2925
- assert_equal 255, json_response['included'].size
2926
- assert_equal 51, json_response['data'][0]['relationships']['book-comments']['data'].size
2927
- end
2928
-
2929
- def test_books_filter_by_book_comment_id_limited_user
2930
- $test_user = Person.find(1)
2931
- get :index, {filter: {book_comments: '0,52' }}
2932
- assert_response :success
2933
- assert_equal 1, json_response['data'].size
2934
- end
2935
-
2936
- def test_books_filter_by_book_comment_id_admin_user
2937
- $test_user = Person.find(5)
2938
- get :index, {filter: {book_comments: '0,52' }}
2939
- assert_response :success
2940
- assert_equal 2, json_response['data'].size
2941
- end
2942
-
2943
- def test_books_create_unapproved_comment_limited_user_using_relation_name
2944
- set_content_type_header!
2945
- $test_user = Person.find(1)
2946
-
2947
- book_comment = BookComment.create(body: 'Not Approved dummy comment', approved: false)
2948
- post :create_relationship, {book_id: 1, relationship: 'book_comments', data: [{type: 'book_comments', id: book_comment.id}]}
2949
-
2950
- # Note the not_found response is coming from the BookComment's overridden records method, not the relation
2951
- assert_response :not_found
2952
-
2953
- ensure
2954
- book_comment.delete
2955
- end
2956
-
2957
- def test_books_create_approved_comment_limited_user_using_relation_name
2958
- set_content_type_header!
2959
- $test_user = Person.find(1)
2960
-
2961
- book_comment = BookComment.create(body: 'Approved dummy comment', approved: true)
2962
- post :create_relationship, {book_id: 1, relationship: 'book_comments', data: [{type: 'book_comments', id: book_comment.id}]}
2963
- assert_response :success
2964
-
2965
- ensure
2966
- book_comment.delete
2967
- end
2968
-
2969
- def test_books_delete_unapproved_comment_limited_user_using_relation_name
2970
- $test_user = Person.find(1)
2971
-
2972
- book_comment = BookComment.create(book_id: 1, body: 'Not Approved dummy comment', approved: false)
2973
- delete :destroy_relationship, {book_id: 1, relationship: 'book_comments', data: [{type: 'book_comments', id: book_comment.id}]}
2974
- assert_response :not_found
2975
-
2976
- ensure
2977
- book_comment.delete
2978
- end
2979
-
2980
- def test_books_delete_approved_comment_limited_user_using_relation_name
2981
- $test_user = Person.find(1)
2982
-
2983
- book_comment = BookComment.create(book_id: 1, body: 'Approved dummy comment', approved: true)
2984
- delete :destroy_relationship, {book_id: 1, relationship: 'book_comments', data: [{type: 'book_comments', id: book_comment.id}]}
2985
- assert_response :no_content
2986
-
2987
- ensure
2988
- book_comment.delete
2989
- end
2990
- end
2991
-
2992
- class Api::V2::BookCommentsControllerTest < ActionController::TestCase
2993
- def setup
2994
- JSONAPI.configuration.json_key_format = :dasherized_key
2995
- Api::V2::BookCommentResource.paginator :none
2996
- $test_user = Person.find(1)
2997
- end
2998
-
2999
- def test_book_comments_all_for_admin
3000
- $test_user = Person.find(5)
3001
- count_queries do
3002
- get :index
3003
- end
3004
- assert_response :success
3005
- assert_equal 255, json_response['data'].size
3006
- assert_query_count(1)
3007
- end
3008
-
3009
- def test_book_comments_unapproved_context_based
3010
- $test_user = Person.find(5)
3011
- count_queries do
3012
- get :index, {filter: {approved: 'false'}}
3013
- end
3014
- assert_response :success
3015
- assert_equal 125, json_response['data'].size
3016
- assert_query_count(1)
3017
- end
3018
-
3019
- def test_book_comments_exclude_unapproved_context_based
3020
- $test_user = Person.find(1)
3021
- count_queries do
3022
- get :index
3023
- end
3024
- assert_response :success
3025
- assert_equal 130, json_response['data'].size
3026
- assert_query_count(1)
3027
- end
3028
- end
3029
-
3030
- class Api::V4::BooksControllerTest < ActionController::TestCase
3031
- def setup
3032
- JSONAPI.configuration.json_key_format = :camelized_key
3033
- end
3034
-
3035
- def test_books_offset_pagination_meta
3036
- original_config = JSONAPI.configuration.dup
3037
- JSONAPI.configuration.operations_processor = :counting_active_record
3038
- Api::V4::BookResource.paginator :offset
3039
- get :index, {page: {offset: 50, limit: 12}}
3040
- assert_response :success
3041
- assert_equal 12, json_response['data'].size
3042
- assert_equal 'Book 50', json_response['data'][0]['attributes']['title']
3043
- assert_equal 901, json_response['meta']['totalRecords']
3044
- ensure
3045
- JSONAPI.configuration = original_config
3046
- end
3047
-
3048
- def test_books_operation_links
3049
- original_config = JSONAPI.configuration.dup
3050
- JSONAPI.configuration.operations_processor = :counting_active_record
3051
- Api::V4::BookResource.paginator :offset
3052
- get :index, {page: {offset: 50, limit: 12}}
3053
- assert_response :success
3054
- assert_equal 12, json_response['data'].size
3055
- assert_equal 'Book 50', json_response['data'][0]['attributes']['title']
3056
- assert_equal 5, json_response['links'].size
3057
- assert_equal 'https://test_corp.com', json_response['links']['spec']
3058
- ensure
3059
- JSONAPI.configuration = original_config
3060
- end
3061
- end
3062
-
3063
- class CategoriesControllerTest < ActionController::TestCase
3064
- def test_index_default_filter
3065
- get :index
3066
- assert_response :success
3067
- assert json_response['data'].is_a?(Array)
3068
- assert_equal 3, json_response['data'].size
3069
- end
3070
-
3071
- def test_index_default_filter_override
3072
- get :index, { filter: { status: 'inactive' } }
3073
- assert_response :success
3074
- assert json_response['data'].is_a?(Array)
3075
- assert_equal 4, json_response['data'].size
3076
- end
3077
- end
3078
-
3079
- class Api::V1::PlanetsControllerTest < ActionController::TestCase
3080
- def test_save_model_callbacks
3081
- set_content_type_header!
3082
- post :create,
3083
- {
3084
- data: {
3085
- type: 'planets',
3086
- attributes: {
3087
- name: 'Zeus',
3088
- description: 'The largest planet in the solar system. Discovered in 2015.'
3089
- }
3090
- }
3091
- }
3092
-
3093
- assert_response :created
3094
- assert json_response['data'].is_a?(Hash)
3095
- assert_equal 'Zeus', json_response['data']['attributes']['name']
3096
- end
3097
-
3098
- def test_save_model_callbacks_fail
3099
- set_content_type_header!
3100
- post :create,
3101
- {
3102
- data: {
3103
- type: 'planets',
3104
- attributes: {
3105
- name: 'Pluto',
3106
- description: 'Yes, it is a planet.'
3107
- }
3108
- }
3109
- }
3110
-
3111
- assert_response :unprocessable_entity
3112
- assert_match /Save failed or was cancelled/, json_response['errors'][0]['detail']
3113
- end
3114
- end
3115
-
3116
- class Api::V1::MoonsControllerTest < ActionController::TestCase
3117
- def test_get_related_resource
3118
- get :get_related_resource, {crater_id: 'S56D', relationship: 'moon', source: "api/v1/craters"}
3119
- assert_response :success
3120
- assert_hash_equals({
3121
- data: {
3122
- id: "1",
3123
- type: "moons",
3124
- links: {self: "http://test.host/api/v1/moons/1"},
3125
- attributes: {name: "Titan", description: "Best known of the Saturn moons."},
3126
- relationships: {
3127
- planet: {links: {self: "http://test.host/api/v1/moons/1/relationships/planet", related: "http://test.host/api/v1/moons/1/planet"}},
3128
- craters: {links: {self: "http://test.host/api/v1/moons/1/relationships/craters", related: "http://test.host/api/v1/moons/1/craters"}}}
3129
- }
3130
- }, json_response)
3131
- end
3132
-
3133
- def test_get_related_resources_with_select_some_db_columns
3134
- PlanetResource.paginator :paged
3135
- original_config = JSONAPI.configuration.dup
3136
- JSONAPI.configuration.top_level_meta_include_record_count = true
3137
- JSONAPI.configuration.json_key_format = :dasherized_key
3138
- get :get_related_resources, {planet_id: '1', relationship: 'moons', source: 'api/v1/planets'}
3139
- assert_response :success
3140
- assert_equal 1, json_response['meta']['record-count']
3141
- ensure
3142
- JSONAPI.configuration = original_config
3143
- end
3144
- end
3145
-
3146
- class Api::V1::CratersControllerTest < ActionController::TestCase
3147
- def test_show_single
3148
- get :show, {id: 'S56D'}
3149
- assert_response :success
3150
- assert json_response['data'].is_a?(Hash)
3151
- assert_equal 'S56D', json_response['data']['attributes']['code']
3152
- assert_equal 'Very large crater', json_response['data']['attributes']['description']
3153
- assert_nil json_response['included']
3154
- end
3155
-
3156
- def test_get_related_resources
3157
- get :get_related_resources, {moon_id: '1', relationship: 'craters', source: "api/v1/moons"}
3158
- assert_response :success
3159
- assert_hash_equals({
3160
- data: [
3161
- {
3162
- id:"A4D3",
3163
- type:"craters",
3164
- links:{self: "http://test.host/api/v1/craters/A4D3"},
3165
- attributes:{code: "A4D3", description: "Small crater"},
3166
- relationships:{moon: {links: {self: "http://test.host/api/v1/craters/A4D3/relationships/moon", related: "http://test.host/api/v1/craters/A4D3/moon"}}}
3167
- },
3168
- {
3169
- id: "S56D",
3170
- type: "craters",
3171
- links:{self: "http://test.host/api/v1/craters/S56D"},
3172
- attributes:{code: "S56D", description: "Very large crater"},
3173
- relationships:{moon: {links: {self: "http://test.host/api/v1/craters/S56D/relationships/moon", related: "http://test.host/api/v1/craters/S56D/moon"}}}
3174
- }
3175
- ]
3176
- }, json_response)
3177
- end
3178
-
3179
- def test_show_relationship
3180
- get :show_relationship, {crater_id: 'S56D', relationship: 'moon'}
3181
-
3182
- assert_response :success
3183
- assert_equal "moons", json_response['data']['type']
3184
- assert_equal "1", json_response['data']['id']
3185
- end
3186
- end
3187
-
3188
- class CarsControllerTest < ActionController::TestCase
3189
- def setup
3190
- JSONAPI.configuration.json_key_format = :camelized_key
3191
- end
3192
-
3193
- def test_create_sti
3194
- set_content_type_header!
3195
- post :create,
3196
- {
3197
- data: {
3198
- type: 'cars',
3199
- attributes: {
3200
- make: 'Toyota',
3201
- model: 'Tercel',
3202
- serialNumber: 'asasdsdadsa13544235',
3203
- driveLayout: 'FWD'
3204
- }
3205
- }
3206
- }
3207
-
3208
- assert_response :created
3209
- assert json_response['data'].is_a?(Hash)
3210
- assert_equal 'cars', json_response['data']['type']
3211
- assert_equal 'Toyota', json_response['data']['attributes']['make']
3212
- assert_equal 'FWD', json_response['data']['attributes']['driveLayout']
3213
- end
3214
- end
3215
-
3216
- class VehiclesControllerTest < ActionController::TestCase
3217
- def setup
3218
- JSONAPI.configuration.json_key_format = :camelized_key
3219
- end
3220
-
3221
- def test_immutable_create_not_supported
3222
- set_content_type_header!
3223
-
3224
- assert_raises ActionController::UrlGenerationError do
3225
- post :create,
3226
- {
3227
- data: {
3228
- type: 'cars',
3229
- attributes: {
3230
- make: 'Toyota',
3231
- model: 'Corrola',
3232
- serialNumber: 'dsvffsfv',
3233
- driveLayout: 'FWD'
3234
- }
3235
- }
3236
- }
3237
- end
3238
- end
3239
-
3240
- def test_immutable_update_not_supported
3241
- set_content_type_header!
3242
-
3243
- assert_raises ActionController::UrlGenerationError do
3244
- patch :update,
3245
- data: {
3246
- id: '1',
3247
- type: 'cars',
3248
- attributes: {
3249
- make: 'Toyota',
3250
- }
3251
- }
3252
- end
3253
- end
3254
- end
3255
-
3256
- class Api::V7::ClientsControllerTest < ActionController::TestCase
3257
- def test_get_namespaced_model_not_matching_resource_using_model_hint
3258
- get :index
3259
- assert_response :success
3260
- assert_equal 'clients', json_response['data'][0]['type']
3261
- ensure
3262
- Api::V7::ClientResource._model_hints['api/v7/customer'] = 'clients'
3263
- end
3264
-
3265
- def test_get_namespaced_model_not_matching_resource_not_using_model_hint
3266
- Api::V7::ClientResource._model_hints.delete('api/v7/customer')
3267
- get :index
3268
- assert_response :success
3269
- assert_equal 'customers', json_response['data'][0]['type']
3270
- ensure
3271
- Api::V7::ClientResource._model_hints['api/v7/customer'] = 'clients'
3272
- end
3273
- end
3274
-
3275
- class Api::V7::CustomersControllerTest < ActionController::TestCase
3276
- def test_get_namespaced_model_matching_resource
3277
- get :index
3278
- assert_response :success
3279
- assert_equal 'customers', json_response['data'][0]['type']
3280
- end
3281
- end
3282
-
3283
- class Api::V7::CategoriesControllerTest < ActionController::TestCase
3284
- def test_uncaught_error_in_controller_translated_to_internal_server_error
3285
-
3286
- get :show, {id: '1'}
3287
- assert_response 500
3288
- assert_match /Internal Server Error/, json_response['errors'][0]['detail']
3289
- end
3290
-
3291
- def test_not_whitelisted_error_in_controller
3292
- original_config = JSONAPI.configuration.dup
3293
- JSONAPI.configuration.operations_processor = :error_raising
3294
- JSONAPI.configuration.exception_class_whitelist = []
3295
- get :show, {id: '1'}
3296
- assert_response 500
3297
- assert_match /Internal Server Error/, json_response['errors'][0]['detail']
3298
- ensure
3299
- JSONAPI.configuration = original_config
3300
- end
3301
-
3302
- def test_whitelisted_error_in_controller
3303
- original_config = JSONAPI.configuration.dup
3304
- JSONAPI.configuration.operations_processor = :error_raising
3305
- JSONAPI.configuration.exception_class_whitelist = [PostsController::SubSpecialError]
3306
- assert_raises PostsController::SubSpecialError do
3307
- get :show, {id: '1'}
3308
- end
3309
- ensure
3310
- JSONAPI.configuration = original_config
3311
- end
3312
- end