require 'rails_helper' module Legacy describe 'survey:attempt_questions' do include_context 'rake' it 'should have environment as a prerequisite' do expect(subject.prerequisites).to include('environment') end describe 'basic flow' do let(:now) do n = DateTime.now n += 1.day until n.on_weekday? return n end let(:ready_recipient_schedule) { double('ready recipient schedule', attempt_question: nil) } let(:recipient_schedules) { double('recipient schedules', ready: [ready_recipient_schedule]) } let(:active_schedule) { double('active schedule', recipient_schedules:) } it 'finds all active schedules' do date = ActiveSupport::TimeZone['UTC'].parse(now.strftime('%Y-%m-%dT20:00:00%z')) Timecop.freeze(date) expect(ready_recipient_schedule).to receive(:attempt_question) expect(active_schedule).to receive(:recipient_schedules) expect(Schedule).to receive(:active).and_return([active_schedule]) subject.invoke end it 'works only on weekdays' do now = DateTime.now now += 1.day until now.on_weekend? date = ActiveSupport::TimeZone['UTC'].parse(now.strftime('%Y-%m-%dT20:00:00%z')) Timecop.freeze(date) expect(ready_recipient_schedule).to_not receive(:attempt_question) subject.invoke end end xdescribe 'complex flow' do let(:now) do n = DateTime.now n += 1.day until n.on_weekday? return n end let!(:school) { School.create!(name: 'School') } let!(:recipients) { create_recipients(school, 3) } let!(:recipient_list) do school.recipient_lists.create!(name: 'Parents', recipient_ids: recipients.map(&:id).join(',')) end let!(:category) { Category.create(name: 'Category') } let!(:questions) { create_questions(3, category) } let!(:question_list) do QuestionList.create!(name: 'Parent Questions', question_ids: questions.map(&:id).join(',')) end let!(:schedule) do Schedule.create!( name: 'Parent Schedule', recipient_list_id: recipient_list.id, question_list:, frequency_hours: 24 * 7, start_date: Time.new, end_date: 1.year.from_now, time: 1200 ) end describe 'First attempt not at specified time' do before :each do now = DateTime.new now += 1.day until now.on_weekend? date = ActiveSupport::TimeZone['UTC'].parse(now.strftime('%Y-%m-%dT19:00:00%z')) Timecop.freeze(date) { subject.invoke } end it 'should not create any attempts' do expect(Attempt.count).to eq(0) end end describe 'First attempt at specified time' do before :each do date = ActiveSupport::TimeZone['UTC'].parse(now.strftime('%Y-%m-%dT20:00:00%z')) Timecop.freeze(date) { subject.invoke } end it 'should create the first attempt for each recipient' do recipients.each do |recipient| recipient.reload expect(recipient.attempts.count).to eq(1) attempt = recipient.attempts.first expect(attempt.sent_at).to be_present expect(attempt.answer_index).to be_nil end end end describe 'Second Attempts' do before :each do recipients.each do |recipient| recipient_schedule = schedule.recipient_schedules.for_recipient(recipient).first recipient_schedule.attempt_question end end describe 'Immediate' do before :each do subject.invoke end it 'should do nothing' do recipients.each do |recipient| recipient.reload expect(recipient.attempts.count).to eq(1) end end end describe 'A Week Later' do before :each do recipients[1].attempts.first.update( answer_index: 4, responded_at: Time.new ) Timecop.freeze(now + 7) { subject.invoke } end it 'should resend the first question if unanswered by a recipient' do [recipients[0], recipients[2]].each do |recipient| recipient.reload expect(recipient.attempts.count).to eq(1) attempt = recipient.attempts.last expect(attempt.sent_at).to be > 1.day.ago expect(attempt.answer_index).to be_nil end end it 'should create the second attempt with a new question for each recipient who has answered the first question' do recipient = recipients[1] recipient.reload expect(recipient.attempts.count).to eq(2) attempt = recipient.attempts.last expect(attempt.sent_at).to be_present expect(attempt.answer_index).to be_nil first_attempt = recipient.attempts.first expect(first_attempt.question).to_not eq(attempt.question) end end describe 'And Then A Recipient Answers The First Attempt' do before :each do recipients[1].attempts.first.save_response(answer_index: 4) Timecop.freeze(now + 7) recipients.each do |recipient| recipient_schedule = schedule.recipient_schedules.for_recipient(recipient).first recipient_schedule.attempt_question end @existing_message_count = FakeSMS.messages.length Timecop.freeze(now + 8) recipients[2].attempts.first.save_response(answer_index: 3) subject.invoke end it 'should create the second attempt with a new question for each recipient who just answered the first question' do recipient = recipients[2] recipient.reload expect(recipient.attempts.count).to eq(2) attempt = recipient.attempts.last expect(attempt.sent_at).to be_present expect(attempt.answer_index).to be_nil first_attempt = recipient.attempts.first expect(first_attempt.question).to_not eq(attempt.question) end it 'should not send anything to anyone else' do expect(FakeSMS.messages.length).to eq(@existing_message_count + 2) expect(recipients[0].attempts.count).to eq(1) expect(recipients[1].attempts.count).to eq(2) end end end describe 'Multiple Students In A Family' do before :each do 3.times do |i| recipients[1].students.create(name: "Student#{i}") end end let(:students_recipient) { recipients[1] } let(:students_recipient_schedule) do students_recipient.recipient_schedules.for_schedule(schedule).first end describe 'With A FOR_CHILD Question Is Asked' do let!(:date) { ActiveSupport::TimeZone['UTC'].parse(now.strftime('%Y-%m-%dT20:00:00%z')) } before :each do questions.first.update(for_recipient_students: true) Timecop.freeze(date) { subject.invoke } end it 'should create one attempt per recipient regardless of students' do expect(FakeSMS.messages.length).to eq(6) recipients.each do |recipient| expect(recipient.attempts.count).to eq(1) end end it 'should store queued questions when an attempt is made on first student' do expect(students_recipient_schedule.queued_question_ids).to be_present queued_question_ids = students_recipient_schedule.queued_question_ids.split(/,/) expect(queued_question_ids.length).to eq(1) expect(queued_question_ids.first).to eq(questions[0].id.to_s) end it 'should set the next_attempt_at to now when attempt is made on first student' do students_recipient.attempts.last.save_response(answer_index: 3) expect(students_recipient_schedule.reload.next_attempt_at).to eq(Time.new) end it 'should set the next_attempt_at in the future when an attempts are made on each student' do students_recipient.attempts.last.save_response(answer_index: 3) expect { students_recipient_schedule.attempt_question }.to change { students_recipient.attempts.count }.by(1) expect(students_recipient_schedule.reload.queued_question_ids).to be_present attempt = students_recipient.attempts.last expect(attempt.student).to eq(students_recipient.students[1]) Timecop.freeze(date + 1.day) attempt.save_response(answer_index: 4) expect(students_recipient_schedule.reload.next_attempt_at).to eq(date + 1.day) expect { students_recipient_schedule.attempt_question }.to change { students_recipient.attempts.count }.by(1) expect(students_recipient_schedule.reload.queued_question_ids).to be_nil expect(students_recipient_schedule.reload.next_attempt_at).to_not eq(date + (60 * 60 * schedule.frequency_hours)) attempt = students_recipient.attempts.last expect(attempt.student).to eq(students_recipient.students[2]) Timecop.freeze(date + 2.days) attempt.save_response(answer_index: 2) expect(students_recipient_schedule.reload.next_attempt_at).to_not eq(date + 2.days) end it 'should mention the students name in the text' do expect(FakeSMS.messages[2].body).to match(/\(for Student0\)/) end it 'should not mention the students name in the text if the recipient has no student specified' do expect(FakeSMS.messages[0].body).to_not match(/\(for .*\)/) end it 'resends the question about the same student if not responded to' do message_count = FakeSMS.messages.length expect { students_recipient_schedule.attempt_question }.to change { students_recipient.attempts.count }.by(0) expect(FakeSMS.messages.length).to eq(message_count + 2) expect(FakeSMS.messages[message_count].body).to match(questions.first.text) expect(FakeSMS.messages[message_count].body).to match(/\(for Student0\)/) end it 'doesnt store any queued_question_ids when no students are present' do recipient_schedule = recipients[0].recipient_schedules.for_schedule(schedule).first expect(recipient_schedule.queued_question_ids).to be_nil end end describe 'With A General Question Is Asked' do before :each do subject.invoke end it 'should not queue up an questions regardless of how many students there are' do expect(students_recipient_schedule.queued_question_ids).to be_nil end it 'should not mention the students name in the text' do FakeSMS.messages.each do |message| expect(message.body).to_not match(/\(for .*\)/) end end end end describe 'One Student In A Family' do before :each do recipients[1].students.create(name: 'Only Student') end let(:students_recipient) { recipients[1] } let(:students_recipient_schedule) do students_recipient.recipient_schedules.for_schedule(schedule).first end describe 'With A FOR_CHILD Question Is Asked' do let!(:date) { ActiveSupport::TimeZone['UTC'].parse(now.strftime('%Y-%m-%dT20:00:00%z')) } before :each do questions.first.update(for_recipient_students: true) Timecop.freeze(date) { subject.invoke } end it 'should create one attempt per recipient regardless of students' do expect(FakeSMS.messages.length).to eq(6) recipients.each do |recipient| expect(recipient.attempts.count).to eq(1) end end it 'doesnt store any queued_question_ids' do expect(students_recipient_schedule.queued_question_ids).to be_nil end end end describe 'Opted Out Recipient' do before :each do recipients[1].update(opted_out: true) date = ActiveSupport::TimeZone['UTC'].parse(now.strftime('%Y-%m-%dT20:00:00%z')) Timecop.freeze(date) { subject.invoke } end it 'should create the first attempt for each recipient' do recipients.each_with_index do |recipient, index| recipient.reload if index == 1 expect(recipient.attempts.count).to eq(0) expect(recipient.attempts.first).to be_nil else expect(recipient.attempts.count).to eq(1) attempt = recipient.attempts.first expect(attempt.sent_at).to be_present expect(attempt.answer_index).to be_nil end end end end end end end