canvas-lms/spec/integration/assignments_spec.rb

496 lines
18 KiB
Ruby

# frozen_string_literal: true
#
# Copyright (C) 2012 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
require 'nokogiri'
describe "assignments" do
def multiple_section_submissions
course_with_student(:active_all => true); @student1 = @student
@s2enrollment = student_in_course(:active_all => true); @student2 = @user
@section = @course.course_sections.create!
@s2enrollment.course_section = @section; @s2enrollment.save!
@assignment = @course.assignments.create!(:title => "Test 1", :submission_types => "online_upload")
@submission1 = @assignment.submit_homework(@student1, :submission_type => "online_text_entry", :body => "hi")
@submission2 = @assignment.submit_homework(@student2, :submission_type => "online_text_entry", :body => "there")
end
def create_assignment_section_override(section, due_at)
override = assignment_override_model(:assignment => @assignment)
override.set = section
override.override_due_at(due_at)
override.save!
end
it "should correctly list ungraded and total submissions for teacher" do
multiple_section_submissions
course_with_teacher_logged_in(:course => @course, :active_all => true)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
expect(Nokogiri::HTML5(response.body).at_css('.graded_count').text).to match(/0 out of 2/)
end
it "should correctly list ungraded and total submissions for ta" do
multiple_section_submissions
@taenrollment = course_with_ta(:course => @course, :active_all => true)
@taenrollment.limit_privileges_to_course_section = true
@taenrollment.save!
user_session(@ta)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
expect(Nokogiri::HTML5(response.body).at_css('.graded_count').text).to match(/0 out of 1/)
end
it "should show student view student submission as needing grading" do
course_with_teacher_logged_in(:active_all => true)
@fake_student = @course.student_view_student
assignment_model(:course => @course, :submission_types => 'online_text_entry', :title => 'Assignment 1')
@assignment.submit_homework(@fake_student, :submission_type => 'online_text_entry', :body => "my submission")
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
expect(Nokogiri::HTML5(response.body).at_css('.graded_count').text).to match(/0 out of 1/)
end
describe "due date overrides" do
include TextHelper
before do
course_with_teacher_logged_in(:active_all => true)
assignment_model(:course => @course, :due_at => 3.days.from_now)
@assignment.update_attribute :due_at, 2.days.from_now
@cs1 = @course.default_section
@cs2 = @course.course_sections.create!
end
it "should show 'Everyone' when there are no overrides" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
doc = Nokogiri::HTML5(response.body)
expect(doc.css(".assignment_dates").text).to include "Everyone"
expect(doc.css(".assignment_dates").text).not_to include "Everyone else"
end
it "should show 'Everyone else' when some sections have due date overrides" do
due_at1 = 3.days.from_now
create_assignment_section_override(@cs1, due_at1)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
doc = Nokogiri::HTML5(response.body)
expect(doc.css(".assignment_dates").text).to include "Everyone else"
end
it "should not show 'Everyone else' when all sections have due date overrides" do
due_at1, due_at2 = 3.days.from_now, 4.days.from_now
create_assignment_section_override(@cs1, due_at1)
create_assignment_section_override(@cs2, due_at2)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
doc = Nokogiri::HTML5(response.body)
expect(doc.css(".assignment_dates").text).not_to include "Everyone"
end
end
end
describe "download submissions link" do
before do
course_with_teacher_logged_in(:active_all => true)
assignment_model(:course => @course, :submission_types => 'online_url', :title => 'Assignment 1')
@student = User.create!(:name => 'student1')
@student.register!
@student.workflow_state = 'active'
@student2 = User.create!(:name => 'student2')
@student2.register
@student2.workflow_state = 'active'
@student2.save
@course.enroll_user(@student, 'StudentEnrollment')
@course.enroll_user(@student2, 'StudentEnrollment')
@course.save!
@student.save!
@student2.save!
end
it "should not show download submissions button with no submissions" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
doc = Nokogiri::HTML5(response.body)
expect(doc.at_css('#download_submission_button')).to be_nil
end
it "should not show download submissions button with no submissions from active students" do
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update(submission_type: 'online_url')
@student.enrollments.each(&:conclude)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
doc = Nokogiri::HTML5(response.body)
expect(doc.at_css('#download_submission_button')).to be_nil
end
it "should show download submissions button with submission not graded" do
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update(submission_type: 'online_url')
expect(@submission.state).to eql(:submitted)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
doc = Nokogiri::HTML5(response.body)
expect(doc.at_css('#download_submission_button')).not_to be_nil
end
it "should show download submissions button with a submission graded" do
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
@submission.grade_it
@submission.score = 5
@submission.save!
expect(@submission.state).to eql(:graded)
@submission2 = @assignment.submissions.find_by!(user: @student2)
@submission2.update!(submission_type: 'online_url')
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
doc = Nokogiri::HTML5(response.body)
expect(doc.at_css('#download_submission_button')).not_to be_nil
end
it "should show download submissions button with all submissions graded" do
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
@submission.grade_it
@submission.score = 5
@submission.save!
expect(@submission.state).to eql(:graded)
@submission2 = @assignment.submissions.find_by!(user: @student2)
@submission2.update!(submission_type: 'online_url')
@submission2.grade_it
@submission2.score = 5
@submission2.save!
expect(@submission2.state).to eql(:graded)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
doc = Nokogiri::HTML5(response.body)
expect(doc.at_css('#download_submission_button')).not_to be_nil
end
it "should not show download submissions button to students" do
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
expect(@submission.state).to eql(:submitted)
user_session(@student)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
doc = Nokogiri::HTML5(response.body)
expect(doc.at_css('#download_submission_button')).to be_nil
end
end
describe "ratio of submissions graded" do
before do
course_with_teacher_logged_in(:active_all => true)
assignment_model(:course => @course, :submission_types => 'online_url', :title => 'Assignment 1')
@student = User.create!(:name => 'student1')
@student.register!
@student.workflow_state = 'active'
@student2 = User.create!(:name => 'student2')
@student2.register
@student2.workflow_state = 'active'
@student2.save
@course.enroll_user(@student, 'StudentEnrollment')
@course.enroll_user(@student2, 'StudentEnrollment')
@course.save!
@student.save!
@student2.save!
end
it "should not show ratio of submissions graded with no submissions" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
doc = Nokogiri::HTML5(response.body)
expect(doc.at_css('#ratio_of_submissions_graded')).to be_nil
end
it "should show ratio of submissions graded with submission not graded" do
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
expect(@submission.state).to eql(:submitted)
@submission2 = @assignment.submissions.find_by!(user: @student2)
@submission2.update!(submission_type: 'online_url')
expect(@submission2.state).to eql(:submitted)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
doc = Nokogiri::HTML5(response.body)
expect(doc.at_css('#ratio_of_submissions_graded').text.strip).to eq "0 out of 2 Submissions Graded"
end
it "should show ratio of submissions graded with a submission graded" do
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
@submission.grade_it
@submission.score = 5
@submission.save!
expect(@submission.state).to eql(:graded)
@submission2 = @assignment.submissions.find_by!(user: @student2)
@submission2.update!(submission_type: 'online_url')
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
doc = Nokogiri::HTML5(response.body)
expect(doc.at_css('#ratio_of_submissions_graded').text.strip).to eq "1 out of 2 Submissions Graded"
end
it "should show ratio of submissions graded with all submissions graded" do
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
@submission.grade_it
@submission.score = 5
@submission.save!
expect(@submission.state).to eql(:graded)
@submission2 = @assignment.submissions.find_by!(user: @student2)
@submission2.update!(submission_type: 'online_url')
@submission2.grade_it
@submission2.score = 5
@submission2.save!
expect(@submission2.state).to eql(:graded)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
doc = Nokogiri::HTML5(response.body)
expect(doc.at_css('#ratio_of_submissions_graded').text.strip).to eq "2 out of 2 Submissions Graded"
end
it "should not show ratio of submissions graded to students" do
@submission = @assignment.submissions.find_by!(user: @student)
@submission.update!(submission_type: 'online_url')
expect(@submission.state).to eql(:submitted)
user_session(@student)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(response).to be_successful
doc = Nokogiri::HTML5(response.body)
expect(doc.at_css('#ratio_of_submissions_graded')).to be_nil
end
describe 'assignment moderation' do
let(:moderate_button) { Nokogiri::HTML5(response.body).at_css('#moderated_grading_button') }
it 'shows the moderation link for moderated assignments' do
@assignment.update!(moderated_grading: true, grader_count: 1, final_grader: @teacher)
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(moderate_button).not_to be_nil
end
it 'does not show the moderation link for non-moderated assignments' do
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(moderate_button).to be_nil
end
end
end
describe "assignments_2 feature flag and parameter" do
context "as a teacher" do
before :once do
course_with_teacher(active_all: true)
@assignment = @course.assignments.create!(title: "some assignment")
end
before :each do
user_session @teacher
end
describe "with feature disabled" do
it "shows the old assignments page even with query parameter" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}?assignments_2=1"
html = Nokogiri::HTML5(response.body)
expect(html.at_css('div#assignment_show')).to be
end
end
describe "with feature enabled" do
before :once do
Account.default.enable_feature! :assignments_2_teacher
end
it "it shows new assignments" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
html = Nokogiri::HTML5(response.body)
expect(html.at_css('div#assignment_show')).not_to be
end
it "shows old assignments when explicitly requested" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}?assignments_2=0"
html = Nokogiri::HTML5(response.body)
expect(html.at_css('div#assignment_show')).to be
end
end
end
describe "as a student" do
before :once do
course_with_student(active_all: true)
@assignment = @course.assignments.create!(title: "some assignment")
end
before :each do
user_session @student
end
describe "with feature disabled" do
it "shows the old assignments page even with query parameter" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}?assignments_2=1"
html = Nokogiri::HTML5(response.body)
expect(html.at_css('div#assignment_show')).to be
end
end
describe "with feature enabled" do
before :once do
Account.default.enable_feature! :assignments_2_student
end
it "shows new assignments by default" do
@assignment.submission_types = 'online_text_entry'
@assignment.save!
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
html = Nokogiri::HTML5(response.body)
expect(html.at_css('div#assignment_show')).not_to be
end
it "shows old assignments if requested" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}?assignments_2=0"
html = Nokogiri::HTML5(response.body)
expect(html.at_css('div#assignment_show')).to be
end
it "sets the necessary RCS ENV" do
@assignment.submission_types = 'online_text_entry'
@assignment.save!
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(controller.js_env).to have_key(:RICH_CONTENT_APP_HOST)
end
end
end
describe "as an observer" do
before(:once) do
course_with_student(active_all: true)
@assignment = @course.assignments.create!(title: "Some Assignment")
@observer = user_factory(active_all: true, active_state: 'active')
@course.enroll_user(
@observer,
'ObserverEnrollment',
section: @course.course_sections.first,
enrollment_state: 'active', allow_multiple_enrollments: true
)
add_linked_observer(@student, @observer)
end
before(:each) do
user_session(@observer)
end
let(:old_assignment_page_indicator) { Nokogiri::HTML5(response.body).at_css('div#assignment_show') }
context "with the feature disabled" do
it "shows the old assignments page even with query parameter" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}?assignments_2=1"
expect(old_assignment_page_indicator).to be_present
end
it "shows the old assignments page without the query parameter" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(old_assignment_page_indicator).to be_present
end
end
context "with the feature enabled" do
before :once do
Account.default.enable_feature! :assignments_2_student
end
# we always send observers to the 'old' assignments page
it "shows the old assignments page even with query parameter" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}?assignments_2=1"
expect(old_assignment_page_indicator).to be_present
end
it "shows the old assignments page without the query parameter" do
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
expect(old_assignment_page_indicator).to be_present
end
end
end
describe "description" do
before :each do
skip "TODO doesn't work right because public_user_content is wonky"
end
let(:description) { <<~HTML }
<a href="#{attachment_model.public_download_url}">link</a>
HTML
it "excludes verifiers if course is not public" do
course_with_student(:active_all => true)
user_session(@student)
expect(UserContent::FilesHandler).to receive(:new).with(hash_including(is_public: false))
assignment = @course.assignments.create(
title: 'some assignment',
description: description
)
get "/courses/#{@course.id}/assignments/#{assignment.id}"
end
it "includes verifiers if course is public" do
expect(UserContent::FilesHandler).to receive(:new).with(hash_including(is_public: true))
course = course_factory(
active_all: true,
is_public: true,
)
assignment = assignment_model(
course: course,
submission_types: "online_url",
description: description
)
get "/courses/#{course.id}/assignments/#{assignment.id}"
end
end
end