Improve unit testing of xblock editing

This commit is contained in:
Andy Armstrong
2014-04-08 19:35:18 -04:00
parent 9de6f1016c
commit 2ae28c5db7
9 changed files with 178 additions and 84 deletions

View File

@@ -30,13 +30,11 @@ define(["jquery", "underscore", "js/spec_helpers/create_sinon", "js/spec_helpers
mockXBlockEditorHtml = readFixtures('mock/mock-xblock-editor.underscore');
beforeEach(function () {
window.MockXBlock = function(runtime, element) {
return { };
};
edit_helpers.installMockXBlock();
});
afterEach(function() {
window.MockXBlock = null;
edit_helpers.uninstallMockXBlock();
});
it('can show itself', function() {

View File

@@ -1,9 +1,9 @@
define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers",
"js/views/pages/container", "js/models/xblock_info"],
function ($, create_sinon, edit_helpers, XBlockContainerPage, XBlockInfo) {
function ($, create_sinon, edit_helpers, ContainerPage, XBlockInfo) {
describe("XBlockContainerView", function() {
var model, containerView, respondWithMockXBlockEditorFragment, mockContainerPage;
describe("ContainerPage", function() {
var model, containerPage, respondWithMockXBlockEditorFragment, mockContainerPage;
mockContainerPage = readFixtures('mock/mock-container-page.underscore');
@@ -16,7 +16,7 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers"
display_name: 'Test Unit',
category: 'vertical'
});
containerView = new XBlockContainerPage({
containerPage = new ContainerPage({
model: model,
el: $('#content')
});
@@ -32,26 +32,26 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers"
it('can render itself', function() {
var requests = create_sinon.requests(this);
containerView.render();
containerPage.render();
respondWithMockXBlockEditorFragment(requests, {
html: mockContainerXBlockHtml,
"resources": []
});
expect(containerView.$el.select('.xblock-header')).toBeTruthy();
expect(containerView.$('.wrapper-xblock')).not.toHaveClass('is-hidden');
expect(containerView.$('.no-container-content')).toHaveClass('is-hidden');
expect(containerPage.$el.select('.xblock-header')).toBeTruthy();
expect(containerPage.$('.wrapper-xblock')).not.toHaveClass('is-hidden');
expect(containerPage.$('.no-container-content')).toHaveClass('is-hidden');
});
it('shows a loading indicator', function() {
var requests = create_sinon.requests(this);
containerView.render();
expect(containerView.$('.ui-loading')).not.toHaveClass('is-hidden');
containerPage.render();
expect(containerPage.$('.ui-loading')).not.toHaveClass('is-hidden');
respondWithMockXBlockEditorFragment(requests, {
html: mockContainerXBlockHtml,
"resources": []
});
expect(containerView.$('.ui-loading')).toHaveClass('is-hidden');
expect(containerPage.$('.ui-loading')).toHaveClass('is-hidden');
});
});
@@ -59,28 +59,19 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers"
describe("Editing an xblock", function() {
var mockContainerXBlockHtml,
mockXBlockEditorHtml,
saved,
newDisplayName = 'New Display Name';
beforeEach(function () {
saved = false;
window.MockXBlock = function(runtime, element) {
return {
save: function() {
saved = true;
return {
data: "<p>Some HTML</p>",
metadata: {
display_name: newDisplayName
}
};
}
};
};
edit_helpers.installMockXBlock({
data: "<p>Some HTML</p>",
metadata: {
display_name: newDisplayName
}
});
});
afterEach(function() {
window.MockXBlock = null;
edit_helpers.uninstallMockXBlock();
edit_helpers.cancelModalIfShowing();
});
@@ -90,12 +81,12 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers"
it('can show an edit modal for a child xblock', function() {
var requests = create_sinon.requests(this),
editButtons;
containerView.render();
containerPage.render();
respondWithMockXBlockEditorFragment(requests, {
html: mockContainerXBlockHtml,
"resources": []
});
editButtons = containerView.$('.edit-button');
editButtons = containerPage.$('.edit-button');
// The container renders four mock xblocks, so there should be four edit buttons
expect(editButtons.length).toBe(4);
editButtons.first().click();
@@ -111,14 +102,15 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers"
});
it('can save changes to settings', function() {
var requests, editButtons, modal;
var requests, editButtons, modal, mockUpdatedXBlockHtml;
mockUpdatedXBlockHtml = readFixtures('mock/mock-updated-xblock.underscore');
requests = create_sinon.requests(this);
containerView.render();
containerPage.render();
respondWithMockXBlockEditorFragment(requests, {
html: mockContainerXBlockHtml,
"resources": []
});
editButtons = containerView.$('.edit-button');
editButtons = containerPage.$('.edit-button');
// The container renders four mock xblocks, so there should be four edit buttons
expect(editButtons.length).toBe(4);
editButtons.first().click();
@@ -131,10 +123,21 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers"
// Click on the settings tab
modal.find('.settings-button').click();
// Change the display name's text
modal.find('.setting-input').text("New display name");
modal.find('.setting-input').text("Mock Update");
// Press the save button
modal.find('.action-save').click();
expect(saved).toBe(true);
// Respond to the save
create_sinon.respondWithJson(requests, {
id: model.id
});
// Respond to the request to refresh
respondWithMockXBlockEditorFragment(requests, {
html: mockUpdatedXBlockHtml,
"resources": []
});
// Verify that the xblock was updated
expect(containerPage.$('.mock-updated-content').text()).toBe('Mock Update');
expect(edit_helpers.hasSavedMockXBlock()).toBe(true);
});
});
@@ -143,14 +146,14 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers"
it('shows the "no children" message', function() {
var requests = create_sinon.requests(this);
containerView.render();
containerPage.render();
respondWithMockXBlockEditorFragment(requests, {
html: mockContainerXBlockHtml,
"resources": []
});
expect(containerView.$('.no-container-content')).not.toHaveClass('is-hidden');
expect(containerView.$('.wrapper-xblock')).toHaveClass('is-hidden');
expect(containerPage.$('.no-container-content')).not.toHaveClass('is-hidden');
expect(containerPage.$('.wrapper-xblock')).toHaveClass('is-hidden');
});
});
});

View File

@@ -1,9 +1,17 @@
define([ "jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers",
"js/views/xblock_editor", "js/models/xblock_info"],
function ($, create_sinon, edit_helpers, XBlockEditorView, XBlockInfo) {
define([ "jquery", "underscore", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers",
"js/views/xblock_editor", "js/models/xblock_info"],
function ($, _, create_sinon, edit_helpers, XBlockEditorView, XBlockInfo) {
describe("XBlockEditorView", function() {
var model, editor;
var model, editor, testDisplayName, mockSaveResponse;
testDisplayName = 'Test Display Name';
mockSaveResponse = {
data: "<p>Some HTML</p>",
metadata: {
display_name: testDisplayName
}
};
beforeEach(function () {
edit_helpers.installEditTemplates();
@@ -21,13 +29,11 @@ define([ "jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers
var mockXBlockEditorHtml;
beforeEach(function () {
window.MockXBlock = function(runtime, element) {
return { };
};
edit_helpers.installMockXBlock(mockSaveResponse);
});
afterEach(function() {
window.MockXBlock = null;
edit_helpers.uninstallMockXBlock();
});
mockXBlockEditorHtml = readFixtures('mock/mock-xblock-editor.underscore');
@@ -41,7 +47,22 @@ define([ "jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers
});
expect(editor.$el.select('.xblock-header')).toBeTruthy();
expect(editor.getMode()).toEqual('editor');
expect(editor.getMode()).toEqual('settings');
});
it('saves any custom metadata', function() {
var requests = create_sinon.requests(this), request, response;
editor.render();
create_sinon.respondWithJson(requests, {
html: mockXBlockEditorHtml,
"resources": []
});
editor.save();
request = requests[requests.length - 1];
response = JSON.parse(request.requestBody);
expect(edit_helpers.hasSavedMockXBlock()).toBeTruthy();
expect(response.metadata.display_name).toBe(testDisplayName);
expect(response.metadata.custom_field).toBe('Custom Value');
});
});
@@ -51,12 +72,11 @@ define([ "jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers
mockXModuleEditorHtml = readFixtures('mock/mock-xmodule-editor.underscore');
beforeEach(function() {
// Mock the VerticalDescriptor so that the module can be rendered
window.VerticalDescriptor = XModule.Descriptor;
edit_helpers.installMockXModule(mockSaveResponse);
});
afterEach(function () {
window.VerticalDescriptor = null;
edit_helpers.uninstallMockXModule();
});
it('can render itself', function() {
@@ -70,26 +90,28 @@ define([ "jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers
expect(editor.$el.select('.xblock-header')).toBeTruthy();
expect(editor.getMode()).toEqual('editor');
});
});
describe("Editing an xmodule (settings only)", function() {
var mockXModuleEditorHtml;
mockXModuleEditorHtml = readFixtures('mock/mock-xmodule-settings-only-editor.underscore');
beforeEach(function() {
edit_helpers.installEditTemplates();
// Mock the VerticalDescriptor so that the module can be rendered
window.VerticalDescriptor = XModule.Descriptor;
it('saves any custom metadata', function() {
var requests = create_sinon.requests(this), request, response;
editor.render();
create_sinon.respondWithJson(requests, {
html: mockXModuleEditorHtml,
"resources": []
});
// Give the mock xblock a save method...
editor.xblock.save = window.MockDescriptor.save;
editor.save();
request = requests[requests.length - 1];
response = JSON.parse(request.requestBody);
expect(edit_helpers.hasSavedMockXModule()).toBeTruthy();
expect(response.metadata.display_name).toBe(testDisplayName);
expect(response.metadata.custom_field).toBe('Custom Value');
});
afterEach(function () {
window.VerticalDescriptor = null;
});
it('can render a module with only settings', function() {
var requests = create_sinon.requests(this), mockXModuleEditorHtml;
mockXModuleEditorHtml = readFixtures('mock/mock-xmodule-settings-only-editor.underscore');
it('can render itself', function() {
var requests = create_sinon.requests(this);
editor.render();
create_sinon.respondWithJson(requests, {
html: mockXModuleEditorHtml,

View File

@@ -10,9 +10,55 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/modal_helpers
stringEntryTemplate = readFixtures('metadata-string-entry.underscore'),
editXBlockModalTemplate = readFixtures('edit-xblock-modal.underscore'),
editorModeButtonTemplate = readFixtures('editor-mode-button.underscore'),
xblockSaved,
installMockXBlock,
uninstallMockXBlock,
hasSavedMockXBlock,
xmoduleSaved,
installMockXModule,
uninstallMockXModule,
hasSavedMockXModule,
installEditTemplates,
showEditModal;
installMockXBlock = function(mockResult) {
xblockSaved = false;
window.MockXBlock = function(runtime, element) {
return {
save: function() {
xblockSaved = true;
return mockResult;
}
};
};
};
uninstallMockXBlock = function() {
window.MockXBlock = null;
};
hasSavedMockXBlock = function() {
return xblockSaved;
};
installMockXModule = function(mockResult) {
xmoduleSaved = false;
window.MockDescriptor = _.extend(XModule.Descriptor, {
save: function() {
xmoduleSaved = true;
return mockResult;
}
});
};
uninstallMockXModule = function() {
window.MockDescriptor = null;
};
hasSavedMockXModule = function() {
return xmoduleSaved;
};
installEditTemplates = function(append) {
modal_helpers.installModalTemplates(append);
@@ -37,6 +83,12 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/modal_helpers
};
return $.extend(modal_helpers, {
'installMockXBlock': installMockXBlock,
'hasSavedMockXBlock': hasSavedMockXBlock,
'uninstallMockXBlock': uninstallMockXBlock,
'installMockXModule': installMockXModule,
'hasSavedMockXModule': hasSavedMockXModule,
'uninstallMockXModule': uninstallMockXModule,
'installEditTemplates': installEditTemplates,
'showEditModal': showEditModal
});

View File

@@ -85,8 +85,7 @@ define(["jquery", "underscore", "gettext", "js/views/feedback_notification", "js
},
save: function(options) {
var xblock = this.xblock,
xblockInfo = this.model,
var xblockInfo = this.model,
data,
saving;
data = this.getXBlockData();
@@ -131,14 +130,14 @@ define(["jquery", "underscore", "gettext", "js/views/feedback_notification", "js
// Walk through the set of elements which have the 'data-metadata_name' attribute and
// build up an object to pass back to the server on the subsequent POST.
// Note that these values will always be sent back on POST, even if they did not actually change.
var metadata = {},
metadataNameElements;
var metadata, metadataNameElements, i, element, metadataName;
metadata = {};
metadataNameElements = this.$('[data-metadata-name]');
metadataNameElements.each(function (element) {
var key = $(element).data("metadata-name"),
value = element.value;
metadata[key] = value;
});
for (i = 0; i < metadataNameElements.length; i++) {
element = metadataNameElements[i];
metadataName = $(element).data("metadata-name");
metadata[metadataName] = element.value;
}
return metadata;
},