spree-testing

Test Spree applications and extensions with RSpec — `spree_dev_tools` gem (v5.2+) for factories and helpers, FactoryBot patterns (prefer `build` over `create`), Capybara feature specs, controller/request specs, testing decorators and subscribers, dummy app for extension testing, system specs for the Hotwire admin, and CI patterns. Use when writing Spree tests, setting up CI, or refactoring slow specs.

17 stars

Best use case

spree-testing is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Test Spree applications and extensions with RSpec — `spree_dev_tools` gem (v5.2+) for factories and helpers, FactoryBot patterns (prefer `build` over `create`), Capybara feature specs, controller/request specs, testing decorators and subscribers, dummy app for extension testing, system specs for the Hotwire admin, and CI patterns. Use when writing Spree tests, setting up CI, or refactoring slow specs.

Teams using spree-testing should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/spree-testing/SKILL.md --create-dirs "https://raw.githubusercontent.com/OrcaQubits/agentic-commerce-skills-plugins/main/dist/antigravity/spree-commerce/.agent/skills/spree-testing/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/spree-testing/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How spree-testing Compares

Feature / Agentspree-testingStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Test Spree applications and extensions with RSpec — `spree_dev_tools` gem (v5.2+) for factories and helpers, FactoryBot patterns (prefer `build` over `create`), Capybara feature specs, controller/request specs, testing decorators and subscribers, dummy app for extension testing, system specs for the Hotwire admin, and CI patterns. Use when writing Spree tests, setting up CI, or refactoring slow specs.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# Spree Testing

## Before writing code

**Fetch live docs**:
1. Fetch https://spreecommerce.org/docs/developer/tutorial/testing for the canonical testing tutorial.
2. Check the `spree_dev_tools` gem on RubyGems and GitHub for the current factory inventory and helpers.
3. Inspect the Spree gem's own `spec/` directory for the latest test patterns.
4. Cross-reference Rails 7+ testing docs for current request/system spec patterns.
5. For RSpec, FactoryBot, Capybara — check current gem versions vs your Spree's Gemfile.lock.

## Conceptual Architecture

### The Testing Stack

| Tool | Purpose |
|------|---------|
| **RSpec** | Test framework |
| **FactoryBot** | Test data factories |
| **Capybara** | Feature/system specs (browser-driven) |
| **`spree_dev_tools`** (v5.2+) | Spree-specific factories, shared examples, helpers |
| **Selenium / Cuprite** | Headless browser for system specs |
| **Sidekiq Testing** | Background job assertions |
| **VCR / WebMock** | Stub external APIs |

### `spree_dev_tools` (v5.2+)

Formally introduced in v5.2 as a separate gem (was previously bundled). Provides:
- Pre-built factories for every Spree model (`Spree::Order`, `Spree::Product`, `Spree::User`, etc.)
- Shared examples for common test patterns
- Helpers for creating realistic test scenarios (`create_order_with_two_items`, etc.)
- Engine spec setup for extension testing

```ruby
# Gemfile
group :development, :test do
  gem 'spree_dev_tools'
end
```

### Spec Types

| Type | What it tests |
|------|---------------|
| **Model spec** | A model's methods, validations, associations |
| **Request spec** | HTTP request → response, including auth |
| **Controller spec** | (Legacy — Rails 5+ prefers request specs) |
| **Feature spec** | User behavior via Capybara |
| **System spec** | Like feature but with full Rails 5.1+ integration |
| **Job spec** | Background job logic |
| **Mailer spec** | Email content |
| **Subscriber spec** | Event subscriber assertions |

### `build` vs `create`

```ruby
# Slow — hits the database
let(:product) { create(:product) }

# Fast — in-memory only
let(:product) { build(:product) }

# Stub — fastest, no validation
let(:product) { build_stubbed(:product) }
```

Use `build` when you only need the object to call methods. Reach for `create` only when you need persistence (`find_by`, foreign keys, callbacks that hit the DB).

### Common Factories

```ruby
create(:product)                     # basic product
create(:product, name: 'Foo')        # with overrides
create(:product_in_stock)            # has stock
create(:order_with_line_items, line_items_count: 3)
create(:order_ready_to_complete)
create(:completed_order_with_pending_payment)
create(:user_with_addresses)
create(:admin_user)                   # has admin role
```

Verify the actual factory names against the `spree_dev_tools` source.

### Testing a Decorator

```ruby
# spec/models/spree/product_decorator_spec.rb
require 'rails_helper'

RSpec.describe Spree::Product, type: :model do
  describe 'editor_pick scope' do
    let!(:pick) { create(:product, editor_pick: true) }
    let!(:other) { create(:product, editor_pick: false) }

    it 'returns only editor-picked products' do
      expect(Spree::Product.editor_picks).to contain_exactly(pick)
    end
  end

  describe '#display_name' do
    let(:product) { build(:product, seo_title: 'Premium Tee', name: 'Tee') }

    it 'prefers seo_title' do
      expect(product.display_name).to eq('Premium Tee')
    end
  end
end
```

### Testing a Subscriber

```ruby
# spec/subscribers/order_completed_subscriber_spec.rb
require 'rails_helper'

RSpec.describe OrderCompletedSubscriber do
  let(:order) { create(:order, state: 'complete') }

  it 'enqueues an accounting sync' do
    expect {
      Spree::Bus.publish('order.completed', order: order, user: order.user)
    }.to have_enqueued_job(AccountingSyncJob).with(order_id: order.id)
  end
end
```

### Testing a Service / Dependency Override

```ruby
RSpec.describe MyApp::CartAddItemService do
  let(:order)   { create(:order) }
  let(:variant) { create(:variant) }

  it 'adds an item with extra metadata' do
    service = described_class.new
    result = service.call(order: order, variant: variant, quantity: 1, options: { source: 'app' })

    expect(result).to be_a(Spree::LineItem)
    expect(result.metafields.find_by(key: 'source').value).to eq('app')
  end
end
```

### Feature/System Specs (Hotwire-aware)

Spree v5 admin uses Hotwire/Turbo. System specs need a JS driver:

```ruby
# spec/system/admin/products_spec.rb
require 'rails_helper'

RSpec.describe 'Admin products', type: :system do
  let(:admin) { create(:admin_user) }
  before { sign_in admin; driven_by(:cuprite) }   # or :selenium_chrome_headless

  it 'creates a product' do
    visit spree.admin_products_path
    click_on 'New Product'
    fill_in 'Name', with: 'Test Product'
    fill_in 'Price', with: '19.99'
    click_on 'Create'
    expect(page).to have_content('Test Product')
  end
end
```

### Testing API v3 Endpoints

```ruby
RSpec.describe 'Store API v3 products', type: :request do
  let(:store) { create(:store) }
  let(:api_key) { create(:publishable_api_key, store: store).key }
  let!(:product) { create(:product, stores: [store]) }

  it 'lists products' do
    get '/api/v3/store/products', headers: { 'Authorization' => "Bearer #{api_key}" }
    expect(response).to have_http_status(:ok)
    body = JSON.parse(response.body)
    expect(body['data'].first['id']).to start_with('prod_')
    expect(body['data'].first['name']).to eq(product.name)
  end
end
```

(Verify the factory name `:publishable_api_key` in current `spree_dev_tools`.)

### Testing With Sidekiq

```ruby
# config/initializers/sidekiq.rb in test env auto-uses InlineTesting
require 'sidekiq/testing'
Sidekiq::Testing.fake!   # default for specs

RSpec.describe 'webhook delivery' do
  it 'enqueues a delivery job on order.completed' do
    order = create(:order, state: 'complete')
    expect {
      Spree::Bus.publish('order.completed', order: order)
    }.to change(Spree::WebhookDeliveryJob.jobs, :size).by(1)
  end
end
```

(Verify the job class name in the current Webhooks 2.0 implementation.)

### Testing an Extension's Engine

Extensions test against a dummy Rails app:

```bash
cd spree_my_extension
bundle exec rake test_app  # generates spec/dummy
bundle exec rspec
```

The `test_app` rake task (verify it exists in current scaffolding) creates `spec/dummy` mounting Spree + your extension. Specs run against it.

### Mocking External APIs

```ruby
# spec/requests/stripe_webhook_spec.rb
RSpec.describe 'Stripe webhook', type: :request do
  it 'processes payment_intent.succeeded' do
    stub_request(:get, %r{api\.stripe\.com/v1/payment_intents})
      .to_return(body: { id: 'pi_…', status: 'succeeded' }.to_json)
    # ...
  end
end
```

WebMock is the standard; VCR is heavier-handed (records real responses to replay).

## Implementation Guidance

### Spec Suite Setup

```ruby
# spec/rails_helper.rb
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rspec/rails'
require 'capybara/rspec'
require 'sidekiq/testing'

Dir[Rails.root.join('spec/support/**/*.rb')].sort.each { |f| require f }

RSpec.configure do |config|
  config.use_transactional_fixtures = true
  config.infer_spec_type_from_file_location!
  config.filter_rails_from_backtrace!

  config.include FactoryBot::Syntax::Methods
  config.include Spree::TestingSupport::AuthorizationHelpers, type: :controller
  config.include Spree::TestingSupport::ControllerRequests, type: :controller
  config.include Spree::TestingSupport::Capybara, type: :feature
end
```

(Verify the exact testing-support modules — they evolve.)

### Speed Strategies

1. **Prefer `build` and `build_stubbed`** over `create`
2. **Don't load full Rails for unit-y specs** when possible
3. **Parallel test execution** — `parallel_tests` gem with N processes
4. **Skip image processing in tests** — `Spree::Config.image_processor = :stub` (verify config name)
5. **Limit `js: true`** to specs that genuinely need a browser
6. **Mock external HTTP** — every real request is a slow test

### CI Patterns

```yaml
# .github/workflows/ci.yml (sketch)
jobs:
  rspec:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: postgres
      redis:
        image: redis:7
    steps:
      - uses: actions/checkout@v4
      - uses: ruby/setup-ruby@v1
      - run: bundle install --jobs 4
      - run: bin/rails db:create db:migrate
      - run: bundle exec rspec --format progress
```

### Common Pitfalls

- **Using `create` everywhere** — specs take 10x longer than necessary.
- **Forgetting `Sidekiq::Testing.fake!`** — jobs fire synchronously and pollute specs.
- **System specs without `driven_by(:cuprite)` or similar** — Turbo events don't fire.
- **Stubbing `Spree::Order#total`** — breaks downstream service-object behavior; create the right line items instead.
- **Not testing decorators with the real model loaded** — autoloading order matters.
- **Brittle Capybara selectors** — use semantic selectors (`data-test-id`) not classes.
- **Forgetting to seed default Store / Country / Zone** — `spree_dev_tools` provides setup helpers; use them.

Always cross-reference the current `spree_dev_tools` factories and the Spree gem's own `spec/` for the canonical patterns for the version you target.

Related Skills

woo-testing

17
from OrcaQubits/agentic-commerce-skills-plugins

Test WooCommerce extensions — PHPUnit unit/integration tests, WP test suite, WooCommerce test helpers, E2E with Playwright, and WP-CLI test scaffolding. Use when writing tests for WooCommerce plugins or setting up a test environment.

webmcp-testing

17
from OrcaQubits/agentic-commerce-skills-plugins

Test WebMCP tools with AI agents — Chrome DevTools integration, agent testing workflows, tool discovery verification, and end-to-end commerce flow testing. Use when validating that tools work correctly with real AI agents.

spree-upgrades

17
from OrcaQubits/agentic-commerce-skills-plugins

Upgrade a Spree application — version-to-version migration paths (v4 → v5 is a major rewrite; v5.x → v5.y are simpler), Gemfile pinning strategy, decorator brittleness across versions, deprecated gems to remove (`spree_auth_devise`, `deface`, `spree_backend`), API v2 → v3 migration via `spree_legacy_api_v2`, admin Bootstrap → Tailwind transition, the upgrade guide workflow, and rollback strategy. Use when planning a Spree upgrade or auditing technical debt blocking one.

spree-typescript-sdk

17
from OrcaQubits/agentic-commerce-skills-plugins

Build storefronts and integrations using `@spree/sdk` — the official TypeScript SDK for Spree's API v3 (v5.4+). Covers installation, the resource-builder pattern (`spree.products.list`, `spree.checkout.create`, etc.), Zod schema validation, server-only auth (httpOnly JWTs, never exposing API keys), error handling, typing customizations, and pinning SDK versions to backend Spree releases. Use when integrating Spree into a Next.js / Node.js / TypeScript project.

spree-shipping-fulfillment

17
from OrcaQubits/agentic-commerce-skills-plugins

Build and customize Spree's shipping and fulfillment — ShippingMethod, ShippingCategory, Zone/ZoneMember, ShippingRate, the Stock::Estimator service, StockLocation/StockItem/StockMovement, multi-shipment orders, ShippingCalculator classes (FlatRate, FlatPercentItemTotal, PerItem, FlexiRate), shipment state machine, returns (ReturnAuthorization → CustomerReturn → Reimbursement → Refund), and integrating carrier APIs (UPS, FedEx, ShipStation). Use when configuring shipping rules, building fulfillment integrations, or debugging shipping-rate calculations.

spree-setup

17
from OrcaQubits/agentic-commerce-skills-plugins

Bootstrap a new Spree project — `create-spree-app` CLI (v5.2+), `spree-starter` Rails backend, the Next.js storefront repo, `bin/rails g spree:install`, sample data, Docker Compose, and the PostgreSQL + Redis + Sidekiq prerequisites. Use when starting a new Spree project from scratch or onboarding an existing repo.

spree-security

17
from OrcaQubits/agentic-commerce-skills-plugins

Secure a Spree deployment — Rails credentials and env-var hygiene, Devise auth (Spree v5 ships it in-core; `spree_auth_devise` is archived), CanCanCan authorization rules, Doorkeeper OAuth2 scopes, Storefront publishable key vs admin API key, webhook HMAC verification, OWASP Top 10 for Rails (mass assignment, CSRF, SQL injection via Ransack, XSS, IDOR through prefixed IDs), PCI scope (Spree never touches raw cards thanks to gateway tokenization), and multi-store data isolation. Use when auditing a Spree app, hardening a deploy, or addressing a security incident.

spree-promotions

17
from OrcaQubits/agentic-commerce-skills-plugins

Build and customize Spree's promotions engine — Promotion + PromotionRule + PromotionAction + CouponCode + Adjustment, the bundled rules (FirstOrder/ItemTotal/Product/Taxon/User/OneUsePerUser/Country/CustomerGroup/etc.), bundled actions (CreateAdjustment/CreateItemAdjustments/FreeShipping/CreateLineItems), Calculator classes, coupon batches with CSV export, the v5.1+ advanced rule-based engine, and authoring custom rules/actions/calculators. Use when modeling promotions, building discount UIs, or extending the promotions engine.

spree-performance

17
from OrcaQubits/agentic-commerce-skills-plugins

Profile and optimize a Spree application — N+1 queries with bullet/scout, database indexing strategy for Spree's polymorphic associations, Rails fragment + Russian doll caching, ActiveStorage variant pre-generation, Sidekiq queue tuning, MeiliSearch vs Postgres FTS tradeoffs, Puma worker/thread sizing, CDN strategy for catalog pages, asset precompile time, and load testing. Use when Spree is slow, the database is hot, or you're preparing for a traffic spike (Black Friday, launch).

spree-payments

17
from OrcaQubits/agentic-commerce-skills-plugins

Integrate payment gateways with Spree — PaymentMethod model, the v5.4+ PaymentSession provider-agnostic checkout flow, Stripe via `spree_stripe` (Apple/Google Pay, Link, Connect for marketplaces), Adyen via `spree_adyen`, PayPal via `spree_paypal_checkout`, StoreCredit / GiftCard as payment methods, refunds, payment state machine, and authoring a custom gateway. Use when wiring a payment integration, handling webhooks from a gateway, or debugging payment-state issues.

spree-multi-store

17
from OrcaQubits/agentic-commerce-skills-plugins

Configure Spree for multi-store and multi-region commerce — one Rails install running many `Store` records, the v5.4+ `Market` model (currency + locale + payment methods + shipping per region), what's shared vs per-store (products+inventory+customers shared; orders+payments+themes per-store), the Marketplace module (Enterprise — vendors/commission/payouts via Stripe Connect), and the Multi-tenant SaaS model. Use when planning a multi-brand or multi-region Spree deployment.

spree-legacy-api-v2

17
from OrcaQubits/agentic-commerce-skills-plugins

Work with Spree's legacy v2 APIs — JSON:API-style Storefront API at `/api/v2/storefront/*` and Platform API at `/api/v2/platform/*`, Doorkeeper OAuth2 (password grant for storefront, client_credentials + admin scope for platform), the `spree_legacy_api_v2` gem (required in v5+ for backward compatibility), and migration patterns to API v3. Use when maintaining a v2 client during a migration window, integrating an older partner system, or deciding when to cut over to v3.