From 96ae49b90cc5f14536c90b3e9e22af031cac0f7e Mon Sep 17 00:00:00 2001 From: Andrew White Date: Fri, 19 Dec 2025 06:01:07 +0000 Subject: [PATCH] Add a validation requests controller to bops_preapps All the redirect_to/return_to handling was becoming unmanageable. --- app/models/validation_request.rb | 8 +- bin/brakeman | 16 + config/brakeman.ignore | 116 ++- .../cancellations_controller.rb | 86 +++ .../validation_requests_controller.rb | 157 ++++ .../tasks/other_validation_requests_form.rb | 23 +- .../other-validation-requests/show.html.erb | 8 +- .../validation_requests/_breadcrumbs.html.erb | 3 + .../cancellations/new.html.erb | 2 + .../cancellations/new/_other_change.html.erb | 37 + .../validation_requests/edit.html.erb | 2 + .../edit/_other_change.html.erb | 27 + .../validation_requests/new.html.erb | 2 + .../new/_other_change.html.erb | 33 + .../validation_requests/show.html.erb | 2 + .../show/_other_change.html.erb | 64 ++ engines/bops_preapps/config/locales/en.yml | 33 + engines/bops_preapps/config/routes.rb | 4 + .../tasks/other_validation_requests_spec.rb | 729 ++++++++++++++++++ 19 files changed, 1314 insertions(+), 38 deletions(-) create mode 100755 bin/brakeman create mode 100644 engines/bops_preapps/app/controllers/bops_preapps/validation_requests/cancellations_controller.rb create mode 100644 engines/bops_preapps/app/controllers/bops_preapps/validation_requests_controller.rb create mode 100644 engines/bops_preapps/app/views/bops_preapps/validation_requests/_breadcrumbs.html.erb create mode 100644 engines/bops_preapps/app/views/bops_preapps/validation_requests/cancellations/new.html.erb create mode 100644 engines/bops_preapps/app/views/bops_preapps/validation_requests/cancellations/new/_other_change.html.erb create mode 100644 engines/bops_preapps/app/views/bops_preapps/validation_requests/edit.html.erb create mode 100644 engines/bops_preapps/app/views/bops_preapps/validation_requests/edit/_other_change.html.erb create mode 100644 engines/bops_preapps/app/views/bops_preapps/validation_requests/new.html.erb create mode 100644 engines/bops_preapps/app/views/bops_preapps/validation_requests/new/_other_change.html.erb create mode 100644 engines/bops_preapps/app/views/bops_preapps/validation_requests/show.html.erb create mode 100644 engines/bops_preapps/app/views/bops_preapps/validation_requests/show/_other_change.html.erb create mode 100644 engines/bops_preapps/spec/system/tasks/other_validation_requests_spec.rb diff --git a/app/models/validation_request.rb b/app/models/validation_request.rb index 3473df784b..eab383e7f0 100644 --- a/app/models/validation_request.rb +++ b/app/models/validation_request.rb @@ -16,6 +16,8 @@ class ValidationRequest < ApplicationRecord TimeExtensionValidationRequest ].freeze + REQUEST_TYPE_MAP = REQUEST_TYPES.index_by { |type| type[0..-18].underscore }.freeze + with_options to: :planning_application do delegate :audits delegate :validated?, prefix: :planning_application @@ -122,8 +124,12 @@ def grouped_by_type end end + def type_param + type[0..-18].underscore + end + def type_symbol - type.underscore.gsub(/_validation_request\z/, "").to_sym + type_param.to_sym end def response_due diff --git a/bin/brakeman b/bin/brakeman new file mode 100755 index 0000000000..a2eeb02f0c --- /dev/null +++ b/bin/brakeman @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'brakeman' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("brakeman", "brakeman") diff --git a/config/brakeman.ignore b/config/brakeman.ignore index 8e69c40a3e..dbdd167ff7 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -7,7 +7,7 @@ "check_name": "VerbConfusion", "message": "Potential HTTP verb confusion. `HEAD` is routed like `GET` but `request.get?` will return `false`", "file": "engines/bops_core/app/controllers/concerns/bops_core/application_controller.rb", - "line": 98, + "line": 128, "link": "https://brakemanscanner.org/docs/warning_types/http_verb_confusion/", "code": "session[:back_path] = request.referer if request.get?", "render_path": null, @@ -57,6 +57,40 @@ ], "note": "" }, + { + "warning_type": "Dynamic Render Path", + "warning_code": 15, + "fingerprint": "5240d450204c9e3b74401ae28b8c08ad7dc4788ca35f31cfe0a56b8fa6005635", + "check_name": "Render", + "message": "Render path contains parameter value", + "file": "engines/bops_preapps/app/views/bops_preapps/validation_requests/cancellations/new.html.erb", + "line": 2, + "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "code": "render(action => \"#{controller_path}/new/#{PlanningApplicationPresenter.new(view_context, current_local_authority.planning_applications.find_by!(:reference => params[:reference])).validation_requests.find(params[:validation_request_id]).type_param}\", {})", + "render_path": [ + { + "type": "controller", + "class": "BopsPreapps::ValidationRequests::CancellationsController", + "method": "create", + "line": 36, + "file": "engines/bops_preapps/app/controllers/bops_preapps/validation_requests/cancellations_controller.rb", + "rendered": { + "name": "bops_preapps/validation_requests/cancellations/new", + "file": "engines/bops_preapps/app/views/bops_preapps/validation_requests/cancellations/new.html.erb" + } + } + ], + "location": { + "type": "template", + "template": "bops_preapps/validation_requests/cancellations/new" + }, + "user_input": "params[:validation_request_id]", + "confidence": "Weak", + "cwe_id": [ + 22 + ], + "note": "" + }, { "warning_type": "Denial of Service", "warning_code": 76, @@ -64,7 +98,7 @@ "check_name": "RegexDoS", "message": "Parameter value used in regular expression", "file": "app/controllers/application_controller.rb", - "line": 48, + "line": 55, "link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/", "code": "/\\/#{get_planning_application(params[planning_application_param]).id}/", "render_path": null, @@ -82,46 +116,36 @@ "note": "" }, { - "warning_type": "Cross-Site Scripting", - "warning_code": 2, - "fingerprint": "98a2eb7517c9b0fbbbb711af14b9eb2241ece8b3b375dc85bc30d394a659a0f5", - "check_name": "CrossSiteScripting", - "message": "Unescaped parameter value", - "file": "app/views/planning_applications/site_notices/_status.html.erb", - "line": 23, - "link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting", - "code": "PlanningApplicationPresenter.new(view_context, get_planning_application(params[planning_application_param])).last_site_notice.preview_content", + "warning_type": "Dynamic Render Path", + "warning_code": 15, + "fingerprint": "afeab00e1d4d52748bb9e6533d9761489e90595357a5f6ad2166530f1817d400", + "check_name": "Render", + "message": "Render path contains parameter value", + "file": "engines/bops_preapps/app/views/bops_preapps/validation_requests/edit.html.erb", + "line": 2, + "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "code": "render(action => \"#{controller_path}/edit/#{PlanningApplicationPresenter.new(view_context, current_local_authority.planning_applications.find_by!(:reference => params[:reference])).validation_requests.find(params[:id]).type_param}\", {})", "render_path": [ { "type": "controller", - "class": "PlanningApplications::SiteNoticesController", - "method": "create", + "class": "BopsPreapps::ValidationRequestsController", + "method": "update", "line": 54, - "file": "app/controllers/planning_applications/site_notices_controller.rb", + "file": "engines/bops_preapps/app/controllers/bops_preapps/validation_requests_controller.rb", "rendered": { - "name": "planning_applications/site_notices/new", - "file": "app/views/planning_applications/site_notices/new.html.erb" - } - }, - { - "type": "template", - "name": "planning_applications/site_notices/new", - "line": 22, - "file": "app/views/planning_applications/site_notices/new.html.erb", - "rendered": { - "name": "planning_applications/site_notices/_status", - "file": "app/views/planning_applications/site_notices/_status.html.erb" + "name": "bops_preapps/validation_requests/edit", + "file": "engines/bops_preapps/app/views/bops_preapps/validation_requests/edit.html.erb" } } ], "location": { "type": "template", - "template": "planning_applications/site_notices/_status" + "template": "bops_preapps/validation_requests/edit" }, - "user_input": "params[planning_application_param]", + "user_input": "params[:id]", "confidence": "Weak", "cwe_id": [ - 79 + 22 ], "note": "" }, @@ -158,6 +182,40 @@ 22 ], "note": "" + }, + { + "warning_type": "Dynamic Render Path", + "warning_code": 15, + "fingerprint": "df3f134a8f88aadd7d08404d76efb177eef78b6f38546392f66e0dba8b39a71d", + "check_name": "Render", + "message": "Render path contains parameter value", + "file": "engines/bops_preapps/app/views/bops_preapps/validation_requests/new.html.erb", + "line": 2, + "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "code": "render(action => \"#{controller_path}/new/#{PlanningApplicationPresenter.new(view_context, current_local_authority.planning_applications.find_by!(:reference => params[:reference])).validation_requests.new(:type => request_type).type_param}\", {})", + "render_path": [ + { + "type": "controller", + "class": "BopsPreapps::ValidationRequestsController", + "method": "create", + "line": 30, + "file": "engines/bops_preapps/app/controllers/bops_preapps/validation_requests_controller.rb", + "rendered": { + "name": "bops_preapps/validation_requests/new", + "file": "engines/bops_preapps/app/views/bops_preapps/validation_requests/new.html.erb" + } + } + ], + "location": { + "type": "template", + "template": "bops_preapps/validation_requests/new" + }, + "user_input": "params[:reference]", + "confidence": "Weak", + "cwe_id": [ + 22 + ], + "note": "" } ], "brakeman_version": "7.0.0" diff --git a/engines/bops_preapps/app/controllers/bops_preapps/validation_requests/cancellations_controller.rb b/engines/bops_preapps/app/controllers/bops_preapps/validation_requests/cancellations_controller.rb new file mode 100644 index 0000000000..f39f5bad26 --- /dev/null +++ b/engines/bops_preapps/app/controllers/bops_preapps/validation_requests/cancellations_controller.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +module BopsPreapps + module ValidationRequests + class CancellationsController < AuthenticationController + before_action :set_layout + before_action :set_planning_application + before_action :set_case_record + before_action :set_validation_request + + before_action :ensure_request_is_cancelable + + helper_method :task_redirect_path + + def new + respond_to do |format| + format.html + end + end + + def create + @validation_request.assign_attributes(validation_request_params) + @validation_request.cancel_request! + + if @planning_application.validation_complete? + @validation_request.send_cancelled_validation_request_mail + end + + respond_to do |format| + format.html do + redirect_to task_redirect_path, notice: t(".#{@validation_request.type_param}") + end + end + rescue ValidationRequest::RecordCancelError + respond_to do |format| + format.html { render :new } + end + end + + private + + def set_layout + @show_header_bar = true + @show_sidebar = true + end + + def set_planning_application + scope = current_local_authority.planning_applications + planning_application = scope.find_by!(reference: params[:reference]) + + @planning_application = PlanningApplicationPresenter.new(view_context, planning_application) + end + + def set_case_record + @case_record = @planning_application.case_record + end + + def set_validation_request + @validation_request = @planning_application.validation_requests.find(params[:validation_request_id]) + end + + def validation_request_params + params.require(:validation_request).permit(:cancel_reason) + end + + def task_redirect_lookup(scope) + scope = "bops_preapps.validation_requests.#{scope}" + t(@validation_request.type_symbol, scope: scope.to_sym) + end + + def task_redirect_slug + task_redirect_lookup("redirect_slugs") + end + + def task_redirect_path + task_path(@planning_application, task_redirect_slug) + end + + def ensure_request_is_cancelable + unless @validation_request.open_or_pending? && @planning_application.validation_complete? + redirect_to task_redirect_path, alert: t(".validation_request_not_cancelable") + end + end + end + end +end diff --git a/engines/bops_preapps/app/controllers/bops_preapps/validation_requests_controller.rb b/engines/bops_preapps/app/controllers/bops_preapps/validation_requests_controller.rb new file mode 100644 index 0000000000..c3339707f9 --- /dev/null +++ b/engines/bops_preapps/app/controllers/bops_preapps/validation_requests_controller.rb @@ -0,0 +1,157 @@ +# frozen_string_literal: true + +module BopsPreapps + class ValidationRequestsController < AuthenticationController + before_action :set_layout + before_action :set_planning_application + before_action :set_case_record + before_action :set_validation_request, except: %i[new create] + before_action :build_validation_request, only: %i[new create] + + before_action :ensure_request_is_createable, only: %i[new create] + before_action :ensure_request_is_editable, only: %i[edit update] + before_action :ensure_request_is_destroyable, only: %i[destroy] + + helper_method :task_redirect_path + + def new + respond_to do |format| + format.html + end + end + + def create + respond_to do |format| + if @validation_request.save + format.html do + redirect_to task_redirect_path, notice: task_redirect_notice + end + else + format.html { render :new } + end + end + end + + def show + respond_to do |format| + format.html + end + end + + def edit + respond_to do |format| + format.html + end + end + + def update + respond_to do |format| + if @validation_request.update(validation_request_params) + format.html do + redirect_to task_redirect_path, notice: task_redirect_notice + end + else + format.html { render :edit } + end + end + end + + def destroy + respond_to do |format| + if @validation_request.destroy + format.html do + redirect_to task_redirect_path, notice: task_redirect_notice + end + else + format.html do + redirect_to task_redirect_path, alert: task_redirect_alert + end + end + end + end + + private + + def set_layout + @show_header_bar = true + @show_sidebar = true + end + + def set_planning_application + scope = current_local_authority.planning_applications + planning_application = scope.find_by!(reference: params[:reference]) + + @planning_application = PlanningApplicationPresenter.new(view_context, planning_application) + end + + def set_case_record + @case_record = @planning_application.case_record + end + + def set_validation_request + @validation_request = @planning_application.validation_requests.find(params[:id]) + end + + def request_type + ValidationRequest::REQUEST_TYPE_MAP.fetch(params.fetch(:type)) + rescue KeyError + raise BopsCore::Errors::BadRequestError, "Invalid validation request type" + end + + def build_validation_request + @validation_request = @planning_application.validation_requests.new(type: request_type) + + if action_name == "create" + @validation_request.assign_attributes(validation_request_params) + end + end + + def validation_request_attributes + scope = "bops_preapps.validation_requests.attributes" + t(@validation_request.type_symbol, scope: scope.to_sym) + end + + def validation_request_params + params.require(:validation_request).permit(*validation_request_attributes).merge(user: current_user) + end + + def task_redirect_lookup(scope) + scope = "bops_preapps.validation_requests.#{scope}" + t(@validation_request.type_symbol, scope: scope.to_sym) + end + + def task_redirect_notice + task_redirect_lookup("redirect_notices.#{action_name}") + end + + def task_redirect_alert + task_redirect_lookup("redirect_alerts.#{action_name}") + end + + def task_redirect_slug + task_redirect_lookup("redirect_slugs") + end + + def task_redirect_path + task_path(@planning_application, task_redirect_slug) + end + + def ensure_request_is_createable + if @planning_application.validated? + redirect_to task_redirect_path, alert: t(".validation_request_not_createable") + end + end + + def ensure_request_is_editable + unless @planning_application.not_started? + redirect_to task_redirect_path, alert: t(".validation_request_not_editable") + end + end + + def ensure_request_is_destroyable + unless @planning_application.not_started? + redirect_to task_redirect_path, alert: t(".validation_request_not_destroyable") + end + end + end +end diff --git a/engines/bops_preapps/app/forms/bops_preapps/tasks/other_validation_requests_form.rb b/engines/bops_preapps/app/forms/bops_preapps/tasks/other_validation_requests_form.rb index f0a372ddd6..79dd332395 100644 --- a/engines/bops_preapps/app/forms/bops_preapps/tasks/other_validation_requests_form.rb +++ b/engines/bops_preapps/app/forms/bops_preapps/tasks/other_validation_requests_form.rb @@ -10,12 +10,27 @@ def created_by def status case state + when "pending" + "Not sent yet" + when "open" + overdue? ? "Overdue" : "Sent" when "closed" - :updated + "Responded" when "cancelled" - :cancelled - else - :invalid + "Cancelled" + end + end + + def status_colour + case state + when "pending" + "yellow" + when "open" + overdue? ? "red" : "green" + when "closed" + nil + when "cancelled" + "red" end end end diff --git a/engines/bops_preapps/app/views/bops_preapps/tasks/check-and-validate/other-validation-issues/other-validation-requests/show.html.erb b/engines/bops_preapps/app/views/bops_preapps/tasks/check-and-validate/other-validation-issues/other-validation-requests/show.html.erb index b384279088..8b86aa87a8 100644 --- a/engines/bops_preapps/app/views/bops_preapps/tasks/check-and-validate/other-validation-issues/other-validation-requests/show.html.erb +++ b/engines/bops_preapps/app/views/bops_preapps/tasks/check-and-validate/other-validation-issues/other-validation-requests/show.html.erb @@ -17,14 +17,14 @@ <% @form.each_validation_request do |validation_request| %> - <%= govuk_link_to(main_app.planning_application_validation_validation_request_path(@planning_application, validation_request)) do %> + <%= govuk_link_to(validation_request_path(@planning_application, validation_request)) do %> <%= truncate(validation_request.reason, length: 50) %> <% end %> <%= truncate(validation_request.suggestion, length: 50) %> <%= validation_request.created_by %> - <%= render(StatusTags::BaseComponent.new(status: validation_request.status)) %> + <%= govuk_tag(text: validation_request.status, colour: validation_request.status_colour) %> <% end %> @@ -38,9 +38,9 @@ <% end %> - <% unless @planning_application.determined? %> + <% unless @planning_application.validated? %>

- <%= govuk_link_to "Add other validation request", main_app.new_planning_application_validation_validation_request_path(@planning_application, type: "other_change") %> + <%= govuk_link_to "Add other validation request", new_validation_request_path(@planning_application, type: "other_change") %>

<% end %> diff --git a/engines/bops_preapps/app/views/bops_preapps/validation_requests/_breadcrumbs.html.erb b/engines/bops_preapps/app/views/bops_preapps/validation_requests/_breadcrumbs.html.erb new file mode 100644 index 0000000000..d4255232de --- /dev/null +++ b/engines/bops_preapps/app/views/bops_preapps/validation_requests/_breadcrumbs.html.erb @@ -0,0 +1,3 @@ +<% add_parent_breadcrumb_link "Home", preapp_home_path %> +<% add_parent_breadcrumb_link "Application", main_app.planning_application_path(@planning_application) %> +<% add_parent_breadcrumb_link "Validation", main_app.planning_application_validation_tasks_path(@planning_application) %> diff --git a/engines/bops_preapps/app/views/bops_preapps/validation_requests/cancellations/new.html.erb b/engines/bops_preapps/app/views/bops_preapps/validation_requests/cancellations/new.html.erb new file mode 100644 index 0000000000..86fb2b42aa --- /dev/null +++ b/engines/bops_preapps/app/views/bops_preapps/validation_requests/cancellations/new.html.erb @@ -0,0 +1,2 @@ +<%= render "bops_preapps/validation_requests/breadcrumbs" %> +<%= render "#{controller_path}/new/#{@validation_request.type_param}" %> diff --git a/engines/bops_preapps/app/views/bops_preapps/validation_requests/cancellations/new/_other_change.html.erb b/engines/bops_preapps/app/views/bops_preapps/validation_requests/cancellations/new/_other_change.html.erb new file mode 100644 index 0000000000..66f92e7ec4 --- /dev/null +++ b/engines/bops_preapps/app/views/bops_preapps/validation_requests/cancellations/new/_other_change.html.erb @@ -0,0 +1,37 @@ +<% content_for :page_title do %> + Cancel other validation request — <%= t("page_title") %> +<% end %> + +<%= form_with model: @validation_request, scope: :validation_request, method: :post, url: validation_request_cancellation_path(@planning_application) do |form| %> + <%= form.govuk_error_summary %> + +

Cancel validation request

+ <%= render "shared/proposal_header" %> + +
+
+

+ Other request to be cancelled +

+ +
+

Reason it is invalid:

+ <%= render(FormattedContentComponent.new(text: @validation_request.reason)) %> + +

How it can be made valid:

+ <%= render(FormattedContentComponent.new(text: @validation_request.suggestion)) %> + +

+ <%= @validation_request.created_at.to_fs %> +

+
+ + <%= form.govuk_text_area(:cancel_reason, rows: 5, + label: {size: "m", text: "Explain to the applicant why this request is being cancelled"}) %> + + <%= form.govuk_submit "Confirm cancellation" do %> + <%= govuk_button_link_to "Back", task_redirect_path, secondary: true %> + <% end %> +
+
+<% end %> diff --git a/engines/bops_preapps/app/views/bops_preapps/validation_requests/edit.html.erb b/engines/bops_preapps/app/views/bops_preapps/validation_requests/edit.html.erb new file mode 100644 index 0000000000..bfa38ca755 --- /dev/null +++ b/engines/bops_preapps/app/views/bops_preapps/validation_requests/edit.html.erb @@ -0,0 +1,2 @@ +<%= render "breadcrumbs" %> +<%= render "#{controller_path}/edit/#{@validation_request.type_param}" %> diff --git a/engines/bops_preapps/app/views/bops_preapps/validation_requests/edit/_other_change.html.erb b/engines/bops_preapps/app/views/bops_preapps/validation_requests/edit/_other_change.html.erb new file mode 100644 index 0000000000..dc3b22ebfe --- /dev/null +++ b/engines/bops_preapps/app/views/bops_preapps/validation_requests/edit/_other_change.html.erb @@ -0,0 +1,27 @@ +<% content_for :page_title do %> + Update other validation request — <%= t("page_title") %> +<% end %> + +<%= form_with model: @validation_request, scope: :validation_request, url: validation_request_path(@planning_application) do |form| %> + <%= form.govuk_error_summary %> + +

Request other validation change

+ <%= render "shared/proposal_header" %> + +
+
+ <%= hidden_field_tag :type, "other_change" %> + + <%= form.govuk_text_area(:reason, rows: 5, + label: {size: "m", text: "Tell the applicant another reason why the application is invalid"}) %> + + <%= form.govuk_text_area(:suggestion, rows: 5, + hint: {text: "Add all information that they will need to complete this action"}, + label: {size: "m", text: "Explain to the applicant how the application can be made valid"}) %> + + <%= form.govuk_submit "Update request" do %> + <%= govuk_button_link_to "Back", task_redirect_path, secondary: true %> + <% end %> +
+
+<% end %> diff --git a/engines/bops_preapps/app/views/bops_preapps/validation_requests/new.html.erb b/engines/bops_preapps/app/views/bops_preapps/validation_requests/new.html.erb new file mode 100644 index 0000000000..b9112753da --- /dev/null +++ b/engines/bops_preapps/app/views/bops_preapps/validation_requests/new.html.erb @@ -0,0 +1,2 @@ +<%= render "breadcrumbs" %> +<%= render "#{controller_path}/new/#{@validation_request.type_param}" %> diff --git a/engines/bops_preapps/app/views/bops_preapps/validation_requests/new/_other_change.html.erb b/engines/bops_preapps/app/views/bops_preapps/validation_requests/new/_other_change.html.erb new file mode 100644 index 0000000000..5a74774c96 --- /dev/null +++ b/engines/bops_preapps/app/views/bops_preapps/validation_requests/new/_other_change.html.erb @@ -0,0 +1,33 @@ +<% content_for :page_title do %> + Other validation request — <%= t("page_title") %> +<% end %> + +<%= form_with model: @validation_request, scope: :validation_request, url: validation_requests_path(@planning_application) do |form| %> + <%= form.govuk_error_summary %> + +

Request other validation change

+ <%= render "shared/proposal_header" %> + +
+
+ <%= hidden_field_tag :type, "other_change" %> + + <%= form.govuk_text_area(:reason, rows: 5, + label: {size: "m", text: "Tell the applicant another reason why the application is invalid"}) %> + + <%= form.govuk_text_area(:suggestion, rows: 5, + hint: {text: "Add all information that they will need to complete this action"}, + label: {size: "m", text: "Explain to the applicant how the application can be made valid"}) %> + + <% if @planning_application.not_started? %> + <%= form.govuk_submit "Save request" do %> + <%= govuk_button_link_to "Back", task_redirect_path, secondary: true %> + <% end %> + <% else %> + <%= form.govuk_submit "Send request" do %> + <%= govuk_button_link_to "Back", task_redirect_path, secondary: true %> + <% end %> + <% end %> +
+
+<% end %> diff --git a/engines/bops_preapps/app/views/bops_preapps/validation_requests/show.html.erb b/engines/bops_preapps/app/views/bops_preapps/validation_requests/show.html.erb new file mode 100644 index 0000000000..d46e37dcf4 --- /dev/null +++ b/engines/bops_preapps/app/views/bops_preapps/validation_requests/show.html.erb @@ -0,0 +1,2 @@ +<%= render "breadcrumbs" %> +<%= render "#{controller_path}/show/#{@validation_request.type_param}" %> diff --git a/engines/bops_preapps/app/views/bops_preapps/validation_requests/show/_other_change.html.erb b/engines/bops_preapps/app/views/bops_preapps/validation_requests/show/_other_change.html.erb new file mode 100644 index 0000000000..08d8456bc1 --- /dev/null +++ b/engines/bops_preapps/app/views/bops_preapps/validation_requests/show/_other_change.html.erb @@ -0,0 +1,64 @@ +<% content_for :page_title do %> + Other validation request — <%= t("page_title") %> +<% end %> + +

+ <% if @validation_request.closed? %> + Check the response to other request + <% else %> + View other request + <% end %> +

+<%= render "shared/proposal_header" %> + +
+
+

Officer request

+ +
+

Reason it is invalid:

+ <%= render(FormattedContentComponent.new(text: @validation_request.reason)) %> + +

How it can be made valid:

+ <%= render(FormattedContentComponent.new(text: @validation_request.suggestion)) %> + +

+ <%= @validation_request.created_at.to_fs %> +

+
+ +

Applicant response

+ +
+ <% if @validation_request.closed? %> + <%= render(FormattedContentComponent.new(text: @validation_request.response)) %> + +

+ <%= @validation_request.updated_at.to_fs %> +

+ <% else %> +

Applicant has not responded yet

+ <% end %> +
+ + <% if @validation_request.open_or_pending? %> + <% if @planning_application.not_started? %> +
+ <%= govuk_button_to "Delete request", validation_request_path(@planning_application, @validation_request), secondary: true, method: :delete, data: {confirm: "Are you sure?"} %> +
+ <% elsif @planning_application.validation_complete? %> +
+ <%= govuk_button_link_to "Cancel request", new_validation_request_cancellation_path(@planning_application, @validation_request), secondary: true %> +
+ <% end %> + <% end %> + +
+ <%= govuk_button_link_to "Back", task_redirect_path, secondary: true %> + + <% if @planning_application.not_started? %> + <%= govuk_link_to "Edit request", edit_validation_request_path(@planning_application, @validation_request) %> + <% end %> +
+
+
diff --git a/engines/bops_preapps/config/locales/en.yml b/engines/bops_preapps/config/locales/en.yml index 60e4c3ad6f..e0a6e9a37a 100644 --- a/engines/bops_preapps/config/locales/en.yml +++ b/engines/bops_preapps/config/locales/en.yml @@ -133,6 +133,39 @@ en: summary-of-advice: failure: Failed to save summary of advice success: Summary of advice successfully updated + validation_requests: + attributes: + other_change: + - :reason + - :suggestion + cancellations: + create: + other_change: Change request successfully cancelled. + validation_request_not_cancelable: Validation request can't be cancelled. + new: + validation_request_not_cancelable: Validation request can't be cancelled. + create: + validation_request_not_createable: Validation requests can't be added. + destroy: + validation_request_not_destroyable: The validation request can't be deleted. + edit: + validation_request_not_editable: The validation request can't be edited. + new: + validation_request_not_createable: Validation requests can't be added. + redirect_alerts: + destroy: + other_change: Couldn't delete validation request — please contact support. + redirect_notices: + create: + other_change: Change request successfully created. + destroy: + other_change: Change request successfully deleted. + update: + other_change: Change request successfully updated. + redirect_slugs: + other_change: check-and-validate/other-validation-issues/other-validation-requests + update: + validation_request_not_editable: The validation request can't be edited. shared: task_submit_buttons: save_draft: Save changes diff --git a/engines/bops_preapps/config/routes.rb b/engines/bops_preapps/config/routes.rb index 4c31d01be6..d3f468709e 100644 --- a/engines/bops_preapps/config/routes.rb +++ b/engines/bops_preapps/config/routes.rb @@ -9,6 +9,10 @@ scope "/:reference" do get "/", to: redirect("/planning_applications/%{reference}") + resources :validation_requests, path: "/validation/requests", except: %i[index] do + resource :cancellation, only: %i[new create], module: "validation_requests" + end + get "/cancel", to: "cancel_requests#show", as: :cancel_request patch "/cancel", to: "cancel_requests#update" get "/*slug/edit", to: "tasks#edit", as: :edit_task diff --git a/engines/bops_preapps/spec/system/tasks/other_validation_requests_spec.rb b/engines/bops_preapps/spec/system/tasks/other_validation_requests_spec.rb new file mode 100644 index 0000000000..3b7b99d910 --- /dev/null +++ b/engines/bops_preapps/spec/system/tasks/other_validation_requests_spec.rb @@ -0,0 +1,729 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe "Other validation requests", type: :system do + let(:local_authority) { create(:local_authority, :default) } + let(:reference) { planning_application.reference } + let(:case_record) { planning_application.case_record } + let(:slug) { "check-and-validate/other-validation-issues/other-validation-requests" } + let(:task) { case_record.find_task_by_slug_path!(slug) } + + let(:user) { create(:user, local_authority:, name: "Vlad Idator") } + + before do + sign_in(user) + visit "/planning_applications/#{planning_application.reference}/validation/tasks" + end + + context "when the application has not started" do + let(:planning_application) { create(:planning_application, :not_started, :pre_application, local_authority:) } + + it "a validation request can be added" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + expect(page).to have_selector("h1", text: "Other validation requests") + expect(page).to have_content("No other validation requests have been added") + + click_link "Add other validation request" + expect(page).to have_selector("h1", text: "Request other validation change") + + fill_in "Tell the applicant another reason why the application is invalid", with: "Reason for invalidation" + fill_in "Explain to the applicant how the application can be made valid", with: "Suggestion on fixing" + + click_button "Save request" + expect(page).to have_content("Change request successfully created") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Not sent yet") + end + end + end + end + + context "and a request has been created" do + before do + create(:other_change_validation_request, :pending, planning_application:, user:, reason: "Reason for invalidation", suggestion: "Suggestion on fixing") + end + + it "then the request can be edited" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Not sent yet") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "View other request") + expect(page).to have_content("Reason it is invalid: Reason for invalidation") + expect(page).to have_content("How it can be made valid: Suggestion on fixing") + + click_link "Edit request" + expect(page).to have_selector("h1", text: "Request other validation change") + + fill_in "Tell the applicant another reason why the application is invalid", with: "Other reason for invalidation" + fill_in "Explain to the applicant how the application can be made valid", with: "Other suggestion on fixing" + + click_button "Update request" + expect(page).to have_selector("h1", text: "Other validation requests") + expect(page).to have_content("Change request successfully updated") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Other reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Other suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Not sent yet") + end + end + end + end + + it "then the request can be deleted" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Not sent yet") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "View other request") + expect(page).to have_content("Reason it is invalid: Reason for invalidation") + expect(page).to have_content("How it can be made valid: Suggestion on fixing") + + click_button "Delete request" + expect(page).to have_selector("h1", text: "Other validation requests") + expect(page).to have_content("Change request successfully deleted.") + expect(page).to have_content("No other validation requests have been added") + end + end + end + + context "when the application has been invalidated" do + let(:planning_application) { create(:planning_application, :invalidated, :pre_application, local_authority:) } + + it "a validation request can be sent" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + expect(page).to have_content("No other validation requests have been added") + + click_link "Add other validation request" + expect(page).to have_selector("h1", text: "Request other validation change") + + fill_in "Tell the applicant another reason why the application is invalid", with: "Reason for invalidation" + fill_in "Explain to the applicant how the application can be made valid", with: "Suggestion on fixing" + + click_button "Send request" + expect(page).to have_content("Change request successfully created") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Sent") + end + end + end + end + + context "and a request has been created" do + context "and it has not been responded to" do + before do + create(:other_change_validation_request, :open, planning_application:, user:, reason: "Reason for invalidation", suggestion: "Suggestion on fixing") + end + + it "then the request can't be edited" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Sent") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "View other request") + expect(page).to have_content("Reason it is invalid: Reason for invalidation") + expect(page).to have_content("How it can be made valid: Suggestion on fixing") + expect(page).not_to have_link("Edit request") + end + + it "then the request can't be deleted" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Sent") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "View other request") + expect(page).to have_content("Reason it is invalid: Reason for invalidation") + expect(page).to have_content("How it can be made valid: Suggestion on fixing") + expect(page).not_to have_button("Delete request") + end + + it "then the request can be cancelled" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Sent") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "View other request") + expect(page).to have_content("Reason it is invalid: Reason for invalidation") + expect(page).to have_content("How it can be made valid: Suggestion on fixing") + + click_link "Cancel request" + expect(page).to have_selector("h1", text: "Cancel validation request") + + click_button "Confirm cancellation" + expect(page).to have_content("Cancel reason can't be blank") + + fill_in "Explain to the applicant why this request is being cancelled", with: "Cancellation reasons" + + click_button "Confirm cancellation" + expect(page).to have_content("Change request successfully cancelled.") + expect(page).to have_selector("h1", text: "Other validation requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Cancelled") + end + end + end + end + end + + context "and it has been responded to" do + before do + create(:other_change_validation_request, :closed, planning_application:, user:, reason: "Reason for invalidation", suggestion: "Suggestion on fixing") + end + + it "then the request can't be edited" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Responded") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "Check the response to other request") + expect(page).to have_content("Some response") + expect(page).not_to have_link("Edit request") + end + + it "then the request can't be deleted" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Responded") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "Check the response to other request") + expect(page).to have_content("Some response") + expect(page).not_to have_button("Delete request") + end + + it "then the request can't be canceled" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Responded") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "Check the response to other request") + expect(page).to have_content("Some response") + expect(page).not_to have_link("Cancel request") + end + end + end + end + + context "when the application has been validated" do + let(:planning_application) { create(:planning_application, :not_started, :pre_application, local_authority:) } + + context "and there are no requests" do + before do + planning_application.update!(validated_at: planning_application.valid_from_date) + planning_application.start! + end + + it "a validation request can't be sent" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + expect(page).to have_content("No other validation requests have been added") + expect(page).not_to have_link("Add other validation request") + end + end + + context "and a request has been created" do + context "and it has not been responded to" do + before do + create(:other_change_validation_request, :open, planning_application:, user:, reason: "Reason for invalidation", suggestion: "Suggestion on fixing") + + planning_application.update!(validated_at: planning_application.valid_from_date) + planning_application.start! + end + + it "then the request can't be edited" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Sent") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "View other request") + expect(page).to have_content("Reason it is invalid: Reason for invalidation") + expect(page).to have_content("How it can be made valid: Suggestion on fixing") + expect(page).not_to have_link("Edit request") + end + + it "then the request can't be deleted" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Sent") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "View other request") + expect(page).to have_content("Reason it is invalid: Reason for invalidation") + expect(page).to have_content("How it can be made valid: Suggestion on fixing") + expect(page).not_to have_button("Delete request") + end + + it "then the request can be cancelled" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Sent") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "View other request") + expect(page).to have_content("Reason it is invalid: Reason for invalidation") + expect(page).to have_content("How it can be made valid: Suggestion on fixing") + + click_link "Cancel request" + expect(page).to have_selector("h1", text: "Cancel validation request") + + click_button "Confirm cancellation" + expect(page).to have_content("Cancel reason can't be blank") + + fill_in "Explain to the applicant why this request is being cancelled", with: "Cancellation reasons" + + click_button "Confirm cancellation" + expect(page).to have_content("Change request successfully cancelled.") + expect(page).to have_selector("h1", text: "Other validation requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Cancelled") + end + end + end + end + end + + context "and it has been responded to" do + before do + create(:other_change_validation_request, :closed, planning_application:, user:, reason: "Reason for invalidation", suggestion: "Suggestion on fixing") + + planning_application.update!(validated_at: planning_application.valid_from_date) + planning_application.start! + end + + it "then the request can't be edited" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Responded") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "Check the response to other request") + expect(page).to have_content("Some response") + expect(page).not_to have_link("Edit request") + end + + it "then the request can't be deleted" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Responded") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "Check the response to other request") + expect(page).to have_content("Some response") + expect(page).not_to have_button("Delete request") + end + + it "then the request can't be canceled" do + within ".bops-sidebar" do + click_link "Other validation requests" + end + + expect(page).to have_current_path("/preapps/#{reference}/check-and-validate/other-validation-issues/other-validation-requests") + + within "#other-validation-requests" do + within "tbody tr:nth-child(1)" do + within "td:nth-child(1)" do + expect(page).to have_content("Reason for invalidation") + end + + within "td:nth-child(2)" do + expect(page).to have_content("Suggestion on fixing") + end + + within "td:nth-child(3)" do + expect(page).to have_content("Vlad Idator") + end + + within "td:nth-child(4)" do + expect(page).to have_content("Responded") + end + end + end + + click_link "Reason for invalidation" + expect(page).to have_selector("h1", text: "Check the response to other request") + expect(page).to have_content("Some response") + expect(page).not_to have_link("Cancel request") + end + end + end + end +end