mirror of
https://github.com/we-promise/sure.git
synced 2026-09-07 15:44:21 +00:00
* Add admin family management features and tests
- Implement FamiliesController with destroy action to delete unused families.
- Add localization for success and error messages related to family deletion.
- Create FamiliesControllerTest to ensure proper functionality of family deletion.
- Update UserPolicyTest to include permissions for super admins to delete users.
- Enhance UsersControllerTest with tests for user family management, including moving users between families and creating new families.
* feat(users): enhance user management with family transfer validation and improved delete warnings
* Simplify user management actions column and combine family options
Move heavy user edit forms from table rows into a DS::Popover action
menu, add role badges to the user column, combine family migration and
creation inputs with a Stimulus controller, enable self-family
transfer for super admins, and add safety guards against demoting the
last super admin in the system.
* feat: add authentication type pills to admin user index to display SSO and local login status
* Add set password feature for local users in admin user management
- Add password field in action popover for users with local password login
- Enforce all registration password criteria (min 8 chars, mixed case, digit, special char)
- Block simultaneous family and password updates with clear error
- Show descriptive success notifications (role, password, both, family)
- Ignore password param for SSO-only users
- Add comprehensive tests for all password validation paths
* Resolve DS Drift Patrol findings and CI scan failures
- Wrap auth-type pills in DS::Tooltip instead of native title= attribute
- Add actions.manage_user key to locale and drop redundant default: fallbacks
- Fix RuboCop style offenses in Admin::UsersController
- Update Brakeman ignore entry fingerprint for Admin::UsersController#user_params
* fix: update badge query to target DS::Pill structure
* Fix DS::Tooltip misuse hiding SSO auth-type pill in admin users view
The SSO pill was passed as a block to DS::Tooltip, which caused it to
render inside the hidden div[role="tooltip"] instead of being visible.
The text: option ("SSO Provider: ...") was also silently ignored because
tooltip_content returns content (the block) over @text when a block is
given.
Fix: render the SSO/Local+SSO pill directly as visible content and pass
DS::Tooltip with no block so text: is used as the tooltip popup. An info
icon now appears next to the pill and shows the provider name on hover.
Fixes test: Admin::UsersControllerTest#test_index_renders_auth_type_pills_for_local_and_sso_users
* Remove redundant default: fallback from role pill i18n lookup
All admin.users.index.roles.{guest,member,admin,super_admin} keys are
defined in the locale file and used elsewhere in the same view without
a default:. The fallback was redundant for every valid role and would
silently mask a missing or renamed key instead of raising in
development.
Drop the default: user.role.humanize argument so that any future
missing key surfaces immediately as I18n::MissingTranslationData.
* Revert unrelated JS/schema/split churn; fix transfer_to_family! default role
- Revert 62 JS files (Biome formatter and unrelated controller changes)
- Revert db/schema.rb dump churn (no new migrations in this branch)
- Revert unrelated split transaction view changes (edit/new.html.erb)
- Fix User#transfer_to_family! role default: role: role evaluates to nil
when omitted; use explicit self.role to read model attribute
Keeps the PR focused on user/family management (~18-20 files).
* Fix last login and session count in admin user management
Store last_login_at and sessions_count directly on the users table
so they remain accurate after a user logs out.
- Add migration to add last_login_at (datetime) and sessions_count
(integer, default 0) columns to users, with backfill from sessions
- Add counter_cache: :sessions_count to Session#belongs_to :user so
the count auto-increments/decrements on session create/destroy
- Add after_create callback on Session to stamp user.last_login_at
- Update Admin::UsersController to read both values from users table
instead of aggregating Session rows (which disappear on logout)
* Fix user management PR pending CI items
* Keep test current session after sign in
* Address PR review comments for user transfers
* refactor: update user removal label to "Delete User" and standardize component attribute naming
* Address PR Review Feedback for User Management
* test: Fix families and users controller tests for user management PR
* Limit PR 2868 schema diff
* Fix PR 2868 user management CI failures
---------
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: sure-admin <sure-admin@splashblot.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
156 lines
5.1 KiB
Ruby
156 lines
5.1 KiB
Ruby
if ENV["COVERAGE"] == "true"
|
|
require "simplecov"
|
|
SimpleCov.start "rails" do
|
|
enable_coverage :branch
|
|
end
|
|
end
|
|
|
|
require_relative "../config/environment"
|
|
|
|
ENV["RAILS_ENV"] ||= "test"
|
|
|
|
# Set Plaid to sandbox mode for tests
|
|
ENV["PLAID_ENV"] = "sandbox"
|
|
ENV["PLAID_CLIENT_ID"] ||= "test_client_id"
|
|
ENV["PLAID_SECRET"] ||= "test_secret"
|
|
|
|
# Fixes Segfaults on M1 Macs when running tests in parallel (temporary workaround)
|
|
ENV["PGGSSENCMODE"] = "disable"
|
|
|
|
require "rails/test_help"
|
|
require "minitest/mock"
|
|
require "minitest/autorun"
|
|
require "mocha/minitest"
|
|
require "aasm/minitest"
|
|
require "webmock/minitest"
|
|
require "rack/test"
|
|
require "tempfile"
|
|
require "uri"
|
|
require Rails.root.join("test/support/sql_query_capture").to_s
|
|
|
|
VCR.configure do |config|
|
|
config.cassette_library_dir = "test/vcr_cassettes"
|
|
config.hook_into :webmock
|
|
config.ignore_localhost = true
|
|
config.ignore_request do |request|
|
|
selenium_remote_url = ENV["SELENIUM_REMOTE_URL"]
|
|
next false if selenium_remote_url.blank?
|
|
|
|
request_uri = URI(request.uri)
|
|
selenium_uri = URI(selenium_remote_url)
|
|
|
|
request_uri.host.present? &&
|
|
selenium_uri.host.present? &&
|
|
request_uri.host == selenium_uri.host &&
|
|
request_uri.port == selenium_uri.port
|
|
rescue URI::InvalidURIError
|
|
false
|
|
end
|
|
config.default_cassette_options = { erb: true }
|
|
config.filter_sensitive_data("<OPENAI_ACCESS_TOKEN>") { ENV["OPENAI_ACCESS_TOKEN"] }
|
|
config.filter_sensitive_data("<OPENAI_ORGANIZATION_ID>") { ENV["OPENAI_ORGANIZATION_ID"] }
|
|
config.filter_sensitive_data("<STRIPE_SECRET_KEY>") { ENV["STRIPE_SECRET_KEY"] }
|
|
config.filter_sensitive_data("<STRIPE_WEBHOOK_SECRET>") { ENV["STRIPE_WEBHOOK_SECRET"] }
|
|
config.filter_sensitive_data("<PLAID_CLIENT_ID>") { ENV["PLAID_CLIENT_ID"] }
|
|
config.filter_sensitive_data("<PLAID_SECRET>") { ENV["PLAID_SECRET"] }
|
|
end
|
|
|
|
# Configure OmniAuth for testing
|
|
OmniAuth.config.test_mode = true
|
|
# Allow both GET and POST for OIDC callbacks in tests
|
|
OmniAuth.config.allowed_request_methods = [ :get, :post ]
|
|
|
|
module ActiveSupport
|
|
class TestCase
|
|
# Run tests in parallel with specified workers
|
|
parallelize(workers: :number_of_processors) unless ENV["DISABLE_PARALLELIZATION"] == "true"
|
|
|
|
# https://github.com/simplecov-ruby/simplecov/issues/718#issuecomment-538201587
|
|
if ENV["COVERAGE"] == "true"
|
|
parallelize_setup do |worker|
|
|
SimpleCov.command_name "#{SimpleCov.command_name}-#{worker}"
|
|
end
|
|
|
|
parallelize_teardown do |worker|
|
|
SimpleCov.result
|
|
end
|
|
end
|
|
|
|
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
|
|
fixtures :all
|
|
|
|
# rails-settings-cached keeps an in-memory cache that survives the per-test
|
|
# transaction rollback, so a Setting.* value written in one test leaks into
|
|
# later tests and causes order-dependent failures (e.g. Settings::Hostings
|
|
# reading a stale "" where nil is expected). Reset the cache before every
|
|
# test so each starts from the rolled-back DB state.
|
|
setup { Setting.clear_cache }
|
|
|
|
include SqlQueryCapture
|
|
|
|
# Add more helper methods to be used by all tests here...
|
|
def sign_in(user)
|
|
post sessions_path, params: { email: user.email, password: user_password_test }
|
|
Current.session = user.sessions.order(:created_at).last
|
|
end
|
|
|
|
def ensure_tailwind_build
|
|
tailwind_build = Rails.root.join("app/assets/builds/tailwind.css")
|
|
FileUtils.mkdir_p(tailwind_build.dirname)
|
|
File.write(tailwind_build, "/* test */") unless tailwind_build.exist?
|
|
end
|
|
|
|
def with_env_overrides(overrides = {}, &block)
|
|
ClimateControl.modify(**overrides, &block)
|
|
end
|
|
|
|
def with_self_hosting
|
|
Rails.configuration.stubs(:app_mode).returns("self_hosted".inquiry)
|
|
yield
|
|
end
|
|
|
|
def api_headers(api_key)
|
|
{ "X-Api-Key" => api_key.plain_key }
|
|
end
|
|
|
|
def user_password_test
|
|
"maybetestpassword817983172"
|
|
end
|
|
|
|
def uploaded_file(filename:, content_type:, content: "date,amount\n2024-01-01,1\n")
|
|
tempfile = Tempfile.new([ File.basename(filename, ".*"), File.extname(filename) ])
|
|
tempfile.binmode
|
|
tempfile.write(content)
|
|
tempfile.rewind
|
|
|
|
Rack::Test::UploadedFile.new(tempfile.path, content_type, true, original_filename: filename)
|
|
end
|
|
|
|
def family_guest
|
|
@family_guest ||= users(:family_admin).family.users.create!(
|
|
first_name: "Readonly",
|
|
last_name: "Guest",
|
|
email: "readonly-guest@example.com",
|
|
password: user_password_test,
|
|
role: "guest",
|
|
onboarded_at: Time.current,
|
|
ui_layout: "dashboard"
|
|
)
|
|
end
|
|
|
|
# Ensures the Investment Contributions category exists for a family
|
|
# Used in transfer tests where this bootstrapped category is required
|
|
# Uses family locale to ensure consistent naming
|
|
def ensure_investment_contributions_category(family)
|
|
I18n.with_locale(family.locale) do
|
|
family.categories.find_or_create_by!(name: Category.investment_contributions_name) do |c|
|
|
c.color = "#0d9488"
|
|
c.lucide_icon = "trending-up"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
Dir[Rails.root.join("test", "interfaces", "**", "*.rb")].each { |f| require f }
|