canvas-lms/spec/models/assignment_group_spec.rb

448 lines
15 KiB
Ruby

#
# Copyright (C) 2011 - 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.rb')
describe AssignmentGroup do
before(:once) do
@valid_attributes = {
:name => "value for name",
:rules => "value for rules",
:default_assignment_name => "value for default assignment name",
:assignment_weighting_scheme => "value for assignment weighting scheme",
:group_weight => 1.0
}
course_with_student(active_all: true)
@course.update_attribute(:group_weighting_scheme, 'percent')
end
it "should act as list" do
expect(AssignmentGroup).to be_respond_to(:acts_as_list)
end
it "should convert NaN group weight values to 0 on save" do
ag = @course.assignment_groups.create!(@valid_attributes)
ag.group_weight = 0/0.0
ag.save!
expect(ag.group_weight).to eq 0
end
context "visible assignments" do
before(:each) do
@ag = @course.assignment_groups.create!(@valid_attributes)
@s = @course.course_sections.create!(name: "test section")
student_in_section(@s, user: @student)
assignments = (0...4).map { @course.assignments.create!({:title => "test_foo",
:assignment_group => @ag,
:points_possible => 10,
:only_visible_to_overrides => true})}
assignments.first.destroy
assignments.second.grade_student(@student, grade: 10, grader: @teacher)
assignment_to_override = assignments.last
create_section_override_for_assignment(assignment_to_override, course_section: @s)
@course.reload
@ag.reload
end
context "with differentiated assignments and draft state on" do
it "should return only active assignments with overrides or grades for the user" do
expect(@ag.active_assignments.count).to eq 3
# one with override, one with grade
expect(@ag.visible_assignments(@student).count).to eq 2
expect(AssignmentGroup.visible_assignments(@student, @course, [@ag]).count).to eq 2
end
end
context "logged out users" do
it "should return published assignments for logged out users so that invited users can see them before accepting a course invite" do
@course.active_assignments.first.unpublish
expect(@ag.visible_assignments(nil).count).to eq 2
expect(AssignmentGroup.visible_assignments(nil, @course, [@ag]).count).to eq 2
end
end
end
context "broadcast policy" do
context "grade weight changed" do
before(:once) do
Notification.create!(name: 'Grade Weight Changed', category: 'TestImmediately')
assignment_group_model
end
it "sends a notification when the grade weight changes" do
@ag.update_attribute(:group_weight, 0.2)
expect(@ag.context.messages_sent['Grade Weight Changed'].any?{|m| m.user_id == @student.id}).to be_truthy
end
it "sends a notification to observers when the grade weight changes" do
course_with_observer(course: @course, associated_user_id: @student.id, active_all: true)
@ag.reload.update_attribute(:group_weight, 0.2)
expect(@ag.context.messages_sent['Grade Weight Changed'].any?{|m| m.user_id == @observer.id}).to be_truthy
end
end
end
it "should have a state machine" do
assignment_group_model
expect(@ag.state).to eql(:available)
end
it "should return never_drop list as ints" do
expected = [ 9, 22, 16, 4 ]
rules = "drop_lowest:2\n"
expected.each do |val|
rules += "never_drop:#{val}\n"
end
assignment_group_model :rules => rules
result = @ag.rules_hash()
expect(result['never_drop']).to eql(expected)
end
it "should return never_drop list as strings if `stringify_json_ids` is true" do
expected = [ '9', '22', '16', '4' ]
rules = "drop_highest:25\n"
expected.each do |val|
rules += "never_drop:#{val}\n"
end
assignment_group_model :rules => rules
result = @ag.rules_hash({stringify_json_ids: true})
expect(result['never_drop']).to eql(expected)
end
it "should return rules that aren't never_drops as ints" do
rules = "drop_highest:25\n"
assignment_group_model :rules => rules
result = @ag.rules_hash()
expect(result['drop_highest']).to eql(25)
end
it "should return rules that aren't never_drops as ints when `strigify_json_ids` is true" do
rules = "drop_lowest:2\n"
assignment_group_model :rules => rules
result = @ag.rules_hash({stringify_json_ids: true})
expect(result['drop_lowest']).to eql(2)
end
describe "#grants_right?" do
before(:once) do
@assignment_group = @course.assignment_groups.create!(@valid_attributes)
assignments = (0..1).map do |n|
@course.assignments.create!(
title: "Example Assignment #{n}",
assignment_group: @assignment_group,
points_possible: 10
)
end
@assignment = assignments.first
@quiz = quiz_model(course: @course)
@quiz.assignment_group_id = @assignment_group.id
@quiz.save!
@admin = account_admin_user()
teacher_in_course(:course => @course)
@grading_period_group = @course.root_account.grading_period_groups.create!(title: "Example Group")
@grading_period_group.enrollment_terms << @course.enrollment_term
@course.enrollment_term.save!
@assignment_group.reload
@grading_period_group.grading_periods.create!({
title: "Example Grading Period",
start_date: 5.weeks.ago,
end_date: 3.weeks.ago,
close_date: 1.week.ago
})
@grading_period_group.grading_periods.create!({
title: "Example Grading Period",
start_date: 3.weeks.ago,
end_date: 1.week.ago,
close_date: 1.week.from_now
})
end
context "to delete" do
context "without grading periods" do
it "is true for admins" do
@course.stubs(:grading_periods?).returns false
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to be true
end
it "is false for teachers" do
@course.stubs(:grading_periods?).returns false
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to be true
end
end
context "when the assignment is due in a closed grading period" do
before(:once) do
@assignment.update_attributes(due_at: 4.weeks.ago)
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is false for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(false)
end
end
context "when the assignment is due in an open grading period" do
before(:once) do
@assignment.update_attributes(due_at: 2.weeks.ago)
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
context "when the assignment is due after all grading periods" do
before(:once) do
@assignment.update_attributes(due_at: 1.day.from_now)
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
context "when the assignment is due before all grading periods" do
before(:once) do
@assignment.update_attributes(due_at: 6.weeks.ago)
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
context "when the assignment has no due date" do
before(:once) do
@assignment.update_attributes(due_at: nil)
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
context "when the assignment is due in a closed grading period for a student" do
before(:once) do
@assignment.update_attributes(due_at: 2.days.from_now)
override = @assignment.assignment_overrides.build
override.set = @course.default_section
override.override_due_at(4.weeks.ago)
override.save!
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is false for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(false)
end
end
context "when the assignment is overridden with no due date for a student" do
before(:once) do
@assignment.update_attributes(due_at: nil)
override = @assignment.assignment_overrides.build
override.set = @course.default_section
override.save!
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
context "when the assignment is deleted and due in a closed grading period" do
before(:once) do
@assignment.update_attributes(due_at: 4.weeks.ago)
@assignment.destroy
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
context "when the quiz is due in a closed grading period" do
before(:once) do
@quiz.update_attributes(due_at: 4.weeks.ago)
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is false for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(false)
end
end
context "when the quiz is due in an open grading period" do
before(:once) do
@quiz.update_attributes(due_at: 2.weeks.ago)
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
context "when the quiz is due after all grading periods" do
before(:once) do
@quiz.update_attributes(due_at: 1.day.from_now)
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
context "when the quiz is due before all grading periods" do
before(:once) do
@quiz.update_attributes(due_at: 6.weeks.ago)
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
context "when the quiz has no due date" do
before(:once) do
@quiz.update_attributes(due_at: nil)
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
context "when the quiz is due in a closed grading period for a student" do
before(:once) do
@quiz.update_attributes(due_at: 2.days.from_now)
override = @quiz.assignment_overrides.build
override.set = @course.default_section
override.override_due_at(4.weeks.ago)
override.save!
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is false for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(false)
end
end
context "when the quiz is overridden with no due date for a student" do
before(:once) do
@quiz.update_attributes(due_at: nil)
override = @quiz.assignment_overrides.build
override.set = @course.default_section
override.save!
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
context "when the quiz is deleted and due in a closed grading period" do
before(:once) do
@quiz.update_attributes(due_at: 4.weeks.ago)
@quiz.destroy
end
it "is true for admins" do
expect(@assignment_group.reload.grants_right?(@admin, :delete)).to eql(true)
end
it "is true for teachers" do
expect(@assignment_group.reload.grants_right?(@teacher, :delete)).to eql(true)
end
end
end
end
describe '#any_assignment_in_closed_grading_period?' do
it 'calls EffectiveDueDates#in_closed_grading_period?' do
assignment_group_model
edd = EffectiveDueDates.for_course(@ag.context, @ag.published_assignments)
EffectiveDueDates.expects(:for_course).with(@ag.context, @ag.published_assignments).returns(edd)
edd.expects(:any_in_closed_grading_period?).returns(true)
expect(@ag.any_assignment_in_closed_grading_period?).to eq(true)
end
end
end
def assignment_group_model(opts={})
@ag = @course.assignment_groups.create!(@valid_attributes.merge(opts))
end