solidus_graphql_api 0.1.0 → 0.3.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 (282) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +43 -67
  3. data/.github/dependabot.yml +23 -0
  4. data/.github/stale.yml +3 -3
  5. data/.github_changelog_generator +2 -0
  6. data/.rubocop.yml +10 -4
  7. data/CHANGELOG.md +4 -0
  8. data/CONTRIBUTING.md +5 -5
  9. data/Gemfile +1 -1
  10. data/Gemfile-local +1 -0
  11. data/LICENSE +1 -1
  12. data/OLD_CHANGELOG.md +170 -0
  13. data/README.md +26 -10
  14. data/Rakefile +22 -7
  15. data/app/assets/javascripts/spree/backend/solidus_graphql_api.js +2 -0
  16. data/app/assets/javascripts/spree/frontend/solidus_graphql_api.js +2 -0
  17. data/app/assets/stylesheets/spree/backend/solidus_graphql_api.css +4 -0
  18. data/app/assets/stylesheets/spree/frontend/solidus_graphql_api.css +4 -0
  19. data/app/controllers/spree/graphql_controller.rb +2 -0
  20. data/bin/console +2 -2
  21. data/bin/rails +0 -2
  22. data/bin/rails-engine +0 -3
  23. data/bin/rails-sandbox +1 -3
  24. data/bin/rake +0 -1
  25. data/bin/sandbox +5 -7
  26. data/docs/assets/images/graphiql-headers.png +0 -0
  27. data/docs/assets/images/graphiql-variables.png +0 -0
  28. data/docs/assets/images/graphiql.png +0 -0
  29. data/docs/assets/images/menu.png +0 -0
  30. data/docs/assets/images/navbar.png +0 -0
  31. data/docs/assets/style.css +1115 -0
  32. data/docs/assets/webfonts/2C4B9D_B_0.eot +0 -0
  33. data/docs/assets/webfonts/2C4B9D_B_0.ttf +0 -0
  34. data/docs/assets/webfonts/2C4B9D_B_0.woff +0 -0
  35. data/docs/assets/webfonts/2C4B9D_B_0.woff2 +0 -0
  36. data/docs/assets/webfonts/2C4B9D_C_0.eot +0 -0
  37. data/docs/assets/webfonts/2C4B9D_C_0.ttf +0 -0
  38. data/docs/assets/webfonts/2C4B9D_C_0.woff +0 -0
  39. data/docs/assets/webfonts/2C4B9D_C_0.woff2 +0 -0
  40. data/docs/assets/webfonts/2C4B9D_D_0.eot +0 -0
  41. data/docs/assets/webfonts/2C4B9D_D_0.ttf +0 -0
  42. data/docs/assets/webfonts/2C4B9D_D_0.woff +0 -0
  43. data/docs/assets/webfonts/2C4B9D_D_0.woff2 +0 -0
  44. data/docs/assets/webfonts/2C4B9D_E_0.eot +0 -0
  45. data/docs/assets/webfonts/2C4B9D_E_0.ttf +0 -0
  46. data/docs/assets/webfonts/2C4B9D_E_0.woff +0 -0
  47. data/docs/assets/webfonts/2C4B9D_E_0.woff2 +0 -0
  48. data/docs/directive/deprecated/index.html +1142 -0
  49. data/docs/directive/include/index.html +1141 -0
  50. data/docs/directive/index.html +1113 -0
  51. data/docs/directive/skip/index.html +1141 -0
  52. data/docs/enum/__directivelocation/index.html +1204 -0
  53. data/docs/enum/__typekind/index.html +1154 -0
  54. data/docs/enum/addresstypeinput/index.html +1121 -0
  55. data/docs/enum/index.html +1113 -0
  56. data/docs/index.html +1122 -0
  57. data/docs/input_object/addaddressestocheckoutinput/index.html +1135 -0
  58. data/docs/input_object/addpaymenttocheckoutinput/index.html +1135 -0
  59. data/docs/input_object/addressinput/index.html +1169 -0
  60. data/docs/input_object/addtocartinput/index.html +1130 -0
  61. data/docs/input_object/advancecheckoutinput/index.html +1120 -0
  62. data/docs/input_object/applycouponcodeinput/index.html +1125 -0
  63. data/docs/input_object/completecheckoutinput/index.html +1120 -0
  64. data/docs/input_object/createorderinput/index.html +1120 -0
  65. data/docs/input_object/emptycartinput/index.html +1120 -0
  66. data/docs/input_object/index.html +1113 -0
  67. data/docs/input_object/markdefaultshipaddressinput/index.html +1125 -0
  68. data/docs/input_object/nextcheckoutstateinput/index.html +1120 -0
  69. data/docs/input_object/productsqueryinput/index.html +1132 -0
  70. data/docs/input_object/removefromaddressbookinput/index.html +1125 -0
  71. data/docs/input_object/removefromcartinput/index.html +1125 -0
  72. data/docs/input_object/saveinaddressbookinput/index.html +1135 -0
  73. data/docs/input_object/selectshippingrateinput/index.html +1125 -0
  74. data/docs/input_object/setorderemailinput/index.html +1125 -0
  75. data/docs/input_object/updatecartquantityinput/index.html +1130 -0
  76. data/docs/interface/adjustment/index.html +1145 -0
  77. data/docs/interface/index.html +1113 -0
  78. data/docs/interface/node/index.html +1151 -0
  79. data/docs/interface/paymentsource/index.html +1134 -0
  80. data/docs/mutation/addaddressestocheckout/index.html +1137 -0
  81. data/docs/mutation/addpaymenttocheckout/index.html +1137 -0
  82. data/docs/mutation/addtocart/index.html +1137 -0
  83. data/docs/mutation/advancecheckout/index.html +1137 -0
  84. data/docs/mutation/applycouponcode/index.html +1137 -0
  85. data/docs/mutation/completecheckout/index.html +1137 -0
  86. data/docs/mutation/createorder/index.html +1137 -0
  87. data/docs/mutation/emptycart/index.html +1137 -0
  88. data/docs/mutation/markdefaultshipaddress/index.html +1132 -0
  89. data/docs/mutation/nextcheckoutstate/index.html +1137 -0
  90. data/docs/mutation/removefromaddressbook/index.html +1132 -0
  91. data/docs/mutation/removefromcart/index.html +1137 -0
  92. data/docs/mutation/saveinaddressbook/index.html +1137 -0
  93. data/docs/mutation/selectshippingrate/index.html +1137 -0
  94. data/docs/mutation/setorderemail/index.html +1137 -0
  95. data/docs/mutation/updatecartquantity/index.html +1137 -0
  96. data/docs/object/__directive/index.html +1182 -0
  97. data/docs/object/__enumvalue/index.html +1134 -0
  98. data/docs/object/__field/index.html +1164 -0
  99. data/docs/object/__inputvalue/index.html +1145 -0
  100. data/docs/object/__schema/index.html +1144 -0
  101. data/docs/object/__type/index.html +1220 -0
  102. data/docs/object/addaddressestocheckoutpayload/index.html +1130 -0
  103. data/docs/object/addpaymenttocheckoutpayload/index.html +1130 -0
  104. data/docs/object/address/index.html +1189 -0
  105. data/docs/object/addressconnection/index.html +1132 -0
  106. data/docs/object/addressedge/index.html +1126 -0
  107. data/docs/object/addtocartpayload/index.html +1130 -0
  108. data/docs/object/adjustmentconnection/index.html +1132 -0
  109. data/docs/object/adjustmentedge/index.html +1126 -0
  110. data/docs/object/advancecheckoutpayload/index.html +1130 -0
  111. data/docs/object/applycouponcodepayload/index.html +1130 -0
  112. data/docs/object/completecheckoutpayload/index.html +1130 -0
  113. data/docs/object/country/index.html +1218 -0
  114. data/docs/object/countryconnection/index.html +1132 -0
  115. data/docs/object/countryedge/index.html +1126 -0
  116. data/docs/object/createorderpayload/index.html +1130 -0
  117. data/docs/object/creditcard/index.html +1170 -0
  118. data/docs/object/currency/index.html +1144 -0
  119. data/docs/object/currencyconnection/index.html +1132 -0
  120. data/docs/object/currencyedge/index.html +1126 -0
  121. data/docs/object/emptycartpayload/index.html +1130 -0
  122. data/docs/object/image/index.html +1169 -0
  123. data/docs/object/imageconnection/index.html +1132 -0
  124. data/docs/object/imageedge/index.html +1126 -0
  125. data/docs/object/index.html +1113 -0
  126. data/docs/object/lineitem/index.html +1184 -0
  127. data/docs/object/lineitemconnection/index.html +1132 -0
  128. data/docs/object/lineitemedge/index.html +1126 -0
  129. data/docs/object/manifestitem/index.html +1124 -0
  130. data/docs/object/markdefaultshipaddresspayload/index.html +1125 -0
  131. data/docs/object/nextcheckoutstatepayload/index.html +1130 -0
  132. data/docs/object/optiontype/index.html +1203 -0
  133. data/docs/object/optiontypeconnection/index.html +1132 -0
  134. data/docs/object/optiontypeedge/index.html +1126 -0
  135. data/docs/object/optionvalue/index.html +1154 -0
  136. data/docs/object/optionvalueconnection/index.html +1132 -0
  137. data/docs/object/optionvalueedge/index.html +1126 -0
  138. data/docs/object/order/index.html +1412 -0
  139. data/docs/object/orderconnection/index.html +1132 -0
  140. data/docs/object/orderedge/index.html +1126 -0
  141. data/docs/object/pageinfo/index.html +1138 -0
  142. data/docs/object/payment/index.html +1149 -0
  143. data/docs/object/paymentmethod/index.html +1149 -0
  144. data/docs/object/price/index.html +1159 -0
  145. data/docs/object/priceconnection/index.html +1132 -0
  146. data/docs/object/priceedge/index.html +1126 -0
  147. data/docs/object/product/index.html +1327 -0
  148. data/docs/object/productconnection/index.html +1132 -0
  149. data/docs/object/productedge/index.html +1126 -0
  150. data/docs/object/productproperty/index.html +1149 -0
  151. data/docs/object/productpropertyconnection/index.html +1132 -0
  152. data/docs/object/productpropertyedge/index.html +1126 -0
  153. data/docs/object/promotionadjustment/index.html +1155 -0
  154. data/docs/object/property/index.html +1144 -0
  155. data/docs/object/removefromaddressbookpayload/index.html +1125 -0
  156. data/docs/object/removefromcartpayload/index.html +1130 -0
  157. data/docs/object/saveinaddressbookpayload/index.html +1130 -0
  158. data/docs/object/selectshippingratepayload/index.html +1130 -0
  159. data/docs/object/setorderemailpayload/index.html +1130 -0
  160. data/docs/object/shipment/index.html +1218 -0
  161. data/docs/object/shipmentconnection/index.html +1132 -0
  162. data/docs/object/shipmentedge/index.html +1126 -0
  163. data/docs/object/shippingmethod/index.html +1174 -0
  164. data/docs/object/shippingrate/index.html +1154 -0
  165. data/docs/object/shippingrateconnection/index.html +1132 -0
  166. data/docs/object/shippingrateedge/index.html +1126 -0
  167. data/docs/object/state/index.html +1144 -0
  168. data/docs/object/stateconnection/index.html +1132 -0
  169. data/docs/object/stateedge/index.html +1126 -0
  170. data/docs/object/store/index.html +1238 -0
  171. data/docs/object/taxadjustment/index.html +1150 -0
  172. data/docs/object/taxon/index.html +1228 -0
  173. data/docs/object/taxonconnection/index.html +1132 -0
  174. data/docs/object/taxonedge/index.html +1126 -0
  175. data/docs/object/taxonomy/index.html +1198 -0
  176. data/docs/object/taxonomyconnection/index.html +1132 -0
  177. data/docs/object/taxonomyedge/index.html +1126 -0
  178. data/docs/object/updatecartquantitypayload/index.html +1130 -0
  179. data/docs/object/user/index.html +1280 -0
  180. data/docs/object/usererror/index.html +1126 -0
  181. data/docs/object/variant/index.html +1332 -0
  182. data/docs/object/variantconnection/index.html +1132 -0
  183. data/docs/object/variantedge/index.html +1126 -0
  184. data/docs/object/walletpaymentsource/index.html +1144 -0
  185. data/docs/object/walletpaymentsourceconnection/index.html +1132 -0
  186. data/docs/object/walletpaymentsourceedge/index.html +1126 -0
  187. data/docs/operation/mutation/index.html +1114 -0
  188. data/docs/operation/query/index.html +1431 -0
  189. data/docs/scalar/boolean/index.html +1112 -0
  190. data/docs/scalar/float/index.html +1112 -0
  191. data/docs/scalar/id/index.html +1112 -0
  192. data/docs/scalar/index.html +1113 -0
  193. data/docs/scalar/int/index.html +1112 -0
  194. data/docs/scalar/iso8601datetime/index.html +1112 -0
  195. data/docs/scalar/json/index.html +1112 -0
  196. data/docs/scalar/string/index.html +1112 -0
  197. data/docs/union/index.html +1113 -0
  198. data/lib/generators/solidus_graphql_api/install/install_generator.rb +19 -0
  199. data/lib/generators/solidus_graphql_api/install/templates/initializer.rb +6 -0
  200. data/lib/graphql_docs/landing_pages/index.md +16 -0
  201. data/lib/solidus_graphql_api/batch_loader/has_many_through.rb +1 -0
  202. data/lib/solidus_graphql_api/batch_loader.rb +1 -1
  203. data/lib/solidus_graphql_api/configuration.rb +12 -8
  204. data/lib/solidus_graphql_api/context.rb +8 -2
  205. data/lib/solidus_graphql_api/engine.rb +2 -2
  206. data/lib/solidus_graphql_api/mutations/base_mutation.rb +3 -3
  207. data/lib/solidus_graphql_api/mutations/checkout/add_payment_to_checkout.rb +1 -1
  208. data/lib/solidus_graphql_api/mutations/user/{mark_default_address.rb → mark_default_ship_address.rb} +2 -2
  209. data/lib/solidus_graphql_api/mutations/user/save_in_address_book.rb +8 -2
  210. data/lib/solidus_graphql_api/queries/option_value/option_type_query.rb +19 -0
  211. data/lib/solidus_graphql_api/queries/shipping_rate/shipping_method_query.rb +19 -0
  212. data/lib/solidus_graphql_api/queries/taxon/children_query.rb +1 -1
  213. data/lib/solidus_graphql_api/queries/taxonomy/taxons_query.rb +1 -1
  214. data/lib/solidus_graphql_api/queries/variant/default_price_query.rb +1 -1
  215. data/lib/solidus_graphql_api/{factories → testing_support/factories}/address_factory.rb +1 -2
  216. data/lib/solidus_graphql_api/{factories → testing_support/factories}/taxonomy_factory.rb +10 -0
  217. data/lib/solidus_graphql_api/testing_support/factories.rb +9 -0
  218. data/lib/solidus_graphql_api/types/address.rb +1 -2
  219. data/lib/solidus_graphql_api/types/base/relay_node.rb +1 -1
  220. data/lib/solidus_graphql_api/types/input_objects/address_input.rb +1 -2
  221. data/lib/solidus_graphql_api/types/json.rb +6 -3
  222. data/lib/solidus_graphql_api/types/mutation.rb +1 -1
  223. data/lib/solidus_graphql_api/types/option_value.rb +5 -0
  224. data/lib/solidus_graphql_api/types/query.rb +2 -2
  225. data/lib/solidus_graphql_api/types/shipping_method.rb +20 -0
  226. data/lib/solidus_graphql_api/types/shipping_rate.rb +5 -0
  227. data/lib/solidus_graphql_api/types/user.rb +1 -1
  228. data/lib/solidus_graphql_api/version.rb +1 -1
  229. data/lib/solidus_graphql_api.rb +0 -3
  230. data/schema.graphql +128 -26
  231. data/solidus_graphql_api.gemspec +12 -12
  232. data/spec/integration/mutations/checkout/add_addresses_to_checkout_spec.rb +13 -19
  233. data/spec/integration/mutations/checkout/apply_coupon_code_spec.rb +3 -1
  234. data/spec/integration/mutations/{mark_default_address_spec.rb → mark_default_ship_address_spec.rb} +5 -5
  235. data/spec/integration/mutations/remove_from_address_book_spec.rb +4 -4
  236. data/spec/integration/mutations/save_in_address_book_spec.rb +25 -12
  237. data/spec/integration/queries/completed_orders_spec.rb +19 -15
  238. data/spec/integration/queries/countries_spec.rb +2 -2
  239. data/spec/integration/queries/current_order_spec.rb +4 -1
  240. data/spec/integration/queries/current_store_spec.rb +1 -1
  241. data/spec/integration/queries/current_user_spec.rb +7 -2
  242. data/spec/integration/queries/products_spec.rb +4 -1
  243. data/spec/integration/queries/taxonomies_spec.rb +12 -4
  244. data/spec/integration/types/json_spec.rb +17 -0
  245. data/spec/lib/solidus_graphql_api/batch_loader/belongs_to_spec.rb +24 -25
  246. data/spec/lib/solidus_graphql_api/batch_loader/has_many_spec.rb +17 -15
  247. data/spec/lib/solidus_graphql_api/batch_loader/has_many_through_spec.rb +42 -25
  248. data/spec/lib/solidus_graphql_api/batch_loader/has_one_spec.rb +17 -15
  249. data/spec/lib/solidus_graphql_api/context_spec.rb +119 -6
  250. data/spec/lib/solidus_graphql_api/queries/option_value/option_type_query_spec.rb +10 -0
  251. data/spec/lib/solidus_graphql_api/queries/shipping_rate/shipping_method_query_spec.rb +11 -0
  252. data/spec/lib/solidus_graphql_api/queries/taxon/children_query_spec.rb +9 -5
  253. data/spec/lib/solidus_graphql_api/queries/taxonomy/taxons_query_spec.rb +8 -5
  254. data/spec/lib/solidus_graphql_api/queries/variant/default_price_query_spec.rb +1 -1
  255. data/spec/lib/solidus_graphql_api/types/base/object_spec.rb +5 -1
  256. data/spec/lib/solidus_graphql_api/types/json_spec.rb +2 -1
  257. data/spec/lib/solidus_graphql_api/types/option_value_spec.rb +22 -0
  258. data/spec/lib/solidus_graphql_api/types/product_spec.rb +3 -1
  259. data/spec/lib/solidus_graphql_api/types/query_spec.rb +3 -1
  260. data/spec/lib/solidus_graphql_api/types/shipping_rate_spec.rb +22 -0
  261. data/spec/requests/spree/graphql_controller_spec.rb +15 -2
  262. data/spec/spec_helper.rb +20 -12
  263. data/spec/support/expected_schema.graphql +128 -26
  264. data/spec/support/graphql/mutations/add_addresses_to_checkout.gql +2 -2
  265. data/spec/support/graphql/mutations/mark_default_ship_address.gql +9 -0
  266. data/spec/support/graphql/mutations/remove_from_address_book.gql +1 -1
  267. data/spec/support/graphql/mutations/save_in_address_book.gql +6 -5
  268. data/spec/support/graphql/queries/completed_orders/billing_address.gql +1 -2
  269. data/spec/support/graphql/queries/completed_orders/shipping_address.gql +1 -2
  270. data/spec/support/graphql/queries/current_user.gql +6 -11
  271. data/spec/support/graphql/responses/completed_orders/billing_address.json.erb +2 -4
  272. data/spec/support/graphql/responses/completed_orders/shipping_address.json.erb +2 -4
  273. data/spec/support/graphql/responses/current_store.json.erb +1 -1
  274. data/spec/support/graphql/responses/current_user.json.erb +7 -13
  275. data/spec/support/graphql/responses/taxonomies.json.erb +7 -7
  276. data/spec/support/helpers/active_record.rb +18 -0
  277. data/spec/support/helpers/graphql.rb +4 -4
  278. metadata +245 -54
  279. data/lib/solidus_graphql_api/factories.rb +0 -11
  280. data/spec/support/graphql/mutations/mark_default_address.gql +0 -9
  281. /data/lib/solidus_graphql_api/{factories → testing_support/factories}/country_factory.rb +0 -0
  282. /data/lib/solidus_graphql_api/{factories → testing_support/factories}/store_factory.rb +0 -0
@@ -12,8 +12,13 @@ RSpec.describe_query :current_user, query: :current_user, freeze_date: true do
12
12
  bill_address: bill_address)
13
13
  }
14
14
 
15
- let(:ship_address) { create(:ship_address, id: 1, zipcode: 10_001) }
16
- let(:bill_address) { create(:bill_address, id: 2, zipcode: 10_002) }
15
+ # Previos to Solidus v3.3, states_required was always false and the state was
16
+ # always automatically assigned. We force the behavior here to have the same
17
+ # response for any Solidus version.
18
+ let(:country) { create(:country, states_required: false) }
19
+ let(:state) { create(:state, name: "Alabama", abbr: "AL", country: country) }
20
+ let(:ship_address) { create(:ship_address, id: 1, zipcode: 10_001, country: country, state: state) }
21
+ let(:bill_address) { create(:bill_address, id: 2, zipcode: 10_002, country: country, state: state) }
17
22
  let(:credit_card) {
18
23
  create(:credit_card,
19
24
  user: user,
@@ -24,7 +24,10 @@ RSpec.describe_query :products, query: :products, freeze_date: true do
24
24
  let!(:solidus_tote) { create(:product, name: 'Solidus Tote', id: 4, price: 15.99) }
25
25
 
26
26
  context 'when no query is passed' do
27
- it { is_expected.to match_array([{ id: solidus_t_shirt.id }, { id: ruby_mug.id }, { id: solidus_mug.id }, { id: solidus_tote.id }]) }
27
+ it {
28
+ expect(subject).to match_array([{ id: solidus_t_shirt.id }, { id: ruby_mug.id }, { id: solidus_mug.id },
29
+ { id: solidus_tote.id }])
30
+ }
28
31
  end
29
32
 
30
33
  context 'when a query is passed' do
@@ -9,14 +9,22 @@ RSpec.describe_query :taxonomies do
9
9
  end
10
10
 
11
11
  context 'when taxonomies exists' do
12
- let!(:brand_taxonomy) { create(:taxonomy, :with_taxon_meta, id: 1, root_taxon_id: 1) }
13
- let!(:category_taxonomy) { create(:taxonomy, id: 2, name: 'Category', root_taxon_id: 2) }
12
+ let!(:brand_taxonomy) do
13
+ create(:taxonomy, :with_taxon_meta, :with_root_icon, id: 1, name: "Brand", root_taxon_id: 1)
14
+ end
15
+ let!(:category_taxonomy) { create(:taxonomy, :with_root_icon, id: 2, name: 'Category', root_taxon_id: 2) }
16
+ # Need to reload taxon to get the correct icon url, because the icon is attached after the taxon is created
17
+ let!(:taxon) { create(:taxon, :with_icon, id: 3, name: 'Solidus', taxonomy: brand_taxonomy).tap(&:reload) }
14
18
 
15
19
  before do
16
- create(:taxon, id: 3, name: 'Solidus', parent: brand_taxonomy.root, taxonomy: brand_taxonomy)
20
+ taxon.update(parent: brand_taxonomy.root)
17
21
  end
18
22
 
19
- it { is_expected.to match_response(:taxonomies) }
23
+ it {
24
+ expect(subject).to match_response(:taxonomies).with_args(brand_url: brand_taxonomy.taxons.first.icon.url,
25
+ category_url: category_taxonomy.taxons.first.icon.url,
26
+ taxon_url: taxon.icon.url)
27
+ }
20
28
  end
21
29
  end
22
30
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'JSON type' do
6
+ it 'coerces JSON custom type', type: :feature do
7
+ create(:product, name: 'Shirt')
8
+
9
+ post '/graphql',
10
+ params: {
11
+ query: "{ products(query: { search: { name_cont: \"Shirt\" } }) { nodes { name } } }"
12
+ },
13
+ headers: headers
14
+
15
+ expect(JSON.parse(response.body).dig(*%w[data products nodes])[0]['name']).to eq('Shirt')
16
+ end
17
+ end
@@ -2,7 +2,9 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- RSpec.describe SolidusGraphqlApi::BatchLoader::BelongsTo do
5
+ RSpec.describe SolidusGraphqlApi::BatchLoader::BelongsTo, skip: (ENV["DB"] == "mysql") do
6
+ include Helpers::ActiveRecord
7
+
6
8
  subject(:loader) do
7
9
  described_class.new(
8
10
  object,
@@ -14,19 +16,21 @@ RSpec.describe SolidusGraphqlApi::BatchLoader::BelongsTo do
14
16
  let(:options) { {} }
15
17
 
16
18
  context 'with a regular association' do
17
- with_model :Article, scope: :all do
18
- model do
19
- has_many :comments
19
+ before do
20
+ run_migrations do
21
+ create_table :articles, force: true
22
+ create_table :comments, force: true do |t|
23
+ t.belongs_to :article
24
+ end
20
25
  end
26
+ create_model("Article")
27
+ create_model("Comment") { belongs_to :article }
21
28
  end
22
29
 
23
- with_model :Comment, scope: :all do
24
- table do |t|
25
- t.belongs_to :article
26
- end
27
-
28
- model do
29
- belongs_to :article
30
+ after do
31
+ run_migrations do
32
+ drop_table :articles
33
+ drop_table :comments
30
34
  end
31
35
  end
32
36
 
@@ -39,21 +43,16 @@ RSpec.describe SolidusGraphqlApi::BatchLoader::BelongsTo do
39
43
  end
40
44
 
41
45
  context 'with a polymorphic association' do
42
- with_model :Image, scope: :all do
43
- table do |t|
44
- t.integer :imageable_id
45
- t.string :imageable_type
46
- end
47
-
48
- model do
49
- belongs_to :imageable, polymorphic: true
50
- end
51
- end
52
-
53
- with_model :Article, scope: :all do
54
- model do
55
- has_many :images, as: :imageable
46
+ before do
47
+ run_migrations do
48
+ create_table :images, force: true do |t|
49
+ t.integer :imageable_id
50
+ t.string :imageable_type
51
+ end
52
+ create_table :articles, force: true
56
53
  end
54
+ create_model("Image") { belongs_to :imageable, polymorphic: true }
55
+ create_model("Article") { has_many :images, as: :imageable }
57
56
  end
58
57
 
59
58
  let!(:object) { Image.create!(imageable: Article.create!) }
@@ -2,7 +2,9 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- RSpec.describe SolidusGraphqlApi::BatchLoader::HasMany do
5
+ RSpec.describe SolidusGraphqlApi::BatchLoader::HasMany, skip: (ENV["DB"] == "mysql") do
6
+ include Helpers::ActiveRecord
7
+
6
8
  subject(:loader) do
7
9
  described_class.new(
8
10
  article,
@@ -10,28 +12,28 @@ RSpec.describe SolidusGraphqlApi::BatchLoader::HasMany do
10
12
  )
11
13
  end
12
14
 
13
- with_model :Article, scope: :all do
14
- model do
15
- has_many :comments
15
+ before do
16
+ run_migrations do
17
+ create_table :articles, force: true
18
+ create_table :comments, force: true do |t|
19
+ t.belongs_to :article
20
+ end
16
21
  end
17
- end
22
+ create_model("Article") { has_many :comments }
23
+ create_model("Comment") { belongs_to :article }
18
24
 
19
- with_model :Comment, scope: :all do
20
- table do |t|
21
- t.belongs_to :article
22
- end
25
+ article.comments.create!
26
+ end
23
27
 
24
- model do
25
- belongs_to :article
28
+ after do
29
+ run_migrations do
30
+ drop_table :articles
31
+ drop_table :comments
26
32
  end
27
33
  end
28
34
 
29
35
  let!(:article) { Article.create! }
30
36
 
31
- before do
32
- article.comments.create!
33
- end
34
-
35
37
  it 'loads the association properly' do
36
38
  expect(loader.load.sync).to eq(article.comments)
37
39
  end
@@ -2,46 +2,63 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- RSpec.describe SolidusGraphqlApi::BatchLoader::HasManyThrough do
5
+ RSpec.describe SolidusGraphqlApi::BatchLoader::HasManyThrough, skip: (ENV["DB"] == "mysql") do
6
+ include Helpers::ActiveRecord
7
+
6
8
  subject(:loader) do
7
9
  described_class.new(
8
- article,
9
- Article.reflect_on_association(:comment_authors)
10
+ physician,
11
+ Physician.reflect_on_association(:patients)
10
12
  )
11
13
  end
12
14
 
13
- with_model :Article, scope: :all do
14
- model do
15
- has_many :comments
16
- has_many :comment_authors, through: :comments, source: :author
15
+ before do
16
+ run_migrations do
17
+ create_table :physicians, force: true
18
+ create_table :patients, force: true
19
+ create_table :appointments, force: true do |t|
20
+ t.belongs_to :physician
21
+ t.belongs_to :patient
22
+ end
17
23
  end
18
- end
19
-
20
- with_model :Comment, scope: :all do
21
- table do |t|
22
- t.belongs_to :article
23
- t.belongs_to :author
24
+ create_model("Physician") do
25
+ has_many :appointments
26
+ has_many :patients, through: :appointments
24
27
  end
25
-
26
- model do
27
- belongs_to :article
28
- belongs_to :author
28
+ create_model("Patient") do
29
+ has_many :appointments
30
+ end
31
+ create_model("Appointment") do
32
+ belongs_to :physician
33
+ belongs_to :patient
29
34
  end
35
+
36
+ physician.appointments.create!(patient: Patient.create!)
30
37
  end
31
38
 
32
- with_model :Author, scope: :all do
33
- model do
34
- has_many :comments
39
+ after do
40
+ run_migrations do
41
+ drop_table :physicians
42
+ drop_table :patients
43
+ drop_table :appointments
35
44
  end
36
45
  end
37
46
 
38
- let!(:article) { Article.create! }
47
+ let!(:physician) { Physician.create! }
39
48
 
40
- before do
41
- article.comments.create!(author: Author.create!)
49
+ it 'loads the association properly' do
50
+ expect(loader.load.sync).to eq(physician.patients)
42
51
  end
43
52
 
44
- it 'loads the association properly' do
45
- expect(loader.load.sync).to eq(article.comment_authors)
53
+ it "doesn't duplicate result when another record loaded in the batch is also associated to the same target record" do
54
+ second_physician = Physician.create!
55
+ Appointment.create!(patient: physician.patients.first, physician: second_physician)
56
+
57
+ described_class.new(
58
+ second_physician,
59
+ Physician.reflect_on_association(:patients)
60
+ ).load
61
+
62
+ expect(loader.load.sync.length).to be(1)
46
63
  end
47
64
  end
@@ -2,7 +2,9 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- RSpec.describe SolidusGraphqlApi::BatchLoader::HasOne do
5
+ RSpec.describe SolidusGraphqlApi::BatchLoader::HasOne, skip: (ENV["DB"] == "mysql") do
6
+ include Helpers::ActiveRecord
7
+
6
8
  subject(:loader) do
7
9
  described_class.new(
8
10
  article,
@@ -10,28 +12,28 @@ RSpec.describe SolidusGraphqlApi::BatchLoader::HasOne do
10
12
  )
11
13
  end
12
14
 
13
- with_model :Article, scope: :all do
14
- model do
15
- has_one :image
15
+ before do
16
+ run_migrations do
17
+ create_table :articles, force: true
18
+ create_table :images, force: true do |t|
19
+ t.belongs_to :article
20
+ end
16
21
  end
17
- end
22
+ create_model("Article") { has_one :image }
23
+ create_model("Image") { belongs_to :article }
18
24
 
19
- with_model :Image, scope: :all do
20
- table do |t|
21
- t.belongs_to :article
22
- end
25
+ article.create_image!
26
+ end
23
27
 
24
- model do
25
- belongs_to :article
28
+ after do
29
+ run_migrations do
30
+ drop_table :articles
31
+ drop_table :images
26
32
  end
27
33
  end
28
34
 
29
35
  let!(:article) { Article.create! }
30
36
 
31
- before do
32
- article.create_image!
33
- end
34
-
35
37
  it 'loads the association properly' do
36
38
  expect(loader.load.sync).to eq(article.image)
37
39
  end
@@ -7,7 +7,10 @@ RSpec.describe SolidusGraphqlApi::Context do
7
7
 
8
8
  let(:headers) do
9
9
  headers_hash = {}
10
- headers_hash['Authorization'] = "Bearer #{authorization_token}" if defined?(authorization_token) && authorization_token
10
+ if defined?(authorization_token) && authorization_token
11
+ headers_hash['Authorization'] =
12
+ "Bearer #{authorization_token}"
13
+ end
11
14
  headers_hash['X-Spree-Order-Token'] = order_token if defined?(order_token) && order_token
12
15
  headers_hash
13
16
  end
@@ -55,8 +58,62 @@ RSpec.describe SolidusGraphqlApi::Context do
55
58
  describe '#current_user' do
56
59
  subject { schema_context.current_user }
57
60
 
58
- context 'when headers do not contains the authorization token' do
59
- it { is_expected.to be_nil }
61
+ context 'when headers do not contain the authorization token' do
62
+ context "and there's no user with nil or empty spree_api_key" do
63
+ it { is_expected.to be_nil }
64
+ end
65
+
66
+ context "and there's a user with nil spree_api_key" do
67
+ before { FactoryBot.create(:user, spree_api_key: nil) }
68
+
69
+ it { is_expected.to be_nil }
70
+ end
71
+
72
+ context "and there's a user with empty string as spree_api_key" do
73
+ before { FactoryBot.create(:user, spree_api_key: '') }
74
+
75
+ it { is_expected.to be_nil }
76
+ end
77
+ end
78
+
79
+ context 'when headers contain an empty authorization token' do
80
+ let(:authorization_token) { '' }
81
+
82
+ context "and there's no user with nil or empty spree_api_key" do
83
+ it { is_expected.to be_nil }
84
+ end
85
+
86
+ context "and there's a user with nil spree_api_key" do
87
+ before { FactoryBot.create(:user, spree_api_key: nil) }
88
+
89
+ it { is_expected.to be_nil }
90
+ end
91
+
92
+ context "and there's a user with empty string as spree_api_key" do
93
+ before { FactoryBot.create(:user, spree_api_key: '') }
94
+
95
+ it { is_expected.to be_nil }
96
+ end
97
+ end
98
+
99
+ context "when headers contain a authorization header that doesn't match" do
100
+ let(:headers) { { 'Authorization' => 'abc' } }
101
+
102
+ context "and there's no user with nil or empty spree_api_key" do
103
+ it { is_expected.to be_nil }
104
+ end
105
+
106
+ context "and there's a user with nil spree_api_key" do
107
+ before { FactoryBot.create(:user, spree_api_key: nil) }
108
+
109
+ it { is_expected.to be_nil }
110
+ end
111
+
112
+ context "and there's a user with empty string as spree_api_key" do
113
+ before { FactoryBot.create(:user, spree_api_key: '') }
114
+
115
+ it { is_expected.to be_nil }
116
+ end
60
117
  end
61
118
 
62
119
  context 'when headers contains the authorization token' do
@@ -171,8 +228,12 @@ RSpec.describe SolidusGraphqlApi::Context do
171
228
  end
172
229
 
173
230
  context 'when the current user has many incompleted orders in the current store' do
174
- let!(:first_created_order) { create :order, user: current_user, store: current_store, created_at: Time.zone.yesterday }
175
- let!(:last_created_order) { create :order, user: current_user, store: current_store, created_at: Time.zone.today }
231
+ let!(:first_created_order) {
232
+ create :order, user: current_user, store: current_store, created_at: Time.zone.yesterday
233
+ }
234
+ let!(:last_created_order) {
235
+ create :order, user: current_user, store: current_store, created_at: Time.zone.today
236
+ }
176
237
 
177
238
  it { is_expected.to eq last_created_order }
178
239
  end
@@ -228,9 +289,61 @@ RSpec.describe SolidusGraphqlApi::Context do
228
289
  it { is_expected.to be_nil }
229
290
  end
230
291
 
292
+ # Need to bypass application layer to reproduce race database state
293
+ # rubocop:disable Rails/SkipsModelValidations
231
294
  context 'when is provided no order token' do
232
- it { is_expected.to be_nil }
295
+ context "and there's no order with nil or empty guest_token" do
296
+ it { is_expected.to be_nil }
297
+ end
298
+
299
+ context "and there's an order with nil guest_token" do
300
+ before do
301
+ order = FactoryBot.create(:order)
302
+ order.update_column(:guest_token, nil)
303
+ end
304
+
305
+ it { is_expected.to be_nil }
306
+ end
307
+
308
+ context "and there's an order with empty string as guest_token" do
309
+ before do
310
+ order = FactoryBot.create(:order)
311
+ order.update_column(:guest_token, '')
312
+ end
313
+
314
+ it { is_expected.to be_nil }
315
+ end
316
+ end
317
+ # rubocop:enable Rails/SkipsModelValidations
318
+
319
+ # Need to bypass application layer to reproduce race database state
320
+ # rubocop:disable Rails/SkipsModelValidations
321
+ context 'when is provided an empty order token' do
322
+ let(:order_token) { '' }
323
+
324
+ context "and there's no order with nil or empty guest_token" do
325
+ it { is_expected.to be_nil }
326
+ end
327
+
328
+ context "and there's an order with nil guest_token" do
329
+ before do
330
+ order = FactoryBot.create(:order)
331
+ order.update_column(:guest_token, nil)
332
+ end
333
+
334
+ it { is_expected.to be_nil }
335
+ end
336
+
337
+ context "and there's an order with empty string as guest_token" do
338
+ before do
339
+ order = FactoryBot.create(:order)
340
+ order.update_column(:guest_token, '')
341
+ end
342
+
343
+ it { is_expected.to be_nil }
344
+ end
233
345
  end
346
+ # rubocop:enable Rails/SkipsModelValidations
234
347
  end
235
348
  end
236
349
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe SolidusGraphqlApi::Queries::OptionValue::OptionTypeQuery do
6
+ let(:option_type) { create(:option_type) }
7
+ let(:option_value) { create(:option_value, option_type: option_type) }
8
+
9
+ it { expect(described_class.new(option_value: option_value).call.sync).to eq(option_type) }
10
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe SolidusGraphqlApi::Queries::ShippingRate::ShippingMethodQuery do
6
+ let(:shipping_method) { create(:shipping_method) }
7
+
8
+ let(:shipping_rate) { create(:shipping_rate, shipping_method: shipping_method) }
9
+
10
+ it { expect(described_class.new(shipping_rate: shipping_rate).call.sync).to eq(shipping_method) }
11
+ end
@@ -3,9 +3,13 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe SolidusGraphqlApi::Queries::Taxon::ChildrenQuery do
6
- let(:taxon) { create(:taxon) }
7
-
8
- let!(:children) { create_list(:taxon, 2, parent: taxon) }
9
-
10
- it { expect(described_class.new(taxon: taxon).call.sync).to match_array(children) }
6
+ it do
7
+ taxonomy = create(:taxonomy)
8
+ root = taxonomy.root
9
+ children = [
10
+ create(:taxon, name: "Taxon one", parent: root),
11
+ create(:taxon, name: "Taxon two", parent: root)
12
+ ]
13
+ expect(described_class.new(taxon: root).call.sync).to match_array(children)
14
+ end
11
15
  end
@@ -3,9 +3,12 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe SolidusGraphqlApi::Queries::Taxonomy::TaxonsQuery do
6
- let(:taxons) { build_list(:taxon, 2) }
7
-
8
- let(:taxonomy) { create(:taxonomy, taxons: taxons) }
9
-
10
- it { expect(described_class.new(taxonomy: taxonomy).call.sync).to match_array(taxons) }
6
+ it do
7
+ taxonomy = create(:taxonomy)
8
+ root_taxon = taxonomy.root
9
+ taxon = create(:taxon, taxonomy: taxonomy, parent: root_taxon)
10
+ create(:taxon)
11
+
12
+ expect(described_class.new(taxonomy: taxonomy).call.sync).to match_array([root_taxon, taxon])
13
+ end
11
14
  end
@@ -5,5 +5,5 @@ require 'spec_helper'
5
5
  RSpec.describe SolidusGraphqlApi::Queries::Variant::DefaultPriceQuery do
6
6
  let(:variant) { create(:variant) }
7
7
 
8
- it { expect(described_class.new(variant: variant).call.sync).to eq(variant.default_price) }
8
+ it { expect(described_class.new(variant: variant).call).to eq(variant.default_price) }
9
9
  end
@@ -3,7 +3,11 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe SolidusGraphqlApi::Types::Base::Object do
6
- subject { Class.new(described_class) }
6
+ subject do
7
+ Class.new(described_class) do
8
+ graphql_name :test
9
+ end
10
+ end
7
11
 
8
12
  describe '.remove_field' do
9
13
  context 'when the field is defined' do
@@ -37,7 +37,8 @@ RSpec.describe SolidusGraphqlApi::Types::Json do
37
37
  hash_array: [
38
38
  {
39
39
  ids_array: [
40
- 'U3ByZWU6OlByb21vdGlvbkFjdGlvbi02', 'U3ByZWU6OlByb21vdGlvbkFjdGlvbi04' # Spree::PromotionAction-6, Spree::PromotionAction-8
40
+ 'U3ByZWU6OlByb21vdGlvbkFjdGlvbi02',
41
+ 'U3ByZWU6OlByb21vdGlvbkFjdGlvbi04' # Spree::PromotionAction-6, Spree::PromotionAction-8
41
42
  ],
42
43
  ids_hash: {
43
44
  id: 'U3ByZWU6OkFkanVzdG1lbnQtNQ==', # Spree::Adjustment-5
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe SolidusGraphqlApi::Types::OptionValue do
6
+ let(:option_value) { create(:option_value) }
7
+ let(:query_object) { spy(:query_object) }
8
+
9
+ subject { described_class.send(:new, option_value, {}) }
10
+
11
+ describe '#option_type' do
12
+ before do
13
+ allow(SolidusGraphqlApi::Queries::OptionValue::OptionTypeQuery).
14
+ to receive(:new).with(option_value: option_value).
15
+ and_return(query_object)
16
+ end
17
+
18
+ after { subject.option_type }
19
+
20
+ it { expect(query_object).to receive(:call) }
21
+ end
22
+ end
@@ -34,7 +34,9 @@ RSpec.describe SolidusGraphqlApi::Types::Product do
34
34
 
35
35
  describe '#product_properties' do
36
36
  before do
37
- allow(SolidusGraphqlApi::Queries::Product::ProductPropertiesQuery).to receive(:new).with(product: product).and_return(query_object)
37
+ allow(SolidusGraphqlApi::Queries::Product::ProductPropertiesQuery).
38
+ to receive(:new).with(product: product).
39
+ and_return(query_object)
38
40
  end
39
41
 
40
42
  after { subject.product_properties }
@@ -24,7 +24,9 @@ RSpec.describe SolidusGraphqlApi::Types::Query do
24
24
 
25
25
  let(:slug) { 'slug' }
26
26
 
27
- before { allow(SolidusGraphqlApi::Queries::ProductBySlugQuery).to receive(:new).with(no_args).and_return(query_object) }
27
+ before {
28
+ allow(SolidusGraphqlApi::Queries::ProductBySlugQuery).to receive(:new).with(no_args).and_return(query_object)
29
+ }
28
30
 
29
31
  after { subject.product_by_slug(slug: slug) }
30
32
 
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe SolidusGraphqlApi::Types::ShippingRate do
6
+ let(:shipping_rate) { create(:shipping_rate) }
7
+ let(:query_object) { spy(:query_object) }
8
+
9
+ subject { described_class.send(:new, shipping_rate, {}) }
10
+
11
+ describe '#shipping_method' do
12
+ before do
13
+ allow(SolidusGraphqlApi::Queries::ShippingRate::ShippingMethodQuery).
14
+ to receive(:new).with(shipping_rate: shipping_rate).
15
+ and_return(query_object)
16
+ end
17
+
18
+ after { subject.shipping_method }
19
+
20
+ it { expect(query_object).to receive(:call) }
21
+ end
22
+ end