214 lines
10 KiB
JavaScript
214 lines
10 KiB
JavaScript
define([ "jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/edit_helpers",
|
|
"js/views/container", "js/models/xblock_info", "jquery.simulate",
|
|
"xmodule", "coffee/src/main", "xblock/cms.runtime.v1"],
|
|
function ($, create_sinon, edit_helpers, ContainerView, XBlockInfo) {
|
|
|
|
describe("Container View", function () {
|
|
|
|
describe("Supports reordering components", function () {
|
|
|
|
var model, containerView, mockContainerHTML, respondWithMockXBlockFragment, 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('mock/mock-container-xblock.underscore');
|
|
|
|
respondWithMockXBlockFragment = function (requests, response) {
|
|
var requestIndex = requests.length - 1;
|
|
create_sinon.respondWithJson(requests, response, requestIndex);
|
|
};
|
|
|
|
beforeEach(function () {
|
|
edit_helpers.installMockXBlock();
|
|
edit_helpers.installViewTemplates();
|
|
appendSetFixtures('<div class="wrapper-xblock level-page studio-xblock-wrapper" data-locator="' + rootLocator + '"></div>');
|
|
notificationSpy = edit_helpers.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(function () {
|
|
edit_helpers.uninstallMockXBlock();
|
|
containerView.remove();
|
|
});
|
|
|
|
init = function (caller) {
|
|
var requests = create_sinon.requests(caller);
|
|
containerView.render();
|
|
|
|
respondWithMockXBlockFragment(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', 200);
|
|
|
|
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 + (handle.height() / 2),
|
|
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);
|
|
requests[actualIndex].respond(status);
|
|
};
|
|
|
|
it('does nothing if item not moved far enough', function () {
|
|
var requests = init(this);
|
|
// Drag the first component in Group A down very slightly but not enough to move it.
|
|
dragComponentVertically(groupAComponent1, 5);
|
|
verifyNumReorderCalls(requests, 0);
|
|
});
|
|
|
|
it('can reorder within a group', function () {
|
|
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', function () {
|
|
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', function () {
|
|
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', function () {
|
|
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", function () {
|
|
it('hides saving message upon success', function () {
|
|
var requests, savingOptions;
|
|
requests = init(this);
|
|
|
|
// Drag the first component in Group B to the first group.
|
|
dragComponentAbove(groupBComponent1, groupAComponent1);
|
|
edit_helpers.verifyNotificationShowing(notificationSpy, 'Saving');
|
|
respondToRequest(requests, 0, 200);
|
|
edit_helpers.verifyNotificationShowing(notificationSpy, 'Saving');
|
|
respondToRequest(requests, 1, 200);
|
|
edit_helpers.verifyNotificationHidden(notificationSpy);
|
|
});
|
|
|
|
it('does not hide saving message if failure', function () {
|
|
var requests = init(this);
|
|
|
|
// Drag the first component in Group B to the first group.
|
|
dragComponentAbove(groupBComponent1, groupAComponent1);
|
|
edit_helpers.verifyNotificationShowing(notificationSpy, 'Saving');
|
|
respondToRequest(requests, 0, 500);
|
|
edit_helpers.verifyNotificationShowing(notificationSpy, 'Saving');
|
|
|
|
// Since the first reorder call failed, the removal will not be called.
|
|
verifyNumReorderCalls(requests, 1);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|