@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.
- package/README.md +54 -0
- package/dist/api-reference/platform/authentication.md +38 -0
- package/dist/api-reference/store-api/authentication.md +188 -0
- package/dist/api-reference/store-api/errors.md +277 -0
- package/dist/api-reference/store-api/idempotency.md +129 -0
- package/dist/api-reference/store-api/introduction.md +34 -0
- package/dist/api-reference/store-api/localization.md +279 -0
- package/dist/api-reference/store-api/metadata.md +160 -0
- package/dist/api-reference/store-api/monetary-amounts.md +65 -0
- package/dist/api-reference/store-api/querying.md +399 -0
- package/dist/api-reference/store-api/rate-limitting.md +103 -0
- package/dist/api-reference/store-api/relations.md +185 -0
- package/dist/api-reference/storefront/authentication.md +88 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-android.md +165 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-ios.md +194 -0
- package/dist/api-reference/tutorials/quick-checkout-with-stripe.md +248 -0
- package/dist/api-reference/v2/fetching-multiple-resources.md +26 -0
- package/dist/api-reference/v2/filtering-and-sorting.md +53 -0
- package/dist/api-reference/v2/introduction.md +22 -0
- package/dist/api-reference/v2/pagination.md +37 -0
- package/dist/api-reference/webhooks-events.md +883 -0
- package/dist/developer/admin/admin.md +205 -0
- package/dist/developer/admin/authentication.md +59 -0
- package/dist/developer/admin/components.md +711 -0
- package/dist/developer/admin/custom-css.md +243 -0
- package/dist/developer/admin/custom-javascript.md +116 -0
- package/dist/developer/admin/extending-ui.md +1964 -0
- package/dist/developer/admin/form-builder.md +444 -0
- package/dist/developer/admin/helper-methods.md +531 -0
- package/dist/developer/admin/navigation.md +805 -0
- package/dist/developer/admin/tables.md +491 -0
- package/dist/developer/advanced/adding_spree_to_rails_app.md +106 -0
- package/dist/developer/cli/quickstart.md +137 -0
- package/dist/developer/contributing/creating-an-extension.md +258 -0
- package/dist/developer/contributing/developing-spree.md +339 -0
- package/dist/developer/contributing/quickstart.md +32 -0
- package/dist/developer/contributing/updating-extensions.md +67 -0
- package/dist/developer/core-concepts/addresses.md +265 -0
- package/dist/developer/core-concepts/adjustments.md +107 -0
- package/dist/developer/core-concepts/architecture.md +177 -0
- package/dist/developer/core-concepts/calculators.md +323 -0
- package/dist/developer/core-concepts/customers.md +230 -0
- package/dist/developer/core-concepts/events.md +624 -0
- package/dist/developer/core-concepts/imports-exports.md +698 -0
- package/dist/developer/core-concepts/inventory.md +191 -0
- package/dist/developer/core-concepts/markets.md +250 -0
- package/dist/developer/core-concepts/media.md +167 -0
- package/dist/developer/core-concepts/metafields.md +187 -0
- package/dist/developer/core-concepts/orders.md +328 -0
- package/dist/developer/core-concepts/payments.md +710 -0
- package/dist/developer/core-concepts/pricing.md +163 -0
- package/dist/developer/core-concepts/products.md +360 -0
- package/dist/developer/core-concepts/promotions.md +322 -0
- package/dist/developer/core-concepts/reports.md +206 -0
- package/dist/developer/core-concepts/search-filtering.md +237 -0
- package/dist/developer/core-concepts/shipments.md +212 -0
- package/dist/developer/core-concepts/slugs.md +111 -0
- package/dist/developer/core-concepts/staff-roles.md +123 -0
- package/dist/developer/core-concepts/store-credits-gift-cards.md +317 -0
- package/dist/developer/core-concepts/stores.md +117 -0
- package/dist/developer/core-concepts/taxes.md +135 -0
- package/dist/developer/core-concepts/translations.md +120 -0
- package/dist/developer/core-concepts/users.md +299 -0
- package/dist/developer/core-concepts/webhooks.md +378 -0
- package/dist/developer/create-spree-app/quickstart.md +158 -0
- package/dist/developer/customization/api.md +93 -0
- package/dist/developer/customization/authentication.md +88 -0
- package/dist/developer/customization/checkout.md +204 -0
- package/dist/developer/customization/configuration.md +55 -0
- package/dist/developer/customization/decorators.md +523 -0
- package/dist/developer/customization/dependencies.md +232 -0
- package/dist/developer/customization/emails.md +21 -0
- package/dist/developer/customization/extensions.md +92 -0
- package/dist/developer/customization/metadata.md +236 -0
- package/dist/developer/customization/model-preferences.md +130 -0
- package/dist/developer/customization/permissions.md +265 -0
- package/dist/developer/customization/quickstart.md +229 -0
- package/dist/developer/customization/routes.md +24 -0
- package/dist/developer/customization/v4/admin-panel.md +78 -0
- package/dist/developer/customization/v4/authentication.md +210 -0
- package/dist/developer/customization/v4/checkout.md +212 -0
- package/dist/developer/customization/v4/deface.md +251 -0
- package/dist/developer/customization/v4/images.md +86 -0
- package/dist/developer/customization/v4/storefront.md +450 -0
- package/dist/developer/deployment/assets.md +87 -0
- package/dist/developer/deployment/aws.md +335 -0
- package/dist/developer/deployment/caching.md +27 -0
- package/dist/developer/deployment/cdn.md +39 -0
- package/dist/developer/deployment/database.md +155 -0
- package/dist/developer/deployment/docker.md +128 -0
- package/dist/developer/deployment/emails.md +77 -0
- package/dist/developer/deployment/environment_variables.md +111 -0
- package/dist/developer/deployment/heroku.md +51 -0
- package/dist/developer/deployment/render.md +95 -0
- package/dist/developer/getting-started/quickstart.md +82 -0
- package/dist/developer/how-to/custom-payment-method.md +374 -0
- package/dist/developer/how-to/custom-promotion.md +373 -0
- package/dist/developer/how-to/custom-report.md +387 -0
- package/dist/developer/how-to/custom-search-provider.md +230 -0
- package/dist/developer/multi-store/quickstart.md +71 -0
- package/dist/developer/multi-store/setup.md +38 -0
- package/dist/developer/multi-tenant/configuration.md +41 -0
- package/dist/developer/multi-tenant/core-concepts.md +75 -0
- package/dist/developer/multi-tenant/installation.md +96 -0
- package/dist/developer/multi-tenant/quickstart.md +20 -0
- package/dist/developer/multi-vendor/installation.md +45 -0
- package/dist/developer/multi-vendor/quickstart.md +17 -0
- package/dist/developer/sdk/admin/quickstart.md +22 -0
- package/dist/developer/sdk/authentication.md +89 -0
- package/dist/developer/sdk/configuration.md +225 -0
- package/dist/developer/sdk/quickstart.md +82 -0
- package/dist/developer/sdk/store/account.md +67 -0
- package/dist/developer/sdk/store/cart-checkout.md +140 -0
- package/dist/developer/sdk/store/markets.md +151 -0
- package/dist/developer/sdk/store/payments.md +96 -0
- package/dist/developer/sdk/store/products.md +149 -0
- package/dist/developer/sdk/store/wishlists.md +52 -0
- package/dist/developer/security/pci_compliance.md +15 -0
- package/dist/developer/security/security_policy.md +68 -0
- package/dist/developer/storefront/blocks.md +285 -0
- package/dist/developer/storefront/custom-css.md +260 -0
- package/dist/developer/storefront/custom-javascript.md +166 -0
- package/dist/developer/storefront/helper-methods.md +1288 -0
- package/dist/developer/storefront/links.md +298 -0
- package/dist/developer/storefront/nextjs/architecture.md +150 -0
- package/dist/developer/storefront/nextjs/customization.md +141 -0
- package/dist/developer/storefront/nextjs/deployment.md +180 -0
- package/dist/developer/storefront/nextjs/quickstart.md +92 -0
- package/dist/developer/storefront/nextjs/spree-next-package.md +314 -0
- package/dist/developer/storefront/pages.md +163 -0
- package/dist/developer/storefront/sections.md +569 -0
- package/dist/developer/storefront/storefront.md +56 -0
- package/dist/developer/storefront/themes.md +161 -0
- package/dist/developer/tutorial/admin.md +134 -0
- package/dist/developer/tutorial/extending-models.md +380 -0
- package/dist/developer/tutorial/file-uploads.md +121 -0
- package/dist/developer/tutorial/introduction.md +33 -0
- package/dist/developer/tutorial/model.md +41 -0
- package/dist/developer/tutorial/page-builder.md +487 -0
- package/dist/developer/tutorial/rich-text.md +73 -0
- package/dist/developer/tutorial/seo.md +332 -0
- package/dist/developer/tutorial/storefront.md +352 -0
- package/dist/developer/tutorial/testing.md +558 -0
- package/dist/developer/upgrades/2.0-to-2.1.md +46 -0
- package/dist/developer/upgrades/2.1-to-2.2.md +59 -0
- package/dist/developer/upgrades/2.2-to-2.3.md +44 -0
- package/dist/developer/upgrades/2.3-to-2.4.md +42 -0
- package/dist/developer/upgrades/3.0-to-3.1.md +47 -0
- package/dist/developer/upgrades/3.1-to-3.2.md +34 -0
- package/dist/developer/upgrades/3.2-to-3.3.md +70 -0
- package/dist/developer/upgrades/3.3-to-3.4.md +36 -0
- package/dist/developer/upgrades/3.4-to-3.5.md +44 -0
- package/dist/developer/upgrades/3.5-to-3.6.md +40 -0
- package/dist/developer/upgrades/3.6-to-3.7.md +62 -0
- package/dist/developer/upgrades/3.7-to-4.0.md +152 -0
- package/dist/developer/upgrades/4.0-to-4.1.md +92 -0
- package/dist/developer/upgrades/4.1-to-4.2.md +109 -0
- package/dist/developer/upgrades/4.10-to-5.0.md +129 -0
- package/dist/developer/upgrades/4.2-to-4.3.md +100 -0
- package/dist/developer/upgrades/4.3-to-4.4.md +125 -0
- package/dist/developer/upgrades/4.4-to-4.5.md +94 -0
- package/dist/developer/upgrades/4.5-to-4.6.md +119 -0
- package/dist/developer/upgrades/4.6-to-4.7.md +39 -0
- package/dist/developer/upgrades/4.8-to-4.9.md +24 -0
- package/dist/developer/upgrades/4.9-to-4.10.md +24 -0
- package/dist/developer/upgrades/4.x-to-4.8.md +52 -0
- package/dist/developer/upgrades/5.0-to-5.1.md +28 -0
- package/dist/developer/upgrades/5.1-to-5.2.md +127 -0
- package/dist/developer/upgrades/5.2-to-5.3.md +338 -0
- package/dist/developer/upgrades/5.3-to-5.4.md +248 -0
- package/dist/developer/upgrades/quickstart.md +36 -0
- package/dist/integrations/analytics/google-analytics.md +64 -0
- package/dist/integrations/analytics/google-tag-manager.md +78 -0
- package/dist/integrations/integrations.md +39 -0
- package/dist/integrations/marketing/klaviyo.md +99 -0
- package/dist/integrations/payments/adyen.md +90 -0
- package/dist/integrations/payments/paypal.md +41 -0
- package/dist/integrations/payments/razorpay.md +45 -0
- package/dist/integrations/payments/stripe.md +109 -0
- package/dist/integrations/search/meilisearch.md +236 -0
- package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +57 -0
- package/dist/integrations/sso-mfa-social-login/storefront.md +56 -0
- 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).
|