import $ from 'jquery'; import AjaxHelpers from 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers'; import EditHelpers from 'js/spec_helpers/edit_helpers'; import ContainerView from 'js/views/container'; import XBlockInfo from 'js/models/xblock_info'; import 'jquery.simulate'; import 'xmodule/js/src/xmodule'; import 'cms/js/main'; import 'xblock/cms.runtime.v1'; describe('Container View', () => { describe('Supports reordering components', () => { var model, containerView, mockContainerHTML, init, getComponent, getDragHandle, dragComponentVertically, dragComponentAbove, verifyRequest, verifyNumReorderCalls, respondToRequest, notificationSpy, rootLocator = 'locator-container', containerTestUrl = '/xblock/' + rootLocator, groupAUrl = '/xblock/locator-group-A', groupA = 'locator-group-A', groupAComponent1 = 'locator-component-A1', groupAComponent2 = 'locator-component-A2', groupAComponent3 = 'locator-component-A3', groupBUrl = '/xblock/locator-group-B', groupB = 'locator-group-B', groupBComponent1 = 'locator-component-B1', groupBComponent2 = 'locator-component-B2', groupBComponent3 = 'locator-component-B3'; mockContainerHTML = readFixtures('templates/mock/mock-container-xblock.underscore'); beforeEach(() => { EditHelpers.installMockXBlock(); EditHelpers.installViewTemplates(); appendSetFixtures('
'); notificationSpy = EditHelpers.createNotificationSpy(); model = new XBlockInfo({ id: rootLocator, display_name: 'Test AB Test', category: 'split_test' }); containerView = new ContainerView({ model: model, view: 'container_preview', el: $('.wrapper-xblock') }); }); afterEach(() => { EditHelpers.uninstallMockXBlock(); containerView.remove(); }); init = function(caller) { var requests = AjaxHelpers.requests(caller); containerView.render(); AjaxHelpers.respondWithJson(requests, { html: mockContainerHTML, resources: [] }); $('body').append(containerView.$el); // Give the whole container enough height to contain everything. $('.xblock[data-locator=locator-container]').css('height', 2000); // Give the groups enough height to contain their child vertical elements. $('.is-draggable[data-locator=locator-group-A]').css('height', 800); $('.is-draggable[data-locator=locator-group-B]').css('height', 800); // Give the leaf elements some height to mimic actual components. Otherwise // drag and drop fails as the elements on bunched on top of each other. $('.level-element').css('height', 230); return requests; }; getComponent = function(locator) { return containerView.$('.studio-xblock-wrapper[data-locator="' + locator + '"]'); }; getDragHandle = function(locator) { var component = getComponent(locator); return $(component.find('.drag-handle')[0]); }; dragComponentVertically = function(locator, dy) { var handle = getDragHandle(locator); handle.simulate('drag', {dy: dy}); }; dragComponentAbove = function(sourceLocator, targetLocator) { var targetElement = getComponent(targetLocator), targetTop = targetElement.offset().top + 1, handle = getDragHandle(sourceLocator), handleY = handle.offset().top, dy = targetTop - handleY; handle.simulate('drag', {dy: dy}); }; verifyRequest = function(requests, reorderCallIndex, expectedURL, expectedChildren) { var actualIndex, request, children, i; // 0th call is the response to the initial render call to get HTML. actualIndex = reorderCallIndex + 1; expect(requests.length).toBeGreaterThan(actualIndex); request = requests[actualIndex]; expect(request.url).toEqual(expectedURL); children = (JSON.parse(request.requestBody)).children; expect(children.length).toEqual(expectedChildren.length); for (i = 0; i < children.length; i++) { expect(children[i]).toEqual(expectedChildren[i]); } }; verifyNumReorderCalls = function(requests, expectedCalls) { // Number of calls will be 1 more than expected because of the initial render call to get HTML. expect(requests.length).toEqual(expectedCalls + 1); }; respondToRequest = function(requests, reorderCallIndex, status) { var actualIndex; // Number of calls will be 1 more than expected because of the initial render call to get HTML. actualIndex = reorderCallIndex + 1; expect(requests.length).toBeGreaterThan(actualIndex); // Now process the actual request AjaxHelpers.respond(requests, {statusCode: status}); }; it('can reorder within a group', () => { var requests = init(this); // Drag the third component in Group A to be the first dragComponentAbove(groupAComponent3, groupAComponent1); respondToRequest(requests, 0, 200); verifyRequest(requests, 0, groupAUrl, [groupAComponent3, groupAComponent1, groupAComponent2]); }); it('can drag from one group to another', () => { var requests = init(this); // Drag the first component in Group B to the top of group A. dragComponentAbove(groupBComponent1, groupAComponent1); // Respond to the two requests: add the component to Group A, then remove it from Group B. respondToRequest(requests, 0, 200); respondToRequest(requests, 1, 200); verifyRequest(requests, 0, groupAUrl, [groupBComponent1, groupAComponent1, groupAComponent2, groupAComponent3]); verifyRequest(requests, 1, groupBUrl, [groupBComponent2, groupBComponent3]); }); it('does not remove from old group if addition to new group fails', () => { var requests = init(this); // Drag the first component in Group B to the first group. dragComponentAbove(groupBComponent1, groupAComponent1); respondToRequest(requests, 0, 500); // Send failure for addition to new group -- no removal event should be received. verifyRequest(requests, 0, groupAUrl, [groupBComponent1, groupAComponent1, groupAComponent2, groupAComponent3]); // Verify that a second request was not issued verifyNumReorderCalls(requests, 1); }); it('can swap group A and group B', () => { var requests = init(this); // Drag Group B before group A. dragComponentAbove(groupB, groupA); respondToRequest(requests, 0, 200); verifyRequest(requests, 0, containerTestUrl, [groupB, groupA]); }); describe('Shows a saving message', () => { it('hides saving message upon success', () => { var requests, savingOptions; requests = init(this); // Drag the first component in Group B to the first group. dragComponentAbove(groupBComponent1, groupAComponent1); EditHelpers.verifyNotificationShowing(notificationSpy, 'Saving'); respondToRequest(requests, 0, 200); EditHelpers.verifyNotificationShowing(notificationSpy, 'Saving'); respondToRequest(requests, 1, 200); EditHelpers.verifyNotificationHidden(notificationSpy); }); it('does not hide saving message if failure', () => { var requests = init(this); // Drag the first component in Group B to the first group. dragComponentAbove(groupBComponent1, groupAComponent1); EditHelpers.verifyNotificationShowing(notificationSpy, 'Saving'); respondToRequest(requests, 0, 500); EditHelpers.verifyNotificationShowing(notificationSpy, 'Saving'); // Since the first reorder call failed, the removal will not be called. verifyNumReorderCalls(requests, 1); }); }); }); });