Merge pull request #12165 from edx/efischer/hide_timed_exams

TNL-4366 Hide Timed Exams
This commit is contained in:
Eric Fischer
2016-04-29 09:28:16 -04:00
16 changed files with 481 additions and 338 deletions

View File

@@ -598,7 +598,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
var getDisplayNameWrapper, setEditModalValues, mockServerValuesJson,
selectDisableSpecialExams, selectBasicSettings, selectAdvancedSettings,
selectAccessSettings, selectTimedExam, selectProctoredExam, selectPracticeExam,
selectPrerequisite, selectLastPrerequisiteSubsection;
selectPrerequisite, selectLastPrerequisiteSubsection, checkOptionFieldVisibility;
getDisplayNameWrapper = function() {
return getItemHeaders('subsection').find('.wrapper-xblock-field');
@@ -612,7 +612,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
};
selectDisableSpecialExams = function() {
this.$("#id_not_timed").prop('checked', true).trigger('change');
this.$("input.no_special_exam").prop('checked', true).trigger('change');
};
selectBasicSettings = function() {
@@ -627,22 +627,23 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
this.$(".modal-section .settings-tab-button[data-tab='access']").click();
};
selectTimedExam = function(time_limit) {
this.$("#id_timed_exam").prop('checked', true).trigger('change');
this.$("#id_time_limit").val(time_limit);
this.$("#id_time_limit").trigger('focusout');
selectTimedExam = function(time_limit, hide_after_due) {
this.$("input.timed_exam").prop('checked', true).trigger('change');
this.$(".field-time-limit input").val(time_limit);
this.$(".field-time-limit input").trigger('focusout');
this.$('.field-hide-after-due input').prop('checked', hide_after_due).trigger('change');
};
selectProctoredExam = function(time_limit) {
this.$("#id_proctored_exam").prop('checked', true).trigger('change');
this.$("#id_time_limit").val(time_limit);
this.$("#id_time_limit").trigger('focusout');
this.$("input.proctored_exam").prop('checked', true).trigger('change');
this.$(".field-time-limit input").val(time_limit);
this.$(".field-time-limit input").trigger('focusout');
};
selectPracticeExam = function(time_limit) {
this.$("#id_practice_exam").prop('checked', true).trigger('change');
this.$("#id_time_limit").val(time_limit);
this.$("#id_time_limit").trigger('focusout');
this.$("input.practice_exam").prop('checked', true).trigger('change');
this.$(".field-time-limit input").val(time_limit);
this.$(".field-time-limit input").trigger('focusout');
};
selectPrerequisite = function() {
@@ -654,6 +655,13 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
this.$("#prereq_min_score").val(minScore).trigger('keyup');
};
// Helper to validate oft-checked additional option fields' visibility
checkOptionFieldVisibility = function(time_limit, review_rules, hide_after_due) {
expect($('.field-time-limit').is(':visible')).toBe(time_limit);
expect($('.field-exam-review-rules').is(':visible')).toBe(review_rules);
expect($('.field-hide-after-due').is(':visible')).toBe(hide_after_due);
};
// Contains hard-coded dates because dates are presented in different formats.
mockServerValuesJson = createMockSectionJSON({
release_date: 'Jan 01, 2970 at 05:00 UTC'
@@ -670,8 +678,9 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
is_prereq: false,
"is_time_limited": true,
"is_practice_exam": false,
"is_proctored_exam": true,
"default_time_limit_minutes": 150
"is_proctored_exam": false,
"default_time_limit_minutes": 150,
"hide_after_due": true,
}, [
createMockVerticalJSON({
has_changes: true,
@@ -815,13 +824,13 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
for (i = 0; i < valid_times.length; i++){
time_limit = valid_times[i];
selectTimedExam(time_limit);
expect($("#id_time_limit").val()).toEqual(time_limit);
expect($(".field-time-limit input").val()).toEqual(time_limit);
}
for (i = 0; i < invalid_times.length; i++){
time_limit = invalid_times[i];
selectTimedExam(time_limit);
expect($("#id_time_limit").val()).not.toEqual(time_limit);
expect($("#id_time_limit").val()).toEqual(default_time);
expect($(".field-time-limit input").val()).not.toEqual(time_limit);
expect($(".field-time-limit input").val()).toEqual(default_time);
}
});
@@ -829,7 +838,8 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
createCourseOutlinePage(this, mockCourseJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
setEditModalValues("7/9/2014", "7/10/2014", "Lab", true);
selectProctoredExam("02:30");
selectAdvancedSettings();
selectTimedExam("02:30", true);
$(".wrapper-modal-window .action-save").click();
AjaxHelpers.expectJsonRequest(requests, 'POST', '/xblock/mock-subsection', {
"graderType":"Lab",
@@ -842,8 +852,9 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
"exam_review_rules": "",
"is_time_limited": true,
"is_practice_exam": false,
"is_proctored_enabled": true,
"default_time_limit_minutes": 150
"is_proctored_enabled": false,
"default_time_limit_minutes": 150,
"hide_after_due": true,
}
});
expect(requests[0].requestHeaders['X-HTTP-Method-Override']).toBe('PATCH');
@@ -872,30 +883,35 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
expect($("#due_date").val()).toBe('7/10/2014');
expect($("#grading_type").val()).toBe('Lab');
expect($("#staff_lock").is(":checked")).toBe(true);
expect($("#id_timed_exam").is(":checked")).toBe(false);
expect($("#id_proctored_exam").is(":checked")).toBe(true);
expect($("#id_not_timed").is(":checked")).toBe(false);
expect($("#id_practice_exam").is(":checked")).toBe(false);
expect($("#id_time_limit").val()).toBe("02:30");
expect($("input.timed_exam").is(":checked")).toBe(true);
expect($("input.proctored_exam").is(":checked")).toBe(false);
expect($("input.no_special_exam").is(":checked")).toBe(false);
expect($("input.practice_exam").is(":checked")).toBe(false);
expect($(".field-time-limit input").val()).toBe("02:30");
expect($(".field-hide-after-due input").is(":checked")).toBe(true);
});
it('can hide the time limit field when the None radio box is selected', function() {
it('can hide time limit and hide after due fields when the None radio box is selected', function() {
createCourseOutlinePage(this, mockCourseJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
setEditModalValues("7/9/2014", "7/10/2014", "Lab", true);
selectAdvancedSettings();
selectDisableSpecialExams();
// id_time_limit_div should be hidden when None is specified
expect($('#id_time_limit_div')).toHaveClass('is-hidden');
// all additional options should be hidden
expect($('.exam-options').is(':hidden')).toBe(true);
});
it('can select the practice exam', function() {
createCourseOutlinePage(this, mockCourseJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
setEditModalValues("7/9/2014", "7/10/2014", "Lab", true);
selectAdvancedSettings();
selectPracticeExam("00:30");
// id_time_limit_div should not be hidden when practice exam is specified
expect($('#id_time_limit_div')).not.toHaveClass('is-hidden"');
// time limit should be visible, review rules and hide after due should be hidden
checkOptionFieldVisibility(true, false, false);
$(".wrapper-modal-window .action-save").click();
});
@@ -903,9 +919,12 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
createCourseOutlinePage(this, mockCourseJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
setEditModalValues("7/9/2014", "7/10/2014", "Lab", true);
selectAdvancedSettings();
selectTimedExam("00:30");
// id_time_limit_div should not be hidden when timed exam is specified
expect($('#id_time_limit_div')).not.toHaveClass('is-hidden"');
// time limit and hide after due should be visible, review rules should be hidden
checkOptionFieldVisibility(true, false, true);
$(".wrapper-modal-window .action-save").click();
});
@@ -913,9 +932,12 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
createCourseOutlinePage(this, mockCourseJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
setEditModalValues("7/9/2014", "7/10/2014", "Lab", true);
selectAdvancedSettings();
selectProctoredExam("00:30");
// id_time_limit_div should not be hidden when timed exam is specified
expect($('#id_time_limit_div')).not.toHaveClass('is-hidden"');
// time limit and review rules should be visible, hide after due should be hidden
checkOptionFieldVisibility(true, true, false);
$(".wrapper-modal-window .action-save").click();
});
@@ -924,10 +946,12 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
createCourseOutlinePage(this, mockCourseJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
setEditModalValues("7/9/2014", "7/10/2014", "Lab", true);
selectAdvancedSettings();
selectProctoredExam("abcd");
// id_time_limit_div should not be hidden when timed exam is specified
expect($('#id_time_limit_div')).not.toHaveClass('is-hidden"');
expect($('#id_time_limit')).toHaveValue('00:30');
// time limit field should be visible and have the correct value
expect($('.field-time-limit').is(':visible')).toBe(true);
expect($('.field-time-limit input').val()).toEqual("00:30");
});
@@ -944,21 +968,24 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
"is_time_limited": false,
"is_practice_exam": false,
"is_proctored_exam": false,
"default_time_limit_minutes": 150
"default_time_limit_minutes": 150,
"hide_after_due": false,
}, [
]),
])
]);
createCourseOutlinePage(this, mockCourseWithSpecialExamJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
expect($("#id_timed_exam").is(":checked")).toBe(false);
expect($("#id_proctored_exam").is(":checked")).toBe(false);
expect($("#id_not_timed").is(":checked")).toBe(true);
expect($("#id_practice_exam").is(":checked")).toBe(false);
expect($("#id_time_limit").val()).toBe("02:30");
selectAdvancedSettings();
expect($("input.timed_exam").is(":checked")).toBe(false);
expect($("input.proctored_exam").is(":checked")).toBe(false);
expect($("input.no_special_exam").is(":checked")).toBe(true);
expect($("input.practice_exam").is(":checked")).toBe(false);
expect($(".field-time-limit input").val()).toBe("02:30");
expect($('.field-hide-after-due').is(':hidden')).toBe(true);
});
it('can show a saved timed exam correctly', function() {
it('can show a saved timed exam correctly when hide_after_due is true', function() {
var mockCourseWithSpecialExamJSON = createMockCourseJSON({}, [
createMockSectionJSON({
has_changes: true,
@@ -971,18 +998,51 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
"is_time_limited": true,
"is_practice_exam": false,
"is_proctored_exam": false,
"default_time_limit_minutes": 10
"default_time_limit_minutes": 10,
"hide_after_due": true,
}, [
]),
])
]);
createCourseOutlinePage(this, mockCourseWithSpecialExamJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
expect($("#id_timed_exam").is(":checked")).toBe(true);
expect($("#id_proctored_exam").is(":checked")).toBe(false);
expect($("#id_not_timed").is(":checked")).toBe(false);
expect($("#id_practice_exam").is(":checked")).toBe(false);
expect($("#id_time_limit").val()).toBe("00:10");
selectAdvancedSettings();
expect($("input.timed_exam").is(":checked")).toBe(true);
expect($("input.proctored_exam").is(":checked")).toBe(false);
expect($("input.no_special_exam").is(":checked")).toBe(false);
expect($("input.practice_exam").is(":checked")).toBe(false);
expect($(".field-time-limit input").val()).toBe("00:10");
expect($('.field-hide-after-due input').is(":checked")).toBe(true);
});
it('can show a saved timed exam correctly when hide_after_due is true', function() {
var mockCourseWithSpecialExamJSON = createMockCourseJSON({}, [
createMockSectionJSON({
has_changes: true,
enable_proctored_exams: true,
enable_timed_exams: true
}, [
createMockSubsectionJSON({
has_changes: true,
"is_time_limited": true,
"is_practice_exam": false,
"is_proctored_exam": false,
"default_time_limit_minutes": 10,
"hide_after_due": false,
}, [
]),
])
]);
createCourseOutlinePage(this, mockCourseWithSpecialExamJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
selectAdvancedSettings();
expect($("input.timed_exam").is(":checked")).toBe(true);
expect($("input.proctored_exam").is(":checked")).toBe(false);
expect($("input.no_special_exam").is(":checked")).toBe(false);
expect($("input.practice_exam").is(":checked")).toBe(false);
expect($(".field-time-limit input").val()).toBe("00:10");
expect($('.field-hide-after-due input').is(":checked")).toBe(false);
});
it('can show a saved practice exam correctly', function() {
@@ -1005,11 +1065,13 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
]);
createCourseOutlinePage(this, mockCourseWithSpecialExamJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
expect($("#id_timed_exam").is(":checked")).toBe(false);
expect($("#id_proctored_exam").is(":checked")).toBe(false);
expect($("#id_not_timed").is(":checked")).toBe(false);
expect($("#id_practice_exam").is(":checked")).toBe(true);
expect($("#id_time_limit").val()).toBe("02:30");
selectAdvancedSettings();
expect($("input.timed_exam").is(":checked")).toBe(false);
expect($("input.proctored_exam").is(":checked")).toBe(false);
expect($("input.no_special_exam").is(":checked")).toBe(false);
expect($("input.practice_exam").is(":checked")).toBe(true);
expect($(".field-time-limit input").val()).toBe("02:30");
expect($('.field-hide-after-due').is(':hidden')).toBe(true);
});
it('can show a saved proctored exam correctly', function() {
@@ -1032,11 +1094,13 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
]);
createCourseOutlinePage(this, mockCourseWithSpecialExamJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
expect($("#id_timed_exam").is(":checked")).toBe(false);
expect($("#id_proctored_exam").is(":checked")).toBe(true);
expect($("#id_not_timed").is(":checked")).toBe(false);
expect($("#id_practice_exam").is(":checked")).toBe(false);
expect($("#id_time_limit").val()).toBe("02:30");
selectAdvancedSettings();
expect($("input.timed_exam").is(":checked")).toBe(false);
expect($("input.proctored_exam").is(":checked")).toBe(true);
expect($("input.no_special_exam").is(":checked")).toBe(false);
expect($("input.practice_exam").is(":checked")).toBe(false);
expect($(".field-time-limit input").val()).toBe("02:30");
expect($('.field-hide-after-due').is(':hidden')).toBe(true);
});
it('does not show proctored settings if proctored exams not enabled', function() {
@@ -1052,16 +1116,19 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u
"is_time_limited": true,
"is_practice_exam": false,
"is_proctored_exam": false,
"default_time_limit_minutes": 150
"default_time_limit_minutes": 150,
"hide_after_due": true,
}, [
]),
])
]);
createCourseOutlinePage(this, mockCourseWithSpecialExamJSON, false);
outlinePage.$('.outline-subsection .configure-button').click();
expect($("#id_timed_exam").is(":checked")).toBe(true);
expect($("#id_not_timed").is(":checked")).toBe(false);
expect($("#id_time_limit").val()).toBe("02:30");
selectAdvancedSettings();
expect($("input.timed_exam").is(":checked")).toBe(true);
expect($("input.no_special_exam").is(":checked")).toBe(false);
expect($(".field-time-limit input").val()).toBe("02:30");
expect($('.field-hide-after-due input').is(":checked")).toBe(true);
});
it('can select prerequisite', function() {

View File

@@ -332,41 +332,47 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
templateName: 'timed-examination-preference-editor',
className: 'edit-settings-timed-examination',
events : {
'change #id_not_timed': 'notTimedExam',
'change #id_timed_exam': 'setTimedExam',
'change #id_practice_exam': 'setPracticeExam',
'change #id_proctored_exam': 'setProctoredExam',
'focusout #id_time_limit': 'timeLimitFocusout'
'change input.no_special_exam': 'notTimedExam',
'change input.timed_exam': 'setTimedExam',
'change input.practice_exam': 'setPracticeExam',
'change input.proctored_exam': 'setProctoredExam',
'focusout .field-time-limit input': 'timeLimitFocusout'
},
notTimedExam: function (event) {
event.preventDefault();
this.$('#id_time_limit_div').hide();
this.$('.exam-review-rules-list-fields').hide();
this.$('#id_time_limit').val('00:00');
this.$('.exam-options').hide();
this.$('.field-time-limit input').val('00:00');
},
selectSpecialExam: function (showRulesField) {
this.$('#id_time_limit_div').show();
if (!this.isValidTimeLimit(this.$('#id_time_limit').val())) {
this.$('#id_time_limit').val('00:30');
selectSpecialExam: function (showRulesField, showHideAfterDueField) {
this.$('.exam-options').show();
this.$('.field-time-limit').show();
if (!this.isValidTimeLimit(this.$('.field-time-limit input').val())) {
this.$('.field-time-limit input').val('00:30');
}
if (showRulesField) {
this.$('.exam-review-rules-list-fields').show();
this.$('.field-exam-review-rules').show();
}
else {
this.$('.exam-review-rules-list-fields').hide();
this.$('.field-exam-review-rules').hide();
}
if (showHideAfterDueField) {
this.$('.field-hide-after-due').show();
}
else {
this.$('.field-hide-after-due').hide();
}
},
setTimedExam: function (event) {
event.preventDefault();
this.selectSpecialExam(false);
this.selectSpecialExam(false, true);
},
setPracticeExam: function (event) {
event.preventDefault();
this.selectSpecialExam(false);
this.selectSpecialExam(false, false);
},
setProctoredExam: function (event) {
event.preventDefault();
this.selectSpecialExam(true);
this.selectSpecialExam(true, false);
},
timeLimitFocusout: function(event) {
event.preventDefault();
@@ -389,43 +395,51 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
this.setExamTime(this.model.get('default_time_limit_minutes'));
this.setReviewRules(this.model.get('exam_review_rules'));
this.setHideAfterDue(this.model.get('hide_after_due'));
},
setExamType: function(is_time_limited, is_proctored_exam, is_practice_exam) {
this.$('.field-time-limit').hide();
this.$('.field-exam-review-rules').hide();
this.$('.field-hide-after-due').hide();
if (!is_time_limited) {
this.$("#id_not_timed").prop('checked', true);
this.$('input.no_special_exam').prop('checked', true);
return;
}
this.$('#id_time_limit_div').show();
this.$('.exam-review-rules-list-fields').hide();
this.$('.field-time-limit').show();
if (this.options.enable_proctored_exams && is_proctored_exam) {
if (is_practice_exam) {
this.$('#id_practice_exam').prop('checked', true);
this.$('input.practice_exam').prop('checked', true);
} else {
this.$('#id_proctored_exam').prop('checked', true);
this.$('.exam-review-rules-list-fields').show();
this.$('input.proctored_exam').prop('checked', true);
this.$('.field-exam-review-rules').show();
}
} else {
// Since we have an early exit at the top of the method
// if the subsection is not time limited, then
// here we rightfully assume that it just a timed exam
this.$("#id_timed_exam").prop('checked', true);
this.$('input.timed_exam').prop('checked', true);
this.$('.field-hide-after-due').show();
}
},
setExamTime: function(value) {
var time = this.convertTimeLimitMinutesToString(value);
this.$('#id_time_limit').val(time);
this.$('.field-time-limit input').val(time);
},
setReviewRules: function (value) {
this.$('#id_exam_review_rules').val(value);
this.$('.field-exam-review-rules textarea').val(value);
},
setHideAfterDue: function(value) {
this.$('.field-hide-after-due input').prop('checked', value);
},
isValidTimeLimit: function(time_limit) {
var pattern = new RegExp('^\\d{1,2}:[0-5][0-9]$');
return pattern.test(time_limit) && time_limit !== "00:00";
},
getExamTimeLimit: function () {
return this.$('#id_time_limit').val();
return this.$('.field-time-limit input').val();
},
convertTimeLimitMinutesToString: function (timeLimitMinutes) {
var hoursStr = "" + Math.floor(timeLimitMinutes / 60);
@@ -444,21 +458,22 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
var is_practice_exam;
var is_proctored_exam;
var time_limit = this.getExamTimeLimit();
var exam_review_rules = this.$('#id_exam_review_rules').val();
var exam_review_rules = this.$('.field-exam-review-rules textarea').val();
var hide_after_due = this.$('.field-hide-after-due input').is(':checked');
if (this.$("#id_not_timed").is(':checked')){
if (this.$('input.no_special_exam').is(':checked')){
is_time_limited = false;
is_practice_exam = false;
is_proctored_exam = false;
} else if (this.$("#id_timed_exam").is(':checked')){
} else if (this.$('input.timed_exam').is(':checked')){
is_time_limited = true;
is_practice_exam = false;
is_proctored_exam = false;
} else if (this.$("#id_proctored_exam").is(':checked')){
} else if (this.$('input.proctored_exam').is(':checked')){
is_time_limited = true;
is_practice_exam = false;
is_proctored_exam = true;
} else if (this.$("#id_practice_exam").is(':checked')){
} else if (this.$('input.practice_exam').is(':checked')){
is_time_limited = true;
is_practice_exam = true;
is_proctored_exam = true;
@@ -469,6 +484,7 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
'is_practice_exam': is_practice_exam,
'is_time_limited': is_time_limited,
'exam_review_rules': exam_review_rules,
'hide_after_due': hide_after_due,
// We have to use the legacy field name
// as the Ajax handler directly populates
// the xBlocks fields. We will have to