canvas-lms/spec/helpers/courses_helper_spec.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

274 lines
11 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
#
# 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/>.
#
describe CoursesHelper do
include ApplicationHelper
include AssignmentsHelper
include CoursesHelper
include QuizzesHelper
context "a view with a 'Coming Up' sidebar" do
before(:once) do
course_with_teacher(active_all: true)
@assignment = factory_with_protected_attributes(@course.assignments,
assignment_valid_attributes.merge({ points_possible: 10,
submission_types: "online_text_entry" }))
@assignment2 = factory_with_protected_attributes(@course.assignments,
assignment_valid_attributes.merge({ points_possible: 10,
submission_types: "none" }))
end
before do
user_session(@user)
end
describe "an assignment with no submissions" do
before(:once) do
@student_one = factory_with_protected_attributes(User, valid_user_attributes)
@student_two = factory_with_protected_attributes(User, valid_user_attributes)
[@student_one, @student_two].each do |student|
e = @course.enroll_student(student)
e.invite
e.accept
end
@assignment.reload
end
it "returns a no submission tooltip if there are no submissions" do
expect(self).to receive(:t).with("#courses.recent_event.no_submissions", "no submissions").and_return("no submissions")
check_icon_data("no submissions", "Assignment", "icon-assignment")
end
it "returns a not submitted tooltip for a student if they have not made a submission" do
expect(self).to receive(:t).with("#courses.recent_event.not_submitted", "not submitted").and_return("not submitted")
check_icon_data("not submitted", "Assignment", "icon-assignment", current_user: @student_one)
end
it "returns a nil tooltip for a student if the assignment does not expect a submission" do
expect(self).to receive(:t).with("#courses.recent_event.not_submitted", "not submitted").and_return("not submitted")
check_icon_data(nil, "Assignment", "icon-assignment", current_user: @student_one, recent_event: @assignment2)
end
end
describe "an assignment with submissions" do
before(:once) do
@student_one = factory_with_protected_attributes(User, valid_user_attributes)
@student_two = factory_with_protected_attributes(User, valid_user_attributes)
[@student_one, @student_two].each do |student|
e = @course.enroll_student(student)
e.invite
e.accept
end
@assignment.reload
end
it "returns a needs grading tooltip if assignments have been submitted that aren't graded" do
expect(self).to receive(:t).with("#courses.recent_event.needs_grading", "needs grading").and_return("needs grading")
@assignment.submit_homework(@student_one, { submission_type: "online_text_entry", body: "..." })
check_icon_data("needs grading", "Assignment", "icon-assignment")
end
it "returns the submission's readable_state as the tooltip for a student" do
submission = @assignment.submit_homework(@student_one, { submission_type: "online_text_entry", body: "..." })
check_icon_data(submission.readable_state, "", "icon-check", current_user: @student_one, submission:)
end
it "returns an assignment icon instead of a check icon if show_assignment_type_icon is set" do
submission = @assignment.submit_homework(@student_two, { submission_type: "online_text_entry", body: "..." })
check_icon_data(submission.readable_state,
"Assignment",
"icon-assignment",
current_user: @student_two,
submission:,
show_assignment_type_icon: true)
end
it "returns a no new submissions tooltip if some assignments have been submitted and graded" do
expect(self).to receive(:t).with("#courses.recent_event.no_new_submissions", "no new submissions").and_return("no new submissions")
@assignment.submit_homework(@student_one, { submission_type: "online_text_entry", body: "xyz" })
prevent grading if submission is due in closed grading period closes CNVS-32229 closes CNVS-32232 test plan: * Create a course with MGP enabled and two grading periods in the default term * Create two assignments for this course, one in a closed GP and one in an open GP * To test overrides, create the following as well: * For one of the students, make the open assignment due in the closed grading period * For another student, make the closed assignment due in the open grading period * Ensure the following steps work for all assignment/student combos due in a closed grading period. ** CNVS-32229 ** * Login as a teacher * Go to speedgrader for the assignment in the closed GP * Notice that the grade input is locked down * Right click on the locked-down input and select 'Inspect' * Remove the 'ui-state-disabled' class and remove readonly="readonly" from the input field's HTML * Notice the input is no longer grayed out and you can enter a grade * Enter a grade and tab out of the input * You should see an error message that says something went wrong and notice in the Network tab of your dev tools that the AJAX post failed, meaning the submission was not gradeable * Refresh the page and notice the grade is not there. * Verify it isn't there in Gradebook either * Login as an admin * Go to speedgrader for the assignment in the closed GP * Notice that the grade input is *not* locked down * Enter a grade and tab out of the input * You should *not* see an error message that says something went wrong meaning the submission was graded successfully * Refresh the page and notice the grade is there. * Verify it is also present in Gradebook ** CNVS-32232 ** * Login as a teacher * Go into a gradebook that has an assignment that is locked down because it is in a closed grading period * Notice that the grade cells for the assignment are locked down (because the submissions fall in a closed grading period) * Right-click on one of the locked-down cells and select 'Inspect' * Remove the 'grayed-out' and 'cannot_edit_in_closed_grading_period' classes * Notice the cell is no longer grayed out and you can enter a grade. * Enter a grade * Click on another cell. * You should see an error message that says something went wrong and in the Network tab of your dev tools verify the AJAX post failed, meaning the submission was not gradeable * Refresh the page and notice the grade is not there * Login as an admin * Login as a teacher * Go into a gradebook that has an assignment that is in a closed grading period * Enter a grade in a cell that should be due in a closed grading period * Click on another cell * You should *not* see an error message that says something went wrong meaning the submission was graded successfully * Refresh the page and notice the grade is there. * Verify it is also present in Gradebook Change-Id: Ia80e4de626616309c5e9dffb78ed0f9671ad1076 Reviewed-on: https://gerrit.instructure.com/95687 Reviewed-by: Jeremy Neander <jneander@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> Tested-by: Jenkins QA-Review: Anju Reddy <areddy@instructure.com> Product-Review: Keith T. Garner <kgarner@instructure.com>
2016-11-15 05:36:56 +08:00
@assignment.grade_student(@student_one, grade: 5, grader: @teacher)
check_icon_data("no new submissions", "Assignment", "icon-assignment")
end
it "returns an all graded tooltip if all assignments are submitted and graded" do
expect(self).to receive(:t).with("#courses.recent_event.all_graded", "all graded").and_return("all graded")
[@student_one, @student_two].each do |student|
@assignment.submit_homework(student, { submission_type: "online_text_entry", body: "bod" })
prevent grading if submission is due in closed grading period closes CNVS-32229 closes CNVS-32232 test plan: * Create a course with MGP enabled and two grading periods in the default term * Create two assignments for this course, one in a closed GP and one in an open GP * To test overrides, create the following as well: * For one of the students, make the open assignment due in the closed grading period * For another student, make the closed assignment due in the open grading period * Ensure the following steps work for all assignment/student combos due in a closed grading period. ** CNVS-32229 ** * Login as a teacher * Go to speedgrader for the assignment in the closed GP * Notice that the grade input is locked down * Right click on the locked-down input and select 'Inspect' * Remove the 'ui-state-disabled' class and remove readonly="readonly" from the input field's HTML * Notice the input is no longer grayed out and you can enter a grade * Enter a grade and tab out of the input * You should see an error message that says something went wrong and notice in the Network tab of your dev tools that the AJAX post failed, meaning the submission was not gradeable * Refresh the page and notice the grade is not there. * Verify it isn't there in Gradebook either * Login as an admin * Go to speedgrader for the assignment in the closed GP * Notice that the grade input is *not* locked down * Enter a grade and tab out of the input * You should *not* see an error message that says something went wrong meaning the submission was graded successfully * Refresh the page and notice the grade is there. * Verify it is also present in Gradebook ** CNVS-32232 ** * Login as a teacher * Go into a gradebook that has an assignment that is locked down because it is in a closed grading period * Notice that the grade cells for the assignment are locked down (because the submissions fall in a closed grading period) * Right-click on one of the locked-down cells and select 'Inspect' * Remove the 'grayed-out' and 'cannot_edit_in_closed_grading_period' classes * Notice the cell is no longer grayed out and you can enter a grade. * Enter a grade * Click on another cell. * You should see an error message that says something went wrong and in the Network tab of your dev tools verify the AJAX post failed, meaning the submission was not gradeable * Refresh the page and notice the grade is not there * Login as an admin * Login as a teacher * Go into a gradebook that has an assignment that is in a closed grading period * Enter a grade in a cell that should be due in a closed grading period * Click on another cell * You should *not* see an error message that says something went wrong meaning the submission was graded successfully * Refresh the page and notice the grade is there. * Verify it is also present in Gradebook Change-Id: Ia80e4de626616309c5e9dffb78ed0f9671ad1076 Reviewed-on: https://gerrit.instructure.com/95687 Reviewed-by: Jeremy Neander <jneander@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> Tested-by: Jenkins QA-Review: Anju Reddy <areddy@instructure.com> Product-Review: Keith T. Garner <kgarner@instructure.com>
2016-11-15 05:36:56 +08:00
@assignment.grade_student(student, grade: 5, grader: @teacher)
end
check_icon_data("all graded", "Assignment", "icon-assignment")
end
end
def check_icon_data(msg, aria_label, icon, options = {})
base_options = {
context: @course,
contexts: [@course],
current_user: @teacher,
recent_event: @assignment,
submission: nil
}.merge(options)
@icon_explanation, @icon_aria_label, @icon_class = icon_data(base_options)
expect(@icon_explanation).to eql msg
expect(@icon_aria_label).to eql aria_label
expect(@icon_class).to eql icon
end
end
context "readable_grade" do
it "returns nil if not graded" do
submission = Submission.new
expect(readable_grade(submission)).to be_nil
end
it "returns the score if graded" do
assignment = Assignment.new(points_possible: 5, grading_type: "points")
submission = Submission.new(grade: 1.33333333, workflow_state: "graded", assignment:)
expect(readable_grade(submission)).to eq "1.33 out of 5"
end
it "does not raise an error when passing a numeric type but grading_type is not 'points'" do
assignment = Assignment.new(points_possible: 5, grading_type: "percent")
submission = Submission.new(grade: 1.33333333, workflow_state: "graded", assignment:)
expect(readable_grade(submission)).to eq "1.33333%"
end
end
pass user-related params to docviewer When talking to DocViewer, include relevant data for the current user as well as the filter of users whose comments should be shown. This commit enables functionality for anonymous annotations. closes GRADE-1427 closes GRADE-1456 Test Plan 1: Moderated Assignments 1. Create a moderated assignment and allow for at least two provisional graders in addition to the final grader. Then, leave at least one annotation and one comment per provisional grader, final grader, and the student. 2. When "Graders cannot view student names" is checked, verify that no instructor or admin can see the students identity on annotaions. Instead, the student's name should show up simply as 'Student'. 3. When "Graders cannot view each other's names" is checked, verify that non-admin, non-final-grader provisional graders cannot see each other's names on annotations. Instead, they should see a generic grader name such as "Grader 1". 4. When "Final grader can view other grader names" is unchecked, verify the final grader cannot view the other graders' names on annotations. Instead, they should see a generic grader name such as "Grader 1". 5. Smoke test the settings listed in steps 2, 3, and 4 in various combinations of being on or off. 6. While the assignment is still in moderation, verify the student can only see their own annotations. 7. When grades are published for the assignment, verify the assignment no longer shows any anonymous annotations. Test Plan 2: Anonymous, Not Moderated Assignments 1. Create an anonymous assignment. Submit to the assignment as a student and leave some annotations as the student and as an instructor. 2. Verify the student can only see their own annotations while the assignment is still muted. 3. An instructor *should* be able to see any annotations made by an instructor, but DocViewer has not implemented this functionality on their side yet. As a result, just verify that an instructor can see the student's annotations but they are anonymized while the assignment is muted. 4. Unmute the assignment and verify the annotations are no longer anonymized, and the student can now see annotations from instructors. Test Plan 3: Normal, Not Anonymous Assignments 1. Do a general smoke test of not anonymous, not moderated assignments to verify annotations still show up as expected. Change-Id: I181a6ace3c00ca93ab8e6c7608a034b521ed78b7 Reviewed-on: https://gerrit.instructure.com/161486 Reviewed-by: Derek Bender <djbender@instructure.com> Tested-by: Jenkins Reviewed-by: Keith T. Garner <kgarner@instructure.com> QA-Review: Derek Bender <djbender@instructure.com> Product-Review: Keith T. Garner <kgarner@instructure.com>
2018-08-11 02:52:14 +08:00
describe "#user_type" do
let(:admin) { account_admin_user(account: Account.default, active_user: true) }
let(:course) { Account.default.courses.create! }
let(:teacher) { teacher_in_course(course:, active_all: true).user }
let(:ta) { ta_in_course(course:, active_all: true).user }
let(:student) { student_in_course(course:, active_all: true).user }
let(:test_student) { course.student_view_student }
let(:rando) { User.create! }
let(:observer) do
observer_user = User.create!
enrollment = course.enroll_user(observer_user, "ObserverEnrollment")
enrollment.update!(workflow_state: "active", associated_user: student)
observer_user
end
it "returns nil for random users with no course association" do
expect(user_type(course, rando)).to be_nil
end
it "returns 'teacher' for TeacherEnrollments" do
expect(user_type(course, teacher)).to eq "teacher"
end
it "returns 'ta' for TaEnrollments" do
expect(user_type(course, ta)).to eq "ta"
end
it "returns 'student' for StudentEnrollments" do
expect(user_type(course, student)).to eq "student"
end
it "returns 'student' for StudentViewEnrollments" do
expect(user_type(course, test_student)).to eq "student"
end
it "returns 'student' for ObserverEnrollments" do
expect(user_type(course, observer)).to eq "student"
end
it "returns 'admin' for admin enrollments" do
expect(user_type(course, admin)).to eq "admin"
end
pass user-related params to docviewer When talking to DocViewer, include relevant data for the current user as well as the filter of users whose comments should be shown. This commit enables functionality for anonymous annotations. closes GRADE-1427 closes GRADE-1456 Test Plan 1: Moderated Assignments 1. Create a moderated assignment and allow for at least two provisional graders in addition to the final grader. Then, leave at least one annotation and one comment per provisional grader, final grader, and the student. 2. When "Graders cannot view student names" is checked, verify that no instructor or admin can see the students identity on annotaions. Instead, the student's name should show up simply as 'Student'. 3. When "Graders cannot view each other's names" is checked, verify that non-admin, non-final-grader provisional graders cannot see each other's names on annotations. Instead, they should see a generic grader name such as "Grader 1". 4. When "Final grader can view other grader names" is unchecked, verify the final grader cannot view the other graders' names on annotations. Instead, they should see a generic grader name such as "Grader 1". 5. Smoke test the settings listed in steps 2, 3, and 4 in various combinations of being on or off. 6. While the assignment is still in moderation, verify the student can only see their own annotations. 7. When grades are published for the assignment, verify the assignment no longer shows any anonymous annotations. Test Plan 2: Anonymous, Not Moderated Assignments 1. Create an anonymous assignment. Submit to the assignment as a student and leave some annotations as the student and as an instructor. 2. Verify the student can only see their own annotations while the assignment is still muted. 3. An instructor *should* be able to see any annotations made by an instructor, but DocViewer has not implemented this functionality on their side yet. As a result, just verify that an instructor can see the student's annotations but they are anonymized while the assignment is muted. 4. Unmute the assignment and verify the annotations are no longer anonymized, and the student can now see annotations from instructors. Test Plan 3: Normal, Not Anonymous Assignments 1. Do a general smoke test of not anonymous, not moderated assignments to verify annotations still show up as expected. Change-Id: I181a6ace3c00ca93ab8e6c7608a034b521ed78b7 Reviewed-on: https://gerrit.instructure.com/161486 Reviewed-by: Derek Bender <djbender@instructure.com> Tested-by: Jenkins Reviewed-by: Keith T. Garner <kgarner@instructure.com> QA-Review: Derek Bender <djbender@instructure.com> Product-Review: Keith T. Garner <kgarner@instructure.com>
2018-08-11 02:52:14 +08:00
it "can optionally be passed preloaded enrollments" do
enrollments = course.enrollments.index_by(&:user_id)
expect(course).not_to receive(:enrollments)
user_type(course, teacher, enrollments)
end
it "returns the correct user type when passed preloaded enrollments" do
enrollments = teacher && course.enrollments.index_by(&:user_id)
expect(user_type(course, teacher, enrollments)).to eq "teacher"
end
end
describe "#sortable_tabs" do
it "returns tool tabs" do
tool = external_tool_model(context: course_model)
tool.course_navigation = { enabled: true }
tool.save
controller = CoursesController.new
controller.instance_variable_set(:@context, tool.context)
tabs = controller.sortable_tabs
tool_tab = tabs.find { |t| Lti::ExternalToolTab.tool_for_tab(t) == tool }
expect(tool_tab[:args][1]).to eq(tool.id)
end
context "when given a quizzes tool tab" do
before do
allow_any_instance_of(ContextExternalTool).to receive(:quiz_lti?).and_return(true)
end
context "quizzes is enabled for the course" do
it "includes the tab" do
tool = external_tool_model(context: course_model)
tool.course_navigation = { enabled: true }
tool.save
controller = CoursesController.new
controller.instance_variable_set(:@context, tool.context)
Account.site_admin.enable_feature! :assignments_2_teacher
allow(controller).to receive(:new_quizzes_navigation_placements_enabled?).with(tool.context).and_return(true)
tabs = controller.sortable_tabs
tool_tab = tabs.find { |t| Lti::ExternalToolTab.tool_for_tab(t) == tool }
expect(tool_tab[:args][1]).to eq(tool.id)
end
end
context "quizzes is disabled for the account/course" do
it "doesn't include the tab" do
tool = external_tool_model(context: course_model)
tool.course_navigation = { enabled: true }
tool.save
controller = CoursesController.new
controller.instance_variable_set(:@context, tool.context)
Account.site_admin.disable_feature! :assignments_2_teacher
tabs = controller.sortable_tabs
tool_tab = tabs.find { |t| Lti::ExternalToolTab.tool_for_tab(t) == tool }
expect(tool_tab).to be_nil
end
end
end
end
describe "#format_course_section_date" do
it "returns formatted date when date provided" do
date = Time.zone.parse("January 14, 2019")
expect(format_course_section_date(date)).to eq "Jan 14, 2019"
end
it "returns string (no date) when date not provided" do
expect(self).to receive(:t).with("#courses.sections.no_date", "(no date)").and_return("(no date)")
expect(format_course_section_date).to eq "(no date)"
end
end
end