solidus_graphql_api 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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