Skip to content

Commit cf183ab

Browse files
committed
Add rake task and spec for changing the state of a form
1 parent 30b4376 commit cf183ab

2 files changed

Lines changed: 156 additions & 0 deletions

File tree

lib/tasks/forms.rake

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,35 @@ namespace :forms do
2525
end
2626
end
2727

28+
desc "set the state for a form by transitioning through the form state machine"
29+
task :set_state, %i[form_id state] => :environment do |_, args|
30+
usage_message = "usage: rake forms:set_state[<form_id>, <state>]".freeze
31+
abort usage_message if args[:form_id].blank? || args[:state].blank?
32+
abort "state must be one of #{Form.states.keys.join(', ')}" unless Form.states.key?(args[:state])
33+
34+
form = Form.find(args[:form_id])
35+
36+
# the make_live event guard checks the form's task statuses through a
37+
# service that is normally injected by the controller
38+
form.set_task_status_service(TaskStatusService.new(form:, current_user: nil))
39+
40+
events = Form.event_path(from: form.aasm.current_state, to: args[:state].to_sym)
41+
42+
abort "cannot transition form from \'#{form.state}\' to \'#{args[:state]}\'" if events.nil?
43+
44+
if events.empty?
45+
Rails.logger.info "forms:set_state: #{fmt_form(form)} is already in state \'#{form.state}\'"
46+
next
47+
end
48+
49+
ActiveRecord::Base.transaction do
50+
events.each do |event|
51+
Rails.logger.info "forms:set_state: firing #{event} on #{fmt_form(form)} in state \'#{form.state}\'"
52+
form.public_send(:"#{event}!")
53+
end
54+
end
55+
end
56+
2857
namespace :submission_email do
2958
desc "set the submission email for a form, without validation"
3059
task :update, %i[form_id submission_email] => :environment do |_, args|

spec/lib/tasks/forms.rake_spec.rb

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,133 @@
119119
end
120120
end
121121

122+
describe "forms:set_state" do
123+
subject(:task) do
124+
Rake::Task["forms:set_state"]
125+
end
126+
127+
let(:form) { create :form, :ready_for_live }
128+
let!(:other_form) { create :form }
129+
130+
context "with valid arguments" do
131+
it "sets a draft form's state to archived by transitioning through live" do
132+
expect {
133+
task.invoke(form.id, "archived")
134+
}.to change { form.reload.state }.from("draft").to("archived")
135+
end
136+
137+
it "runs the event callbacks for the intermediate transitions" do
138+
task.invoke(form.id, "archived")
139+
140+
form.reload
141+
expect(form.first_made_live_at).not_to be_nil
142+
expect(form.archived_form_document).not_to be_nil
143+
end
144+
145+
it "sets a draft form's state to archived_with_draft by transitioning through two intermediate states" do
146+
expect {
147+
task.invoke(form.id, "archived_with_draft")
148+
}.to change { form.reload.state }.from("draft").to("archived_with_draft")
149+
end
150+
151+
it "sets an archived form's state to live" do
152+
archived_form = create :form, :archived
153+
154+
expect {
155+
task.invoke(archived_form.id, "live")
156+
}.to change { archived_form.reload.state }.from("archived").to("live")
157+
end
158+
159+
it "does not change other forms" do
160+
expect {
161+
task.invoke(form.id, "archived")
162+
}.not_to(change { other_form.reload.state })
163+
end
164+
end
165+
166+
context "when the form is not ready to be made live" do
167+
let(:form) { create :form }
168+
169+
it "raises an invalid transition error and does not change the form's state" do
170+
expect {
171+
task.invoke(form.id, "archived")
172+
}.to raise_error(AASM::InvalidTransition)
173+
174+
expect(form.reload.state).to eq("draft")
175+
end
176+
end
177+
178+
context "when no sequence of events reaches the target state" do
179+
it "aborts with a message" do
180+
live_form = create :form, :live
181+
182+
expect {
183+
task.invoke(live_form.id, "draft")
184+
}.to raise_error(SystemExit)
185+
.and output(/cannot transition form from 'live' to 'draft'/).to_stderr
186+
end
187+
end
188+
189+
context "when the form is already in the target state" do
190+
it "does not abort and leaves the form's state unchanged" do
191+
expect {
192+
task.invoke(form.id, "draft")
193+
}.not_to raise_error
194+
195+
expect(form.reload.state).to eq("draft")
196+
end
197+
198+
it "logs that the form is already in the target state" do
199+
allow(Rails.logger).to receive(:info)
200+
201+
task.invoke(form.id, "draft")
202+
203+
expect(Rails.logger).to have_received(:info)
204+
.with(/forms:set_state: form #{form.id} \(".*"\) is already in state 'draft'/)
205+
end
206+
end
207+
208+
context "with invalid arguments" do
209+
shared_examples_for "usage error" do
210+
it "aborts with a usage message" do
211+
expect {
212+
task.invoke(*invalid_args)
213+
}.to raise_error(SystemExit)
214+
.and output(/usage: rake forms:set_state/).to_stderr
215+
end
216+
end
217+
218+
context "with no arguments" do
219+
it_behaves_like "usage error" do
220+
let(:invalid_args) { [] }
221+
end
222+
end
223+
224+
context "with only one argument" do
225+
it_behaves_like "usage error" do
226+
let(:invalid_args) { [form.id] }
227+
end
228+
end
229+
230+
context "with a state that is not a form state" do
231+
it "aborts with a message listing the valid states" do
232+
expect {
233+
task.invoke(form.id, "not_a_state")
234+
}.to raise_error(SystemExit)
235+
.and output(/state must be one of draft, deleted, live, live_with_draft, archived, archived_with_draft/).to_stderr
236+
end
237+
end
238+
239+
context "with invalid form_id" do
240+
it "raises an error" do
241+
expect {
242+
task.invoke("99", "archived")
243+
}.to raise_error(ActiveRecord::RecordNotFound)
244+
end
245+
end
246+
end
247+
end
248+
122249
describe "forms:submission_email:update" do
123250
subject(:task) do
124251
Rake::Task["forms:submission_email:update"]

0 commit comments

Comments
 (0)