diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index b026f6180..9de0e18d9 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,51 +6,12 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 4 -Capybara/RSpec/NegationMatcherAfterVisit: - Exclude: - - 'spec/features/member_portal_spec.rb' - - 'spec/support/shared_examples/behaves_like_an_invitation_route.rb' - - 'spec/support/shared_examples/behaves_link_member_viewing_workshop.rb' - -# Offense count: 1 -Capybara/RSpec/VisibilityMatcher: - Exclude: - - 'spec/components/chapters_sidebar_component_spec.rb' - -# Offense count: 2 -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: AllowSafeAssignment. -Lint/AssignmentInCondition: - Exclude: - - 'app/controllers/application_controller.rb' - - 'app/models/feedback.rb' - -# Offense count: 1 -# Configuration parameters: AllowedMethods. -# AllowedMethods: enums -Lint/ConstantDefinitionInBlock: - Exclude: - - 'lib/tasks/setup.rake' - # Offense count: 1 # Configuration parameters: DebuggerMethods, DebuggerRequires. Lint/Debugger: Exclude: - 'spec/spec_helper.rb' -# Offense count: 1 -# Configuration parameters: AllowedParentClasses. -Lint/MissingSuper: - Exclude: - - 'app/components/event_card_component.rb' - -# Offense count: 1 -# Configuration parameters: AllowKeywordBlockArguments. -Lint/UnderscorePrefixedVariableName: - Exclude: - - 'spec/models/group_spec.rb' - # Offense count: 32 # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max. Metrics/AbcSize: @@ -147,22 +108,6 @@ Metrics/PerceivedComplexity: - 'app/services/invitation_manager.rb' - 'lib/omniauth/strategies/codebar.rb' -# Offense count: 6 -Naming/AccessorMethodName: - Exclude: - - 'app/controllers/admin/events_controller.rb' - - 'app/controllers/admin/meetings_controller.rb' - - 'app/controllers/admin/workshops_controller.rb' - - 'app/controllers/feedback_controller.rb' - -# Offense count: 1 -# Configuration parameters: EnforcedStyle, AllowedPatterns, ForbiddenIdentifiers, ForbiddenPatterns. -# SupportedStyles: snake_case, camelCase -# ForbiddenIdentifiers: __id__, __send__ -Naming/MethodName: - Exclude: - - 'app/models/member.rb' - # Offense count: 10 # Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros, UseSorbetSigs. # NamePrefix: is_, has_, have_, does_ @@ -172,7 +117,6 @@ Naming/MethodName: Naming/PredicatePrefix: Exclude: - 'app/controllers/application_controller.rb' - - 'app/models/member.rb' - 'app/models/workshop.rb' - 'app/policies/application_policy.rb' - 'app/policies/chapter_policy.rb' @@ -182,23 +126,8 @@ Naming/PredicatePrefix: # Offense count: 2 RSpec/AnyInstance: Exclude: - - 'spec/controllers/member/details_controller_spec.rb' - 'spec/support/helpers/login_helpers.rb' -# Offense count: 1 -# Configuration parameters: Max, CountAsOne. -RSpec/ExampleLength: - Exclude: - - 'spec/features/admin/event_spec.rb' - -# Offense count: 3 -# Configuration parameters: Max. -RSpec/MultipleExpectations: - Exclude: - - 'spec/features/admin/event_spec.rb' - - 'spec/features/admin/sponsor_spec.rb' - - 'spec/lib/omniauth/strategies/codebar_spec.rb' - # Offense count: 5 Rails/HasAndBelongsToMany: Exclude: diff --git a/app/components/event_card_component.rb b/app/components/event_card_component.rb index 8bcbbad1b..1bbed31a1 100644 --- a/app/components/event_card_component.rb +++ b/app/components/event_card_component.rb @@ -1,5 +1,6 @@ class EventCardComponent < ViewComponent::Base def initialize(event_card:, user: nil) + super() @event = event_card @user = user end diff --git a/app/controllers/admin/events_controller.rb b/app/controllers/admin/events_controller.rb index eab8cdb58..918558c6f 100644 --- a/app/controllers/admin/events_controller.rb +++ b/app/controllers/admin/events_controller.rb @@ -8,7 +8,7 @@ def new def create @event = Event.new(event_params) - set_organisers(organiser_ids) + assign_organisers(organiser_ids) if @event.save redirect_to [:admin, @event], notice: 'Event successfully created.' @@ -31,7 +31,7 @@ def show end def update - set_organisers(organiser_ids) + assign_organisers(organiser_ids) if @event.update(event_params) redirect_to [:admin, @event], notice: 'You have just updated the event' @@ -94,7 +94,7 @@ def grant_organiser_access(organiser_ids = []) organiser_ids.each { |id| Member.find(id).add_role(:organiser, @event) } end - def set_organisers(organiser_ids) + def assign_organisers(organiser_ids) organiser_ids.reject!(&:empty?) grant_organiser_access(organiser_ids) revoke_organiser_access(organiser_ids) diff --git a/app/controllers/admin/meetings_controller.rb b/app/controllers/admin/meetings_controller.rb index 17e8eff5c..5d66687ac 100644 --- a/app/controllers/admin/meetings_controller.rb +++ b/app/controllers/admin/meetings_controller.rb @@ -9,8 +9,8 @@ def create @meeting = Meeting.new(meeting_params) if @meeting.save - set_organisers(organiser_ids) - set_chapters(chapter_ids) + assign_organisers(organiser_ids) + assign_chapters(chapter_ids) redirect_to [:admin, @meeting], notice: t('admin.messages.meeting.created') else flash[:notice] = @meeting.errors.full_messages.join(', ') @@ -27,8 +27,8 @@ def show def edit; end def update - set_organisers(organiser_ids) - set_chapters(chapter_ids) + assign_organisers(organiser_ids) + assign_chapters(chapter_ids) if @meeting.update(meeting_params) redirect_to [:admin, @meeting], notice: t('admin.messages.meeting.updated') @@ -86,13 +86,13 @@ def revoke_organiser_access(organiser_ids) end end - def set_organisers(organiser_ids) + def assign_organisers(organiser_ids) organiser_ids.reject!(&:empty?) grant_organiser_access(organiser_ids) revoke_organiser_access(organiser_ids) end - def set_chapters(chapter_ids) + def assign_chapters(chapter_ids) chapter_ids.reject!(&:empty?) @meeting.chapters = chapter_ids.map { |id| Chapter.find(id) } end diff --git a/app/controllers/admin/workshops_controller.rb b/app/controllers/admin/workshops_controller.rb index c72a01633..d92f353b0 100644 --- a/app/controllers/admin/workshops_controller.rb +++ b/app/controllers/admin/workshops_controller.rb @@ -24,7 +24,7 @@ def create if workshop_type_valid? && @workshop.save grant_organiser_access(@workshop.chapter.organisers.pluck(:id)) - set_host(host_id) + assign_host(host_id) redirect_to admin_workshop_path(@workshop), notice: I18n.t('admin.messages.workshop.created') else @@ -144,7 +144,7 @@ def workshop_id params.permit(:workshop_id)[:workshop_id] end - def set_host(host_id) + def assign_host(host_id) return unless host_id host = @workshop.workshop_sponsors.find_or_initialize_by(sponsor_id: host_id) @@ -154,7 +154,7 @@ def set_host(host_id) host.update(host: true) end - def set_organisers(organiser_ids) + def assign_organisers(organiser_ids) organiser_ids.reject!(&:empty?) grant_organiser_access(organiser_ids) revoke_organiser_access(organiser_ids) @@ -199,7 +199,7 @@ def workshop_type_valid? end def update_workshop_details - set_organisers(organiser_ids) - set_host(host_id) + assign_organisers(organiser_ids) + assign_host(host_id) end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 59bc8881c..dbbb5b83b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -169,7 +169,8 @@ def chapters end def redirect_back(fallback_location:, **args) - if referer = request.headers['Referer'] + referer = request.headers['Referer'] + if referer redirect_to referer, **args else redirect_to fallback_location, **args diff --git a/app/controllers/feedback_controller.rb b/app/controllers/feedback_controller.rb index 15988ad8f..e9992a82b 100644 --- a/app/controllers/feedback_controller.rb +++ b/app/controllers/feedback_controller.rb @@ -9,7 +9,7 @@ def show return redirect_to root_path end - set_coaches(feedback_request.workshop) + assign_coaches(feedback_request.workshop) @workshop = feedback_request.workshop @feedback = Feedback.new @@ -22,7 +22,7 @@ def submit redirect_to root_path else feedback_request = FeedbackRequest.find_by!(token: params[:id], submited: false) - set_coaches(feedback_request.workshop) + assign_coaches(feedback_request.workshop) @workshop = feedback_request.workshop @feedback = Feedback.new(feedback_params) @@ -39,7 +39,7 @@ def feedback_params params.expect(feedback: %i[coach_id tutorial_id request rating suggestions]) end - def set_coaches(workshop) + def assign_coaches(workshop) @coaches = workshop.invitations.to_coaches.accepted_or_attended .order(Arel.sql('attended DESC NULLS LAST')) .map(&:member) diff --git a/app/controllers/workshop_invitation_controller.rb b/app/controllers/workshop_invitation_controller.rb index a1f784de1..1e9312558 100644 --- a/app/controllers/workshop_invitation_controller.rb +++ b/app/controllers/workshop_invitation_controller.rb @@ -29,7 +29,7 @@ def accept return back_with_message(t('messages.already_rsvped')) if @invitation.attending? return back_with_message(t('messages.invitations.closed')) unless workshop.rsvp_available? - if user.has_existing_RSVP_on(workshop.date_and_time) + if user.existing_rsvp_on?(workshop.date_and_time) return back_with_message(t('messages.invitations.rsvped_to_other_workshop')) end diff --git a/app/models/feedback.rb b/app/models/feedback.rb index d2cd52693..dd99f6bce 100644 --- a/app/models/feedback.rb +++ b/app/models/feedback.rb @@ -8,7 +8,8 @@ class Feedback < ApplicationRecord validates :tutorial, presence: true def self.submit_feedback(params, token) - return false unless feedback_request = FeedbackRequest.find_by(token: token) + feedback_request = FeedbackRequest.find_by(token: token) + return false unless feedback_request feedback = Feedback.new(params) feedback.workshop = feedback_request.workshop diff --git a/app/models/member.rb b/app/models/member.rb index 72fa23e44..860a39bc7 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -126,7 +126,7 @@ def requires_additional_details? can_log_in? && !valid? end - def has_existing_RSVP_on(date) + def existing_rsvp_on?(date) invitations_on(date).any? end diff --git a/lib/tasks/setup.rake b/lib/tasks/setup.rake index fd887a223..db71f5898 100644 --- a/lib/tasks/setup.rake +++ b/lib/tasks/setup.rake @@ -1,231 +1,231 @@ # frozen_string_literal: true -namespace :setup do - desc 'Inspect your local development environment and report what is missing or misconfigured' - task check: :environment do - checker = SetupChecker.new - checker.run - exit(checker.all_ok? ? 0 : 1) +class SetupChecker + CHECKS = %i[ + check_ruby_version + check_bundler + check_mise + check_postgresql + check_imagemagick + check_github_credentials + check_bundle + check_database_connection + check_database_exists + check_database_migrated + check_test_database + ].freeze + + def initialize + @results = [] + @expected_ruby = File.read('.ruby-version').strip end - class SetupChecker - CHECKS = %i[ - check_ruby_version - check_bundler - check_mise - check_postgresql - check_imagemagick - check_github_credentials - check_bundle - check_database_connection - check_database_exists - check_database_migrated - check_test_database - ].freeze - - def initialize - @results = [] - @expected_ruby = File.read('.ruby-version').strip - end + def run + puts + puts '== codebar planner setup check ==' + puts + puts 'This command inspects your local development environment and reports' + puts 'anything that needs attention before you can run the application.' + puts - def run - puts - puts '== codebar planner setup check ==' - puts - puts 'This command inspects your local development environment and reports' - puts 'anything that needs attention before you can run the application.' - puts + CHECKS.each { |check| send(check) } - CHECKS.each { |check| send(check) } + print_summary + end - print_summary - end + def all_ok? + @results.none? { |r| r[:status] == :error } + end - def all_ok? - @results.none? { |r| r[:status] == :error } - end + private - private + def ok(title, message) + @results << { status: :ok, title:, message: } + puts " ✅ #{title}: #{message}" + end - def ok(title, message) - @results << { status: :ok, title:, message: } - puts " ✅ #{title}: #{message}" - end + def warn(title, message, fix) + @results << { status: :warn, title:, message:, fix: } + puts " ⚠️ #{title}: #{message}" + puts " → #{fix}" + end - def warn(title, message, fix) - @results << { status: :warn, title:, message:, fix: } - puts " ⚠️ #{title}: #{message}" - puts " → #{fix}" - end + def error(title, message, fix) + @results << { status: :error, title:, message:, fix: } + puts " ❌ #{title}: #{message}" + puts " → #{fix}" + end - def error(title, message, fix) - @results << { status: :error, title:, message:, fix: } - puts " ❌ #{title}: #{message}" - puts " → #{fix}" + def check_ruby_version + current = RUBY_VERSION + if current == @expected_ruby + ok('Ruby version', "#{current} (matches .ruby-version)") + else + error('Ruby version', "#{current} (expected #{@expected_ruby})", + "Install Ruby #{@expected_ruby}. See docs/development-setup.md for options.") end + end - def check_ruby_version - current = RUBY_VERSION - if current == @expected_ruby - ok('Ruby version', "#{current} (matches .ruby-version)") - else - error('Ruby version', "#{current} (expected #{@expected_ruby})", - "Install Ruby #{@expected_ruby}. See docs/development-setup.md for options.") - end + def check_bundler + if system('which bundle > /dev/null 2>&1') + ok('Bundler', 'installed') + else + error('Bundler', 'not found', + 'Run: gem install bundler') end + end - def check_bundler - if system('which bundle > /dev/null 2>&1') - ok('Bundler', 'installed') - else - error('Bundler', 'not found', - 'Run: gem install bundler') - end + def check_mise + if system('which mise > /dev/null 2>&1') + ok('mise', 'installed') + else + warn('mise', 'not found', + 'Optional but recommended. Install: brew install mise (macOS) or see https://mise.jdx.dev') end + end - def check_mise - if system('which mise > /dev/null 2>&1') - ok('mise', 'installed') - else - warn('mise', 'not found', - 'Optional but recommended. Install: brew install mise (macOS) or see https://mise.jdx.dev') - end + def check_postgresql + unless system('which psql > /dev/null 2>&1') + error('PostgreSQL', 'psql not found', + 'Install: brew install postgresql && brew services start postgresql (macOS)' \ + ' or see docs/development-setup.md') + return + end + + # Check if postgres is accepting connections + db_config = ActiveRecord::Base.connection_db_config.configuration_hash + host = db_config[:host] || 'localhost' + port = db_config[:port] || 5432 + user = db_config[:username] || ENV['USER'] + password = db_config[:password] + + env = password ? { 'PGPASSWORD' => password } : {} + cmd = "PGPASSWORD=#{password} psql -h #{host} -p #{port} -U #{user} -c 'SELECT 1' > /dev/null 2>&1" + if system(env, cmd) + ok('PostgreSQL', "running and accepting connections on #{host}:#{port}") + else + error('PostgreSQL', "not accepting connections on #{host}:#{port}", + 'Start PostgreSQL: brew services start postgresql (macOS).' \ + ' Check credentials in config/database.yml or env vars.') end + end - def check_postgresql - unless system('which psql > /dev/null 2>&1') - error('PostgreSQL', 'psql not found', - 'Install: brew install postgresql && brew services start postgresql (macOS)' \ - ' or see docs/development-setup.md') - return - end - - # Check if postgres is accepting connections - db_config = ActiveRecord::Base.connection_db_config.configuration_hash - host = db_config[:host] || 'localhost' - port = db_config[:port] || 5432 - user = db_config[:username] || ENV['USER'] - password = db_config[:password] - - env = password ? { 'PGPASSWORD' => password } : {} - cmd = "PGPASSWORD=#{password} psql -h #{host} -p #{port} -U #{user} -c 'SELECT 1' > /dev/null 2>&1" - if system(env, cmd) - ok('PostgreSQL', "running and accepting connections on #{host}:#{port}") - else - error('PostgreSQL', "not accepting connections on #{host}:#{port}", - 'Start PostgreSQL: brew services start postgresql (macOS).' \ - ' Check credentials in config/database.yml or env vars.') - end + def check_imagemagick + if system('which convert > /dev/null 2>&1') + ok('ImageMagick', 'installed') + else + error('ImageMagick', 'not found (convert command missing)', + 'Install: brew install imagemagick (macOS) or see docs/development-setup.md') end + end - def check_imagemagick - if system('which convert > /dev/null 2>&1') - ok('ImageMagick', 'installed') - else - error('ImageMagick', 'not found (convert command missing)', - 'Install: brew install imagemagick (macOS) or see docs/development-setup.md') - end + def check_github_credentials + unless File.exist?('mise.local.toml') + error('GitHub OAuth', 'mise.local.toml not found', + 'Copy: cp mise.local.toml.example mise.local.toml, then edit with your GitHub app credentials.') + return end - def check_github_credentials - unless File.exist?('mise.local.toml') - error('GitHub OAuth', 'mise.local.toml not found', - 'Copy: cp mise.local.toml.example mise.local.toml, then edit with your GitHub app credentials.') - return - end + content = File.read('mise.local.toml') + if content.include?('your_github_oauth') || content.include?('your_') || content.include?('fill_in') + error('GitHub OAuth', 'mise.local.toml contains placeholder values', + 'Edit mise.local.toml with real GITHUB_KEY and GITHUB_SECRET from your GitHub OAuth app.') + else + ok('GitHub OAuth', 'mise.local.toml configured') + end + end - content = File.read('mise.local.toml') - if content.include?('your_github_oauth') || content.include?('your_') || content.include?('fill_in') - error('GitHub OAuth', 'mise.local.toml contains placeholder values', - 'Edit mise.local.toml with real GITHUB_KEY and GITHUB_SECRET from your GitHub OAuth app.') - else - ok('GitHub OAuth', 'mise.local.toml configured') - end + def check_bundle + if system('bundle check > /dev/null 2>&1') + ok('Ruby dependencies', 'all gems installed') + else + error('Ruby dependencies', 'missing gems', + 'Run: bundle install') end + end + + def check_database_connection + ActiveRecord::Base.connection.execute('SELECT 1') + ok('Database connection', 'can connect to PostgreSQL') + rescue StandardError => e + error('Database connection', "cannot connect (#{e.class}: #{e.message})", + 'Check PostgreSQL is running and credentials in config/database.yml are correct.') + end - def check_bundle - if system('bundle check > /dev/null 2>&1') - ok('Ruby dependencies', 'all gems installed') + def check_database_exists + ActiveRecord::Base.connection.execute('SELECT 1') + if ActiveRecord::Base.connection.execute("SELECT 1 FROM pg_database WHERE datname = 'planner_development'").any? + ok('Development database', 'planner_development exists') else - error('Ruby dependencies', 'missing gems', - 'Run: bundle install') + error('Development database', 'planner_development does not exist', + 'Run: bundle exec rake db:create') end - end - - def check_database_connection - ActiveRecord::Base.connection.execute('SELECT 1') - ok('Database connection', 'can connect to PostgreSQL') - rescue StandardError => e - error('Database connection', "cannot connect (#{e.class}: #{e.message})", - 'Check PostgreSQL is running and credentials in config/database.yml are correct.') - end + rescue StandardError => e + error('Development database', "cannot check (#{e.class}: #{e.message})", + 'Run: bundle exec rake db:create') + end - def check_database_exists - ActiveRecord::Base.connection.execute('SELECT 1') - if ActiveRecord::Base.connection.execute("SELECT 1 FROM pg_database WHERE datname = 'planner_development'").any? - ok('Development database', 'planner_development exists') + def check_database_migrated + if ActiveRecord::Base.connection.execute('SELECT 1 FROM schema_migrations LIMIT 1') + latest = ActiveRecord::Base.connection.execute( + 'SELECT version FROM schema_migrations ORDER BY version DESC LIMIT 1' + ).first + if latest + ok('Database migrations', "up to date (latest: #{latest['version']})") else - error('Development database', 'planner_development does not exist', - 'Run: bundle exec rake db:create') + error('Database migrations', 'no migrations found', + 'Run: bundle exec rake db:migrate') end - rescue StandardError => e - error('Development database', "cannot check (#{e.class}: #{e.message})", - 'Run: bundle exec rake db:create') - end + end + rescue StandardError => e + error('Database migrations', "cannot check (#{e.class}: #{e.message})", + 'Run: bundle exec rake db:migrate') + end - def check_database_migrated - if ActiveRecord::Base.connection.execute('SELECT 1 FROM schema_migrations LIMIT 1') - latest = ActiveRecord::Base.connection.execute( - 'SELECT version FROM schema_migrations ORDER BY version DESC LIMIT 1' - ).first - if latest - ok('Database migrations', "up to date (latest: #{latest['version']})") - else - error('Database migrations', 'no migrations found', - 'Run: bundle exec rake db:migrate') - end - end - rescue StandardError => e - error('Database migrations', "cannot check (#{e.class}: #{e.message})", - 'Run: bundle exec rake db:migrate') + def check_test_database + db_config = Rails.configuration.database_configuration['test'] + host = db_config['host'] || 'localhost' + port = db_config['port'] || 5432 + user = db_config['username'] || ENV['USER'] + password = db_config['password'] + database = db_config['database'] + + env = password ? { 'PGPASSWORD' => password } : {} + cmd = "PGPASSWORD=#{password} psql -h #{host} -p #{port} -U #{user} -c 'SELECT 1' #{database} > /dev/null 2>&1" + if system(env, cmd) + ok('Test database', "#{database} exists and is accessible") + else + error('Test database', "#{database} missing or not accessible", + 'Run: bundle exec rake db:test:prepare') end + end - def check_test_database - db_config = Rails.configuration.database_configuration['test'] - host = db_config['host'] || 'localhost' - port = db_config['port'] || 5432 - user = db_config['username'] || ENV['USER'] - password = db_config['password'] - database = db_config['database'] - - env = password ? { 'PGPASSWORD' => password } : {} - cmd = "PGPASSWORD=#{password} psql -h #{host} -p #{port} -U #{user} -c 'SELECT 1' #{database} > /dev/null 2>&1" - if system(env, cmd) - ok('Test database', "#{database} exists and is accessible") - else - error('Test database', "#{database} missing or not accessible", - 'Run: bundle exec rake db:test:prepare') - end - end + def print_summary + puts + errors = @results.count { |r| r[:status] == :error } + warnings = @results.count { |r| r[:status] == :warn } - def print_summary + if errors.zero? && warnings.zero? + puts '✅ All checks passed! Your environment is ready for development.' puts - errors = @results.count { |r| r[:status] == :error } - warnings = @results.count { |r| r[:status] == :warn } - - if errors.zero? && warnings.zero? - puts '✅ All checks passed! Your environment is ready for development.' - puts - puts 'Next steps:' - puts ' bundle exec rails server # Start the app' - puts ' bundle exec rspec # Run the test suite' - puts ' bundle exec rake db:seed # (Optional) Add sample data' - elsif errors.zero? - puts "⚠️ #{warnings} warning(s). You can probably start developing, but review the warnings above." - else - puts "❌ #{errors} error(s) and #{warnings} warning(s) need attention before you can start developing." - end - puts - end + puts 'Next steps:' + puts ' bundle exec rails server # Start the app' + puts ' bundle exec rspec # Run the test suite' + puts ' bundle exec rake db:seed # (Optional) Add sample data' + elsif errors.zero? + puts "⚠️ #{warnings} warning(s). You can probably start developing, but review the warnings above." + else + puts "❌ #{errors} error(s) and #{warnings} warning(s) need attention before you can start developing." + end + puts + end +end + +namespace :setup do + desc 'Inspect your local development environment and report what is missing or misconfigured' + task check: :environment do + checker = SetupChecker.new + checker.run + exit(checker.all_ok? ? 0 : 1) end end diff --git a/spec/components/chapters_sidebar_component_spec.rb b/spec/components/chapters_sidebar_component_spec.rb index 2ac4a5e95..73bb65e5a 100644 --- a/spec/components/chapters_sidebar_component_spec.rb +++ b/spec/components/chapters_sidebar_component_spec.rb @@ -18,7 +18,7 @@ it 'renders nothing when no chapters' do render_inline described_class.new(chapters: []) - expect(page).to have_css('ul.list-unstyled.ms-0', visible: true) + expect(page).to have_css('ul.list-unstyled.ms-0', visible: :visible) expect(page).to have_no_css('li') end end diff --git a/spec/controllers/member/details_controller_spec.rb b/spec/controllers/member/details_controller_spec.rb index 10b98a639..bb06347f6 100644 --- a/spec/controllers/member/details_controller_spec.rb +++ b/spec/controllers/member/details_controller_spec.rb @@ -1,10 +1,12 @@ RSpec.describe Member::DetailsController do render_views let(:member) { Fabricate(:member) } + let(:mailing_list) { instance_double(Services::MailingList) } before do allow(controller).to receive(:current_user).and_return(member) - allow_any_instance_of(Services::MailingList).to receive(:subscribe).and_return(true) + allow(Services::MailingList).to receive(:new).and_return(mailing_list) + allow(mailing_list).to receive_messages(subscribe: true, unsubscribe: true) end describe 'PATCH #update' do diff --git a/spec/features/admin/event_spec.rb b/spec/features/admin/event_spec.rb index 2c0587a03..5e317d647 100644 --- a/spec/features/admin/event_spec.rb +++ b/spec/features/admin/event_spec.rb @@ -2,6 +2,21 @@ let(:member) { Fabricate(:member) } let(:chapter) { Fabricate(:chapter) } + def fill_in_mandatory_event_fields(name:, slug:, description:, date:, sponsor:) + fill_in 'Event Name', with: name + fill_in 'Slug', with: slug + fill_in 'Date', with: date + fill_in 'Starts at', with: '16:00' + fill_in 'Ends at', with: '18:00' + fill_in 'Description', with: description + fill_in 'RSVP instructions', with: 'Some instructions' + fill_in 'Schedule', with: '9:00 Sign up & breakfast
9:30 kick off' + fill_in 'Coach spaces', with: '19' + fill_in 'Student spaces', with: '25' + select sponsor.name, from: 'Venue' + click_on 'Save' + end + describe 'an authorised member' do before do member.add_role(:organiser, chapter) @@ -14,31 +29,22 @@ date = Time.zone.today + 2.days visit new_admin_event_path - fill_in 'Event Name', with: 'A test event' - fill_in 'Slug', with: 'a-test-event' - fill_in 'Date', with: date - fill_in 'Starts at', with: '16:00' - fill_in 'Ends at', with: '18:00' - fill_in 'Description', with: 'A test event description' - fill_in 'RSVP instructions', with: 'Some instructions' - fill_in 'Schedule', with: '9:00 Sign up & breakfast
9:30 kick off' - fill_in 'Coach spaces', with: '19' - fill_in 'Student spaces', with: '25' - select sponsor.name, from: 'Venue' - click_on 'Save' - - expect(page).to have_text('Event successfully created') + fill_in_mandatory_event_fields(name: 'A test event', slug: 'a-test-event', + description: 'A test event description', date: date, sponsor: sponsor) - expect(page).to have_text('A test event') - expect(page).to have_text(humanize_date(date)) - expect(page).to have_text('A test event description') - expect(page).to have_text('25 student spots, 19 coach spots') - expect(page).to have_text('9:00 Sign up & breakfast 9:30 kick off') + aggregate_failures do + expect(page).to have_text('Event successfully created') + expect(page).to have_text('A test event') + expect(page).to have_text(humanize_date(date)) + expect(page).to have_text('A test event description') + expect(page).to have_text('25 student spots, 19 coach spots') + expect(page).to have_text('9:00 Sign up & breakfast 9:30 kick off') - within '#host' do - expect(page).to have_text sponsor.name - expect(page).to have_text sponsor.address.street - expect(page).to have_text sponsor.address.city + within '#host' do + expect(page).to have_text sponsor.name + expect(page).to have_text sponsor.address.street + expect(page).to have_text sponsor.address.city + end end end end diff --git a/spec/features/admin/sponsor_spec.rb b/spec/features/admin/sponsor_spec.rb index 7f5d3fd35..8ddcaa028 100644 --- a/spec/features/admin/sponsor_spec.rb +++ b/spec/features/admin/sponsor_spec.rb @@ -93,16 +93,18 @@ end scenario 'displays all sponsor details' do - expect(page).to have_text(sponsor.name) - expect(page).to have_text(sponsor.description) - expect(page).to have_link(sponsor.website, href: sponsor.website) - expect(page).to have_text(sponsor.level) - expect(page).to have_text(ContactPresenter.new(sponsor.contacts.first).full_name) - - expect(page).to have_text(sponsor.seats) - expect(page).to have_text(sponsor.coach_spots) - expect(page).to have_text(sponsor.accessibility_info) - expect(page).to have_text(sponsor.address.street) + aggregate_failures do + expect(page).to have_text(sponsor.name) + expect(page).to have_text(sponsor.description) + expect(page).to have_link(sponsor.website, href: sponsor.website) + expect(page).to have_text(sponsor.level) + expect(page).to have_text(ContactPresenter.new(sponsor.contacts.first).full_name) + + expect(page).to have_text(sponsor.seats) + expect(page).to have_text(sponsor.coach_spots) + expect(page).to have_text(sponsor.accessibility_info) + expect(page).to have_text(sponsor.address.street) + end end context 'with sponsorships' do diff --git a/spec/features/member_portal_spec.rb b/spec/features/member_portal_spec.rb index a775e74bd..b22a652f0 100644 --- a/spec/features/member_portal_spec.rb +++ b/spec/features/member_portal_spec.rb @@ -86,6 +86,7 @@ it 'can not access the member portal' do visit dashboard_path + expect(page).to have_current_path(root_path) expect(page).to have_no_css('#profile') end @@ -93,6 +94,7 @@ mock_github_auth visit profile_path + expect(page).to have_current_path(terms_and_conditions_path) expect(page).to have_no_css('#member_profile') end end diff --git a/spec/lib/omniauth/strategies/codebar_spec.rb b/spec/lib/omniauth/strategies/codebar_spec.rb index 21ddfaad9..44d78e563 100644 --- a/spec/lib/omniauth/strategies/codebar_spec.rb +++ b/spec/lib/omniauth/strategies/codebar_spec.rb @@ -47,18 +47,20 @@ def build_env(path, query: '', session: {}) env = build_env('/auth/codebar') status, headers, _body = strategy.call(env) - expect(status).to eq(302) - expect(env['rack.session']['omniauth.codebar.state']).to be_present - expect(env['rack.session']['omniauth.codebar.code_verifier']).to be_present - - location = headers['Location'] - expect(location).to include('/api/auth/oauth2/authorize') - expect(location).to include('client_id=planner') - expect(location).to include('response_type=code') - expect(location).to include('code_challenge=') - expect(location).to include('code_challenge_method=S256') - expect(location).to include('scope=openid+profile+email') - expect(env['rack.session']['omniauth.codebar.redirect_uri']).to eq('http://localhost:3000/auth/codebar/callback') + aggregate_failures do + expect(status).to eq(302) + expect(env['rack.session']['omniauth.codebar.state']).to be_present + expect(env['rack.session']['omniauth.codebar.code_verifier']).to be_present + + location = headers['Location'] + expect(location).to include('/api/auth/oauth2/authorize') + expect(location).to include('client_id=planner') + expect(location).to include('response_type=code') + expect(location).to include('code_challenge=') + expect(location).to include('code_challenge_method=S256') + expect(location).to include('scope=openid+profile+email') + expect(env['rack.session']['omniauth.codebar.redirect_uri']).to eq('http://localhost:3000/auth/codebar/callback') + end end it 'generates unique state per request' do diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 781922936..add457799 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -38,7 +38,7 @@ member_old = Fabricate(:member, groups: [group]) member_new = Fabricate(:member, groups: [group]) - _member_no_rsvp = Fabricate(:member, groups: [group]) + member_no_rsvp = Fabricate(:member, groups: [group]) Fabricate(:workshop_invitation, workshop: old_workshop, member: member_old, attending: true) Fabricate(:workshop_invitation, workshop: new_workshop, member: member_new, attending: true) @@ -46,7 +46,7 @@ results = described_class.members_by_recent_rsvp(group).to_a expect(results.first).to eq(member_new) - expect(results.last).to eq(_member_no_rsvp) + expect(results.last).to eq(member_no_rsvp) end end end diff --git a/spec/support/shared_examples/behaves_like_an_invitation_route.rb b/spec/support/shared_examples/behaves_like_an_invitation_route.rb index 6ddde0f07..5f77ad930 100644 --- a/spec/support/shared_examples/behaves_like_an_invitation_route.rb +++ b/spec/support/shared_examples/behaves_like_an_invitation_route.rb @@ -34,8 +34,8 @@ invitation.update(role: 'Student', attending: nil, tutorial: nil) visit accept_invitation_route - expect(page).to have_no_link 'I can no longer attend' expect(page).to have_text('Tutorial must be selected') + expect(page).to have_no_link 'I can no longer attend' end scenario 'a Coach must can RSVP diredctly' do diff --git a/spec/support/shared_examples/behaves_link_member_viewing_workshop.rb b/spec/support/shared_examples/behaves_link_member_viewing_workshop.rb index 90c1cd3ab..1422dda6c 100644 --- a/spec/support/shared_examples/behaves_link_member_viewing_workshop.rb +++ b/spec/support/shared_examples/behaves_link_member_viewing_workshop.rb @@ -15,6 +15,7 @@ login(banned_member) visit workshop_path(workshop) + expect(page).to have_css('h1') expect(page).to have_no_button("Attend as a #{member_type.downcase}") end end