dhs 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/rubocop.yml +27 -0
  3. data/.github/workflows/test.yml +27 -0
  4. data/.gitignore +39 -0
  5. data/.rubocop.yml +186 -0
  6. data/.ruby-version +1 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +674 -0
  9. data/README.md +2807 -0
  10. data/Rakefile +26 -0
  11. data/dhs.gemspec +44 -0
  12. data/docs/accessing-data.png +0 -0
  13. data/lib/dhs.rb +67 -0
  14. data/lib/dhs/collection.rb +84 -0
  15. data/lib/dhs/complex.rb +158 -0
  16. data/lib/dhs/concerns/autoload_records.rb +57 -0
  17. data/lib/dhs/concerns/collection/handle_nested.rb +43 -0
  18. data/lib/dhs/concerns/collection/internal_collection.rb +74 -0
  19. data/lib/dhs/concerns/configuration.rb +20 -0
  20. data/lib/dhs/concerns/data/becomes.rb +18 -0
  21. data/lib/dhs/concerns/data/equality.rb +14 -0
  22. data/lib/dhs/concerns/data/extend.rb +87 -0
  23. data/lib/dhs/concerns/data/json.rb +14 -0
  24. data/lib/dhs/concerns/data/to_hash.rb +14 -0
  25. data/lib/dhs/concerns/inspect.rb +70 -0
  26. data/lib/dhs/concerns/is_href.rb +15 -0
  27. data/lib/dhs/concerns/item/destroy.rb +38 -0
  28. data/lib/dhs/concerns/item/endpoint_lookup.rb +27 -0
  29. data/lib/dhs/concerns/item/save.rb +55 -0
  30. data/lib/dhs/concerns/item/update.rb +50 -0
  31. data/lib/dhs/concerns/item/validation.rb +61 -0
  32. data/lib/dhs/concerns/o_auth.rb +25 -0
  33. data/lib/dhs/concerns/option_blocks.rb +26 -0
  34. data/lib/dhs/concerns/proxy/accessors.rb +132 -0
  35. data/lib/dhs/concerns/proxy/create.rb +45 -0
  36. data/lib/dhs/concerns/proxy/link.rb +25 -0
  37. data/lib/dhs/concerns/proxy/problems.rb +27 -0
  38. data/lib/dhs/concerns/record/attribute_assignment.rb +25 -0
  39. data/lib/dhs/concerns/record/batch.rb +40 -0
  40. data/lib/dhs/concerns/record/chainable.rb +465 -0
  41. data/lib/dhs/concerns/record/configuration.rb +103 -0
  42. data/lib/dhs/concerns/record/create.rb +24 -0
  43. data/lib/dhs/concerns/record/custom_setters.rb +22 -0
  44. data/lib/dhs/concerns/record/destroy.rb +18 -0
  45. data/lib/dhs/concerns/record/endpoints.rb +108 -0
  46. data/lib/dhs/concerns/record/equality.rb +14 -0
  47. data/lib/dhs/concerns/record/find.rb +86 -0
  48. data/lib/dhs/concerns/record/find_by.rb +38 -0
  49. data/lib/dhs/concerns/record/first.rb +20 -0
  50. data/lib/dhs/concerns/record/href_for.rb +19 -0
  51. data/lib/dhs/concerns/record/last.rb +27 -0
  52. data/lib/dhs/concerns/record/mapping.rb +25 -0
  53. data/lib/dhs/concerns/record/merge.rb +26 -0
  54. data/lib/dhs/concerns/record/model.rb +23 -0
  55. data/lib/dhs/concerns/record/pagination.rb +49 -0
  56. data/lib/dhs/concerns/record/provider.rb +23 -0
  57. data/lib/dhs/concerns/record/relations.rb +26 -0
  58. data/lib/dhs/concerns/record/request.rb +581 -0
  59. data/lib/dhs/concerns/record/scope.rb +25 -0
  60. data/lib/dhs/concerns/record/tracing.rb +24 -0
  61. data/lib/dhs/concerns/record/update.rb +17 -0
  62. data/lib/dhs/config.rb +24 -0
  63. data/lib/dhs/data.rb +180 -0
  64. data/lib/dhs/endpoint.rb +12 -0
  65. data/lib/dhs/interceptors/auto_oauth/interceptor.rb +33 -0
  66. data/lib/dhs/interceptors/auto_oauth/thread_registry.rb +18 -0
  67. data/lib/dhs/interceptors/extended_rollbar/handler.rb +40 -0
  68. data/lib/dhs/interceptors/extended_rollbar/interceptor.rb +20 -0
  69. data/lib/dhs/interceptors/extended_rollbar/thread_registry.rb +19 -0
  70. data/lib/dhs/interceptors/request_cycle_cache/interceptor.rb +41 -0
  71. data/lib/dhs/interceptors/request_cycle_cache/thread_registry.rb +18 -0
  72. data/lib/dhs/item.rb +59 -0
  73. data/lib/dhs/pagination/base.rb +90 -0
  74. data/lib/dhs/pagination/link.rb +21 -0
  75. data/lib/dhs/pagination/offset.rb +22 -0
  76. data/lib/dhs/pagination/page.rb +18 -0
  77. data/lib/dhs/pagination/start.rb +22 -0
  78. data/lib/dhs/pagination/total_pages.rb +9 -0
  79. data/lib/dhs/problems/base.rb +113 -0
  80. data/lib/dhs/problems/errors.rb +69 -0
  81. data/lib/dhs/problems/nested/base.rb +54 -0
  82. data/lib/dhs/problems/nested/errors.rb +16 -0
  83. data/lib/dhs/problems/nested/warnings.rb +15 -0
  84. data/lib/dhs/problems/warnings.rb +24 -0
  85. data/lib/dhs/proxy.rb +69 -0
  86. data/lib/dhs/railtie.rb +34 -0
  87. data/lib/dhs/record.rb +112 -0
  88. data/lib/dhs/rspec.rb +10 -0
  89. data/lib/dhs/test/stubbable_records.rb +34 -0
  90. data/lib/dhs/unprocessable.rb +6 -0
  91. data/lib/dhs/version.rb +5 -0
  92. data/script/ci/build.sh +18 -0
  93. data/spec/auto_oauth_spec.rb +163 -0
  94. data/spec/autoloading_spec.rb +45 -0
  95. data/spec/collection/accessors_spec.rb +31 -0
  96. data/spec/collection/collection_items_spec.rb +44 -0
  97. data/spec/collection/configurable_spec.rb +43 -0
  98. data/spec/collection/delegate_spec.rb +21 -0
  99. data/spec/collection/enumerable_spec.rb +27 -0
  100. data/spec/collection/href_spec.rb +17 -0
  101. data/spec/collection/meta_data_spec.rb +58 -0
  102. data/spec/collection/respond_to_spec.rb +20 -0
  103. data/spec/collection/to_a_spec.rb +34 -0
  104. data/spec/collection/to_ary_spec.rb +40 -0
  105. data/spec/collection/without_object_items_spec.rb +27 -0
  106. data/spec/complex/reduce_spec.rb +202 -0
  107. data/spec/concerns/record/request_spec.rb +78 -0
  108. data/spec/data/collection_spec.rb +56 -0
  109. data/spec/data/equality_spec.rb +23 -0
  110. data/spec/data/inspect_spec.rb +88 -0
  111. data/spec/data/is_item_or_collection_spec.rb +40 -0
  112. data/spec/data/item_spec.rb +106 -0
  113. data/spec/data/merge_spec.rb +27 -0
  114. data/spec/data/parent_spec.rb +39 -0
  115. data/spec/data/raw_spec.rb +48 -0
  116. data/spec/data/respond_to_spec.rb +26 -0
  117. data/spec/data/root_spec.rb +25 -0
  118. data/spec/data/select_spec.rb +27 -0
  119. data/spec/data/to_ary_spec.rb +28 -0
  120. data/spec/data/to_json_spec.rb +68 -0
  121. data/spec/dummy/Rakefile +8 -0
  122. data/spec/dummy/app/assets/images/.keep +0 -0
  123. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  124. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  125. data/spec/dummy/app/controllers/application_controller.rb +26 -0
  126. data/spec/dummy/app/controllers/automatic_authentication_controller.rb +29 -0
  127. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  128. data/spec/dummy/app/controllers/error_handling_with_chains_controller.rb +36 -0
  129. data/spec/dummy/app/controllers/extended_rollbar_controller.rb +10 -0
  130. data/spec/dummy/app/controllers/option_blocks_controller.rb +15 -0
  131. data/spec/dummy/app/controllers/request_cycle_cache_controller.rb +27 -0
  132. data/spec/dummy/app/helpers/application_helper.rb +4 -0
  133. data/spec/dummy/app/mailers/.keep +0 -0
  134. data/spec/dummy/app/models/.keep +0 -0
  135. data/spec/dummy/app/models/concerns/.keep +0 -0
  136. data/spec/dummy/app/models/concerns/dummy_customer/some_concern.rb +9 -0
  137. data/spec/dummy/app/models/dummy_customer.rb +7 -0
  138. data/spec/dummy/app/models/dummy_record.rb +6 -0
  139. data/spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb +6 -0
  140. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb +7 -0
  141. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb +7 -0
  142. data/spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb +6 -0
  143. data/spec/dummy/app/models/dummy_record_with_oauth.rb +7 -0
  144. data/spec/dummy/app/models/dummy_user.rb +6 -0
  145. data/spec/dummy/app/models/providers/customer_system.rb +7 -0
  146. data/spec/dummy/app/models/providers/internal_services.rb +7 -0
  147. data/spec/dummy/app/views/error_handling_with_chains/error.html.erb +1 -0
  148. data/spec/dummy/app/views/error_handling_with_chains/show.html.erb +3 -0
  149. data/spec/dummy/app/views/form_for.html.erb +5 -0
  150. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  151. data/spec/dummy/bin/bundle +5 -0
  152. data/spec/dummy/bin/rails +6 -0
  153. data/spec/dummy/bin/rake +6 -0
  154. data/spec/dummy/config.ru +6 -0
  155. data/spec/dummy/config/application.rb +16 -0
  156. data/spec/dummy/config/boot.rb +7 -0
  157. data/spec/dummy/config/environment.rb +7 -0
  158. data/spec/dummy/config/environments/development.rb +36 -0
  159. data/spec/dummy/config/environments/production.rb +77 -0
  160. data/spec/dummy/config/environments/test.rb +40 -0
  161. data/spec/dummy/config/initializers/assets.rb +10 -0
  162. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  163. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  164. data/spec/dummy/config/initializers/dhs.rb +5 -0
  165. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  166. data/spec/dummy/config/initializers/inflections.rb +18 -0
  167. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  168. data/spec/dummy/config/initializers/rollbar.rb +9 -0
  169. data/spec/dummy/config/initializers/session_store.rb +5 -0
  170. data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
  171. data/spec/dummy/config/locales/en.yml +23 -0
  172. data/spec/dummy/config/routes.rb +27 -0
  173. data/spec/dummy/config/secrets.yml +22 -0
  174. data/spec/dummy/lib/assets/.keep +0 -0
  175. data/spec/dummy/public/404.html +67 -0
  176. data/spec/dummy/public/422.html +67 -0
  177. data/spec/dummy/public/500.html +66 -0
  178. data/spec/dummy/public/favicon.ico +0 -0
  179. data/spec/endpoint/for_url_spec.rb +27 -0
  180. data/spec/extended_rollbar_spec.rb +67 -0
  181. data/spec/item/access_errors_spec.rb +31 -0
  182. data/spec/item/accessors_spec.rb +21 -0
  183. data/spec/item/add_error_spec.rb +21 -0
  184. data/spec/item/becomes_spec.rb +38 -0
  185. data/spec/item/blacklisted_keywords_spec.rb +28 -0
  186. data/spec/item/delegate_spec.rb +32 -0
  187. data/spec/item/destroy_spec.rb +113 -0
  188. data/spec/item/dig_spec.rb +29 -0
  189. data/spec/item/error_codes_spec.rb +55 -0
  190. data/spec/item/errors_spec.rb +324 -0
  191. data/spec/item/fetch_spec.rb +39 -0
  192. data/spec/item/getter_spec.rb +24 -0
  193. data/spec/item/internal_data_structure_spec.rb +37 -0
  194. data/spec/item/map_spec.rb +46 -0
  195. data/spec/item/nested_errors_spec.rb +27 -0
  196. data/spec/item/partial_update_spec.rb +168 -0
  197. data/spec/item/respond_to_spec.rb +31 -0
  198. data/spec/item/save_spec.rb +115 -0
  199. data/spec/item/setter_spec.rb +44 -0
  200. data/spec/item/translate_errors_spec.rb +257 -0
  201. data/spec/item/update_spec.rb +161 -0
  202. data/spec/item/validation_spec.rb +131 -0
  203. data/spec/item/warning_codes_spec.rb +55 -0
  204. data/spec/item/warnings_spec.rb +51 -0
  205. data/spec/option_blocks/ensure_reset_between_requests_spec.rb +23 -0
  206. data/spec/option_blocks/main_spec.rb +54 -0
  207. data/spec/pagination/link/current_page_spec.rb +19 -0
  208. data/spec/pagination/link/pages_left_spec.rb +36 -0
  209. data/spec/pagination/link/parallel_spec.rb +19 -0
  210. data/spec/pagination/link/total_spec.rb +45 -0
  211. data/spec/pagination/offset/pages_left_spec.rb +26 -0
  212. data/spec/pagination/parameters_spec.rb +59 -0
  213. data/spec/pagination/total_pages_spec.rb +51 -0
  214. data/spec/proxy/create_sub_resource_spec.rb +182 -0
  215. data/spec/proxy/load_spec.rb +75 -0
  216. data/spec/proxy/record_identification_spec.rb +35 -0
  217. data/spec/rails_helper.rb +13 -0
  218. data/spec/record/all_spec.rb +133 -0
  219. data/spec/record/attribute_assignment_spec.rb +28 -0
  220. data/spec/record/build_spec.rb +26 -0
  221. data/spec/record/cast_nested_data_spec.rb +80 -0
  222. data/spec/record/compact_spec.rb +93 -0
  223. data/spec/record/create_spec.rb +160 -0
  224. data/spec/record/creation_failed_spec.rb +55 -0
  225. data/spec/record/custom_setters_spec.rb +42 -0
  226. data/spec/record/definitions_spec.rb +29 -0
  227. data/spec/record/destroy_spec.rb +38 -0
  228. data/spec/record/dig_configuration_spec.rb +75 -0
  229. data/spec/record/dup_spec.rb +20 -0
  230. data/spec/record/endpoint_inheritance_spec.rb +65 -0
  231. data/spec/record/endpoint_options_spec.rb +51 -0
  232. data/spec/record/endpoint_priorities_spec.rb +24 -0
  233. data/spec/record/endpoints_spec.rb +96 -0
  234. data/spec/record/equality_spec.rb +27 -0
  235. data/spec/record/error_handling_integration_spec.rb +25 -0
  236. data/spec/record/error_handling_spec.rb +40 -0
  237. data/spec/record/expanded_spec.rb +69 -0
  238. data/spec/record/fetch_spec.rb +40 -0
  239. data/spec/record/find_by_chains_spec.rb +21 -0
  240. data/spec/record/find_by_spec.rb +76 -0
  241. data/spec/record/find_each_spec.rb +57 -0
  242. data/spec/record/find_in_batches_spec.rb +122 -0
  243. data/spec/record/find_in_parallel_spec.rb +67 -0
  244. data/spec/record/find_spec.rb +103 -0
  245. data/spec/record/first_spec.rb +39 -0
  246. data/spec/record/force_merge_spec.rb +55 -0
  247. data/spec/record/handle_includes_errors_spec.rb +33 -0
  248. data/spec/record/has_many_spec.rb +118 -0
  249. data/spec/record/has_one_spec.rb +114 -0
  250. data/spec/record/href_for_spec.rb +24 -0
  251. data/spec/record/ignore_errors_spec.rb +137 -0
  252. data/spec/record/immutable_chains_spec.rb +22 -0
  253. data/spec/record/includes_after_expansion_spec.rb +70 -0
  254. data/spec/record/includes_expanded_spec.rb +37 -0
  255. data/spec/record/includes_first_page_spec.rb +738 -0
  256. data/spec/record/includes_missing_spec.rb +57 -0
  257. data/spec/record/includes_spec.rb +690 -0
  258. data/spec/record/includes_warning_spec.rb +46 -0
  259. data/spec/record/item_key_spec.rb +81 -0
  260. data/spec/record/items_created_key_configuration_spec.rb +37 -0
  261. data/spec/record/last_spec.rb +64 -0
  262. data/spec/record/loading_twice_spec.rb +19 -0
  263. data/spec/record/mapping_spec.rb +103 -0
  264. data/spec/record/model_name_spec.rb +17 -0
  265. data/spec/record/new_spec.rb +106 -0
  266. data/spec/record/options_getter_spec.rb +25 -0
  267. data/spec/record/options_spec.rb +164 -0
  268. data/spec/record/paginatable_collection_spec.rb +360 -0
  269. data/spec/record/pagination_chain_spec.rb +101 -0
  270. data/spec/record/pagination_links_spec.rb +72 -0
  271. data/spec/record/pagination_spec.rb +71 -0
  272. data/spec/record/persisted_spec.rb +52 -0
  273. data/spec/record/provider_spec.rb +40 -0
  274. data/spec/record/references_spec.rb +95 -0
  275. data/spec/record/relation_caching_spec.rb +120 -0
  276. data/spec/record/reload_by_id_spec.rb +43 -0
  277. data/spec/record/reload_spec.rb +64 -0
  278. data/spec/record/request_spec.rb +90 -0
  279. data/spec/record/save_spec.rb +40 -0
  280. data/spec/record/scope_chains_spec.rb +39 -0
  281. data/spec/record/select_spec.rb +17 -0
  282. data/spec/record/to_ary_spec.rb +65 -0
  283. data/spec/record/to_hash_spec.rb +22 -0
  284. data/spec/record/to_json_spec.rb +22 -0
  285. data/spec/record/tracing_spec.rb +149 -0
  286. data/spec/record/update_spec.rb +61 -0
  287. data/spec/record/where_chains_spec.rb +57 -0
  288. data/spec/record/where_spec.rb +62 -0
  289. data/spec/record/where_values_hash_spec.rb +32 -0
  290. data/spec/request_cycle_cache_spec.rb +106 -0
  291. data/spec/require_dhs_spec.rb +9 -0
  292. data/spec/spec_helper.rb +6 -0
  293. data/spec/stubs/all_spec.rb +69 -0
  294. data/spec/support/fixtures/json/feedback.json +11 -0
  295. data/spec/support/fixtures/json/feedbacks.json +174 -0
  296. data/spec/support/fixtures/json/localina_content_ad.json +23 -0
  297. data/spec/support/load_json.rb +5 -0
  298. data/spec/support/request_cycle_cache.rb +10 -0
  299. data/spec/support/reset.rb +67 -0
  300. data/spec/views/form_for_spec.rb +20 -0
  301. metadata +783 -0
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Item do
6
+ before do
7
+ class Record < DHS::Record
8
+ endpoint '{+datastore}/v2/{campaign_id}/feedbacks'
9
+ endpoint '{+datastore}/v2/feedbacks'
10
+ end
11
+ end
12
+
13
+ let(:json) do
14
+ load_json(:feedbacks)
15
+ end
16
+
17
+ let(:data) do
18
+ DHS::Data.new(json, nil, Record)
19
+ end
20
+
21
+ let(:item) do
22
+ data[0]
23
+ end
24
+
25
+ context 'item setter' do
26
+ it 'sets the value for an existing attribute' do
27
+ expect((item.name = 'Steve')).to eq 'Steve'
28
+ expect(item.name).to eq 'Steve'
29
+ expect(item._raw[:name]).to eq 'Steve'
30
+ end
31
+
32
+ it 'sets things to nil' do
33
+ item.name = 'Steve'
34
+ expect((item.name = nil)).to eq nil
35
+ expect(item.name).to eq nil
36
+ end
37
+
38
+ it 'sets things to false' do
39
+ item.recommended = true
40
+ expect((item.recommended = false)).to eq false
41
+ expect(item.recommended).to eq false
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,257 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Item do
6
+ before do
7
+ class Record < DHS::Record
8
+ endpoint 'http://dataste/records'
9
+ end
10
+
11
+ stub_request(:post, 'http://dataste/records')
12
+ .to_return(
13
+ status: 400,
14
+ body: {
15
+ field_errors: [{
16
+ 'code' => 'UNSUPPORTED_PROPERTY_VALUE',
17
+ 'path' => ['name']
18
+ }]
19
+ }.to_json
20
+ )
21
+
22
+ I18n.reload!
23
+ I18n.backend.store_translations(:en, YAML.safe_load(translation)) if translation.present?
24
+ end
25
+
26
+ let(:errors) { Record.create(name: 'Steve').errors }
27
+
28
+ context 'detailed error translation for record and attribute' do
29
+ let(:translation) do
30
+ %q{
31
+ dhs:
32
+ errors:
33
+ records:
34
+ record:
35
+ attributes:
36
+ name:
37
+ unsupported_property_value: 'This value is not supported'
38
+ }
39
+ end
40
+
41
+ it 'translates errors automatically when they are around' do
42
+ expect(errors[:name]).to eq ['This value is not supported']
43
+ end
44
+ end
45
+
46
+ context 'error translation for record' do
47
+ let(:translation) do
48
+ %q{
49
+ dhs:
50
+ errors:
51
+ records:
52
+ record:
53
+ unsupported_property_value: 'This value is unfortunately not supported'
54
+ }
55
+ end
56
+
57
+ it 'translates errors automatically when they are around' do
58
+ expect(errors[:name]).to eq ['This value is unfortunately not supported']
59
+ end
60
+ end
61
+
62
+ context 'error translation for message' do
63
+ let(:translation) do
64
+ %q{
65
+ dhs:
66
+ errors:
67
+ messages:
68
+ unsupported_property_value: 'This value is sadly not supported'
69
+ }
70
+ end
71
+
72
+ it 'translates errors automatically when they are around' do
73
+ expect(errors[:name]).to eq ['This value is sadly not supported']
74
+ end
75
+ end
76
+
77
+ context 'error translation for attributes' do
78
+ let(:translation) do
79
+ %q{
80
+ dhs:
81
+ errors:
82
+ attributes:
83
+ name:
84
+ unsupported_property_value: 'This value is not supported – bummer'
85
+ }
86
+ end
87
+
88
+ it 'translates errors automatically when they are around' do
89
+ expect(errors[:name]).to eq ['This value is not supported – bummer']
90
+ end
91
+ end
92
+
93
+ context 'error translation for fallback message' do
94
+ let(:translation) do
95
+ %q{
96
+ dhs:
97
+ errors:
98
+ fallback_message: 'This value is wrong'
99
+ }
100
+ end
101
+
102
+ it 'translates errors automatically when they are around' do
103
+ expect(errors[:name]).to eq ['This value is wrong']
104
+ end
105
+ end
106
+
107
+ context 'detailed record attribute over other translations' do
108
+ let(:translation) do
109
+ %q{
110
+ dhs:
111
+ errors:
112
+ fallback_message: 'This value is wrong'
113
+ attributes:
114
+ name:
115
+ unsupported_property_value: 'This value is not supported – bummer'
116
+ messages:
117
+ unsupported_property_value: 'This value is sadly not supported'
118
+ records:
119
+ record:
120
+ unsupported_property_value: 'This value is unfortunately not supported'
121
+ attributes:
122
+ name:
123
+ unsupported_property_value: 'This value is not supported'
124
+ }
125
+ end
126
+
127
+ it 'takes detailed record attribute over other translations' do
128
+ expect(errors[:name]).to eq ['This value is not supported']
129
+ end
130
+ end
131
+
132
+ context 'record translations over global messages, attributes and fallback' do
133
+ let(:translation) do
134
+ %q{
135
+ dhs:
136
+ errors:
137
+ fallback_message: 'This value is wrong'
138
+ attributes:
139
+ name:
140
+ unsupported_property_value: 'This value is not supported – bummer'
141
+ messages:
142
+ unsupported_property_value: 'This value is sadly not supported'
143
+ records:
144
+ record:
145
+ unsupported_property_value: 'This value is unfortunately not supported'
146
+ }
147
+ end
148
+
149
+ it 'takes detailed record attribute over other translations' do
150
+ expect(errors[:name]).to eq ['This value is unfortunately not supported']
151
+ end
152
+ end
153
+
154
+ context 'global message translation over attributes and fallback' do
155
+ let(:translation) do
156
+ %q{
157
+ dhs:
158
+ errors:
159
+ fallback_message: 'This value is wrong'
160
+ attributes:
161
+ name:
162
+ unsupported_property_value: 'This value is not supported – bummer'
163
+ messages:
164
+ unsupported_property_value: 'This value is sadly not supported'
165
+ }
166
+ end
167
+
168
+ it 'takes detailed record attribute over other translations' do
169
+ expect(errors[:name]).to eq ['This value is sadly not supported']
170
+ end
171
+ end
172
+
173
+ context 'global attributes over fallback' do
174
+ let(:translation) do
175
+ %q{
176
+ dhs:
177
+ errors:
178
+ fallback_message: 'This value is wrong'
179
+ attributes:
180
+ name:
181
+ unsupported_property_value: 'This value is not supported – bummer'
182
+ }
183
+ end
184
+
185
+ it 'takes detailed record attribute over other translations' do
186
+ expect(errors[:name]).to eq ['This value is not supported – bummer']
187
+ end
188
+ end
189
+
190
+ context 'no translation' do
191
+ let(:translation) do
192
+ %q{}
193
+ end
194
+
195
+ it 'takes no translation but keeps on storing the error message/code' do
196
+ expect(errors[:name]).to eq ['UNSUPPORTED_PROPERTY_VALUE']
197
+ end
198
+ end
199
+
200
+ context 'error translation for nested record' do
201
+ before do
202
+ class AppointmentProposal < DHS::Record
203
+ endpoint 'http://dataste/appointment_proposals'
204
+ endpoint 'http://dataste/appointment_proposals/{id}'
205
+
206
+ has_many :appointments
207
+ end
208
+
209
+ class Appointment < DHS::Record
210
+ end
211
+
212
+ stub_request(:get, 'http://dataste/appointment_proposals/1')
213
+ .to_return(body: {
214
+ appointments: [
215
+ { 'date_time' => '13.12.2018' },
216
+ { 'date_time' => '18.10.2028' }
217
+ ]
218
+ }.to_json)
219
+
220
+ stub_request(:post, 'http://dataste/appointment_proposals')
221
+ .to_return(
222
+ status: 400,
223
+ body: {
224
+ field_errors: [{
225
+ 'code' => 'DATE_PROPERTY_NOT_IN_FUTURE',
226
+ 'path' => ['appointments', 0, 'date_time']
227
+ }]
228
+ }.to_json
229
+ )
230
+ end
231
+
232
+ let(:translation) do
233
+ %q{
234
+ dhs:
235
+ errors:
236
+ records:
237
+ appointment_proposal:
238
+ attributes:
239
+ appointments:
240
+ date_time:
241
+ date_property_not_in_future: 'You cannot select a date in the past.'
242
+ }
243
+ end
244
+
245
+ it 'translates errors automatically when they are around' do
246
+ appointment_proposal = AppointmentProposal.find(1)
247
+ appointment_proposal.update(
248
+ 'appointments_attributes' => {
249
+ '0' => { 'date_time' => '13.12.2018' },
250
+ '1' => { 'date_time' => '18.10.2028' }
251
+ }
252
+ )
253
+ expect(appointment_proposal.appointments[0].errors[:date_time]).to eql(['You cannot select a date in the past.'])
254
+ expect(appointment_proposal.appointments[1].errors[:date_time]).to eql([])
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Item do
6
+ before do
7
+ class Record < DHS::Record
8
+ endpoint '{+datastore}/v2/{campaign_id}/feedbacks'
9
+ endpoint '{+datastore}/v2/feedbacks'
10
+ end
11
+ end
12
+
13
+ let(:json) do
14
+ load_json(:feedbacks)
15
+ end
16
+
17
+ let(:data) do
18
+ DHS::Data.new(json, nil, Record)
19
+ end
20
+
21
+ let(:item) do
22
+ data[0]
23
+ end
24
+
25
+ context 'update' do
26
+ it 'persists changes on the backend' do
27
+ stub_request(:post, item.href)
28
+ .with(body: item._raw.merge(name: 'Steve').to_json)
29
+ result = item.update(name: 'Steve')
30
+ expect(result).to eq true
31
+ end
32
+
33
+ it 'returns false if persisting went wrong' do
34
+ stub_request(:post, item.href).to_return(status: 500)
35
+ result = item.update(name: 'Steve')
36
+ expect(result).to eq false
37
+ end
38
+
39
+ it 'merges reponse data with object' do
40
+ stub_request(:post, item.href)
41
+ .to_return(status: 200, body: item._raw.merge(likes: 'Banana').to_json)
42
+ item.update(name: 'Steve')
43
+ expect(item.likes).to eq 'Banana'
44
+ end
45
+
46
+ it 'updates local version of an object even if BE request fails' do
47
+ stub_request(:post, item.href)
48
+ .to_return(status: 400, body: item._raw.merge(likes: 'Banana').to_json)
49
+ item.update(name: 'Andrea')
50
+ expect(item.name).to eq 'Andrea'
51
+ expect(item.likes).not_to eq 'Banana'
52
+ end
53
+
54
+ context 'with custom setters' do
55
+ before do
56
+ class Booking < DHS::Record
57
+ endpoint 'http://bookings/bookings'
58
+
59
+ def appointments=(appointments)
60
+ super(
61
+ appointments.map { |appointment| appointment[:id] }
62
+ )
63
+ end
64
+ end
65
+ end
66
+
67
+ let(:item) do
68
+ Booking.new(id: 'abc')
69
+ end
70
+
71
+ it 'updates data using custom setters before send to backend' do
72
+ stub_request(:post, 'http://bookings/bookings')
73
+ .with(body: {
74
+ id: 'abc',
75
+ appointments: [1, 2, 3]
76
+ }.to_json)
77
+ .to_return(status: 200)
78
+ item.update(appointments: [{ id: 1 }, { id: 2 }, { id: 3 }])
79
+ expect(item.appointments.to_a).to eq([1, 2, 3])
80
+ end
81
+
82
+ context 'with nested items' do
83
+ before do
84
+ class Booking < DHS::Record
85
+ endpoint 'http://bookings/bookings'
86
+ has_one :appointment_proposal
87
+ end
88
+
89
+ class AppointmentProposal < DHS::Record
90
+ endpoint 'http://bookings/bookings'
91
+ has_many :appointments
92
+
93
+ def appointments_attributes=(attributes)
94
+ self.appointments = attributes.map { |attribute| Appointment.new('date_time': attribute[:date]) }
95
+ end
96
+ end
97
+
98
+ class Appointment < DHS::Record
99
+ end
100
+ end
101
+
102
+ let(:item) do
103
+ Booking.new(id: 'abc', appointment_proposal: { appointments: [] })
104
+ end
105
+
106
+ it 'updates data using custom setters before send to backend' do
107
+ stub_request(:post, 'http://bookings/bookings')
108
+ .with(body: {
109
+ appointments: [{ date_time: '2018-01-18' }]
110
+ }.to_json)
111
+ .to_return(status: 200)
112
+ item.appointment_proposal.update(appointments_attributes: [{ date: '2018-01-18' }])
113
+ expect(item.appointment_proposal.appointments.as_json).to eq([{ 'date_time' => '2018-01-18' }])
114
+ end
115
+ end
116
+ end
117
+
118
+ context 'with many placeholders' do
119
+ before do
120
+ class GrandChild < DHS::Record
121
+ endpoint 'http://host/v2/parents/{parent_id}/children/{child_id}/grand_children'
122
+ endpoint 'http://host/v2/parents/{parent_id}/children/{child_id}/grand_children/{id}'
123
+ end
124
+ end
125
+
126
+ let(:data) do
127
+ {
128
+ id: 'aaa',
129
+ parent_id: 'bbb',
130
+ child_id: 'ccc',
131
+ name: 'Lorem'
132
+ }
133
+ end
134
+
135
+ let(:item) do
136
+ GrandChild.new(data)
137
+ end
138
+
139
+ it 'persists changes on the backend' do
140
+ stub_request(:get, 'http://host/v2/parents/bbb/children/ccc/grand_children/aaa')
141
+ .to_return(status: 200, body: data.to_json)
142
+ stub_request(:post, 'http://host/v2/parents/bbb/children/ccc/grand_children/aaa')
143
+ .with(body: { name: 'Steve' }.to_json)
144
+
145
+ grand_child = GrandChild.find(parent_id: 'bbb', child_id: 'ccc', id: 'aaa')
146
+ expect(grand_child.name).to eq('Lorem')
147
+ result = grand_child.update(name: 'Steve')
148
+ expect(result).to eq true
149
+ end
150
+ end
151
+ end
152
+
153
+ context 'update!' do
154
+ it 'raises if something goes wrong' do
155
+ stub_request(:post, item.href)
156
+ .with(body: item._raw.merge(name: 'Steve').to_json)
157
+ .to_return(status: 500)
158
+ expect(-> { item.update!(name: 'Steve') }).to raise_error DHC::ServerError
159
+ end
160
+ end
161
+ end