Skip to content

Commit

Permalink
fix: ignore dates set in studio edit modal when non-manual date confi…
Browse files Browse the repository at this point in the history
…g is set (#2229)

* fix: ignore dates set in studio edit modal when non-manual date config is set

* test: fix failing tests

* fix: add config for optional firefox headless

* chore: static

* chore: version
  • Loading branch information
jansenk authored Dec 19, 2024
1 parent b5d96f3 commit da41f73
Show file tree
Hide file tree
Showing 14 changed files with 391 additions and 37 deletions.
19 changes: 16 additions & 3 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module.exports = function(config) {
'karma-sinon',
'karma-jasmine-html-reporter',
'karma-spec-reporter',
'karma-webpack'
'karma-webpack',
require("karma-firefox-launcher")
],

// frameworks to use
Expand Down Expand Up @@ -107,7 +108,13 @@ module.exports = function(config) {

// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['HeadlessChrome'],

browsers: [
'HeadlessChrome'
// 'HeadlessFirefox'
],
// If chrome headless is not working, try swapping out which line is commented above
// to use firefox for local dev
customLaunchers: {
HeadlessChrome: {
base: 'ChromeHeadless',
Expand All @@ -118,7 +125,13 @@ module.exports = function(config) {
'--disable-translate',
'--disable-extensions'
]
}
},
HeadlessFirefox: {
base: 'Firefox',
flags: [
'--headless',
]
},
},

// Continuous Integration mode
Expand Down
2 changes: 1 addition & 1 deletion openassessment/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Initialization Information for Open Assessment Module
"""

__version__ = '6.14.3'
__version__ = '6.14.4'
12 changes: 6 additions & 6 deletions openassessment/xblock/static/dist/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"openassessment-editor-textarea.js.map": "/openassessment-editor-textarea.cbb31e4372be87d437fb.js.map",
"openassessment-editor-tinymce.js": "/openassessment-editor-tinymce.2a1e66e98a2a1132f633.js",
"openassessment-editor-tinymce.js.map": "/openassessment-editor-tinymce.2a1e66e98a2a1132f633.js.map",
"openassessment-lms.css": "/openassessment-lms.7deea212f43fa92a5945.css",
"openassessment-lms.js": "/openassessment-lms.7deea212f43fa92a5945.js",
"openassessment-lms.css.map": "/openassessment-lms.7deea212f43fa92a5945.css.map",
"openassessment-lms.js.map": "/openassessment-lms.7deea212f43fa92a5945.js.map",
"openassessment-lms.css": "/openassessment-lms.51b88d7de00c69ab0a2e.css",
"openassessment-lms.js": "/openassessment-lms.51b88d7de00c69ab0a2e.js",
"openassessment-lms.css.map": "/openassessment-lms.51b88d7de00c69ab0a2e.css.map",
"openassessment-lms.js.map": "/openassessment-lms.51b88d7de00c69ab0a2e.js.map",
"openassessment-ltr.css": "/openassessment-ltr.2c55d39b6a9784df6e13.css",
"openassessment-ltr.js": "/openassessment-ltr.2c55d39b6a9784df6e13.js",
"openassessment-ltr.css.map": "/openassessment-ltr.2c55d39b6a9784df6e13.css.map",
Expand All @@ -16,8 +16,8 @@
"openassessment-rtl.js": "/openassessment-rtl.86c76a295df3b3a8f88c.js",
"openassessment-rtl.css.map": "/openassessment-rtl.86c76a295df3b3a8f88c.css.map",
"openassessment-rtl.js.map": "/openassessment-rtl.86c76a295df3b3a8f88c.js.map",
"openassessment-studio.js": "/openassessment-studio.aa11b230153dce64cd29.js",
"openassessment-studio.js.map": "/openassessment-studio.aa11b230153dce64cd29.js.map",
"openassessment-studio.js": "/openassessment-studio.65076e7e76039d8c8ab2.js",
"openassessment-studio.js.map": "/openassessment-studio.65076e7e76039d8c8ab2.js.map",
"fallback-default.png": "/1b90ce76fe01a1aa6e5ec289a5fb3799.png",
"default-avatar.svg": "/95ec738c0b7faac5b5c9126794446bbd.svg"
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

This file was deleted.

Large diffs are not rendered by default.

99 changes: 98 additions & 1 deletion openassessment/xblock/static/js/fixtures/templates.json
Original file line number Diff line number Diff line change
Expand Up @@ -510,10 +510,107 @@
"peer_assessment",
"self_assessment",
"staff_assessment"
]
],
"subsection_end_date": "2024-09-09",
"course_end_date": "2040-10-11"
},
"output": "oa_edit.html"
},
{
"template": "legacy/edit/oa_edit.html",
"context": {
"prompts": [{ "description": "How much do you like waffles?" }, { "description": "How much do you like waffles 2?" }],
"title": "The most important of all questions.",
"submission_start": "2014-01-02T12:15",
"submission_due": "2014-10-01T04:53",
"date_config_type": "manual",
"text_response": "required",
"file_upload_response": "",
"leaderboard_show": 12,
"allow_learner_resubmissions": false,
"resubmissions_grace_period": "",
"necessity_options": {
"required": "Required",
"optional": "Optional",
"": "None"
},
"teams_feature_enabled": true,
"teams_enabled": false,
"criteria": [
{
"name": "criterion_1",
"label": "Criterion with two options",
"prompt": "Prompt for criterion with two options",
"order_num": 0,
"feedback": "disabled",
"options": [
{
"order_num": 0,
"points": 1,
"name": "option_1",
"label": "Fair",
"explanation": "Fair explanation"
},
{
"order_num": 1,
"points": 2,
"name": "option_2",
"label": "Good",
"explanation": "Good explanation"
}
],
"points_possible": 2
},
{
"name": "criterion_2",
"label": "Criterion with no options",
"prompt": "Prompt for criterion with no options",
"order_num": 0,
"options": [],
"feedback": "required",
"points_possible": 0
},
{
"name": "criterion_3",
"label": "Criterion with optional feedback",
"prompt": "Prompt for criterion with optional feedback",
"order_num": 2,
"feedback": "optional",
"options": [
{
"order_num": 0,
"points": 2,
"name": "option_1",
"label": "Good",
"explanation": "Good explanation"
}
],
"points_possible": 2
}
],
"feedbackprompt": "Feedback default prompt",
"feedback_default_text": "Feedback default text",
"assessments": {
"peer_assessment": {
"start": "2014-01-02T00:00",
"due": "2014-01-03T00:00",
"must_grade": 5,
"must_be_graded_by": 3
},
"self_assessment": {
"start": "2014-01-04T00:00",
"due": "2014-01-05T00:00"
}
},
"editor_assessments_order": [
"student_training",
"peer_assessment",
"self_assessment",
"staff_assessment"
]
},
"output": "oa_edit_no_subsection_course_deadlines.html"
},
{
"template": "legacy/edit/oa_edit.html",
"context": {
Expand Down
40 changes: 40 additions & 0 deletions openassessment/xblock/static/js/spec/studio/oa_edit_fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,46 @@ describe("OpenAssessment.DatetimeControl", function() {
datetimeControl.clearValidationErrors();
expect(datetimeControl.validationErrors()).toEqual([]);
});

describe("stash and pop", function() {
const dates = ["2024-09-09", "2030-03-02", "2031-03-05"]
const times = ["05:28", null, "02:13"]

beforeEach(function() {
datetimeControl.datetime(dates[0], times[0]);
expect(datetimeControl.datetime()).toEqual(`${dates[0]}T${times[0]}`);
})

it('update values correctly', function() {
datetimeControl.stash(dates[1]);
expect(datetimeControl.datetime()).toEqual(`${dates[1]}T00:00`);

datetimeControl.pop()
expect(datetimeControl.datetime()).toEqual(`${dates[0]}T${times[0]}`);
});

it('stashing multiple times does nothing until popping', function() {
datetimeControl.stash(dates[1], times[1]);
expect(datetimeControl.datetime()).toEqual(`${dates[1]}T00:00`);
datetimeControl.stash(dates[2], times[2]);
expect(datetimeControl.datetime()).toEqual(`${dates[1]}T00:00`);

datetimeControl.pop()
expect(datetimeControl.datetime()).toEqual(`${dates[0]}T${times[0]}`);
});

it('popping multiple times does nothing', function() {
datetimeControl.stash(dates[1], times[1]);
expect(datetimeControl.datetime()).toEqual(`${dates[1]}T00:00`);

datetimeControl.pop()
expect(datetimeControl.datetime()).toEqual(`${dates[0]}T${times[0]}`);

datetimeControl.pop()
expect(datetimeControl.datetime()).toEqual(`${dates[0]}T${times[0]}`);
});
})

});

describe("OpenAssessment.ToggleControl", function() {
Expand Down
72 changes: 70 additions & 2 deletions openassessment/xblock/static/js/spec/studio/oa_edit_schedule.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ describe('OpenAssessment.EditScheduleView', function() {
}
};

beforeEach(function() {
var setupTest = function (fixture) {
// Load the DOM fixture
loadFixtures('oa_edit.html');
loadFixtures(fixture);

// Create the view
var element = $('#oa_schedule_editor_wrapper', this.element).get(0);
Expand All @@ -54,6 +54,13 @@ describe('OpenAssessment.EditScheduleView', function() {

view.submissionStart('2014-01-01', '00:00');
view.submissionDue('2014-03-04', '00:00');
}
beforeAll(function() {
this.setupTest = setupTest.bind(this)
})

beforeEach(function() {
this.setupTest('oa_edit.html')
});

it('sets and loads the submission start/due dates', function() {
Expand All @@ -65,6 +72,7 @@ describe('OpenAssessment.EditScheduleView', function() {
});

it('has working date config type', function() {
this.setupTest('oa_edit_no_subsection_course_deadlines.html')
const expectedValue = $('input[name="date_config_type"][type="radio"]:checked', this.element).val();
expect(view.dateConfigType()).toEqual(expectedValue);

Expand All @@ -77,6 +85,66 @@ describe('OpenAssessment.EditScheduleView', function() {
expect(courseEndEl.prop('disabled')).toBe(true);
});

it('stashes and restores manual dates on date config change', function() {
const dateConfigRadios = {
manual: $('input#manual_date_config_type', this.element),
subsection: $('input#subsection_date_config_type', this.element),
course_end: $('input#course_end_date_config_type', this.element),
}
function expectSelectedRadio(expectedValue) {
// Helper to cleanly assert the currently selected radio button
expect($('input[name="date_config_type"][type="radio"]:checked').val()).toEqual(expectedValue);
}
function getCurrentValues() {
// Helper to get the current state of the controls as an object
return {
submission: {
start: view.submissionStart(),
due: view.submissionDue(),
},
self: {
start: assessmentViews.oa_self_assessment_editor.startDatetimeControl.datetime(),
due: assessmentViews.oa_self_assessment_editor.dueDatetimeControl.datetime(),
},
peer: {
start: assessmentViews.oa_peer_assessment_editor.startDatetimeControl.datetime(),
due: assessmentViews.oa_peer_assessment_editor.dueDatetimeControl.datetime(),
}
}
}
// If we select a non-manual setting, the current manual values should be stashed, and the
// values of the controls should be set to a default, to avoid any backend validation issues.
const startingValues = getCurrentValues();
expectSelectedRadio('manual')
dateConfigRadios.subsection.trigger('click');
expectSelectedRadio('subsection');

const expectedPostStashValues = {
submission: {
start: "2001-01-01T00:00",
due: "2099-12-31T00:00",
},
self: {
start: "2001-01-01T00:00",
due: "2099-12-31T00:00",
},
peer: {
start: "2001-01-01T00:00",
due: "2099-12-31T00:00",
},
}

expect(getCurrentValues()).toEqual(expectedPostStashValues);
// clicking course end now should have no effect
dateConfigRadios.course_end.trigger('click');
expectSelectedRadio('course_end');
expect(getCurrentValues()).toEqual(expectedPostStashValues);
// clicking manual will pop the stashed values back into the controls
dateConfigRadios.manual.trigger('click');
expectSelectedRadio('manual');
expect(getCurrentValues()).toEqual(startingValues);
});

it('validates submission start datetime fields', function() {
testValidateDate(
view.startDatetimeControl,
Expand Down
26 changes: 26 additions & 0 deletions openassessment/xblock/static/js/src/studio/oa_edit_fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ export class DatetimeControl {
this.element = element;
this.datePicker = datePicker;
this.timePicker = timePicker;
this.stashedDate = null;
this.stashedTime = null;
}

/**
Expand Down Expand Up @@ -234,6 +236,30 @@ export class DatetimeControl {
return `${datePickerSel.val()}T${timePickerSel.val()}`;
}

hasStash() {
return this.stashedDate !== null && this.stashedTime !== null;
}

stash(dateString) {
if (this.hasStash()) { return; }
const datePickerSel = $(this.datePicker, this.element);
const timePickerSel = $(this.timePicker, this.element);
this.stashedDate = datePickerSel.val();
this.stashedTime = timePickerSel.val();
datePickerSel.val(dateString);
timePickerSel.val('00:00');
}

pop() {
if (!this.hasStash()) { return; }
const datePickerSel = $(this.datePicker, this.element);
const timePickerSel = $(this.timePicker, this.element);
datePickerSel.val(this.stashedDate);
timePickerSel.val(this.stashedTime);
this.stashedDate = null;
this.stashedTime = null;
}

/**
Mark validation errors.
Expand Down
Loading

0 comments on commit da41f73

Please sign in to comment.