-
- % for usage_key in child_usage_keys:
-
- % endfor
-
Some HTML
", + metadata: { + display_name: newDisplayName + } + }); + + initialDisplayName = 'Test Container'; + model = new XBlockInfo({ id: 'locator-container', - display_name: 'Test Container', + display_name: initialDisplayName, category: 'vertical' }); containerPage = new ContainerPage({ @@ -26,6 +38,10 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin }); }); + afterEach(function() { + edit_helpers.uninstallMockXBlock(); + }); + lastRequest = function() { return requests[requests.length - 1]; }; respondWithHtml = function(html) { @@ -55,9 +71,8 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin describe("Initial display", function() { it('can render itself', function() { renderContainerPage(mockContainerXBlockHtml, this); - expect(containerPage.$el.select('.xblock-header')).toBeTruthy(); - expect(containerPage.$('.wrapper-xblock')).not.toHaveClass('is-hidden'); - expect(containerPage.$('.no-container-content')).toHaveClass('is-hidden'); + expect(containerPage.$('.xblock-header').length).toBe(9); + expect(containerPage.$('.wrapper-xblock .level-nesting')).not.toHaveClass('is-hidden'); }); it('shows a loading indicator', function() { @@ -70,25 +85,27 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin }); describe("Editing the container", function() { - var newDisplayName = 'New Display Name'; + var updatedDisplayName = 'Updated Test Container', + inlineEditDisplayName, displayNameElement, displayNameInput; - beforeEach(function () { - edit_helpers.installMockXBlock({ - data: "Some HTML
", - metadata: { - display_name: newDisplayName - } - }); + beforeEach(function() { + displayNameElement = containerPage.$('.page-header-title'); }); afterEach(function() { - edit_helpers.uninstallMockXBlock(); edit_helpers.cancelModalIfShowing(); }); + inlineEditDisplayName = function(newTitle) { + displayNameElement.click(); + expect(displayNameElement).toHaveClass('is-hidden'); + displayNameInput = containerPage.$('.xblock-string-field-editor .xblock-field-input'); + expect(displayNameInput).not.toHaveClass('is-hidden'); + displayNameInput.val(newTitle); + }; + it('can edit itself', function() { - var editButtons, - updatedTitle = 'Updated Test Container'; + var editButtons; renderContainerPage(mockContainerXBlockHtml, this); // Click the root edit button @@ -118,26 +135,49 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin resources: [] }); - // Expect the title and breadcrumb to be updated - expect(containerPage.$('.page-header-title').text().trim()).toBe(updatedTitle); - expect(containerPage.$('.page-header .subtitle a').last().text().trim()).toBe(updatedTitle); + // Expect the title to have been updated + expect(displayNameElement.text().trim()).toBe(updatedDisplayName); }); - }); - describe("Editing an xblock", function() { - var newDisplayName = 'New Display Name'; + it('can inline edit the display name', function() { + renderContainerPage(mockContainerXBlockHtml, this); + inlineEditDisplayName(updatedDisplayName); + displayNameInput.change(); + create_sinon.respondWithJson(requests, { }); + expect(displayNameInput).toHaveClass('is-hidden'); + expect(displayNameElement).not.toHaveClass('is-hidden'); + expect(displayNameElement.text().trim()).toBe(updatedDisplayName); + expect(containerPage.model.get('display_name')).toBe(updatedDisplayName); + }); - beforeEach(function () { - edit_helpers.installMockXBlock({ - data: "Some HTML
", - metadata: { - display_name: newDisplayName - } - }); + it('does not change the title when a display name update fails', function() { + renderContainerPage(mockContainerXBlockHtml, this); + inlineEditDisplayName(updatedDisplayName); + displayNameInput.change(); + create_sinon.respondWithError(requests); + expect(displayNameElement).toHaveClass('is-hidden'); + expect(displayNameInput).not.toHaveClass('is-hidden'); + expect(displayNameInput.val().trim()).toBe(updatedDisplayName); + expect(containerPage.model.get('display_name')).toBe(initialDisplayName); + }); + + it('can cancel an inline edit', function() { + var numRequests; + renderContainerPage(mockContainerXBlockHtml, this); + inlineEditDisplayName(updatedDisplayName); + numRequests = requests.length; + displayNameInput.simulate("keydown", { keyCode: $.simulate.keyCode.ESCAPE }); + displayNameInput.simulate("keyup", { keyCode: $.simulate.keyCode.ESCAPE }); + expect(requests.length).toBe(numRequests); + expect(displayNameInput).toHaveClass('is-hidden'); + expect(displayNameElement).not.toHaveClass('is-hidden'); + expect(displayNameElement.text().trim()).toBe(initialDisplayName); + expect(containerPage.model.get('display_name')).toBe(initialDisplayName); }); + }); + describe("Editing an xblock", function() { afterEach(function() { - edit_helpers.uninstallMockXBlock(); edit_helpers.cancelModalIfShowing(); }); @@ -190,6 +230,7 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin }); modal = $('.edit-xblock-modal'); + expect(modal.length).toBe(1); // Click on the settings tab modal.find('.settings-button').click(); // Change the display name's text @@ -426,7 +467,7 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin }); describe('createNewComponent ', function () { - var clickNewComponent, verifyComponents; + var clickNewComponent; clickNewComponent = function (index) { containerPage.$(".new-component .new-component-type a.single-template")[index].click(); diff --git a/cms/static/js/spec/views/unit_spec.js b/cms/static/js/spec/views/unit_spec.js deleted file mode 100644 index 2464fa2653fd..000000000000 --- a/cms/static/js/spec/views/unit_spec.js +++ /dev/null @@ -1,272 +0,0 @@ -define(["jquery", "underscore.string", "jasmine", "coffee/src/views/unit", "js/models/module_info", - "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers", "jasmine-stealth"], - function ($, str, jasmine, UnitEditView, ModuleModel, create_sinon, edit_helpers) { - var requests, unitView, initialize, lastRequest, respondWithHtml, verifyComponents, i, - mockXBlockEditorHtml = readFixtures('mock/mock-xblock-editor.underscore'); - - respondWithHtml = function(html, requestIndex) { - create_sinon.respondWithJson( - requests, - { html: html, "resources": [] }, - requestIndex - ); - }; - - initialize = function(test) { - var mockXBlockHtml = readFixtures('mock/mock-unit-page-xblock.underscore'), - mockChildContainerHtml = readFixtures('mock/mock-unit-page-child-container.underscore'), - model; - requests = create_sinon.requests(test); - model = new ModuleModel({ - id: 'unit_locator', - state: 'draft' - }); - unitView = new UnitEditView({ - el: $('.main-wrapper'), - templates: edit_helpers.mockComponentTemplates, - model: model - }); - - // Respond with renderings for the two xblocks in the unit (the second is itself a child container) - respondWithHtml(mockXBlockHtml, 0); - respondWithHtml(mockChildContainerHtml, 1); - }; - - lastRequest = function() { return requests[requests.length - 1]; }; - - verifyComponents = function (unit, locators) { - var components = unit.$(".component"); - expect(components.length).toBe(locators.length); - for (i = 0; i < locators.length; i++) { - expect($(components[i]).data('locator')).toBe(locators[i]); - } - }; - - beforeEach(function() { - edit_helpers.installMockXBlock(); - - // needed to stub out the ajax - window.analytics = jasmine.createSpyObj('analytics', ['track']); - window.course_location_analytics = jasmine.createSpy('course_location_analytics'); - window.unit_location_analytics = jasmine.createSpy('unit_location_analytics'); - }); - - afterEach(function () { - edit_helpers.uninstallMockXBlock(); - }); - - describe("UnitEditView", function() { - beforeEach(function() { - edit_helpers.installEditTemplates(); - appendSetFixtures(readFixtures('mock/mock-unit-page.underscore')); - }); - - describe('duplicateComponent', function() { - var clickDuplicate; - - clickDuplicate = function (index) { - unitView.$(".duplicate-button")[index].click(); - }; - - it('sends the correct JSON to the server', function () { - initialize(this); - clickDuplicate(0); - edit_helpers.verifyXBlockRequest(requests, { - "duplicate_source_locator": "loc_1", - "parent_locator": "unit_locator" - }); - }); - - it('inserts duplicated component immediately after source upon success', function () { - initialize(this); - clickDuplicate(0); - create_sinon.respondWithJson(requests, {"locator": "duplicated_item"}); - verifyComponents(unitView, ['loc_1', 'duplicated_item', 'loc_2']); - }); - - it('inserts duplicated component at end if source at end', function () { - initialize(this); - clickDuplicate(1); - create_sinon.respondWithJson(requests, {"locator": "duplicated_item"}); - verifyComponents(unitView, ['loc_1', 'loc_2', 'duplicated_item']); - }); - - it('shows a notification while duplicating', function () { - var notificationSpy = edit_helpers.createNotificationSpy(); - initialize(this); - clickDuplicate(0); - edit_helpers.verifyNotificationShowing(notificationSpy, /Duplicating/); - create_sinon.respondWithJson(requests, {"locator": "new_item"}); - edit_helpers.verifyNotificationHidden(notificationSpy); - }); - - it('does not insert duplicated component upon failure', function () { - initialize(this); - clickDuplicate(0); - create_sinon.respondWithError(requests); - verifyComponents(unitView, ['loc_1', 'loc_2']); - }); - }); - - describe('createNewComponent ', function () { - var clickNewComponent; - - clickNewComponent = function () { - unitView.$(".new-component .new-component-type a.single-template").click(); - }; - - it('sends the correct JSON to the server', function () { - initialize(this); - clickNewComponent(); - edit_helpers.verifyXBlockRequest(requests, { - "category": "discussion", - "type": "discussion", - "parent_locator": "unit_locator" - }); - }); - - it('inserts new component at end', function () { - initialize(this); - clickNewComponent(); - create_sinon.respondWithJson(requests, {"locator": "new_item"}); - verifyComponents(unitView, ['loc_1', 'loc_2', 'new_item']); - }); - - it('shows a notification while creating', function () { - var notificationSpy = edit_helpers.createNotificationSpy(); - initialize(this); - clickNewComponent(); - edit_helpers.verifyNotificationShowing(notificationSpy, /Adding/); - create_sinon.respondWithJson(requests, {"locator": "new_item"}); - edit_helpers.verifyNotificationHidden(notificationSpy); - }); - - it('does not insert new component upon failure', function () { - initialize(this); - clickNewComponent(); - create_sinon.respondWithError(requests); - verifyComponents(unitView, ['loc_1', 'loc_2']); - }); - }); - - describe("Disabled edit/publish links during ajax call", function() { - var link, - draft_states = [ - { - state: "draft", - selector: ".publish-draft" - }, - { - state: "public", - selector: ".create-draft" - } - ]; - - function test_link_disabled_during_ajax_call(draft_state) { - it("re-enables the " + draft_state.selector + " link once the ajax call returns", function() { - initialize(this); - link = $(draft_state.selector); - expect(link).not.toHaveClass('is-disabled'); - link.click(); - expect(link).toHaveClass('is-disabled'); - create_sinon.respondWithError(requests); - expect(link).not.toHaveClass('is-disabled'); - }); - } - - for (i = 0; i < draft_states.length; i++) { - test_link_disabled_during_ajax_call(draft_states[i]); - } - }); - - describe("Editing an xblock", function() { - var newDisplayName = 'New Display Name'; - - beforeEach(function () { - edit_helpers.installMockXBlock({ - data: "Some HTML
", - metadata: { - display_name: newDisplayName - } - }); - }); - - afterEach(function() { - edit_helpers.uninstallMockXBlock(); - edit_helpers.cancelModalIfShowing(); - }); - - it('can show an edit modal for a child xblock', function() { - var editButtons; - initialize(this); - editButtons = unitView.$('.edit-button'); - // The container renders two mock xblocks - expect(editButtons.length).toBe(2); - editButtons[1].click(); - // Make sure that the correct xblock is requested to be edited - expect(str.startsWith(lastRequest().url, '/xblock/loc_2/studio_view')).toBeTruthy(); - create_sinon.respondWithJson(requests, { - html: mockXBlockEditorHtml, - resources: [] - }); - - // Expect that a modal is shown with the correct title - expect(edit_helpers.isShowingModal()).toBeTruthy(); - expect(edit_helpers.getModalTitle()).toBe('Editing: Test Child Container'); - - }); - }); - - describe("Editing an xmodule", function() { - var mockXModuleEditor = readFixtures('mock/mock-xmodule-editor.underscore'), - newDisplayName = 'New Display Name'; - - beforeEach(function () { - edit_helpers.installMockXModule({ - data: "Some HTML
", - metadata: { - display_name: newDisplayName - } - }); - }); - - afterEach(function() { - edit_helpers.uninstallMockXModule(); - edit_helpers.cancelModalIfShowing(); - }); - - it('can save changes to settings', function() { - var editButtons, modal, mockUpdatedXBlockHtml; - mockUpdatedXBlockHtml = readFixtures('mock/mock-updated-xblock.underscore'); - initialize(this); - editButtons = unitView.$('.edit-button'); - // The container renders two mock xblocks - expect(editButtons.length).toBe(2); - editButtons[1].click(); - create_sinon.respondWithJson(requests, { - html: mockXModuleEditor, - resources: [] - }); - - modal = $('.edit-xblock-modal'); - // Click on the settings tab - modal.find('.settings-button').click(); - // Change the display name's text - modal.find('.setting-input').text("Mock Update"); - // Press the save button - modal.find('.action-save').click(); - // Respond to the save - create_sinon.respondWithJson(requests, { - id: 'mock-id' - }); - - // Respond to the request to refresh - respondWithHtml(mockUpdatedXBlockHtml); - - // Verify that the xblock was updated - expect(unitView.$('.mock-updated-content').text()).toBe('Mock Update'); - }); - }); - - }); - }); diff --git a/cms/static/js/spec/views/xblock_editor_spec.js b/cms/static/js/spec/views/xblock_editor_spec.js index d9af3e32ece7..8b771e2fb4cf 100644 --- a/cms/static/js/spec/views/xblock_editor_spec.js +++ b/cms/static/js/spec/views/xblock_editor_spec.js @@ -85,7 +85,7 @@ define([ "jquery", "underscore", "js/spec_helpers/create_sinon", "js/spec_helper }); // Give the mock xblock a save method... editor.xblock.save = window.MockDescriptor.save; - editor.save(); + editor.model.save(editor.getXModuleData()); request = requests[requests.length - 1]; response = JSON.parse(request.requestBody); expect(response.metadata.display_name).toBe(testDisplayName); diff --git a/cms/static/js/spec_helpers/edit_helpers.js b/cms/static/js/spec_helpers/edit_helpers.js index 869949b39f31..d59abb3c11c0 100644 --- a/cms/static/js/spec_helpers/edit_helpers.js +++ b/cms/static/js/spec_helpers/edit_helpers.js @@ -83,8 +83,8 @@ define(["jquery", "underscore", "js/spec_helpers/create_sinon", "js/spec_helpers // Add templates needed by the settings editor modal_helpers.installTemplate('metadata-editor'); - modal_helpers.installTemplate('metadata-number-entry'); - modal_helpers.installTemplate('metadata-string-entry'); + modal_helpers.installTemplate('metadata-number-entry', false, 'metadata-number-entry'); + modal_helpers.installTemplate('metadata-string-entry', false, 'metadata-string-entry'); }; showEditModal = function(requests, xblockElement, model, mockHtml, options) { diff --git a/cms/static/js/spec_helpers/view_helpers.js b/cms/static/js/spec_helpers/view_helpers.js index 1cbbd1e5d4fe..3e6aaaca6da7 100644 --- a/cms/static/js/spec_helpers/view_helpers.js +++ b/cms/static/js/spec_helpers/view_helpers.js @@ -1,14 +1,16 @@ /** * Provides helper methods for invoking Studio modal windows in Jasmine tests. */ -define(["jquery", "js/views/feedback_notification", "js/spec_helpers/create_sinon"], - function($, NotificationView, create_sinon) { +define(["jquery", "js/views/feedback_notification"], + function($, NotificationView) { var installTemplate, installViewTemplates, createNotificationSpy, verifyNotificationShowing, verifyNotificationHidden; - installTemplate = function(templateName, isFirst) { - var template = readFixtures(templateName + '.underscore'), + installTemplate = function(templateName, isFirst, templateId) { + var template = readFixtures(templateName + '.underscore'); + if (!templateId) { templateId = templateName + '-tpl'; + } if (isFirst) { setFixtures($(" -% endfor -%block> - -<%block name="jsextra"> - -%block> - -<%block name="content"> -- - -
-Words of encouragement! This is a short note that most students will read.
- -