canvas-lms/spec/selenium/quizzes_student_spec.rb

292 lines
9.4 KiB
Ruby

require File.expand_path(File.dirname(__FILE__) + '/helpers/quizzes_common')
describe 'quizzes' do
include_context 'in-process server selenium tests'
def prepare_quiz
@quiz = quiz_model({ course: @course, time_limit: 5 })
@quiz.quiz_questions.create!(question_data: multiple_choice_question_data)
@quiz.generate_quiz_data
@quiz.save
@quiz
end
before(:each) do
course_with_student_logged_in
end
context 'with a student' do
it 'can\'t see unpublished quizzes', priority: "1", test_id: 140651 do
# create course with an unpublished quiz
assignment_quiz([], course: @course)
@quiz.update_attribute(:published_at, nil)
@quiz.update_attribute(:workflow_state, 'unavailable')
get "/courses/#{@course.id}/quizzes/"
expect(f('#content-wrapper')).to include_text 'No quizzes available'
end
it 'can see published quizzes', priority: "1", test_id: 220304 do
# create course with a published quiz
assignment_quiz([], course: @course)
get "/courses/#{@course.id}/quizzes/"
expect(f('#assignment-quizzes')).to be_present
end
context 'with a quiz started' do
before(:each) do
@qsub = quiz_with_submission(false)
end
context 'when taking a timed quiz' do
it 'warns the student before the lock date is exceeded', priority: "1", test_id: 209407 do
@context = @course
bank = @course.assessment_question_banks.create!(title: 'Test Bank')
q = quiz_model
a = bank.assessment_questions.create!
answers = [
{
id: 1,
answer_text: 'A',
weight: 100
},
{
id: 2,
answer_text: 'B',
weight: 0
}
]
question = q.quiz_questions.create!(
question_data: {
name: 'first question',
question_type: 'multiple_choice_question',
answers: answers,
points_possible: 1
}, assessment_question: a
)
q.generate_quiz_data
q.lock_at = Time.now.utc + 5.seconds
q.save!
get "/courses/#{@course.id}/quizzes/#{q.id}/take?user_id=#{@student.id}"
f('#take_quiz_link').click
answer_one = f("#question_#{question.id}_answer_1")
# force a save to create a submission
answer_one.click
wait_for_ajaximations
keep_trying_until do
Quizzes::QuizSubmission.last
expect(fj('#times_up_dialog:visible')).to be_present
end
end
end
context 'when attempting to resume a quiz' do
def update_quiz_lock(lock_at, unlock_at)
@quiz.update_attributes(lock_at: lock_at, unlock_at: unlock_at)
end
describe 'on individual quiz page' do
def validate_resume_button_text(text)
expect(f('#not_right_side .take_quiz_button').text).to eq text
end
before(:each) do
@resume_text = 'Resume Quiz'
end
it 'can see the resume quiz button if the quiz is unlocked', priority: "1", test_id: 209408 do
get "/courses/#{@course.id}/quizzes/#{@quiz.id}"
validate_resume_button_text(@resume_text)
end
it 'can see the resume quiz button if the quiz unlock_at date is < now', priority: "1", test_id: 209409 do
update_quiz_lock(nil, 10.minutes.ago)
get "/courses/#{@course.id}/quizzes/#{@quiz.id}"
validate_resume_button_text(@resume_text)
end
it 'can\'t see the resume quiz button if quiz is locked', priority: "1", test_id: 209410 do
update_quiz_lock(5.minutes.ago, nil)
get "/courses/#{@course.id}/quizzes/#{@quiz.id}"
expect(f('#not_right_side .take_quiz_button')).not_to be_present
end
it 'can\'t see the publish button', priority: "1", test_id: 209411 do
get "/courses/#{@course.id}/quizzes/#{@quiz.id}"
expect(f('#quiz-publish-link')).not_to be_present
end
it 'can\'t see unpublished warning', priority: "1", test_id: 209412 do
# set to unpublished state
@quiz.last_edited_at = Time.now.utc
@quiz.published_at = 1.hour.ago
@quiz.save!
get "/courses/#{@course.id}/quizzes/#{@quiz.id}"
expect(f('.unpublished_warning')).not_to be_present
end
end
end
context 'when logged out while taking a quiz' do
it 'is notified and able to relogin', priority: "1", test_id: 209413 do
# setup a quiz and start taking it
quiz_with_new_questions(!:goto_edit)
get "/courses/#{@course.id}/quizzes/#{@quiz.id}"
expect_new_page_load { f('#take_quiz_link').click }
sleep 1 # sleep because display is updated on timer, not ajax callback
# answer a question, and check that it is saved
ff('.answers .answer_input input')[0].click
wait_for_ajaximations
expect(f('#last_saved_indicator').text).to match(/^Quiz saved at \d+:\d+(pm|am)$/)
# now kill our session (like logging out)
destroy_session(false)
index = 1
keep_trying_until do
# and try answering another question
ff('.answers .answer_input input')[index].click
wait_for_ajaximations
# we should get notified that we are logged out
expect(fj('#deauthorized_dialog:visible')).to be_present
index = (index + 1) % 2
end
expect_new_page_load { submit_dialog('#deauthorized_dialog') }
# log back in
expect_new_page_load { fill_in_login_form(@pseudonym.unique_id, @pseudonym.password) }
# we should be back at the quiz show page
expect(fln('Resume Quiz')).to be_present
end
end
end
end
context 'with multiple fill in the blanks' do
it 'displays MFITB responses in their respective boxes on submission view page', priority: "2", test_id: 209414 do
# create new multiple fill in the blank quiz and question
@quiz = quiz_model({ course: @course, time_limit: 5 })
question = @quiz.quiz_questions.create!(question_data: fill_in_multiple_blanks_question_data )
@quiz.generate_quiz_data
@quiz.tap(&:save)
# create and grade a submission on our mfitb quiz
qs = @quiz.generate_submission(@student)
# this generates 6 answers on our submission for each blank in fill_in_multiple_blanks_question_data
(1..6).each do |var|
qs.submission_data[
"question_#{question.id}_#{AssessmentQuestion.variable_id("answer#{var}")}"
] = ("this is my answer ##{var}")
end
response_array = qs.submission_data.values
Quizzes::SubmissionGrader.new(qs).grade_submission
get "/courses/#{@course.id}/quizzes/#{@quiz.id}/"
wait_for_ajaximations
answer_fields = ff('.question_input')
answer_array = answer_fields.map { |element| driver.execute_script("return $(arguments[0]).val()", element) }
expect(answer_array).to eq response_array
end
end
context 'when a student closes the session without submitting' do
it 'automatically grades the submission when it becomes overdue', priority: "1", test_id: 209415 do
skip('disabled because of regression')
job_tag = 'Quizzes::QuizSubmission#grade_if_untaken'
prepare_quiz
expect(Delayed::Job.find_by_tag(job_tag)).to eq nil
take_and_answer_quiz(false)
driver.execute_script('window.close()')
quiz_sub = @quiz.quiz_submissions.where(user_id: @user).first
expect(quiz_sub).to be_present
expect(quiz_sub.workflow_state).to eq 'untaken'
job = Delayed::Job.find_by_tag(job_tag)
expect(job).to be_present
# okay, we will manually "run" the job because we can't afford to wait
# for it to be picked up by DJ in a spec:
auto_grader = YAML.parse(job.handler).transform
auto_grader.perform
quiz_sub.reload
expect(quiz_sub.workflow_state).to eq 'complete'
end
end
context 'when the \'show correct answers\' setting is on' do
before(:each) do
prepare_quiz
end
it 'highlights correct answers', priority: "1", test_id: 209417 do
@quiz.update_attributes(show_correct_answers: true)
@quiz.save!
take_and_answer_quiz
expect(ff('.correct_answer').length).to be > 0
end
it 'always highlights incorrect answers', priority: "1", test_id: 209418 do
@quiz.update_attributes(show_correct_answers: true)
@quiz.save!
take_and_answer_quiz do |answers|
answers[1][:id] # don't answer
end
expect(ff('.incorrect.answer_arrow').length).to be > 0
end
end
context 'when the \'show correct answers\' setting is off' do
before(:each) do
prepare_quiz
end
it 'doesn\'t highlight correct answers', priority: "1", test_id: 209416 do
@quiz.update_attributes(show_correct_answers: false)
@quiz.save!
take_and_answer_quiz
expect(ff('.correct_answer').length).to eq 0
end
it 'always highlights incorrect answers', priority: "1", test_id: 209480 do
@quiz.update_attributes(show_correct_answers: false)
@quiz.save!
take_and_answer_quiz do |answers|
answers[1][:id] # don't answer
end
expect(ff('.incorrect.answer_arrow').length).to be > 0
end
end
end