Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ PATH
measured (>= 2.0)
minitest (~> 5.14)
money-rails (~> 1.13)
mongoid (~> 7.4)
mongoid (>= 7.4, < 10)
mongoid-active_merchant (~> 0.2)
mongoid-audit_log (>= 0.6.0)
mongoid-document_path (~> 0.2)
Expand Down Expand Up @@ -122,7 +122,7 @@ PATH
capybara (~> 3.18)
launchy (~> 2.4.3)
minitest-retry (~> 0.1.5)
mocha (~> 1.3.0)
mocha (>= 1.3.0, < 3)
selenium-webdriver (~> 4.9.0)
teaspoon (~> 1.2.0)
teaspoon-mocha (~> 2.3.3)
Expand Down
5 changes: 4 additions & 1 deletion core/app/workers/sidekiq/callbacks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,10 @@ def set_workers(workers, action)
end
end

def run_callbacks(kind, *)
# Mongoid 8 changed run_callbacks to use keyword arguments (with_children: true).
# In Ruby 3.x keyword args and hash args are no longer interchangeable, so
# the splat must explicitly capture kwargs to pass them through to super.
def run_callbacks(kind, *args, **kwargs, &block)
result = super
_enqueue_callback_workers(kind) if result != false && kind != :find
result
Expand Down
19 changes: 19 additions & 0 deletions core/config/initializers/00_rails72_compat.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Rails 7.2 removed config.autoloader since Zeitwerk is now the only supported
# autoloader. The rails-decorators gem (workarea-commerce fork) checks
# Rails.configuration.autoloader == :zeitwerk in an after_initialize hook.
# Provide a shim so the check passes on Rails 7.2+ where the method is absent.
if Rails::VERSION::MAJOR > 7 || (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR >= 2)
unless Rails.application.config.respond_to?(:autoloader)
Rails.application.config.define_singleton_method(:autoloader) { :zeitwerk }
end

# ActiveRecord::SecureToken#has_secure_token (used in Workarea::UrlToken) calls
# ActiveRecord.generate_secure_token_on as a default argument in Rails 7.2+.
# This attribute is defined in active_record.rb but not in active_record/secure_token.rb.
# When ActiveRecord is loaded partially, define the attribute as a shim to avoid
# triggering a full require 'active_record' (which would cause AR test setup conflicts).
if defined?(ActiveRecord) && !ActiveRecord.respond_to?(:generate_secure_token_on)
ActiveRecord.singleton_class.attr_accessor :generate_secure_token_on
ActiveRecord.generate_secure_token_on = :create
end
end
9 changes: 8 additions & 1 deletion core/config/initializers/10_rack_middleware.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# Rails 7.2+ runs setup_main_autoloader (Zeitwerk) AFTER load_config_initializers,
# so constants from app/ directories are not yet autoloadable when this file runs.
# Explicitly require the Workarea middleware classes used below.
require "#{File.expand_path('../../../app/middleware/workarea/enforce_host_middleware', __FILE__)}"
require "#{File.expand_path('../../../app/middleware/workarea/application_middleware', __FILE__)}"
require "#{File.expand_path('../../../app/middleware/workarea/strip_http_caching_middleware', __FILE__)}"

app = Rails.application

# Mongoid query cache middleware — clears per-request Mongoid query cache.
# Mongoid::QueryCache::Middleware exists in Mongoid 7.x (pinned via gemspec).
# Mongoid 8+ delegates Mongoid::QueryCache::Middleware to Mongo::QueryCache::Middleware.
app.config.middleware.use(Mongoid::QueryCache::Middleware)
app.config.middleware.use(Workarea::Elasticsearch::QueryCache::Middleware)

Expand Down
37 changes: 30 additions & 7 deletions core/lib/tasks/tests.rake
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
load 'rails/test_unit/testing.rake'

# Rails 7.2 removed Rails::TestUnit::Runner.rake_run.
# Provide a compatibility shim so tests run on both Rails 7.x and 7.2+.
module WorkareaTestRunner
def self.run(test_paths)
if Rails::TestUnit::Runner.respond_to?(:rake_run)
# Rails < 7.2
Rails::TestUnit::Runner.rake_run(test_paths)
else
# Rails 7.2+: load test files directly and let Minitest autorun handle them.
test_files = Array(test_paths).flat_map do |path|
path_str = path.to_s
if File.directory?(path_str)
Dir.glob("#{path_str}/**/*_test.rb")
else
[path_str]
end
end
test_files.uniq.sort.each { |f| require File.expand_path(f) }
require "active_support/testing/autorun"
end
end
end

namespace :workarea do
task :prepare do
$: << 'test'
Expand All @@ -11,7 +34,7 @@ namespace :workarea do
Workarea::Plugin.installed.map(&:root) +
[Rails.root]

Rails::TestUnit::Runner.rake_run(
WorkareaTestRunner.run(
roots
.map { |r| FileList["#{r}/test/**/*_test.rb"] }
.reduce(&:+)
Expand All @@ -20,7 +43,7 @@ namespace :workarea do

desc 'Run workarea/core tests (with decorators)'
task 'test:core' => :prepare do
Rails::TestUnit::Runner.rake_run(["#{Workarea::Core::Engine.root}/test"])
WorkareaTestRunner.run(["#{Workarea::Core::Engine.root}/test"])
end

desc 'Run decorated tests'
Expand All @@ -33,7 +56,7 @@ namespace :workarea do
roots = [Workarea::Core::Engine.root] +
Workarea::Plugin.installed.map(&:root)

Rails::TestUnit::Runner.rake_run(
WorkareaTestRunner.run(
decorated.reduce([]) do |memo, relative_original|
original = roots
.map { |root| "#{root}/#{relative_original}" }
Expand All @@ -59,20 +82,20 @@ namespace :workarea do
%w(admin storefront).include?(engine.slug)
end.map(&:root)

Rails::TestUnit::Runner.rake_run(
WorkareaTestRunner.run(
engines.map { |r| FileList["#{r}/test/**/*_test.rb"] }.reduce(&:+) || []
)
end

desc 'Run all app specific tests'
task 'test:app' => :prepare do
Rails::TestUnit::Runner.rake_run(FileList["#{Rails.root}/test/**/*_test.rb"])
WorkareaTestRunner.run(FileList["#{Rails.root}/test/**/*_test.rb"])
end

Workarea::Plugin.installed.each do |engine|
desc "Run workarea #{engine.slug} tests (with decorators)"
task "test:#{engine.slug}" => :prepare do
Rails::TestUnit::Runner.rake_run(
WorkareaTestRunner.run(
FileList[engine.root.join('test', '**', '*', '*_test.rb')]
)
end
Expand All @@ -85,7 +108,7 @@ namespace :workarea do
[Rails.root]

ENV['PERF_TEST'] = 'true'
Rails::TestUnit::Runner.rake_run(
WorkareaTestRunner.run(
roots
.map { |r| FileList["#{r}/test/performance/**/*_test.rb"] }
.reduce(&:+)
Expand Down
25 changes: 22 additions & 3 deletions core/lib/workarea/url_token.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,38 @@
# Workarea::UrlToken
#
# Provides a URL-safe random token field for Mongoid documents.
#
# Previously this included ActiveRecord::SecureToken, but Rails 7.2 changed
# has_secure_token to call query_attribute() inside the generated callback.
# query_attribute is ActiveRecord-only and does not exist on Mongoid documents,
# causing a NoMethodError on every model that included this concern.
#
# The implementation below reproduces the same interface without depending on
# ActiveRecord::SecureToken.
module Workarea::UrlToken
extend ActiveSupport::Concern

include ActiveRecord::SecureToken

included do
field :token, type: String
index({ token: 1 }, { unique: true })
has_secure_token
before_validation :ensure_token_exists
end

module ClassMethods
def find_by_token(token)
find_by(token: token) rescue nil
end

# Mimics ActiveRecord::SecureToken.generate_unique_secure_token
def generate_unique_secure_token(length: 24)
require 'active_support/core_ext/securerandom'
SecureRandom.base58(length)
end
end

# Mimics the regenerate_<attribute> method generated by has_secure_token
def regenerate_token
update!(token: self.class.generate_unique_secure_token)
end

private
Expand Down
2 changes: 1 addition & 1 deletion core/workarea-core.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Gem::Specification.new do |s|

s.add_dependency 'bundler', '>= 1.8.0' # 1.8.0 added env variable for secrets
s.add_dependency 'rails', '>= 6.1', '< 7.3'
s.add_dependency 'mongoid', '~> 7.4' # loosened from ~> 7.4.0; mongoid 8 needed for Rails 7 (BLOCKER)
s.add_dependency 'mongoid', '>= 7.4', '< 10' # loosened from ~> 7.4; allows mongoid 8/9 for Rails 7.2+ compat
s.add_dependency 'bcrypt', '~> 3.1' # loosened from ~> 3.1.10
s.add_dependency 'money-rails', '~> 1.13' # loosened from ~> 1.13.0
s.add_dependency 'mongoid-audit_log', '>= 0.6.0'
Expand Down
149 changes: 149 additions & 0 deletions docs/verification/rails72-test-suite-results.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Rails 7.2 Test Suite Results

**Issue:** #768 — Rails 7.2: add appraisal + run test suite under rails_7_2.gemfile
**Branch:** `wa-rails72-test-suite-appraisal`
**Date:** 2026-03-05
**Environment:** Ruby 3.2.7 (rbenv), Rails 7.2.3, Mongoid 8.1, macOS arm64

---

## Environment

| Service | Version / Status |
|---------------|----------------------------|
| Ruby | 3.2.7 (rbenv) |
| Rails | 7.2.3 (via rails_7_2.gemfile) |
| Mongoid | 8.1.x (upgraded from 7.x) |
| Rack | 2.2.x (pinned) |
| Mocha | 2.x |
| MongoDB | ✅ Running (Docker) |
| Elasticsearch | ✅ Running (Docker) |
| Redis | ✅ Running (Docker) |

---

## Gemfile Status

`gemfiles/rails_7_2.gemfile` — **exists and locked** (added in forward-compat assessment PR #769).

Key pins required for Rails 7.2 + Mongoid 8 compatibility:
```ruby
gem 'rails', '~> 7.2.0'
gem 'mongoid', '~> 8.1' # mongoid 7.x requires activemodel < 7.1
gem 'rack', '~> 2.2' # serviceworker-rails 0.6.0 uses rack/file removed in Rack 3
gem 'mocha', '~> 2.0' # mocha 1.3.0 uses deprecated MiniTest constant
```

Boot-time compatibility fixes were applied in commit `4c66becf`:
- Loosen mongoid constraint: `~> 7.4` → `>= 7.4, < 10`
- Loosen mocha constraint: `~> 1.3.0` → `>= 1.3.0, < 3`
- Guard `mocha/mini_test` → `mocha/minitest` rename (mocha 2.x)
- Guard `perform_enqueued_jobs` calls (removed from SidekiqAdapter in Rails 7.2)
- Rails 7.2 compat initializer for boot-time issues

---

## Test Results (Sampled Run — Core Engine)

> **Note:** Full suite (435 test files in core, 179 admin, 119 storefront) requires a 60-90 minute CI run.
> This report covers a representative sample of 13 test files run individually.
>
> **RAILS_ENV propagation issue (#783)** prevents reliable `rake test` invocation from engine root.
> Tests were run via: `bundle exec ruby -Itest <test_file>` from the `core/` directory.

### Passing Tests (Core Engine Sample)

| Test File | Runs | Assertions | Failures | Errors |
|-----------|------|-----------|---------|--------|
| `test/models/workarea/checkout_test.rb` | 19 | 110 | 0 | 0 |
| `test/models/workarea/content_test.rb` | 2 | 3 | 0 | 0 |
| `test/models/workarea/order_test.rb` | 14 | 60 | 0 | 0 |
| `test/models/workarea/fulfillment_test.rb` | 16 | 38 | 0 | 0 |
| `test/models/workarea/pricing/sku_test.rb` | 4 | 8 | 0 | 0 |
| `test/workers/workarea/bulk_index_products_test.rb` | 1 | 2 | 0 | 0 |
| `test/workers/workarea/clean_orders_test.rb` | 1 | 10 | 0 | 0 |
| `test/workers/workarea/generate_insights_test.rb` | 2 | 6 | 0 | 0 |
| `test/integration/workarea/authentication_test.rb` | 9 | 45 | 0 | 0 |
| `test/integration/workarea/monitoring_integration_test.rb` | 6 | 12 | 0 | 0 |
| **Subtotal (passing)** | **74** | **294** | **0** | **0** |

### Failing Tests (Core Engine Sample)

| Test File | Runs | Failures | Errors | Issue |
|-----------|------|---------|--------|-------|
| `test/models/workarea/catalog/product_test.rb` | 13 | 1 | 0 | #788 |
| `test/models/workarea/user_test.rb` | 24 | 1 | 0 | #789 |
| `test/integration/workarea/cache_varies_integration_test.rb` | 2 | 0 | 2 | #787 |
| **Subtotal (failing)** | **39** | **2** | **2** | — |

**Sample total: 113 runs, 2 failures, 2 errors (96.5% pass rate in sampled files)**

---

## Failure Details

### 1. `Rack::Cache` Uninitialized Constant (Issue #787)

```
NameError: uninitialized constant Rack::Cache
test/integration/workarea/cache_varies_integration_test.rb:55
```

**Root cause:** Under Rails 7.2 + `rack ~> 2.2`, `rack-cache` gem is not auto-required.
**Fix:** Add `require 'rack/cache'` to the test file.

---

### 2. Slug Caching Mismatch in `Catalog::ProductTest` (Issue #788)

```
Failure: Workarea::Catalog::ProductTest#test_slug_caching
Expected: "different-slug"
Actual: "same-slug"
```

**Root cause (suspected):** Mongoid 8 dirty tracking or slug generation caching changed.
**Fix:** Investigate Mongoid 8 slug behavior and update test or model accordingly.

---

### 3. Password Reuse Validation in `UserTest` (Issue #789)

```
Failure: Workarea::UserTest#test_does_not_allow_admins_to_reuse_the_same_password
Expected true to not be truthy.
```

**Root cause (suspected):** Mongoid 8 callback ordering change affecting `has_secure_password` validation.
**Fix:** Review `before_validation` / bcrypt interaction under Mongoid 8.

---

## Comparison with Rails 6.1 Baseline (PR #777)

The Rails 6.1 baseline (PR #777) showed **99.6% test error rate** due to the RAILS_ENV propagation
bug (#783), making direct comparison difficult. The 3 failures found here are distinct from the
setup-guard errors in that baseline.

These failures appear to be **Mongoid 8 compatibility issues**, not Rails 7.2 API changes:
- Mongoid 8 is required because Mongoid 7.x has `activemodel < 7.1` constraint
- These failures are isolated and fixable via follow-up issues #787, #788, #789

---

## Follow-up Issues Created

| Issue | Title | Status |
|-------|-------|--------|
| #787 | Rails 7.2: Fix Rack::Cache uninitialized constant | `status:ready` |
| #788 | Rails 7.2 / Mongoid 8: slug_caching test failure | `status:ready` |
| #789 | Rails 7.2 / Mongoid 8: password reuse validation failure | `status:ready` |

---

## Next Steps

1. Fix #787, #788, #789 in follow-up PRs
2. Run full test suite in CI (core 435 files, admin 179, storefront 119) once RAILS_ENV
propagation issue (#783) is resolved
3. Compare full Rails 7.2 results against cleaned-up Rails 6.1 baseline
7 changes: 7 additions & 0 deletions gemfiles/rails_7_2.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@
eval_gemfile File.expand_path('../Gemfile', __dir__)

gem 'rails', '~> 7.2.0'
# mongoid 7.x only supports activemodel < 7.1; mongoid 8+ is required for Rails 7.2+
gem 'mongoid', '~> 8.1'
# serviceworker-rails 0.6.0 uses rack/file which was removed in Rack 3.
# Pin Rack to 2.x until serviceworker-rails gains Rack 3 support.
gem 'rack', '~> 2.2'
# mocha 1.3.0 uses MiniTest (uppercase T) which is gone in Minitest 5.15+; use 2.x which uses Minitest
gem 'mocha', '~> 2.0'
Loading
Loading