diff --git a/app/components/a_level_row_component.html.erb b/app/components/a_level_row_component.html.erb index 001b6f9857..0413dfd603 100644 --- a/app/components/a_level_row_component.html.erb +++ b/app/components/a_level_row_component.html.erb @@ -1,4 +1,18 @@ -<% if course.a_levels_requirements_answered? %> +<% if has_errors? %> + <%= govuk_inset_text(classes: "app-inset-text--narrow-border app-inset-text--error") do %> + <% a_level_errors.each do |a_level_error| %> +
+ <%= t("course.#{wizard_step(a_level_error)}.heading") %> +
++ <%= govuk_link_to( + @errors[a_level_error], + enrichment_error_url(course:, provider_code:, field: a_level_error.to_s, message: @errors[a_level_error]) + ) %> +
+ <% end %> + <% end %> +<% elsif minimum_a_level_completed? %> <% if @course.a_level_requirements.present? %> <% Array(@course.a_level_subject_requirements).map do |a_level_subject_requirement| %>@@ -26,17 +40,17 @@ <% else %> <%= a_level_not_required_content %> <% end %> - <% else %> - <%= govuk_inset_text(classes: inset_text_css_classes) do %> -
<%= t("publish.providers.courses.description_content.a_levels_heading") %>
+ <%= govuk_inset_text(classes: "app-inset-text--narrow-border app-inset-text--important") do %> ++ <%= t("publish.providers.courses.description_content.a_levels_heading") %> +
<%= govuk_link_to t("publish.providers.courses.description_content.enter_a_levels"), publish_provider_recruitment_cycle_course_a_levels_are_any_a_levels_required_for_this_course_path( course.provider.provider_code, course.provider.recruitment_cycle_year, - course.course_code, - display_errors: has_errors? ? true : nil + course.course_code ) %>
<% end %> diff --git a/app/components/a_level_row_component.rb b/app/components/a_level_row_component.rb index 4a20116d88..33d9f40834 100644 --- a/app/components/a_level_row_component.rb +++ b/app/components/a_level_row_component.rb @@ -3,10 +3,21 @@ class ALevelRowComponent < ViewComponent::Base attr_reader :course, :errors + delegate :provider, to: :course + delegate :provider_code, to: :provider + include ViewHelper + + A_LEVEL_ERRORS = %i[ + a_level_requirements + a_level_subject_requirements + accept_pending_a_level + accept_a_level_equivalency + ].freeze + def initialize(course:, errors: nil) super @course = course - @errors = errors&.values&.flatten + @errors = errors end def a_level_not_required_content @@ -34,11 +45,26 @@ def a_level_equivalency_summary_content I18n.t("course.a_level_equivalencies.row.#{@course.accept_a_level_equivalency?}") unless @course.accept_a_level_equivalency.nil? end - def inset_text_css_classes - 'app-inset-text--narrow-border app-inset-text--important' + def has_errors? + @errors.present? && a_level_errors.any? end - def has_errors? - false + def a_level_errors + Array(@errors.keys & A_LEVEL_ERRORS) + end + + def wizard_step(a_level_error) + { + a_level_requirements: :are_any_a_levels_required_for_this_course, + a_level_subject_requirements: :what_a_level_is_required, + accept_pending_a_level: :consider_pending_a_level, + accept_a_level_equivalency: :a_level_equivalencies + }.with_indifferent_access[a_level_error] + end + + def minimum_a_level_completed? + !course.a_level_requirements.nil? && + (course.a_level_requirements.blank? || + (course.a_level_requirements.present? && course.a_level_subject_requirements.present?)) end end diff --git a/app/controllers/publish/courses/a_level_requirements/a_level_requirements_controller.rb b/app/controllers/publish/courses/a_level_requirements/a_level_requirements_controller.rb index 94fea35763..cf9a55a5cd 100644 --- a/app/controllers/publish/courses/a_level_requirements/a_level_requirements_controller.rb +++ b/app/controllers/publish/courses/a_level_requirements/a_level_requirements_controller.rb @@ -14,6 +14,8 @@ def new course: @course, step_params: ) + + @wizard.valid_step? if params[:display_errors].present? end def create diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 5736f7cc40..226a70f57a 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -37,15 +37,14 @@ def enrichment_error_link(model, field, error) end # TODO: refactor enrichment_summary method to not use an instance variable - def enrichment_summary(summary_list, model, key, value, fields, action_path: nil, action_visually_hidden_text: nil) + def enrichment_summary(summary_list, model, key, value, fields, action_path: nil, action_visually_hidden_text: nil, render_errors: true) action = render_action(action_path, action_visually_hidden_text || key.downcase) - if fields.any? { |field| @errors&.key? field.to_sym } errors = fields.map do |field| @errors[field.to_sym]&.map { |error| enrichment_error_link(model, field, error) } end.flatten - value = raw(*errors) + value = raw(*errors) if render_errors.present? action = nil end diff --git a/app/helpers/view_helper.rb b/app/helpers/view_helper.rb index 3800e63dbc..43f85f98a7 100644 --- a/app/helpers/view_helper.rb +++ b/app/helpers/view_helper.rb @@ -63,7 +63,31 @@ def enrichment_error_url(provider_code:, course:, field:, message: nil) sites: "#{base}/schools?display_errors=true", study_sites: (course.provider&.study_sites&.none? ? "#{provider_base}/study-sites" : "#{base}/study-sites").to_s, accrediting_provider: accredited_provider_publish_provider_recruitment_cycle_course_path(course.provider_code, course.recruitment_cycle_year, course.course_code), - applications_open_from: "#{base}/applications-open" + applications_open_from: "#{base}/applications-open", + a_level_requirements: publish_provider_recruitment_cycle_course_a_levels_are_any_a_levels_required_for_this_course_path( + course.provider_code, + course.provider.recruitment_cycle_year, + course.course_code, + display_errors: true + ), + a_level_subject_requirements: publish_provider_recruitment_cycle_course_a_levels_what_a_level_is_required_path( + course.provider_code, + course.provider.recruitment_cycle_year, + course.course_code, + display_errors: true + ), + accept_pending_a_level: publish_provider_recruitment_cycle_course_a_levels_consider_pending_a_level_path( + course.provider_code, + course.provider.recruitment_cycle_year, + course.course_code, + display_errors: true + ), + accept_a_level_equivalency: publish_provider_recruitment_cycle_course_a_levels_a_level_equivalencies_path( + course.provider_code, + course.provider.recruitment_cycle_year, + course.course_code, + display_errors: true + ) }.with_indifferent_access[field] end end diff --git a/app/models/course.rb b/app/models/course.rb index 96fc7cbcac..1e6d2e516b 100644 --- a/app/models/course.rb +++ b/app/models/course.rb @@ -344,6 +344,7 @@ def self.entry_requirement_options_without_nil_choice validate :validate_custom_age_range, on: %i[create new], if: -> { age_range_in_years.present? } validate :accredited_provider_exists_in_current_cycle, on: :publish, unless: -> { self_accredited? } validates_with UniqueCourseValidator, on: :new + validates_with ALevelCourseValidator, on: :publish, if: :teacher_degree_apprenticeship? validates :name, :profpost_flag, :program_type, :qualification, :start_date, :study_mode, presence: true validates :age_range_in_years, presence: true, on: %i[new create publish], unless: :further_education_course? diff --git a/app/validators/a_level_course_validator.rb b/app/validators/a_level_course_validator.rb new file mode 100644 index 0000000000..1800749f49 --- /dev/null +++ b/app/validators/a_level_course_validator.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class ALevelCourseValidator < ActiveModel::Validator + def validate(record) + return record.errors.add(:a_level_requirements, :blank) if record.a_level_requirements.nil? + + return if record.a_level_requirements.blank? # No A level required + + return record.errors.add(:a_level_subject_requirements, :blank) if record.a_level_subject_requirements.blank? + + return record.errors.add(:accept_pending_a_level, :blank) if record.accept_pending_a_level.nil? + + record.errors.add(:accept_a_level_equivalency, :blank) if record.accept_a_level_equivalency.nil? + end +end diff --git a/app/views/publish/courses/_description_content.html.erb b/app/views/publish/courses/_description_content.html.erb index 6a3cf8b95f..093551d8e7 100644 --- a/app/views/publish/courses/_description_content.html.erb +++ b/app/views/publish/courses/_description_content.html.erb @@ -136,9 +136,14 @@ :course, t("publish.providers.courses.description_content.a_levels_label"), (render ALevelRowComponent.new(course:, errors: @errors)), - %w[a_levels_requirements], - action_path: publish_provider_recruitment_cycle_course_a_levels_are_any_a_levels_required_for_this_course_path(@provider.provider_code, @provider.recruitment_cycle_year, course.course_code), - action_visually_hidden_text: "A levels" + %w[a_level_requirements a_level_subject_requirements accept_pending_a_level accept_a_level_equivalency], + action_path: publish_provider_recruitment_cycle_course_a_levels_are_any_a_levels_required_for_this_course_path( + @provider.provider_code, + @provider.recruitment_cycle_year, + course.course_code + ), + action_visually_hidden_text: "A levels", + render_errors: false ) %> <% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 7b9cfea4b2..b133523b05 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -755,6 +755,14 @@ en: does_not_exist_in_cycle: "The accredited provider %{accredited_provider_code} does not exist in this cycle" is_send: inclusion: Select if this course has a special educational needs and disability (SEND) specialism + a_level_requirements: + blank: Enter A level requirements + a_level_subject_requirements: + blank: Enter A level requirements + accept_pending_a_level: + blank: Enter information on pending A levels + accept_a_level_equivalency: + blank: Enter A level equivalency test requirements base: duplicate: "This course already exists. You should add further schools for this course to the existing profile in Publish" visa_sponsorship_not_publishable: "Select if visas can be sponsored" diff --git a/spec/components/a_level_row_component_spec.rb b/spec/components/a_level_row_component_spec.rb index df36bb97c2..6938a9967d 100644 --- a/spec/components/a_level_row_component_spec.rb +++ b/spec/components/a_level_row_component_spec.rb @@ -3,6 +3,12 @@ require 'rails_helper' RSpec.describe ALevelRowComponent do + include Rails.application.routes.url_helpers + + let(:a_level_subject_requirement) do + { 'subject' => 'other_subject', 'other_subject' => 'Math', 'minimum_grade_required' => 'A' } + end + it 'renders the a_level_not_required_content when a level requirements are not present' do course = create(:course, a_level_requirements: false) component = described_class.new(course: course.decorate) @@ -11,6 +17,22 @@ expect(rendered_component.text).to include(I18n.t('publish.providers.courses.description_content.a_levels_not_required')) end + it 'does render to enter A levels when not A levels are answered' do + course = create(:course, a_level_requirements: nil) + component = described_class.new(course: course.decorate) + rendered_component = render_inline(component) + + expect(rendered_component.text).to include(I18n.t('publish.providers.courses.description_content.enter_a_levels')) + end + + it 'does render to enter A levels when not A level subjects are answered' do + course = create(:course, a_level_requirements: true) + component = described_class.new(course: course.decorate) + rendered_component = render_inline(component) + + expect(rendered_component.text).to include(I18n.t('publish.providers.courses.description_content.enter_a_levels')) + end + it 'renders the a_level_subject_row_content when a level requirements and subject requirements are present' do a_level_subject_requirement = { 'subject' => 'other_subject', 'other_subject' => 'Math', 'minimum_grade_required' => 'A' } course = create(:course, a_level_requirements: true, a_level_subject_requirements: [a_level_subject_requirement]) @@ -21,7 +43,7 @@ end it 'renders the pending a level summary content for acceptance when course accepts pending a levels' do - course = create(:course, accept_pending_a_level: true, a_level_requirements: true) + course = create(:course, :with_a_level_requirements, accept_pending_a_level: true, a_level_requirements: true) component = described_class.new(course: course.decorate) rendered_component = render_inline(component) @@ -29,7 +51,7 @@ end it 'renders the pending a level summary content for non-acceptance when course does not accept pending a levels' do - course = create(:course, accept_pending_a_level: false, a_level_requirements: true) + course = create(:course, :with_a_level_requirements, accept_pending_a_level: false, a_level_requirements: true) component = described_class.new(course: course.decorate) rendered_component = render_inline(component) @@ -37,7 +59,7 @@ end it 'renders the a level equivalency summary content for acceptance when course accepts a level equivalencies' do - course = create(:course, accept_a_level_equivalency: true, a_level_requirements: true) + course = create(:course, :with_a_level_requirements, accept_a_level_equivalency: true, a_level_requirements: true) component = described_class.new(course: course.decorate) rendered_component = render_inline(component) @@ -45,7 +67,7 @@ end it 'renders the a level equivalency summary content for non-acceptance when course does not accept a level equivalencies' do - course = create(:course, accept_a_level_equivalency: false, a_level_requirements: true) + course = create(:course, :with_a_level_requirements, accept_a_level_equivalency: false, a_level_requirements: true) component = described_class.new(course: course.decorate) rendered_component = render_inline(component) @@ -53,7 +75,7 @@ end it 'renders the additional a level equivalencies content when present' do - course = create(:course, accept_a_level_equivalency: true, additional_a_level_equivalencies: 'Some additional information', a_level_requirements: true) + course = create(:course, :with_a_level_requirements, accept_a_level_equivalency: true, additional_a_level_equivalencies: 'Some additional information', a_level_requirements: true) component = described_class.new(course: course.decorate) rendered_component = render_inline(component) @@ -61,7 +83,7 @@ end it 'does not render the additional a level equivalencies when no equivalencies' do - course = create(:course, accept_a_level_equivalency: false, additional_a_level_equivalencies: 'Some additional information', a_level_requirements: true) + course = create(:course, :with_a_level_requirements, accept_a_level_equivalency: false, additional_a_level_equivalencies: 'Some additional information', a_level_requirements: true) component = described_class.new(course: course.decorate) rendered_component = render_inline(component) @@ -70,7 +92,7 @@ it 'does not render the pending A level if the question is not answered' do a_level_subject_requirement = { 'subject' => 'other_subject', 'other_subject' => 'Math', 'minimum_grade_required' => 'A' } - course = create(:course, accept_pending_a_level: nil, a_level_requirements: true, a_level_subject_requirements: [a_level_subject_requirement]) + course = create(:course, :with_a_level_requirements, accept_pending_a_level: nil, a_level_requirements: true, a_level_subject_requirements: [a_level_subject_requirement]) component = described_class.new(course: course.decorate) rendered_component = render_inline(component) @@ -79,7 +101,7 @@ it 'does not render the equivalency A level if the question is not answered' do a_level_subject_requirement = { 'subject' => 'other_subject', 'other_subject' => 'Math', 'minimum_grade_required' => 'A' } - course = create(:course, accept_a_level_equivalency: nil, a_level_requirements: true, a_level_subject_requirements: [a_level_subject_requirement]) + course = create(:course, :with_a_level_requirements, accept_a_level_equivalency: nil, a_level_requirements: true, a_level_subject_requirements: [a_level_subject_requirement]) component = described_class.new(course: course.decorate) rendered_component = render_inline(component) @@ -92,4 +114,95 @@ expect(component.has_errors?).to be(false) end + + describe 'when course has errors on A levels' do + let(:rendered_component) { render_inline(component) } + let(:component) do + described_class.new(course: course.decorate, errors: course.errors.messages) + end + let(:course) do + create( + :course, + :with_teacher_degree_apprenticeship, + :resulting_in_undergraduate_degree_with_qts, + :with_gcse_equivalency, + :draft_enrichment, + :with_a_level_requirements, + attributes + ) + end + let(:attributes) { {} } + + before do + course.valid?(:publish) + end + + context 'when accept_a_level_equivalency is nil' do + let(:attributes) { { accept_a_level_equivalency: nil } } + + it 'renders the error message for accept_a_level_equivalency' do + expect(rendered_component).to have_text(I18n.t("course.#{component.wizard_step(:accept_a_level_equivalency)}.heading")) + expect(rendered_component).to have_link( + component.errors[:accept_a_level_equivalency].first, + href: publish_provider_recruitment_cycle_course_a_levels_a_level_equivalencies_path( + course.provider.provider_code, + course.provider.recruitment_cycle_year, + course.course_code, + display_errors: true + ) + ) + end + end + + context 'when a_level_requirements is nil' do + let(:attributes) { { a_level_requirements: nil } } + + it 'renders the error message for a_level_requirements' do + expect(rendered_component).to have_text(I18n.t("course.#{component.wizard_step(:a_level_requirements)}.heading")) + expect(rendered_component).to have_link( + component.errors[:a_level_requirements].first, + href: publish_provider_recruitment_cycle_course_a_levels_are_any_a_levels_required_for_this_course_path( + course.provider.provider_code, + course.provider.recruitment_cycle_year, + course.course_code, + display_errors: true + ) + ) + end + end + + context 'when a_level_subject_requirements is blank' do + let(:attributes) { { a_level_requirements: true, a_level_subject_requirements: [] } } + + it 'renders the error message for a_level_subject_requirements' do + expect(rendered_component).to have_text(I18n.t("course.#{component.wizard_step(:a_level_subject_requirements)}.heading")) + expect(rendered_component).to have_link( + component.errors[:a_level_subject_requirements].first, + href: publish_provider_recruitment_cycle_course_a_levels_what_a_level_is_required_path( + course.provider.provider_code, + course.provider.recruitment_cycle_year, + course.course_code, + display_errors: true + ) + ) + end + end + + context 'when accept_pending_a_level is nil' do + let(:attributes) { { accept_pending_a_level: nil } } + + it 'renders the error message for accept_pending_a_level' do + expect(rendered_component).to have_text(I18n.t("course.#{component.wizard_step(:accept_pending_a_level)}.heading")) + expect(rendered_component).to have_link( + component.errors[:accept_pending_a_level].first, + href: publish_provider_recruitment_cycle_course_a_levels_consider_pending_a_level_path( + course.provider.provider_code, + course.provider.recruitment_cycle_year, + course.course_code, + display_errors: true + ) + ) + end + end + end end diff --git a/spec/features/publish/courses/new_tda_course_spec.rb b/spec/features/publish/courses/new_tda_course_spec.rb index 0b24466592..235c2c78f4 100644 --- a/spec/features/publish/courses/new_tda_course_spec.rb +++ b/spec/features/publish/courses/new_tda_course_spec.rb @@ -44,6 +44,7 @@ and_i_do_not_see_the_change_link_for_course_length given_i_fill_in_all_other_fields_for_the_course + and_i_add_a_level_requirements when_i_publish_the_course then_the_course_is_published end @@ -84,6 +85,7 @@ and_i_do_not_see_the_change_link_for_course_length given_i_fill_in_all_other_fields_for_the_course + and_i_add_a_level_requirements when_i_publish_the_course then_the_course_is_published end @@ -123,6 +125,7 @@ and_i_do_not_see_the_change_link_for_course_length given_i_fill_in_all_other_fields_for_the_course + and_i_add_a_level_requirements when_i_publish_the_course then_the_course_is_published end @@ -650,6 +653,12 @@ def then_i_am_on_the_funding_type_page expect(page).to have_current_path(new_publish_provider_recruitment_cycle_courses_funding_type_path(provider_code: provider.provider_code, recruitment_cycle_year: 2025), ignore_query: true) end + def and_i_add_a_level_requirements + click_on 'Enter A levels and equivalency test requirements' + choose 'No' + and_i_click_continue + end + alias_method :and_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship, :then_i_do_not_see_the_change_links_for_study_mode_funding_type_and_visa_sponsorship alias_method :and_i_visit_the_courses_page, :when_i_visit_the_courses_page alias_method :and_i_choose_a_degree_awarding_qualification, :when_i_choose_a_degree_awarding_qualification diff --git a/spec/features/publish/courses/publishing_a_teacher_degree_apprenticeship_course_with_validation_errors_spec.rb b/spec/features/publish/courses/publishing_a_teacher_degree_apprenticeship_course_with_validation_errors_spec.rb new file mode 100644 index 0000000000..873c69f36d --- /dev/null +++ b/spec/features/publish/courses/publishing_a_teacher_degree_apprenticeship_course_with_validation_errors_spec.rb @@ -0,0 +1,238 @@ +# frozen_string_literal: true + +require 'rails_helper' + +feature 'Publishing courses errors', { can_edit_current_and_next_cycles: false } do + scenario 'The error links target the correct pages' do + given_i_am_authenticated_as_a_provider_user + and_the_tda_feature_flag_is_active + and_there_is_an_invalid_tda_course_i_want_to_publish + + when_i_visit_the_course_page + and_i_click_the_publish_link + then_i_see_a_level_is_required + and_i_see_a_level_is_required_in_a_level_row + + when_i_click_on_the_a_level_is_required_error + then_i_am_on_the_a_levels_required_for_the_course_page + and_i_see_a_level_required_error + + when_i_choose_yes + and_i_click_continue + + when_i_visit_the_course_page + and_i_click_the_publish_link + then_i_see_a_level_subject_is_required + when_i_click_on_the_a_level_is_required_error + then_i_am_on_the_what_a_levels_is_required_for_the_course_page + and_i_see_what_a_level_required_error + + when_i_choose_any_subject + and_i_click_continue + + when_i_visit_the_course_page + and_i_click_the_publish_link + then_i_see_pending_a_level_is_required + + when_i_click_on_the_pending_a_level_error + then_i_am_on_the_consider_pending_a_level_page + and_i_see_the_pending_a_level_error + + when_i_choose_yes + and_i_click_continue + + when_i_visit_the_course_page + and_i_click_the_publish_link + then_i_see_a_level_equivalencies_is_required + + when_i_click_on_the_a_level_equivalencies + then_i_am_on_the_a_level_equivalencies_page + + when_i_choose_yes + and_i_click_update_a_levels + + when_i_visit_the_course_page + and_i_click_the_publish_link + then_the_course_is_published + end + + def given_i_am_authenticated_as_a_provider_user + recruitment_cycle = create(:recruitment_cycle, year: 2025) + @user = create(:user, providers: [build(:provider, recruitment_cycle:, provider_type: 'lead_school', sites: [build(:site), build(:site)], study_sites: [build(:site, :study_site), build(:site, :study_site)])]) + @provider = @user.providers.first + create(:provider, :accredited_provider, provider_code: '1BJ') + @accredited_provider = create(:provider, :accredited_provider, provider_code: '1BJ', recruitment_cycle:) + @provider.accrediting_provider_enrichments = [] + @provider.accrediting_provider_enrichments << AccreditingProviderEnrichment.new( + { + UcasProviderCode: @accredited_provider.provider_code, + Description: 'description' + } + ) + + given_i_am_authenticated(user: @user) + end + + def and_the_tda_feature_flag_is_active + allow(Settings.features).to receive(:teacher_degree_apprenticeship).and_return(true) + end + + def and_there_is_an_invalid_tda_course_i_want_to_publish + @course = create( + :course, + :with_teacher_degree_apprenticeship, + :resulting_in_undergraduate_degree_with_qts, + :with_gcse_equivalency, + :draft_enrichment, + provider: @provider, + accrediting_provider: @accredited_provider, + a_level_requirements: nil, + a_level_subject_requirements: [], + accept_pending_a_level: nil, + accept_a_level_equivalency: nil + ) + @course.sites << build_list(:site, 1, provider: @provider) + end + + def when_i_visit_the_course_page + publish_provider_courses_show_page.load( + provider_code: @provider.provider_code, + recruitment_cycle_year: @provider.recruitment_cycle_year, + course_code: @course.course_code + ) + end + + def then_i_am_on_the_course_page + expect(page).to have_current_path( + publish_provider_recruitment_cycle_course_path( + @provider.provider_code, + 2025, + @course.course_code + ) + ) + end + + def and_i_click_the_publish_link + publish_provider_courses_show_page.course_button_panel.publish_button.click + end + alias_method :when_i_click_the_publish_link, :and_i_click_the_publish_link + + def then_i_see_a_level_is_required + and_i_see_that_i_need_to_enter_a_level_requirements + expect(page).to have_content('Are any A levels required for this course?') + end + + def then_i_see_a_level_subject_is_required + and_i_see_that_i_need_to_enter_a_level_requirements + expect(page).to have_content('What A level is required?') + end + + def and_i_see_that_i_need_to_enter_a_level_requirements + within '.govuk-error-summary' do + expect(page).to have_content('Enter A level requirements') + end + end + + def and_i_see_a_level_is_required_in_a_level_row + expect(page).to have_content('Enter A level requirements').twice + end + + def then_i_am_on_the_a_levels_required_for_the_course_page + expect(page).to have_current_path( + publish_provider_recruitment_cycle_course_a_levels_are_any_a_levels_required_for_this_course_path( + @provider.provider_code, + 2025, + @course.course_code, + display_errors: true + ) + ) + end + + def when_i_click_on_the_a_level_is_required_error + click_on 'Enter A level requirements', match: :first + end + + def and_i_see_a_level_required_error + expect(page).to have_content('Select if this course requires any A levels').twice + end + + def when_i_choose_yes + choose 'Yes' + end + + def and_i_click_continue + click_on 'Continue' + end + + def then_i_am_on_the_what_a_levels_is_required_for_the_course_page + expect(page).to have_current_path( + publish_provider_recruitment_cycle_course_a_levels_what_a_level_is_required_path( + @provider.provider_code, + 2025, + @course.course_code, + display_errors: true + ) + ) + end + + def and_i_see_what_a_level_required_error + expect(page).to have_content('Select a subject').twice + end + + def when_i_choose_any_subject + choose 'Any subject' + end + + def then_i_see_pending_a_level_is_required + expect(page).to have_content('Enter information on pending A levels').twice + expect(page).to have_content('Will you consider candidates with pending A levels?') + end + + def when_i_click_on_the_pending_a_level_error + click_on 'Enter information on pending A levels', match: :first + end + + def then_i_am_on_the_consider_pending_a_level_page + expect(page).to have_current_path( + publish_provider_recruitment_cycle_course_a_levels_consider_pending_a_level_path( + @provider.provider_code, + @provider.recruitment_cycle_year, + @course.course_code, + display_errors: true + ) + ) + end + + def and_i_see_the_pending_a_level_error + expect(page).to have_content('Select if you will consider candidates with pending A levels').twice + end + + def then_i_see_a_level_equivalencies_is_required + expect(page).to have_content('Will you consider candidates who need to take an equivalency test for their A levels?') + expect(page).to have_content('Enter A level equivalency test requirements').twice + end + + def when_i_click_on_the_a_level_equivalencies + click_on 'Enter A level equivalency test requirements', match: :first + end + + def then_i_am_on_the_a_level_equivalencies_page + expect(page).to have_current_path( + publish_provider_recruitment_cycle_course_a_levels_a_level_equivalencies_path( + @provider.provider_code, + @provider.recruitment_cycle_year, + @course.course_code, + display_errors: true + ) + ) + end + + def and_i_click_update_a_levels + click_on 'Update A levels' + end + + def then_the_course_is_published + expect(page).to have_content('Your course has been published.') + expect(@course.reload.is_published?).to be true + end +end diff --git a/spec/models/course/publishable_spec.rb b/spec/models/course/publishable_spec.rb index 55ce9372c5..ff9ef5a286 100644 --- a/spec/models/course/publishable_spec.rb +++ b/spec/models/course/publishable_spec.rb @@ -81,4 +81,89 @@ it { is_expected.not_to be_empty } end end + + context 'when publishing a NON teacher degree apprenticeship course without A levels' do + it 'does not require A level to be answered' do + course = create( + :course, + a_level_requirements: nil + ) + course.valid?(:publish) + expect(course.errors[:a_level_requirements]).to eq([]) + end + end + + context 'when publishing a teacher degree apprenticeship course without A levels' do + it 'requires A level to be answered' do + course = create( + :course, + :with_teacher_degree_apprenticeship, + :resulting_in_undergraduate_degree_with_qts, + a_level_requirements: nil + ) + course.valid?(:publish) + expect(course.errors[:a_level_requirements]).to include('Enter A level requirements') + end + end + + context 'when publishing a teacher degree apprenticeship course without A levels subject requirements' do + it 'requires to add A level subject requirement' do + course = create( + :course, + :with_teacher_degree_apprenticeship, + :resulting_in_undergraduate_degree_with_qts, + a_level_requirements: true, + a_level_subject_requirements: [] + ) + course.valid?(:publish) + expect(course.errors[:a_level_subject_requirements]).to include('Enter A level requirements') + end + end + + context 'when publishing a teacher degree apprenticeship course with A levels without pending A level answered' do + it 'requires to add if accept pending A level' do + course = create( + :course, + :with_teacher_degree_apprenticeship, + :resulting_in_undergraduate_degree_with_qts, + :with_a_level_requirements, + accept_pending_a_level: nil + ) + course.valid?(:publish) + expect(course.errors[:accept_pending_a_level]).to include('Enter information on pending A levels') + end + end + + context 'when publishing a teacher degree apprenticeship course with A levels without A level equivalency answered' do + it 'requires to add A level equivalency requirement' do + course = create( + :course, + :with_teacher_degree_apprenticeship, + :resulting_in_undergraduate_degree_with_qts, + :with_a_level_requirements, + accept_a_level_equivalency: nil + ) + course.valid?(:publish) + expect(course.errors[:accept_a_level_equivalency]).to include('Enter A level equivalency test requirements') + end + end + + context 'when publishing a teacher degree apprenticeship course and no A levels required' do + it 'is valid' do + course = create( + :course, + :with_teacher_degree_apprenticeship, + :resulting_in_undergraduate_degree_with_qts, + a_level_requirements: false, + a_level_subject_requirements: [], + accept_pending_a_level: nil, + accept_a_level_equivalency: nil + ) + course.valid?(:publish) + expect(course.errors[:a_level_requirements]).to eq([]) + expect(course.errors[:a_level_subject_requirements]).to eq([]) + expect(course.errors[:accept_pending_a_level]).to eq([]) + expect(course.errors[:accept_a_level_equivalency]).to eq([]) + end + end end diff --git a/spec/support/page_objects/publish/provider_courses_show.rb b/spec/support/page_objects/publish/provider_courses_show.rb index 259d756f6a..2692fe35dc 100644 --- a/spec/support/page_objects/publish/provider_courses_show.rb +++ b/spec/support/page_objects/publish/provider_courses_show.rb @@ -23,6 +23,7 @@ class ProviderCoursesShow < PageObjects::Base section :salary_details, Sections::SummaryList, '[data-qa="enrichment__salary_details"]' section :degree, Sections::SummaryList, '[data-qa="enrichment__degree_grade"]' section :gcse, Sections::SummaryList, '[data-qa="enrichment__accept_pending_gcse"]' + section :a_level, Sections::SummaryList, '[data-qa="enrichment__a_level_requirements"]' section :personal_qualities, Sections::SummaryList, '[data-qa="enrichment__personal_qualities"]' section :other_requirements, Sections::SummaryList, '[data-qa="enrichment__other_requirements"]' section :course_button_panel, Sections::CourseButtonPanel, '[data-qa="course__button_panel"]'