Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions xmodule/js/spec/capa/display_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,73 @@ data-url='/problem/quiz/'> \
expect(self.problem.submitButton).toHaveAttr("disabled");
expect(self.problem.submitButtonLabel.text()).toBe("Submit");
});

// Unit test — Bug #36824
// Verifies that disableAllButtonsWhileRunning re-evaluates the Submit button
// state after the operation completes, rather than blindly re-enabling it.
it("unit: disableAllButtonsWhileRunning re-evaluates submit button after operation", function () {
const self = this;
// Start with Submit enabled (as if an answer were previously selected)
self.problem.enableSubmitButton(true);
expect(self.problem.submitButton).not.toHaveAttr("disabled");
spyOn(self.problem, "submitAnswersAndSubmitButton").and.callThrough();
// Operation that mimics a reset: clears the form answered state
const operationCallback = function () {
return {
always(callable) {
return callable();
},
};
};
self.problem.disableAllButtonsWhileRunning(operationCallback, false);
// After the operation, submitAnswersAndSubmitButton must have been called
// to re-evaluate the Submit button state.
expect(self.problem.submitAnswersAndSubmitButton).toHaveBeenCalled();
});

// Integration test — Bug #36824
// After a reset, the Submit button must be disabled because no answer is selected.
it("integration: submit button is disabled after reset when no answer is selected", function () {
const self = this;
// Simulate a previously answered state
self.problem.enableSubmitButton(true);
expect(self.problem.submitButton).not.toHaveAttr("disabled");
spyOn($, "postWithPrefix").and.callFake(function (url, answers, callback) {
// Simulate server returning a fresh (empty) problem HTML
callback({ success: true, html: self.problem.el.html() });
return {
always(callable) {
return callable();
},
};
});
self.problem.reset();
// After reset: Submit must be disabled since no answer is selected
expect(self.problem.submitButton).toHaveAttr("disabled");
});

// Regression test — Bug #36824
// Reproduces the exact original scenario: answer selected → click Reset →
// click Submit (without selecting a new answer). Submit must be disabled.
it("regression: bug_36824 reset must disable submit button even when it was enabled before", function () {
const self = this;
// Pre-condition: user had selected an answer, Submit is enabled
self.problem.enableSubmitButton(true);
expect(self.problem.submitButton).not.toHaveAttr("disabled");
spyOn($, "postWithPrefix").and.callFake(function (url, answers, callback) {
callback({ success: true, html: self.problem.el.html() });
return {
always(callable) {
return callable();
},
};
});
// User clicks Reset
self.problem.reset();
// Bug: before the fix, Submit would be re-enabled by the .always() callback
// in disableAllButtonsWhileRunning. After the fix, Submit stays disabled.
expect(self.problem.submitButton).toHaveAttr("disabled");
});
});

describe("show problem with column in id", function () {
Expand Down
8 changes: 7 additions & 1 deletion xmodule/js/src/capa/display.js
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,13 @@
});
this.enableButtons(initiallyEnabledButtons, false, isFromCheckOperation);
return operationCallback().always(function () {
return that.enableButtons(initiallyEnabledButtons, true, isFromCheckOperation);
that.enableButtons(initiallyEnabledButtons, true, isFromCheckOperation);
// Re-evaluate the Submit button based on the current form state. After a reset,
// the form is empty so Submit must be disabled — but enableButtons above would
// blindly re-enable it if it was enabled before the operation. See bug #36824.
if (that.submitButton.length) {
that.submitAnswersAndSubmitButton();
}
});
};

Expand Down