From 5812aed18147e8c4d7226adb949c060ccfbf0cd3 Mon Sep 17 00:00:00 2001 From: kingoftech-v01 Date: Fri, 10 Apr 2026 03:12:23 +0000 Subject: [PATCH] fix(capa): disable submit button after reset when no answer is selected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After clicking Reset on a problem, the Submit button was incorrectly re-enabled by the .always() callback in disableAllButtonsWhileRunning, overriding the correct disabled state set by render() → bind() → submitAnswersAndSubmitButton. Re-evaluate the Submit button state after the operation completes so reset correctly leaves Submit disabled while preserving the enabled state for save, show, and submit flows where the form still has answers. Closes #36824 --- xmodule/js/spec/capa/display_spec.js | 67 ++++++++++++++++++++++++++++ xmodule/js/src/capa/display.js | 8 +++- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/xmodule/js/spec/capa/display_spec.js b/xmodule/js/spec/capa/display_spec.js index f55106f31758..7a176394f51b 100644 --- a/xmodule/js/spec/capa/display_spec.js +++ b/xmodule/js/spec/capa/display_spec.js @@ -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 () { diff --git a/xmodule/js/src/capa/display.js b/xmodule/js/src/capa/display.js index fea25a654049..e755652c7ac0 100644 --- a/xmodule/js/src/capa/display.js +++ b/xmodule/js/src/capa/display.js @@ -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(); + } }); };