feat: AA-883 basic prototype for custom pacing pls in studio

fix: make new field in xblock json serializable and don't assign due dates to ORAs

feat: display warning message in Studio if the relative date input is more than 18 weeks for custom pacing in self paced course

fix: handle due dates for mix of ORA and non ORA problems under a subsection and other styling fixes

feat: add a minimum restriction for self paced courses due date editor input

fix: naming of warning id divs to be more specific and exclude children of ORA problems in setting due dates

test: extracting dates for a self paced course with custom pacing

test: frontend for self paced custom pacing modal in studio and clean up its backend tests

fix: remove an unused line when getting children of custom pacing subsection, reorganize testing for custom pacing

fix: more specific comments to testing for custom PLS and remove a test case course

fix: more cleanup for self paced custom pacing PLS backend tests
This commit is contained in:
Sofia Yoon
2021-06-23 16:04:07 -04:00
parent 4d96449134
commit 09eb36e550
12 changed files with 506 additions and 115 deletions

View File

@@ -12,7 +12,7 @@ describe('CourseOutlinePage', function() {
var createCourseOutlinePage, displayNameInput, model, outlinePage, requests, getItemsOfType, getItemHeaders,
verifyItemsExpanded, expandItemsAndVerifyState, collapseItemsAndVerifyState, selectBasicSettings,
selectVisibilitySettings, selectAdvancedSettings, createMockCourseJSON, createMockSectionJSON,
createMockSubsectionJSON, verifyTypePublishable, mockCourseJSON, mockEmptyCourseJSON, setSelfPaced,
createMockSubsectionJSON, verifyTypePublishable, mockCourseJSON, mockEmptyCourseJSON, setSelfPaced,setSelfPacedCustomPLS,
mockSingleSectionCourseJSON, createMockVerticalJSON, createMockIndexJSON, mockCourseEntranceExamJSON,
selectOnboardingExam, createMockCourseJSONWithReviewRules,mockCourseJSONWithReviewRules,
mockOutlinePage = readFixtures('templates/mock/mock-course-outline-page.underscore'),
@@ -202,6 +202,11 @@ describe('CourseOutlinePage', function() {
course.set('self_paced', true);
};
setSelfPacedCustomPLS = function() {
setSelfPaced();
course.set('is_custom_pls_active', true);
}
createCourseOutlinePage = function(test, courseJSON, createOnly) {
requests = AjaxHelpers.requests(test);
model = new XBlockOutlineInfo(courseJSON, {parse: true});
@@ -1002,9 +1007,9 @@ describe('CourseOutlinePage', function() {
});
describe('Subsection', function() {
var getDisplayNameWrapper, setEditModalValues, setContentVisibility, mockServerValuesJson,
selectDisableSpecialExams, selectTimedExam, selectProctoredExam, selectPracticeExam,
selectPrerequisite, selectLastPrerequisiteSubsection, checkOptionFieldVisibility,
var getDisplayNameWrapper, setEditModalValues, setEditModalValuesForCustomPacing, setContentVisibility, mockServerValuesJson,
mockCustomPacingServerValuesJson, selectDisableSpecialExams, selectTimedExam, selectProctoredExam, selectPracticeExam,
selectPrerequisite, selectLastPrerequisiteSubsection, selectDueNumWeeksSubsection, checkOptionFieldVisibility,
defaultModalSettings, modalSettingsWithExamReviewRules, getMockNoPrereqOrExamsCourseJSON, expectShowCorrectness;
getDisplayNameWrapper = function() {
@@ -2117,6 +2122,170 @@ describe('CourseOutlinePage', function() {
);
expect($modalWindow.find('.outline-subsection')).not.toExist();
});
describe('Self Paced with Custom Personalized Learner Schedules (PLS)', function () {
beforeEach(function() {
var mockCourseJSON = createMockCourseJSON({}, [
createMockSectionJSON({}, [
createMockSubsectionJSON({}, [])
])
]);
createCourseOutlinePage(this, mockCourseJSON, false);
setSelfPacedCustomPLS();
});
setEditModalValuesForCustomPacing = function(due_in, grading_type) {
$('#due_in').val(due_in);
$('#grading_type').val(grading_type);
};
selectDueNumWeeksSubsection = function(weeks) {
$('#due_in').val(weeks).trigger('keyup');
}
mockCustomPacingServerValuesJson = createMockSectionJSON({
release_date: 'Jan 01, 2970 at 05:00 UTC'
}, [
createMockSubsectionJSON({
graded: true,
due_num_weeks: 3,
format: 'Lab',
has_explicit_staff_lock: true,
staff_only_message: true,
is_prereq: false,
show_correctness: 'never',
is_time_limited: false,
is_practice_exam: false,
is_proctored_exam: false,
default_time_limit_minutes: null,
}, [
createMockVerticalJSON({
has_changes: true,
published: false
})
])
]);
it('can show correct editors for self_paced course with custom pacing', function (){
outlinePage.$('.outline-subsection .configure-button').click();
expect($('.edit-settings-release').length).toBe(0);
// Due date input exists for custom pacing self paced courses
expect($('.grading-due-date').length).toBe(1);
expect($('.edit-settings-grading').length).toBe(1);
expect($('.edit-content-visibility').length).toBe(1);
expect($('.edit-show-correctness').length).toBe(1);
});
it('can be edited when custom pacing for self paced course is active', function() {
outlinePage.$('.outline-subsection .configure-button').click();
setEditModalValuesForCustomPacing('3', 'Lab');
selectAdvancedSettings();
$('.wrapper-modal-window .action-save').click();
AjaxHelpers.expectJsonRequest(requests, 'POST', '/xblock/mock-subsection', {
graderType: 'Lab',
isPrereq: false,
metadata: {
due_num_weeks: 3,
is_time_limited: false,
is_practice_exam: false,
is_proctored_enabled: false,
default_time_limit_minutes: null,
is_onboarding_exam: false,
}
});
expect(requests[0].requestHeaders['X-HTTP-Method-Override']).toBe('PATCH');
AjaxHelpers.respondWithJson(requests, {});
AjaxHelpers.expectJsonRequest(requests, 'GET', '/xblock/outline/mock-section');
AjaxHelpers.respondWithJson(requests, mockCustomPacingServerValuesJson);
AjaxHelpers.expectNoRequests(requests);
expect($('.outline-subsection .status-grading-value')).toContainText(
'Lab'
);
expect($('.outline-subsection .status-message-copy')).toContainText(
'Contains staff only content'
);
expect($('.outline-item .outline-subsection .status-grading-value')).toContainText('Lab');
outlinePage.$('.outline-item .outline-subsection .configure-button').click();
expect($('#due_in').val()).toBe('3');
expect($('#grading_type').val()).toBe('Lab');
expect($('input[name=content-visibility][value=staff_only]').is(':checked')).toBe(true);
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);
expectShowCorrectness('never');
});
it('shows validation error on due number of weeks', function() {
outlinePage.$('.outline-subsection .configure-button').click();
// when due number of weeks goes over 18
selectDueNumWeeksSubsection('19');
expect($('#due-num-weeks-warning-max').css('display')).not.toBe('none');
expect($('.wrapper-modal-window .action-save').prop('disabled')).toBe(true);
expect($('.wrapper-modal-window .action-save').hasClass('is-disabled')).toBe(true);
// when due number of weeks is less than 1
selectDueNumWeeksSubsection('-1');
expect($('#due-num-weeks-warning-min').css('display')).not.toBe('none');
expect($('.wrapper-modal-window .action-save').prop('disabled')).toBe(true);
expect($('.wrapper-modal-window .action-save').hasClass('is-disabled')).toBe(true);
// when no validation error should show up
selectDueNumWeeksSubsection('10');
expect($('#due-num-weeks-warning-max').css('display')).toBe('none');
expect($('#due-num-weeks-warning-min').css('display')).toBe('none');
expect($('.wrapper-modal-window .action-save').prop('disabled')).toBe(false);
expect($('.wrapper-modal-window .action-save').hasClass('is-disabled')).toBe(false);
});
it('due num weeks (due_in) can be cleared.', function() {
outlinePage.$('.outline-item .outline-subsection .configure-button').click();
setEditModalValuesForCustomPacing('3', 'Lab');
setContentVisibility('staff_only');
$('.wrapper-modal-window .action-save').click();
// This is the response for the change operation.
AjaxHelpers.respondWithJson(requests, {});
// This is the response for the subsequent fetch operation.
AjaxHelpers.respondWithJson(requests, mockCustomPacingServerValuesJson);
expect($('.outline-subsection .status-grading-value')).toContainText(
'Lab'
);
expect($('.outline-subsection .status-message-copy')).toContainText(
'Contains staff only content'
);
outlinePage.$('.outline-subsection .configure-button').click();
expect($('#due_in').val()).toBe('3');
expect($('#grading_type').val()).toBe('Lab');
expect($('input[name=content-visibility][value=staff_only]').is(':checked')).toBe(true);
$('.wrapper-modal-window .due-date-input .action-clear').click();
expect($('#due_in').val()).toBe('');
$('#grading_type').val('notgraded');
setContentVisibility('visible');
$('.wrapper-modal-window .action-save').click();
// This is the response for the change operation.
AjaxHelpers.respondWithJson(requests, {});
// This is the response for the subsequent fetch operation.
AjaxHelpers.respondWithJson(requests,
createMockSectionJSON({}, [createMockSubsectionJSON()])
);
expect($('.outline-subsection .status-grading-value')).not.toExist();
expect($('.outline-subsection .status-message-copy')).not.toContainText(
'Contains staff only content'
);
});
})
});
// Note: most tests for units can be found in Bok Choy

View File

@@ -15,10 +15,9 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
'use strict';
var CourseOutlineXBlockModal, SettingsXBlockModal, PublishXBlockModal, HighlightsXBlockModal,
AbstractEditor, BaseDateEditor,
ReleaseDateEditor, DueDateEditor, GradingEditor, PublishEditor, AbstractVisibilityEditor,
ReleaseDateEditor, DueDateEditor, SelfPacedDueDateEditor, GradingEditor, PublishEditor, AbstractVisibilityEditor,
StaffLockEditor, UnitAccessEditor, ContentVisibilityEditor, TimedExaminationPreferenceEditor,
AccessEditor, ShowCorrectnessEditor, HighlightsEditor, HighlightsEnableXBlockModal, HighlightsEnableEditor,
SelfPacedDueDateEditor;
AccessEditor, ShowCorrectnessEditor, HighlightsEditor, HighlightsEnableXBlockModal, HighlightsEnableEditor;
CourseOutlineXBlockModal = BaseModal.extend({
events: _.extend({}, BaseModal.prototype.events, {
@@ -75,7 +74,6 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
event.preventDefault();
requestData = this.getRequestData();
console.log(requestData)
if (!_.isEqual(requestData, {metadata: {}})) {
XBlockViewUtils.updateXBlockFields(this.model, requestData, {
success: this.options.onSave
@@ -391,32 +389,55 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
}
});
SelfPacedDueDateEditor = BaseDateEditor.extend({
fieldName: 'due',
SelfPacedDueDateEditor = AbstractEditor.extend({
fieldName: 'due_num_weeks',
templateName: 'self-paced-due-date-editor',
className: 'modal-section-content has-actions due-date-input grading-due-date',
events: {
'click .clear-date': 'clearValue',
'keyup #due_in': 'validateDueIn',
'blur #due_in': 'validateDueIn',
},
getValue: function() {
return this.$('#due_date').val();
return parseInt(this.$('#due_in').val());
},
validateDueIn: function() {
if (this.getValue() > 18){
this.$('#due-num-weeks-warning-max').show();
BaseModal.prototype.disableActionButton.call(this.parent, 'save');
}
else if (this.getValue() < 1){
this.$('#due-num-weeks-warning-min').show()
BaseModal.prototype.disableActionButton.call(this.parent, 'save');
}
else {
this.$('#due-num-weeks-warning-max').hide();
this.$('#due-num-weeks-warning-min').hide();
BaseModal.prototype.enableActionButton.call(this.parent, 'save');
}
},
clearValue: function(event) {
event.preventDefault();
this.$('#due_date').val('');
this.$('#due_in').val('');
},
afterRender: function() {
AbstractEditor.prototype.afterRender.call(this);
this.$('.field-due-in input').val(this.model.get('due_num_weeks'));
},
getRequestData: function() {
let currentDate = parseInt(this.getValue())
if (parseInt(this.getValue())){
currentDate = new Date()
currentDate.setDate(currentDate.getDate() + parseInt(this.getValue())*7)
};
// due_num_weeks
return {
metadata: {
due: currentDate
}
};
if (this.getValue() < 19 && this.getValue() > 0) {
return {
metadata: {
due_num_weeks: this.getValue()
}
};
}
}
});
@@ -1108,9 +1129,8 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
} else if (xblockInfo.isSequential()) {
tabs[0].editors = [ReleaseDateEditor, GradingEditor, DueDateEditor];
tabs[1].editors = [ContentVisibilityEditor, ShowCorrectnessEditor];
if (course.get('self_paced')) {
tabs[0].editors.push(SelfPacedDueDateEditor)
if (course.get('self_paced') && course.get('is_custom_pls_active')) {
tabs[0].editors.push(SelfPacedDueDateEditor);
}
if (options.enable_proctored_exams || options.enable_timed_exams) {