@spree/docs 0.1.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 (183) hide show
  1. package/README.md +54 -0
  2. package/dist/api-reference/platform/authentication.md +38 -0
  3. package/dist/api-reference/store-api/authentication.md +188 -0
  4. package/dist/api-reference/store-api/errors.md +277 -0
  5. package/dist/api-reference/store-api/idempotency.md +129 -0
  6. package/dist/api-reference/store-api/introduction.md +34 -0
  7. package/dist/api-reference/store-api/localization.md +279 -0
  8. package/dist/api-reference/store-api/metadata.md +160 -0
  9. package/dist/api-reference/store-api/monetary-amounts.md +65 -0
  10. package/dist/api-reference/store-api/querying.md +399 -0
  11. package/dist/api-reference/store-api/rate-limitting.md +103 -0
  12. package/dist/api-reference/store-api/relations.md +185 -0
  13. package/dist/api-reference/storefront/authentication.md +88 -0
  14. package/dist/api-reference/tutorials/adyen-integration-guide-for-android.md +165 -0
  15. package/dist/api-reference/tutorials/adyen-integration-guide-for-ios.md +194 -0
  16. package/dist/api-reference/tutorials/quick-checkout-with-stripe.md +248 -0
  17. package/dist/api-reference/v2/fetching-multiple-resources.md +26 -0
  18. package/dist/api-reference/v2/filtering-and-sorting.md +53 -0
  19. package/dist/api-reference/v2/introduction.md +22 -0
  20. package/dist/api-reference/v2/pagination.md +37 -0
  21. package/dist/api-reference/webhooks-events.md +883 -0
  22. package/dist/developer/admin/admin.md +205 -0
  23. package/dist/developer/admin/authentication.md +59 -0
  24. package/dist/developer/admin/components.md +711 -0
  25. package/dist/developer/admin/custom-css.md +243 -0
  26. package/dist/developer/admin/custom-javascript.md +116 -0
  27. package/dist/developer/admin/extending-ui.md +1964 -0
  28. package/dist/developer/admin/form-builder.md +444 -0
  29. package/dist/developer/admin/helper-methods.md +531 -0
  30. package/dist/developer/admin/navigation.md +805 -0
  31. package/dist/developer/admin/tables.md +491 -0
  32. package/dist/developer/advanced/adding_spree_to_rails_app.md +106 -0
  33. package/dist/developer/cli/quickstart.md +137 -0
  34. package/dist/developer/contributing/creating-an-extension.md +258 -0
  35. package/dist/developer/contributing/developing-spree.md +339 -0
  36. package/dist/developer/contributing/quickstart.md +32 -0
  37. package/dist/developer/contributing/updating-extensions.md +67 -0
  38. package/dist/developer/core-concepts/addresses.md +265 -0
  39. package/dist/developer/core-concepts/adjustments.md +107 -0
  40. package/dist/developer/core-concepts/architecture.md +177 -0
  41. package/dist/developer/core-concepts/calculators.md +323 -0
  42. package/dist/developer/core-concepts/customers.md +230 -0
  43. package/dist/developer/core-concepts/events.md +624 -0
  44. package/dist/developer/core-concepts/imports-exports.md +698 -0
  45. package/dist/developer/core-concepts/inventory.md +191 -0
  46. package/dist/developer/core-concepts/markets.md +250 -0
  47. package/dist/developer/core-concepts/media.md +167 -0
  48. package/dist/developer/core-concepts/metafields.md +187 -0
  49. package/dist/developer/core-concepts/orders.md +328 -0
  50. package/dist/developer/core-concepts/payments.md +710 -0
  51. package/dist/developer/core-concepts/pricing.md +163 -0
  52. package/dist/developer/core-concepts/products.md +360 -0
  53. package/dist/developer/core-concepts/promotions.md +322 -0
  54. package/dist/developer/core-concepts/reports.md +206 -0
  55. package/dist/developer/core-concepts/search-filtering.md +237 -0
  56. package/dist/developer/core-concepts/shipments.md +212 -0
  57. package/dist/developer/core-concepts/slugs.md +111 -0
  58. package/dist/developer/core-concepts/staff-roles.md +123 -0
  59. package/dist/developer/core-concepts/store-credits-gift-cards.md +317 -0
  60. package/dist/developer/core-concepts/stores.md +117 -0
  61. package/dist/developer/core-concepts/taxes.md +135 -0
  62. package/dist/developer/core-concepts/translations.md +120 -0
  63. package/dist/developer/core-concepts/users.md +299 -0
  64. package/dist/developer/core-concepts/webhooks.md +378 -0
  65. package/dist/developer/create-spree-app/quickstart.md +158 -0
  66. package/dist/developer/customization/api.md +93 -0
  67. package/dist/developer/customization/authentication.md +88 -0
  68. package/dist/developer/customization/checkout.md +204 -0
  69. package/dist/developer/customization/configuration.md +55 -0
  70. package/dist/developer/customization/decorators.md +523 -0
  71. package/dist/developer/customization/dependencies.md +232 -0
  72. package/dist/developer/customization/emails.md +21 -0
  73. package/dist/developer/customization/extensions.md +92 -0
  74. package/dist/developer/customization/metadata.md +236 -0
  75. package/dist/developer/customization/model-preferences.md +130 -0
  76. package/dist/developer/customization/permissions.md +265 -0
  77. package/dist/developer/customization/quickstart.md +229 -0
  78. package/dist/developer/customization/routes.md +24 -0
  79. package/dist/developer/customization/v4/admin-panel.md +78 -0
  80. package/dist/developer/customization/v4/authentication.md +210 -0
  81. package/dist/developer/customization/v4/checkout.md +212 -0
  82. package/dist/developer/customization/v4/deface.md +251 -0
  83. package/dist/developer/customization/v4/images.md +86 -0
  84. package/dist/developer/customization/v4/storefront.md +450 -0
  85. package/dist/developer/deployment/assets.md +87 -0
  86. package/dist/developer/deployment/aws.md +335 -0
  87. package/dist/developer/deployment/caching.md +27 -0
  88. package/dist/developer/deployment/cdn.md +39 -0
  89. package/dist/developer/deployment/database.md +155 -0
  90. package/dist/developer/deployment/docker.md +128 -0
  91. package/dist/developer/deployment/emails.md +77 -0
  92. package/dist/developer/deployment/environment_variables.md +111 -0
  93. package/dist/developer/deployment/heroku.md +51 -0
  94. package/dist/developer/deployment/render.md +95 -0
  95. package/dist/developer/getting-started/quickstart.md +82 -0
  96. package/dist/developer/how-to/custom-payment-method.md +374 -0
  97. package/dist/developer/how-to/custom-promotion.md +373 -0
  98. package/dist/developer/how-to/custom-report.md +387 -0
  99. package/dist/developer/how-to/custom-search-provider.md +230 -0
  100. package/dist/developer/multi-store/quickstart.md +71 -0
  101. package/dist/developer/multi-store/setup.md +38 -0
  102. package/dist/developer/multi-tenant/configuration.md +41 -0
  103. package/dist/developer/multi-tenant/core-concepts.md +75 -0
  104. package/dist/developer/multi-tenant/installation.md +96 -0
  105. package/dist/developer/multi-tenant/quickstart.md +20 -0
  106. package/dist/developer/multi-vendor/installation.md +45 -0
  107. package/dist/developer/multi-vendor/quickstart.md +17 -0
  108. package/dist/developer/sdk/admin/quickstart.md +22 -0
  109. package/dist/developer/sdk/authentication.md +89 -0
  110. package/dist/developer/sdk/configuration.md +225 -0
  111. package/dist/developer/sdk/quickstart.md +82 -0
  112. package/dist/developer/sdk/store/account.md +67 -0
  113. package/dist/developer/sdk/store/cart-checkout.md +140 -0
  114. package/dist/developer/sdk/store/markets.md +151 -0
  115. package/dist/developer/sdk/store/payments.md +96 -0
  116. package/dist/developer/sdk/store/products.md +149 -0
  117. package/dist/developer/sdk/store/wishlists.md +52 -0
  118. package/dist/developer/security/pci_compliance.md +15 -0
  119. package/dist/developer/security/security_policy.md +68 -0
  120. package/dist/developer/storefront/blocks.md +285 -0
  121. package/dist/developer/storefront/custom-css.md +260 -0
  122. package/dist/developer/storefront/custom-javascript.md +166 -0
  123. package/dist/developer/storefront/helper-methods.md +1288 -0
  124. package/dist/developer/storefront/links.md +298 -0
  125. package/dist/developer/storefront/nextjs/architecture.md +150 -0
  126. package/dist/developer/storefront/nextjs/customization.md +141 -0
  127. package/dist/developer/storefront/nextjs/deployment.md +180 -0
  128. package/dist/developer/storefront/nextjs/quickstart.md +92 -0
  129. package/dist/developer/storefront/nextjs/spree-next-package.md +314 -0
  130. package/dist/developer/storefront/pages.md +163 -0
  131. package/dist/developer/storefront/sections.md +569 -0
  132. package/dist/developer/storefront/storefront.md +56 -0
  133. package/dist/developer/storefront/themes.md +161 -0
  134. package/dist/developer/tutorial/admin.md +134 -0
  135. package/dist/developer/tutorial/extending-models.md +380 -0
  136. package/dist/developer/tutorial/file-uploads.md +121 -0
  137. package/dist/developer/tutorial/introduction.md +33 -0
  138. package/dist/developer/tutorial/model.md +41 -0
  139. package/dist/developer/tutorial/page-builder.md +487 -0
  140. package/dist/developer/tutorial/rich-text.md +73 -0
  141. package/dist/developer/tutorial/seo.md +332 -0
  142. package/dist/developer/tutorial/storefront.md +352 -0
  143. package/dist/developer/tutorial/testing.md +558 -0
  144. package/dist/developer/upgrades/2.0-to-2.1.md +46 -0
  145. package/dist/developer/upgrades/2.1-to-2.2.md +59 -0
  146. package/dist/developer/upgrades/2.2-to-2.3.md +44 -0
  147. package/dist/developer/upgrades/2.3-to-2.4.md +42 -0
  148. package/dist/developer/upgrades/3.0-to-3.1.md +47 -0
  149. package/dist/developer/upgrades/3.1-to-3.2.md +34 -0
  150. package/dist/developer/upgrades/3.2-to-3.3.md +70 -0
  151. package/dist/developer/upgrades/3.3-to-3.4.md +36 -0
  152. package/dist/developer/upgrades/3.4-to-3.5.md +44 -0
  153. package/dist/developer/upgrades/3.5-to-3.6.md +40 -0
  154. package/dist/developer/upgrades/3.6-to-3.7.md +62 -0
  155. package/dist/developer/upgrades/3.7-to-4.0.md +152 -0
  156. package/dist/developer/upgrades/4.0-to-4.1.md +92 -0
  157. package/dist/developer/upgrades/4.1-to-4.2.md +109 -0
  158. package/dist/developer/upgrades/4.10-to-5.0.md +129 -0
  159. package/dist/developer/upgrades/4.2-to-4.3.md +100 -0
  160. package/dist/developer/upgrades/4.3-to-4.4.md +125 -0
  161. package/dist/developer/upgrades/4.4-to-4.5.md +94 -0
  162. package/dist/developer/upgrades/4.5-to-4.6.md +119 -0
  163. package/dist/developer/upgrades/4.6-to-4.7.md +39 -0
  164. package/dist/developer/upgrades/4.8-to-4.9.md +24 -0
  165. package/dist/developer/upgrades/4.9-to-4.10.md +24 -0
  166. package/dist/developer/upgrades/4.x-to-4.8.md +52 -0
  167. package/dist/developer/upgrades/5.0-to-5.1.md +28 -0
  168. package/dist/developer/upgrades/5.1-to-5.2.md +127 -0
  169. package/dist/developer/upgrades/5.2-to-5.3.md +338 -0
  170. package/dist/developer/upgrades/5.3-to-5.4.md +248 -0
  171. package/dist/developer/upgrades/quickstart.md +36 -0
  172. package/dist/integrations/analytics/google-analytics.md +64 -0
  173. package/dist/integrations/analytics/google-tag-manager.md +78 -0
  174. package/dist/integrations/integrations.md +39 -0
  175. package/dist/integrations/marketing/klaviyo.md +99 -0
  176. package/dist/integrations/payments/adyen.md +90 -0
  177. package/dist/integrations/payments/paypal.md +41 -0
  178. package/dist/integrations/payments/razorpay.md +45 -0
  179. package/dist/integrations/payments/stripe.md +109 -0
  180. package/dist/integrations/search/meilisearch.md +236 -0
  181. package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +57 -0
  182. package/dist/integrations/sso-mfa-social-login/storefront.md +56 -0
  183. package/package.json +27 -0
@@ -0,0 +1,558 @@
1
+ Learn how to write automated tests for the Brands feature
2
+
3
+ Automated testing is a crucial part of the development process. It helps you ensure that your code works as expected and catches bugs early.
4
+ Spree uses [RSpec](https://rspec.info), [Factory Bot](https://github.com/thoughtbot/factory_bot_rails), and [Capybara](https://github.com/teamcapybara/capybara) for testing.
5
+ We also provide the `spree_dev_tools` gem that helps you write Spree-specific tests.
6
+
7
+ > **INFO:** This guide assumes you've completed all previous tutorials through [Page Builder](/developer/tutorial/page-builder). You should have a complete `Spree::Brand` model with admin, storefront, and SEO features.
8
+
9
+ ## Setup
10
+
11
+ ### Step 1: Set RSpec as the Test Framework
12
+
13
+ ```bash
14
+ bin/rails g rspec:install
15
+ ```
16
+
17
+ ### Step 2: Run the spree\_dev\_tools Generator
18
+
19
+ ```bash
20
+ bin/rails g spree_dev_tools:install
21
+ ```
22
+
23
+ This adds Spree-specific test helpers to your `spec/support/` directory, including:
24
+
25
+ * Authorization helpers (`stub_authorization!`)
26
+ * Factory Bot configuration
27
+ * Capybara setup for feature tests
28
+ * and more…
29
+
30
+ ### Step 3: Create the Fixtures Directory and File
31
+
32
+ When writing tests that involve file attachments (like images, PDFs, etc.), you need fixture files that your factories can use. Here's how to set them up.
33
+
34
+ ```bash
35
+ mkdir -p spec/fixtures/files && printf '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc\xf8\x0f\x00\x00\x01\x01\x00\x05\x18\xd8N\x00\x00\x00\x00IEND\xaeB`\x82' > spec/fixtures/files/logo.png
36
+ ```
37
+
38
+ ### Step 4: Generate Test Files
39
+
40
+ ```bash
41
+ bin/rails g rspec:model Spree::Brand
42
+ ```
43
+
44
+ This creates `spec/models/spree/brand_spec.rb`.
45
+
46
+ ## Writing Factories
47
+
48
+ Factories provide a convenient way to create test data. Create a factory for your Brand model:
49
+
50
+ ```ruby spec/factories/spree/brand_factory.rb
51
+ FactoryBot.define do
52
+ factory :brand, class: Spree::Brand do
53
+ sequence(:name) { |n| "Brand #{n}" }
54
+ sequence(:slug) { |n| "brand-#{n}" }
55
+
56
+ trait :with_description do
57
+ description { '<div>A great brand for <strong>quality products</strong></div>' }
58
+ end
59
+
60
+ trait :with_logo do
61
+ after(:create) do |brand|
62
+ brand.logo.attach(
63
+ io: File.new(Rails.root.join('spec', 'fixtures', 'files', 'logo.png')),
64
+ filename: 'logo.png'
65
+ )
66
+ end
67
+ end
68
+
69
+ trait :with_products do
70
+ transient do
71
+ products_count { 3 }
72
+ store { nil }
73
+ end
74
+
75
+ after(:create) do |brand, evaluator|
76
+ store = evaluator.store || create(:store)
77
+ create_list(:product, evaluator.products_count, brand: brand, stores: [store])
78
+ end
79
+ end
80
+ end
81
+ end
82
+ ```
83
+
84
+ ### Factory Usage Examples
85
+
86
+ ```ruby
87
+ # Basic factory
88
+ brand = create(:brand)
89
+
90
+ # With traits
91
+ brand = create(:brand, :with_description, :with_logo)
92
+
93
+ # With custom attributes
94
+ brand = create(:brand, name: 'Nike')
95
+
96
+ # Build without persisting (faster for unit tests)
97
+ brand = build(:brand)
98
+
99
+ # Create multiple records
100
+ brands = create_list(:brand, 5)
101
+
102
+ # With associated products
103
+ brand = create(:brand, :with_products)
104
+ brand = create(:brand, :with_products, products_count: 5)
105
+ ```
106
+
107
+ ## Writing Model Tests
108
+
109
+ Model tests verify your business logic, validations, associations, and scopes.
110
+
111
+ ```ruby spec/models/spree/brand_spec.rb
112
+ require 'rails_helper'
113
+
114
+ RSpec.describe Spree::Brand, type: :model do
115
+ describe 'associations' do
116
+ it 'has many products' do
117
+ association = described_class.reflect_on_association(:products)
118
+ expect(association.macro).to eq(:has_many)
119
+ expect(association.class_name).to eq('Spree::Product')
120
+ end
121
+ end
122
+
123
+ describe 'validations' do
124
+ it 'validates presence of name' do
125
+ brand = build(:brand, name: nil)
126
+ expect(brand).not_to be_valid
127
+ expect(brand.errors[:name]).to include("can't be blank")
128
+ end
129
+
130
+ describe 'slug uniqueness' do
131
+ let!(:existing_brand) { create(:brand, slug: 'nike') }
132
+
133
+ it 'validates uniqueness of slug' do
134
+ brand = build(:brand, slug: 'nike')
135
+ expect(brand).not_to be_valid
136
+ expect(brand.errors[:slug]).to include('has already been taken')
137
+ end
138
+ end
139
+ end
140
+
141
+ describe 'FriendlyId' do
142
+ it 'generates slug from name' do
143
+ brand = create(:brand, name: 'Nike Sportswear', slug: nil)
144
+ expect(brand.slug).to eq('nike-sportswear')
145
+ end
146
+
147
+ it 'handles duplicate names by appending UUID' do
148
+ create(:brand, name: 'Nike', slug: 'nike')
149
+ brand = create(:brand, name: 'Nike', slug: nil)
150
+ expect(brand.slug).to match(/nike-[a-f0-9-]+/)
151
+ end
152
+ end
153
+
154
+ describe '#image' do
155
+ let(:brand) { create(:brand, :with_logo) }
156
+
157
+ it 'returns logo as image for Open Graph' do
158
+ expect(brand.image).to eq(brand.logo)
159
+ end
160
+ end
161
+ end
162
+ ```
163
+
164
+ ### Testing Decorators
165
+
166
+ When you extend core Spree models with decorators (see [Extending Core Models](/developer/tutorial/extending-models)), test the added functionality:
167
+
168
+ ```ruby spec/models/spree/product_decorator_spec.rb
169
+ require 'rails_helper'
170
+
171
+ RSpec.describe 'Spree::Product brand association' do
172
+ let(:store) { @default_store }
173
+ let(:brand) { create(:brand) }
174
+ let(:product) { create(:product, stores: [store]) }
175
+
176
+ describe 'brand association' do
177
+ it 'can be assigned a brand' do
178
+ product.brand = brand
179
+ product.save!
180
+
181
+ expect(product.reload.brand).to eq(brand)
182
+ end
183
+
184
+ it 'is optional' do
185
+ product.brand = nil
186
+ expect(product).to be_valid
187
+ end
188
+ end
189
+
190
+ describe 'brand.products' do
191
+ let!(:product1) { create(:product, brand: brand, stores: [store]) }
192
+ let!(:product2) { create(:product, brand: brand, stores: [store]) }
193
+ let!(:other_product) { create(:product, stores: [store]) }
194
+
195
+ it 'returns products for the brand' do
196
+ expect(brand.products).to contain_exactly(product1, product2)
197
+ end
198
+
199
+ it 'nullifies brand_id when brand is destroyed' do
200
+ brand.destroy
201
+ expect(product1.reload.brand_id).to be_nil
202
+ end
203
+ end
204
+ end
205
+ ```
206
+
207
+ ## Writing Controller Tests
208
+
209
+ Controller tests verify that your endpoints respond correctly and perform the expected actions.
210
+
211
+ ### Admin Controller Tests
212
+
213
+ ```ruby spec/controllers/spree/admin/brands_controller_spec.rb
214
+ require 'rails_helper'
215
+
216
+ RSpec.describe Spree::Admin::BrandsController, type: :controller do
217
+ stub_authorization!
218
+ render_views
219
+
220
+ describe 'GET #index' do
221
+ let!(:brand1) { create(:brand, name: 'Adidas') }
222
+ let!(:brand2) { create(:brand, name: 'Nike') }
223
+
224
+ it 'returns a successful response' do
225
+ get :index
226
+ expect(response).to be_successful
227
+ end
228
+
229
+ it 'displays all brands' do
230
+ get :index
231
+ expect(response.body).to include('Adidas')
232
+ expect(response.body).to include('Nike')
233
+ end
234
+ end
235
+
236
+ describe 'GET #new' do
237
+ it 'returns a successful response' do
238
+ get :new
239
+ expect(response).to be_successful
240
+ end
241
+
242
+ it 'displays the new brand form' do
243
+ get :new
244
+ expect(response.body).to include('brand[name]')
245
+ end
246
+ end
247
+
248
+ describe 'POST #create' do
249
+ context 'with valid params' do
250
+ let(:valid_params) do
251
+ { brand: { name: 'New Brand' } }
252
+ end
253
+
254
+ it 'creates a new brand' do
255
+ expect {
256
+ post :create, params: valid_params
257
+ }.to change(Spree::Brand, :count).by(1)
258
+ end
259
+
260
+ it 'redirects to the edit page' do
261
+ post :create, params: valid_params
262
+ expect(response).to redirect_to(spree.edit_admin_brand_path(Spree::Brand.last))
263
+ end
264
+ end
265
+
266
+ context 'with invalid params' do
267
+ let(:invalid_params) do
268
+ { brand: { name: '' } }
269
+ end
270
+
271
+ it 'does not create a new brand' do
272
+ expect {
273
+ post :create, params: invalid_params
274
+ }.not_to change(Spree::Brand, :count)
275
+ end
276
+
277
+ it 'returns unprocessable entity status' do
278
+ post :create, params: invalid_params
279
+ expect(response).to have_http_status(:unprocessable_content)
280
+ end
281
+ end
282
+ end
283
+
284
+ describe 'GET #edit' do
285
+ let(:brand) { create(:brand) }
286
+
287
+ it 'returns a successful response' do
288
+ get :edit, params: { id: brand.id }
289
+ expect(response).to be_successful
290
+ end
291
+ end
292
+
293
+ describe 'PUT #update' do
294
+ let(:brand) { create(:brand, name: 'Old Name') }
295
+
296
+ context 'with valid params' do
297
+ it 'updates the brand' do
298
+ put :update, params: { id: brand.id, brand: { name: 'New Name' } }
299
+ expect(brand.reload.name).to eq('New Name')
300
+ end
301
+
302
+ it 'redirects to the edit page' do
303
+ put :update, params: { id: brand.id, brand: { name: 'New Name' } }
304
+ expect(response).to redirect_to(spree.edit_admin_brand_path(brand))
305
+ end
306
+ end
307
+ end
308
+
309
+ describe 'DELETE #destroy' do
310
+ let!(:brand) { create(:brand) }
311
+
312
+ it 'removes the brand from the database' do
313
+ expect {
314
+ delete :destroy, params: { id: brand.id }, format: :html
315
+ }.to change(Spree::Brand, :count).by(-1)
316
+ end
317
+ end
318
+ end
319
+ ```
320
+
321
+ ### Storefront Controller Tests
322
+
323
+ ```ruby spec/controllers/spree/brands_controller_spec.rb
324
+ require 'rails_helper'
325
+
326
+ RSpec.describe Spree::Brand, type: :model do
327
+ describe 'associations' do
328
+ it 'has many products' do
329
+ association = described_class.reflect_on_association(:products)
330
+ expect(association.macro).to eq(:has_many)
331
+ expect(association.class_name).to eq('Spree::Product')
332
+ end
333
+ end
334
+
335
+ describe 'validations' do
336
+ it 'validates presence of name' do
337
+ brand = build(:brand, name: nil)
338
+ expect(brand).not_to be_valid
339
+ expect(brand.errors[:name]).to include("can't be blank")
340
+ end
341
+
342
+ describe 'slug uniqueness' do
343
+ let!(:existing_brand) { create(:brand, slug: 'nike') }
344
+
345
+ it 'validates uniqueness of slug' do
346
+ brand = build(:brand, slug: 'nike')
347
+ expect(brand).not_to be_valid
348
+ expect(brand.errors[:slug]).to include('has already been taken')
349
+ end
350
+ end
351
+ end
352
+
353
+ describe 'FriendlyId' do
354
+ it 'generates slug from name' do
355
+ brand = create(:brand, name: 'Nike Sportswear', slug: nil)
356
+ expect(brand.slug).to eq('nike-sportswear')
357
+ end
358
+
359
+ it 'handles duplicate names by appending UUID' do
360
+ create(:brand, name: 'Nike', slug: 'nike')
361
+ brand = create(:brand, name: 'Nike', slug: nil)
362
+ expect(brand.slug).to match(/nike-[a-f0-9-]+/)
363
+ end
364
+ end
365
+
366
+ describe '#image' do
367
+ let(:brand) { create(:brand, :with_logo) }
368
+
369
+ it 'returns logo as image for Open Graph' do
370
+ expect(brand.image).to eq(brand.logo)
371
+ end
372
+ end
373
+ end
374
+ ```
375
+
376
+ ## Writing Feature Tests
377
+
378
+ Feature tests (also called system tests) simulate real user interactions using Capybara.
379
+
380
+ ### Admin Feature Tests
381
+
382
+ ```ruby spec/features/spree/admin/brands_spec.rb
383
+ require 'rails_helper'
384
+
385
+ RSpec.feature 'Admin Brands', type: :feature do
386
+ stub_authorization!
387
+
388
+ describe 'listing brands' do
389
+ let!(:brand1) { create(:brand, name: 'Nike') }
390
+ let!(:brand2) { create(:brand, name: 'Adidas') }
391
+
392
+ it 'displays all brands' do
393
+ visit spree.admin_brands_path
394
+
395
+ expect(page).to have_content('Nike')
396
+ expect(page).to have_content('Adidas')
397
+ end
398
+ end
399
+
400
+ describe 'creating a brand' do
401
+ it 'creates a new brand successfully' do
402
+ visit spree.admin_brands_path
403
+ click_on 'New Brand'
404
+
405
+ fill_in 'Name', with: 'Puma'
406
+ fill_in 'Slug', with: 'puma'
407
+
408
+ click_on 'Create'
409
+ wait_for_turbo
410
+
411
+ expect(page).to have_content('Brand "Puma" has been successfully created!')
412
+ expect(Spree::Brand.find_by(name: 'Puma')).to be_present
413
+ end
414
+
415
+ it 'shows validation errors' do
416
+ visit spree.new_admin_brand_path
417
+
418
+ click_on 'Create'
419
+ wait_for_turbo
420
+
421
+ expect(page).to have_content("can't be blank")
422
+ end
423
+ end
424
+
425
+ describe 'editing a brand' do
426
+ let!(:brand) { create(:brand, name: 'Nike') }
427
+
428
+ it 'updates the brand successfully' do
429
+ visit spree.admin_brands_path
430
+ click_on 'Edit'
431
+
432
+ fill_in 'Name', with: 'Nike Inc.'
433
+ within('#page-header') { click_button 'Update' }
434
+
435
+ wait_for_turbo
436
+ expect(page).to have_content('Brand "Nike Inc." has been successfully updated!')
437
+ expect(brand.reload.name).to eq('Nike Inc.')
438
+ end
439
+ end
440
+
441
+ describe 'deleting a brand' do
442
+ let!(:brand) { create(:brand, name: 'Nike') }
443
+
444
+ it 'removes the brand' do
445
+ expect {
446
+ page.driver.submit :delete, spree.admin_brand_path(brand), {}
447
+ }.to change(Spree::Brand, :count).by(-1)
448
+ end
449
+ end
450
+ end
451
+ ```
452
+
453
+ ## Test Helpers
454
+
455
+ ### Authorization Helper
456
+
457
+ Use `stub_authorization!` to bypass authorization checks in admin tests:
458
+
459
+ ```ruby
460
+ RSpec.describe Spree::Admin::BrandsController, type: :controller do
461
+ stub_authorization! # Grants full admin access
462
+
463
+ # ... your tests
464
+ end
465
+ ```
466
+
467
+ ### wait\_for\_turbo Helper
468
+
469
+ When testing with Turbo/Hotwire, use `wait_for_turbo` to ensure the page has fully loaded:
470
+
471
+ ```ruby
472
+ click_on 'Create'
473
+ wait_for_turbo
474
+ expect(page).to have_content('Success!')
475
+ ```
476
+
477
+ ## Running Tests
478
+
479
+ ```bash
480
+ # Run all tests
481
+ bundle exec rspec
482
+
483
+ # Run specific test file
484
+ bundle exec rspec spec/models/spree/brand_spec.rb
485
+
486
+ # Run specific test
487
+ bundle exec rspec spec/models/spree/brand_spec.rb:15
488
+
489
+ # Run with documentation format
490
+ bundle exec rspec --format documentation
491
+
492
+ # Run only feature tests
493
+ bundle exec rspec spec/features/
494
+ ```
495
+
496
+ ## Best Practices
497
+
498
+
499
+ - **Use build over create** — Use `build` instead of `create` when you don't need a persisted record. It's faster because it skips database operations.
500
+
501
+ - **Use let over instance variables** — Prefer `let` and `let!` over instance variables. They're lazily evaluated and scoped to each example.
502
+
503
+ - **One assertion per test** — Keep tests focused on a single behavior. Use `aggregate_failures` if you need multiple assertions.
504
+
505
+ - **Test behavior, not implementation** — Focus on what the code does, not how it does it. This makes tests more resilient to refactoring.
506
+
507
+
508
+ ### Example: aggregate\_failures
509
+
510
+ ```ruby
511
+ it 'creates brand with all attributes', :aggregate_failures do
512
+ brand = create(:brand, name: 'Nike')
513
+
514
+ expect(brand.name).to eq('Nike')
515
+ expect(brand.slug).to eq('nike')
516
+ end
517
+ ```
518
+
519
+ ## Complete Test Suite Structure
520
+
521
+ After completing this tutorial, your test structure should look like:
522
+
523
+ ```
524
+ spec/
525
+ ├── factories/
526
+ │ └── spree/
527
+ │ ├── brand_factory.rb
528
+ │ └── brands.rb
529
+ ├── models/
530
+ │ └── spree/
531
+ │ ├── brand_spec.rb
532
+ │ └── product_decorator_spec.rb
533
+ ├── controllers/
534
+ │ └── spree/
535
+ │ ├── admin/
536
+ │ │ └── brands_controller_spec.rb
537
+ │ └── brands_controller_spec.rb
538
+ ├── features/
539
+ │ └── spree/
540
+ │ └── admin/
541
+ │ └── brands_spec.rb
542
+ ├── support/
543
+ │ └── (various support files)
544
+ ├── rails_helper.rb
545
+ └── spec_helper.rb
546
+ ```
547
+
548
+ ## Related Documentation
549
+
550
+ * [Model Tutorial](/developer/tutorial/model) - Creating the Brand model
551
+ * [Admin Tutorial](/developer/tutorial/admin) - Building the admin interface
552
+ * [Extending Core Models](/developer/tutorial/extending-models) - Connecting Brands to Products
553
+ * [Storefront Tutorial](/developer/tutorial/storefront) - Creating storefront pages
554
+ * [RSpec Documentation](https://rspec.info/documentation/) - Official RSpec docs
555
+ * [Factory Bot Documentation](https://github.com/thoughtbot/factory_bot/blob/main/GETTING_STARTED.md) - Factory Bot guide
556
+
557
+
558
+ ---
@@ -0,0 +1,46 @@
1
+ ---
2
+ title: 2.0 to 2.1
3
+ description: 'This guide covers upgrading a 2.0 Spree store, to a 2.1 store.'
4
+ ---
5
+
6
+ ## Overview
7
+
8
+ This guide has been written from the perspective of a blank Spree 2.0 store with no extensions.
9
+
10
+ If you have extensions that your store depends on, you will need to manually verify that each of those extensions works within your 2.1 store once this upgrade is complete. Typically, extensions that are compatible with this version of Spree will have a 2-1-stable branch.
11
+
12
+ This is the first Spree release that supports Rails 4 exclusively. Spree releases after this point will continue to support Rails 4 only.
13
+
14
+ ## Upgrade Rails
15
+
16
+ For this Spree release, you will need to upgrade your Rails version to at least 4.0.0.
17
+
18
+ It is recommended to read through the [Upgrading Ruby on Rails guide](http://guides.rubyonrails.org/upgrading_ruby_on_rails.html#upgrading-%20from-rails-3-2-to-rails-4-0) to learn what needs to be done for your application to migrate to Rails 4.
19
+
20
+ ```ruby
21
+ gem 'rails', '~> 4.0'
22
+ ```
23
+
24
+ ## Upgrade Spree
25
+
26
+ For best results, use the 2-1-stable branch from GitHub:
27
+
28
+ ```ruby
29
+ gem 'spree', '~> 2.1'
30
+ ```
31
+
32
+ Run `bundle update spree`.
33
+
34
+ ## Copy and run migrations
35
+
36
+ Copy over the migrations from Spree (and any other engine) and run them using
37
+ these commands:
38
+
39
+ ```bash
40
+ rake railties:install:migrations
41
+ rake db:migrate
42
+ ```
43
+
44
+ ## Read the release notes
45
+
46
+ For information about changes contained with this release, please read the [2.1.0 Release Notes](https://github.com/spree/spree/releases/tag/v2.1.0).
@@ -0,0 +1,59 @@
1
+ ---
2
+ title: 2.1 to 2.2
3
+ section: upgrades
4
+ description: 'This guide covers upgrading a 2.1 Spree store, to a 2.2 store.'
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ This guide has been written from the perspective of a blank Spree 2.1 store with no extensions.
10
+
11
+ If you have extensions that your store depends on, you will need to manually verify that each of those extensions works within your 2.2 store once this upgrade is complete. Typically, extensions that are compatible with this version of Spree will have a 2-2-stable branch.
12
+
13
+ ## Upgrade Rails
14
+
15
+ For this Spree release, you will need to upgrade your Rails version to at least 4.0.6.
16
+
17
+ ```ruby
18
+ gem 'rails', '~> 4.0.6'
19
+ ```
20
+
21
+ ## Upgrade Spree
22
+
23
+ For best results, use the 2-2-stable branch from GitHub:
24
+
25
+ ```ruby
26
+ gem 'spree', '~> 2.2'
27
+ ```
28
+
29
+ Run `bundle update spree`.
30
+
31
+ ## Copy and run migrations
32
+
33
+ Copy over the migrations from Spree (and any other engine) and run them using
34
+ these commands:
35
+
36
+ ```bash
37
+ rake railties:install:migrations
38
+ ```
39
+
40
+ ```bash
41
+ rake db:migrate
42
+ ```
43
+
44
+ ## Read the release notes
45
+
46
+ For information about changes contained with this release, please read the [2.2.0 Release Notes](http://guides.spreecommerce.org/release_notes/spree_2_2_0.html).
47
+
48
+ ### Rename assets
49
+
50
+ As mentioned in the release notes, asset paths have changed. Change the references on the left, to the ones on the right:
51
+
52
+ * `admin/spree_backend` => `spree/backend`
53
+ * `store/spree_frontend` => `spree/frontend`
54
+
55
+ This applies across the board on Spree, and may need to be done in your store's extensions.
56
+
57
+ ### Paperclip settings have been removed from master
58
+
59
+ Please consult [this section](http://guides.spreecommerce.org/release_notes/spree_2_2_0.html#paperclip-settings-have-been-removed) of the release notes if you were using custom Paperclip settings. This will direct you what to do in that particular case.
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: 2.2 to 2.3
3
+ description: 'This guide covers upgrading a 2.2 Spree store, to a 2.3 store.'
4
+ ---
5
+
6
+ ## Overview
7
+
8
+ This guide has been written from the perspective of a blank Spree 2.2 store with no extensions.
9
+
10
+ If you have extensions that your store depends on, you will need to manually verify that each of those extensions works within your 2.3 store once this upgrade is complete. Typically, extensions that are compatible with this version of Spree will have a 2-3-stable branch.
11
+
12
+ This is the first Spree release that supports Rails 4.1.
13
+
14
+ ## Upgrade Rails
15
+
16
+ For this Spree release, you will need to upgrade your Rails version to at least 4.1.2.
17
+
18
+ ```ruby
19
+ gem 'rails', '~> 4.1.2'
20
+ ```
21
+
22
+ ## Upgrade Spree
23
+
24
+ For best results, use the 2-3-stable branch from GitHub:
25
+
26
+ ```ruby
27
+ gem 'spree', '~> 2.3'
28
+ ```
29
+
30
+ Run `bundle update spree`.
31
+
32
+ ## Copy and run migrations
33
+
34
+ Copy over the migrations from Spree (and any other engine) and run them using
35
+ these commands:
36
+
37
+ ```bash
38
+ rake railties:install:migrations
39
+ rake db:migrate
40
+ ```
41
+
42
+ ## Read the release notes
43
+
44
+ For information about changes contained with this release, please read the [2.3.0 Release Notes](https://github.com/spree/spree/releases/tag/v2.3.0).