Files
edx-platform/cms/static/js/spec/views/container_spec.js
Andy Armstrong b2a0b2f728 Improve response handling in AjaxHelpers
I've changed the logic so that AjaxHelpers keeps
track of which requests have not yet had mock
responses sent. This ensures that every response
is handled before moving on to the next one,
rather than always handling the last request.
My intention is that this won't allow bugs to creep
in where a request isn't fired and instead the test
responds to an old request. It also should ensure
that extra events aren't accidentally fired.
2015-09-23 20:23:09 -04:00

209 lines
10 KiB
JavaScript

define([ "jquery", "common/js/spec_helpers/ajax_helpers", "js/spec_helpers/edit_helpers",
"js/views/container", "js/models/xblock_info", "jquery.simulate",
"xmodule", "coffee/src/main", "xblock/cms.runtime.v1"],
function ($, AjaxHelpers, EditHelpers, ContainerView, XBlockInfo) {
describe("Container View", function () {
describe("Supports reordering components", function () {
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('mock/mock-container-xblock.underscore');
beforeEach(function () {
EditHelpers.installMockXBlock();
EditHelpers.installViewTemplates();
appendSetFixtures('<div class="wrapper-xblock level-page studio-xblock-wrapper" data-locator="' + rootLocator + '"></div>');
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(function () {
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', 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);
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', function () {
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);
});
});
});
});
});