Commit 9896d39f by Will Daly

Merge pull request #203 from edx/will/saved-but-not-submitted

TIM-304
parents 94a82c6b 6a28f277
...@@ -71,7 +71,8 @@ ...@@ -71,7 +71,8 @@
<ul class="list list--actions"> <ul class="list list--actions">
<li class="list--actions__item"> <li class="list--actions__item">
<a aria-role="button" href="#" id="step--response__submit" class="action action--submit step--response__submit is--disabled"> <a aria-role="button" href="#" id="step--response__submit"
class="action action--submit step--response__submit {{ submit_enabled|yesno:",is--disabled" }}">
<span class="copy">Submit your response and move to the next step</span> <span class="copy">Submit your response and move to the next step</span>
<i class="ico icon-caret-right"></i> <i class="ico icon-caret-right"></i>
</a> </a>
......
<div id="openassessment-base">
<ol>
<li id="openassessment__response" class="openassessment__steps__step step--response ui-toggle-visibility">
<div class="ui-toggle-visibility__content">
<div class="wrapper--step__content">
<div class="step__content">
<form id="response__submission" class="response__submission">
<ol class="list list--fields response__submission__content">
<li class="field field--textarea submission__answer" id="submission__answer">
<label class="sr" for="submission__answer__value">Provide your response to the question.</label>
<textarea id="submission__answer__value" placeholder=""></textarea>
<span class="tip">You may continue to work on your response until you submit it.</span>
</li>
</ol>
<div class="response__submission__actions">
<div class="message message--inline message--error message--error-server">
<h3 class="message__title">We could not save your progress</h3>
</div>
<ul class="list list--actions">
<li class="list--actions__item">
<button type="submit" id="submission__save" class="action action--save submission__save is--disabled">Save Your Progress</button>
<div id="response__save_status" class="response__submission__status">
<h3 class="response__submission__status__title">
<span class="sr">Your Working Submission Status:</span>
Unsaved draft
</h3>
</div>
</li>
</ul>
</div>
</form>
</div>
<div class="step__actions">
<div class="message message--inline message--error message--error-server">
<h3 class="message__title">We could not submit your response</h3>
</div>
<ul class="list list--actions">
<li class="list--actions__item">
<a aria-role="button" href="#" id="step--response__submit" class="action action--submit step--response__submit is--disabled">
<span class="copy">Submit your response and move to the next step</span>
<i class="ico icon-caret-right"></i>
</a>
</li>
</ul>
</div>
</div>
</div>
</li>
</ol>
</div>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Tests for OA student-facing views. Tests for OA student-facing views.
**/ **/
describe("OpenAssessment.BaseUI", function() { describe("OpenAssessment.BaseView", function() {
// Stub server that returns dummy data // Stub server that returns dummy data
var StubServer = function() { var StubServer = function() {
...@@ -15,12 +15,6 @@ describe("OpenAssessment.BaseUI", function() { ...@@ -15,12 +15,6 @@ describe("OpenAssessment.BaseUI", function() {
grade: "Test fragment" grade: "Test fragment"
}; };
this.submit = function(submission) {
return $.Deferred(function(defer) {
defer.resolveWith(this, ['student', 0]);
}).promise();
};
this.peerAssess = function(submissionId, optionsSelected, feedback) { this.peerAssess = function(submissionId, optionsSelected, feedback) {
return $.Deferred(function(defer) { defer.resolve(); }).promise(); return $.Deferred(function(defer) { defer.resolve(); }).promise();
}; };
...@@ -42,7 +36,7 @@ describe("OpenAssessment.BaseUI", function() { ...@@ -42,7 +36,7 @@ describe("OpenAssessment.BaseUI", function() {
this.feedbackOptions = options; this.feedbackOptions = options;
// Return a promise that always resolves successfully // Return a promise that always resolves successfully
return $.Deferred(function(defer) { defer.resolve() }).promise(); return $.Deferred(function(defer) { defer.resolve(); }).promise();
}; };
}; };
...@@ -50,7 +44,7 @@ describe("OpenAssessment.BaseUI", function() { ...@@ -50,7 +44,7 @@ describe("OpenAssessment.BaseUI", function() {
var runtime = {}; var runtime = {};
var server = null; var server = null;
var ui = null; var view = null;
/** /**
Wait for subviews to load before executing callback. Wait for subviews to load before executing callback.
...@@ -60,7 +54,7 @@ describe("OpenAssessment.BaseUI", function() { ...@@ -60,7 +54,7 @@ describe("OpenAssessment.BaseUI", function() {
**/ **/
var loadSubviews = function(callback) { var loadSubviews = function(callback) {
runs(function() { runs(function() {
ui.load(); view.load();
}); });
waitsFor(function() { waitsFor(function() {
...@@ -85,21 +79,13 @@ describe("OpenAssessment.BaseUI", function() { ...@@ -85,21 +79,13 @@ describe("OpenAssessment.BaseUI", function() {
// Create the object under test // Create the object under test
var el = $("#openassessment-base").get(0); var el = $("#openassessment-base").get(0);
ui = new OpenAssessment.BaseUI(runtime, el, server); view = new OpenAssessment.BaseView(runtime, el, server);
});
it("Sends a submission to the server", function() {
loadSubviews(function() {
spyOn(server, 'submit').andCallThrough();
ui.submit();
expect(server.submit).toHaveBeenCalled();
});
}); });
it("Sends a peer assessment to the server", function() { it("Sends a peer assessment to the server", function() {
loadSubviews(function() { loadSubviews(function() {
spyOn(server, 'peerAssess').andCallThrough(); spyOn(server, 'peerAssess').andCallThrough();
ui.peerAssess(); view.peerAssess();
expect(server.peerAssess).toHaveBeenCalled(); expect(server.peerAssess).toHaveBeenCalled();
}); });
}); });
...@@ -107,7 +93,7 @@ describe("OpenAssessment.BaseUI", function() { ...@@ -107,7 +93,7 @@ describe("OpenAssessment.BaseUI", function() {
it("Sends a self assessment to the server", function() { it("Sends a self assessment to the server", function() {
loadSubviews(function() { loadSubviews(function() {
spyOn(server, 'selfAssess').andCallThrough(); spyOn(server, 'selfAssess').andCallThrough();
ui.selfAssess(); view.selfAssess();
expect(server.selfAssess).toHaveBeenCalled(); expect(server.selfAssess).toHaveBeenCalled();
}); });
}); });
...@@ -126,10 +112,10 @@ describe("OpenAssessment.BaseUI", function() { ...@@ -126,10 +112,10 @@ describe("OpenAssessment.BaseUI", function() {
// Create the object under test // Create the object under test
var el = $("#openassessment-base").get(0); var el = $("#openassessment-base").get(0);
ui = new OpenAssessment.BaseUI(runtime, el, server); view = new OpenAssessment.BaseView(runtime, el, server);
// Submit feedback on an assessment // Submit feedback on an assessment
ui.submitFeedbackOnAssessment(); view.submitFeedbackOnAssessment();
// Expect that the feedback was retrieved from the DOM and sent to the server // Expect that the feedback was retrieved from the DOM and sent to the server
expect(server.feedbackText).toEqual('I disliked the feedback I received.'); expect(server.feedbackText).toEqual('I disliked the feedback I received.');
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Tests for OA XBlock editing. Tests for OA XBlock editing.
**/ **/
describe("OpenAssessment.StudioUI", function() { describe("OpenAssessment.StudioView", function() {
var runtime = { var runtime = {
notify: function(type, data) {} notify: function(type, data) {}
...@@ -52,7 +52,7 @@ describe("OpenAssessment.StudioUI", function() { ...@@ -52,7 +52,7 @@ describe("OpenAssessment.StudioUI", function() {
}; };
var server = null; var server = null;
var ui = null; var view = null;
beforeEach(function() { beforeEach(function() {
...@@ -68,24 +68,24 @@ describe("OpenAssessment.StudioUI", function() { ...@@ -68,24 +68,24 @@ describe("OpenAssessment.StudioUI", function() {
// Create the object under test // Create the object under test
var el = $('#openassessment-edit').get(0); var el = $('#openassessment-edit').get(0);
ui = new OpenAssessment.StudioUI(runtime, el, server); view = new OpenAssessment.StudioView(runtime, el, server);
}); });
it("loads the XML definition", function() { it("loads the XML definition", function() {
// Initialize the UI // Initialize the view
ui.load(); view.load();
// Expect that the XML definition was loaded // Expect that the XML definition was loaded
var contents = ui.codeBox.getValue(); var contents = view.codeBox.getValue();
expect(contents).toEqual('<openassessment></openassessment>'); expect(contents).toEqual('<openassessment></openassessment>');
}); });
it("saves the XML definition", function() { it("saves the XML definition", function() {
// Update the XML // Update the XML
ui.codeBox.setValue('<openassessment>test!</openassessment>'); view.codeBox.setValue('<openassessment>test!</openassessment>');
// Save the updated XML // Save the updated XML
ui.save(); view.save();
// Expect the saving notification to start/end // Expect the saving notification to start/end
expect(runtime.notify).toHaveBeenCalledWith('save', {state: 'start'}); expect(runtime.notify).toHaveBeenCalledWith('save', {state: 'start'});
...@@ -100,31 +100,31 @@ describe("OpenAssessment.StudioUI", function() { ...@@ -100,31 +100,31 @@ describe("OpenAssessment.StudioUI", function() {
server.isReleased = true; server.isReleased = true;
// Stub the confirmation step (avoid showing the dialog) // Stub the confirmation step (avoid showing the dialog)
spyOn(ui, 'confirmPostReleaseUpdate').andCallFake( spyOn(view, 'confirmPostReleaseUpdate').andCallFake(
function(onConfirm) { onConfirm(); } function(onConfirm) { onConfirm(); }
); );
// Save the updated XML // Save the updated XML
ui.save(); view.save();
// Verify that the user was asked to confirm the changes // Verify that the user was asked to confirm the changes
expect(ui.confirmPostReleaseUpdate).toHaveBeenCalled(); expect(view.confirmPostReleaseUpdate).toHaveBeenCalled();
}); });
it("cancels editing", function() { it("cancels editing", function() {
ui.cancel(); view.cancel();
expect(runtime.notify).toHaveBeenCalledWith('cancel', {}); expect(runtime.notify).toHaveBeenCalledWith('cancel', {});
}); });
it("displays an error when server reports a load XML error", function() { it("displays an error when server reports a load XML error", function() {
server.loadError = true; server.loadError = true;
ui.load(); view.load();
expect(runtime.notify).toHaveBeenCalledWith('error', {msg: 'Test error'}); expect(runtime.notify).toHaveBeenCalledWith('error', {msg: 'Test error'});
}); });
it("displays an error when server reports an update XML error", function() { it("displays an error when server reports an update XML error", function() {
server.updateError = true; server.updateError = true;
ui.save('<openassessment>test!</openassessment>'); view.save('<openassessment>test!</openassessment>');
expect(runtime.notify).toHaveBeenCalledWith('error', {msg: 'Test error'}); expect(runtime.notify).toHaveBeenCalledWith('error', {msg: 'Test error'});
}); });
......
/**
Tests for OpenAssessment response (submission) step.
**/
describe("OpenAssessment.ResponseView", function() {
// Stub server
var StubServer = function() {
var successPromise = $.Deferred(
function(defer) {
defer.resolve();
}
).promise();
this.save = function(submission) {
return successPromise;
};
this.submit = function(submission) {
return successPromise;
};
this.render = function(step) {
return successPromise;
};
};
// Stub base view
var StubBaseView = function() {
this.showLoadError = function(msg) {};
this.toggleActionError = function(msg, step) {};
this.setUpCollapseExpand = function(sel) {};
this.renderPeerAssessmentStep = function() {};
};
// Stubs
var baseView = null;
var server = null;
// View under test
var view = null;
beforeEach(function() {
// Load the DOM fixture
jasmine.getFixtures().fixturesPath = 'base/fixtures';
loadFixtures('oa_response.html');
// Create the stub server
server = new StubServer();
// Create the stub base view
baseView = new StubBaseView();
// Create and install the view
var el = $('#openassessment-base').get(0);
view = new OpenAssessment.ResponseView(el, server, baseView);
view.installHandlers();
});
it("updates submit/save buttons and save status when response text changes", function() {
// Response is blank --> save/submit buttons disabled
view.response('');
view.responseChanged();
expect(view.submitEnabled()).toBe(false);
expect(view.saveEnabled()).toBe(false);
expect(view.saveStatus()).toContain('Unsaved draft');
// Response is not blank --> submit button enabled
view.response('Test response');
view.responseChanged();
expect(view.submitEnabled()).toBe(true);
expect(view.saveEnabled()).toBe(true);
expect(view.saveStatus()).toContain('Unsaved draft');
});
it("updates submit/save buttons and save status when the user saves a response", function() {
// Response is blank --> save/submit button is disabled
view.response('');
view.save();
expect(view.submitEnabled()).toBe(false);
expect(view.saveEnabled()).toBe(false);
expect(view.saveStatus()).toContain('Saved but not submitted');
// Response is not blank --> submit button enabled
view.response('Test response');
view.save();
expect(view.submitEnabled()).toBe(true);
expect(view.saveEnabled()).toBe(false);
expect(view.saveStatus()).toContain('Saved but not submitted');
});
it("shows unsaved draft only when response text has changed", function() {
// Save the initial response
view.response('Lorem ipsum');
view.save();
expect(view.saveEnabled()).toBe(false);
expect(view.saveStatus()).toContain('Saved but not submitted');
// Keep the text the same, but trigger an update
// Should still be saved
view.response('Lorem ipsum');
view.responseChanged();
expect(view.saveEnabled()).toBe(false);
expect(view.saveStatus()).toContain('Saved but not submitted');
// Change the text
// This should cause it to change to unsaved draft
view.response('changed ');
view.responseChanged();
expect(view.saveEnabled()).toBe(true);
expect(view.saveStatus()).toContain('Unsaved draft');
});
it("sends the saved submission to the server", function() {
spyOn(server, 'save').andCallThrough();
view.response('Test response');
view.save();
expect(server.save).toHaveBeenCalledWith('Test response');
});
it("submits a response to the server", function() {
spyOn(server, 'submit').andCallThrough();
view.response('Test response');
view.submit();
expect(server.submit).toHaveBeenCalledWith('Test response');
});
});
...@@ -8,7 +8,7 @@ if (typeof OpenAssessment == "undefined" || !OpenAssessment) { ...@@ -8,7 +8,7 @@ if (typeof OpenAssessment == "undefined" || !OpenAssessment) {
/** /**
Interface for editing UI in Studio. Interface for editing view in Studio.
The constructor initializes the DOM for editing. The constructor initializes the DOM for editing.
Args: Args:
...@@ -17,9 +17,9 @@ Args: ...@@ -17,9 +17,9 @@ Args:
server (OpenAssessment.Server): The interface to the XBlock server. server (OpenAssessment.Server): The interface to the XBlock server.
Returns: Returns:
OpenAssessment.StudioUI OpenAssessment.StudioView
**/ **/
OpenAssessment.StudioUI = function(runtime, element, server) { OpenAssessment.StudioView = function(runtime, element, server) {
this.runtime = runtime; this.runtime = runtime;
this.server = server; this.server = server;
...@@ -30,31 +30,31 @@ OpenAssessment.StudioUI = function(runtime, element, server) { ...@@ -30,31 +30,31 @@ OpenAssessment.StudioUI = function(runtime, element, server) {
); );
// Install click handlers // Install click handlers
var ui = this; var view = this;
$(element).find('.openassessment-save-button').click( $(element).find('.openassessment-save-button').click(
function(eventData) { function(eventData) {
ui.save(); view.save();
}); });
$(element).find('.openassessment-cancel-button').click( $(element).find('.openassessment-cancel-button').click(
function(eventData) { function(eventData) {
ui.cancel(); view.cancel();
}); });
}; };
OpenAssessment.StudioUI.prototype = { OpenAssessment.StudioView.prototype = {
/** /**
Load the XBlock XML definition from the server and display it in the UI. Load the XBlock XML definition from the server and display it in the view.
**/ **/
load: function() { load: function() {
var ui = this; var view = this;
this.server.loadXml().done( this.server.loadXml().done(
function(xml) { function(xml) {
ui.codeBox.setValue(xml); view.codeBox.setValue(xml);
}).fail(function(msg) { }).fail(function(msg) {
ui.showError(msg); view.showError(msg);
} }
); );
}, },
...@@ -64,17 +64,17 @@ OpenAssessment.StudioUI.prototype = { ...@@ -64,17 +64,17 @@ OpenAssessment.StudioUI.prototype = {
If the problem has been released, make the user confirm the save. If the problem has been released, make the user confirm the save.
**/ **/
save: function() { save: function() {
var ui = this; var view = this;
// Check whether the problem has been released; if not, // Check whether the problem has been released; if not,
// warn the user and allow them to cancel. // warn the user and allow them to cancel.
this.server.checkReleased().done( this.server.checkReleased().done(
function(isReleased) { function(isReleased) {
if (isReleased) { ui.confirmPostReleaseUpdate($.proxy(ui.updateXml, ui)); } if (isReleased) { view.confirmPostReleaseUpdate($.proxy(view.updateXml, view)); }
else { ui.updateXml(); } else { view.updateXml(); }
} }
).fail(function(errMsg) { ).fail(function(errMsg) {
ui.showError(msg); view.showError(msg);
}); });
}, },
...@@ -102,16 +102,16 @@ OpenAssessment.StudioUI.prototype = { ...@@ -102,16 +102,16 @@ OpenAssessment.StudioUI.prototype = {
// Send the updated XML to the server // Send the updated XML to the server
var xml = this.codeBox.getValue(); var xml = this.codeBox.getValue();
var ui = this; var view = this;
this.server.updateXml(xml).done(function() { this.server.updateXml(xml).done(function() {
// Notify the client-side runtime that we finished saving // Notify the client-side runtime that we finished saving
// so it can hide the "Saving..." notification. // so it can hide the "Saving..." notification.
ui.runtime.notify('save', {state: 'end'}); view.runtime.notify('save', {state: 'end'});
// Reload the XML definition in the editor // Reload the XML definition in the editor
ui.load(); view.load();
}).fail(function(msg) { }).fail(function(msg) {
ui.showError(msg); view.showError(msg);
}); });
}, },
...@@ -143,7 +143,7 @@ function OpenAssessmentEditor(runtime, element) { ...@@ -143,7 +143,7 @@ function OpenAssessmentEditor(runtime, element) {
**/ **/
$(function($) { $(function($) {
var server = new OpenAssessment.Server(runtime, element); var server = new OpenAssessment.Server(runtime, element);
var ui = new OpenAssessment.StudioUI(runtime, element, server); var view = new OpenAssessment.StudioView(runtime, element, server);
ui.load(); view.load();
}); });
} }
/* JavaScript for response (submission) view */
/* Namespace for open assessment */
if (typeof OpenAssessment == "undefined" || !OpenAssessment) {
OpenAssessment = {};
}
/**
Interface for response (submission) view.
Args:
element (DOM element): The DOM element representing the XBlock.
server (OpenAssessment.Server): The interface to the XBlock server.
baseView (OpenAssessment.BaseView): Container view.
Returns:
OpenAssessment.ResponseView
**/
OpenAssessment.ResponseView = function(element, server, baseView) {
this.element = element;
this.server = server;
this.baseView = baseView;
this.savedResponse = "";
};
OpenAssessment.ResponseView.prototype = {
/**
Load the response (submission) view.
**/
load: function() {
var view = this;
this.server.render('submission').done(
function(html) {
// Load the HTML and install event handlers
$('#openassessment__response', view.element).replaceWith(html);
view.installHandlers();
}
).fail(function(errMsg) {
view.baseView.showLoadError('response');
});
},
/**
Install event handlers for the view.
**/
installHandlers: function() {
var sel = $('#openassessment__response', this.element);
var view = this;
// Install a click handler for collapse/expand
this.baseView.setUpCollapseExpand(sel);
// Install change handler for textarea (to enable submission button)
this.savedResponse = this.response();
var handleChange = function(eventData) { view.responseChanged(); };
sel.find('#submission__answer__value').on('change keyup drop paste', handleChange);
// Install a click handler for submission
sel.find('#step--response__submit').click(
function(eventObject) {
// Override default form submission
eventObject.preventDefault();
view.submit();
}
);
// Install a click handler for the save button
sel.find('#submission__save').click(
function(eventObject) {
// Override default form submission
eventObject.preventDefault();
view.save();
}
);
},
/**
Enable/disable the submit button.
Check that whether the submit button is enabled.
Args:
enabled (bool): If specified, set the state of the button.
Returns:
bool: Whether the button is enabled.
Examples:
>> view.submitEnabled(true); // enable the button
>> view.submitEnabled(); // check whether the button is enabled
>> true
**/
submitEnabled: function(enabled) {
var sel = $('#step--response__submit', this.element);
if (typeof enabled === 'undefined') {
return !sel.hasClass('is--disabled');
} else {
sel.toggleClass('is--disabled', !enabled)
}
},
/**
Enable/disable the save button.
Check that whether the save button is enabled.
Args:
enabled (bool): If specified, set the state of the button.
Returns:
bool: Whether the button is enabled.
Examples:
>> view.submitEnabled(true); // enable the button
>> view.submitEnabled(); // check whether the button is enabled
>> true
**/
saveEnabled: function(enabled) {
var sel = $('#submission__save', this.element);
if (typeof enabled === 'undefined') {
return !sel.hasClass('is--disabled');
} else {
sel.toggleClass('is--disabled', !enabled);
}
},
/**
Set the save status message.
Retrieve the save status message.
Args:
msg (string): If specified, the message to display.
Returns:
string: The current status message.
**/
saveStatus: function(msg) {
var sel = $('#response__save_status h3', this.element);
if (typeof msg === 'undefined') {
return sel.text();
} else {
// Setting the HTML will overwrite the screen reader tag,
// so prepend it to the message.
sel.html('<span class="sr">Your Working Submission Status:</span>\n' + msg);
}
},
/**
Set the response text.
Retrieve the response text.
Args:
text (string): If specified, the text to set for the response.
Returns:
string: The current response text.
**/
response: function(text) {
var sel = $('#submission__answer__value', this.element);
if (typeof text === 'undefined') {
return sel.val();
} else {
sel.val(text);
}
},
/**
Enable/disable the submission and save buttons based on whether
the user has entered a response.
**/
responseChanged: function() {
// Enable the save/submit button only for non-blank responses
var currentResponse = this.response();
var isBlank = (currentResponse !== '');
this.submitEnabled(isBlank);
// Update the save button and status only if the response has changed
if (this.savedResponse !== currentResponse) {
this.saveEnabled(isBlank);
this.saveStatus('Unsaved draft');
}
},
/**
Save a response without submitting it.
**/
save: function() {
// Update the save status and error notifications
this.saveStatus('Saving...');
this.baseView.toggleActionError('save', null);
var view = this;
var savedResponse = this.response();
this.server.save(savedResponse).done(function() {
// Remember which response we saved, once the server confirms that it's been saved...
view.savedResponse = savedResponse;
// ... but update the UI based on what the user may have entered
// since hitting the save button.
var currentResponse = view.response();
view.submitEnabled(currentResponse !== '');
if (currentResponse == savedResponse) {
view.saveEnabled(false);
view.saveStatus("Saved but not submitted");
}
}).fail(function(errMsg) {
view.saveStatus('Error');
view.baseView.toggleActionError('save', errMsg);
});
},
/**
Send a response submission to the server and update the view.
**/
submit: function() {
// Send the submission to the server
var submission = $('#submission__answer__value', this.element).val();
this.baseView.toggleActionError('response', null);
var view = this;
var baseView = this.baseView;
this.server.submit(submission).done(
// When we have successfully sent the submission, move on to the next step
function(studentId, attemptNum) {
view.load();
baseView.renderPeerAssessmentStep();
}
).fail(function(errCode, errMsg) {
baseView.toggleActionError('submit', errMsg);
});
}
};
...@@ -155,7 +155,7 @@ class SubmissionMixin(object): ...@@ -155,7 +155,7 @@ class SubmissionMixin(object):
Returns: Returns:
unicode unicode
""" """
return _(u'Saved but not submitted') if self.has_saved else _(u'Not saved') return _(u'Saved but not submitted') if self.has_saved else _(u'Unsaved draft')
@XBlock.handler @XBlock.handler
def render_submission(self, data, suffix=''): def render_submission(self, data, suffix=''):
...@@ -185,6 +185,7 @@ class SubmissionMixin(object): ...@@ -185,6 +185,7 @@ class SubmissionMixin(object):
context = { context = {
"saved_response": self.saved_response, "saved_response": self.saved_response,
"save_status": self.save_status, "save_status": self.save_status,
"submit_enabled": self.saved_response != '',
"submission_due": sub_due, "submission_due": sub_due,
} }
......
...@@ -14,7 +14,7 @@ class SaveResponseTest(XBlockHandlerTestCase): ...@@ -14,7 +14,7 @@ class SaveResponseTest(XBlockHandlerTestCase):
def test_default_saved_response_blank(self, xblock): def test_default_saved_response_blank(self, xblock):
resp = self.request(xblock, 'render_submission', json.dumps({})) resp = self.request(xblock, 'render_submission', json.dumps({}))
self.assertIn('<textarea id="submission__answer__value" placeholder=""></textarea>', resp) self.assertIn('<textarea id="submission__answer__value" placeholder=""></textarea>', resp)
self.assertIn('Not saved', resp) self.assertIn('Unsaved draft', resp)
@ddt.file_data('data/save_responses.json') @ddt.file_data('data/save_responses.json')
@scenario('data/save_scenario.xml', user_id="Perleman") @scenario('data/save_scenario.xml', user_id="Perleman")
...@@ -57,4 +57,4 @@ class SaveResponseTest(XBlockHandlerTestCase): ...@@ -57,4 +57,4 @@ class SaveResponseTest(XBlockHandlerTestCase):
def test_missing_submission_key(self, xblock): def test_missing_submission_key(self, xblock):
resp = self.request(xblock, 'save_submission', json.dumps({}), response_format="json") resp = self.request(xblock, 'save_submission', json.dumps({}), response_format="json")
self.assertFalse(resp['success']) self.assertFalse(resp['success'])
self.assertIn('submission', resp['msg']) self.assertIn('submission', resp['msg'])
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment