Fix Jasmine tests

Also, rewrite them to be easier to comprehend, and to not use magic constants (or to use fewer, at least).
This commit is contained in:
Andy Armstrong
2014-05-01 23:04:11 -04:00
committed by cahrens
parent c6b96f32a2
commit e20a7fc53c
4 changed files with 91 additions and 76 deletions

View File

@@ -1,15 +1,15 @@
define([ "jquery", "js/spec_helpers/create_sinon", "URI", "js/views/container", "js/models/xblock_info",
"js/views/feedback_notification", "jquery.simulate",
define([ "jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers",
"js/views/container", "js/models/xblock_info", "js/views/feedback_notification", "jquery.simulate",
"xmodule", "coffee/src/main", "xblock/cms.runtime.v1"],
function ($, create_sinon, URI, ContainerView, XBlockInfo, Notification) {
function ($, create_sinon, view_helpers, ContainerView, XBlockInfo, Notification) {
describe("Container View", function () {
describe("Supports reordering components", function () {
var model, containerView, mockContainerHTML, respondWithMockXBlockFragment,
init, dragHandleVertically, dragHandleOver, verifyRequest, verifyNumReorderCalls,
respondToRequest,
var model, containerView, mockContainerHTML, respondWithMockXBlockFragment, init, getComponent,
getDragHandle, dragComponentVertically, dragComponentToY, dragComponentAbove, dragComponentBelow,
verifyRequest, verifyNumReorderCalls, respondToRequest,
rootLocator = 'testCourse/branch/draft/split_test/splitFFF',
containerTestUrl = '/xblock/' + rootLocator,
@@ -35,7 +35,8 @@ define([ "jquery", "js/spec_helpers/create_sinon", "URI", "js/views/container",
};
beforeEach(function () {
setFixtures('<div class="wrapper-xblock level-page" data-locator="' + rootLocator + '"></div>');
view_helpers.installViewTemplates();
appendSetFixtures('<div class="wrapper-xblock level-page" data-locator="' + rootLocator + '"></div>');
model = new XBlockInfo({
id: rootLocator,
display_name: 'Test AB Test',
@@ -66,22 +67,43 @@ define([ "jquery", "js/spec_helpers/create_sinon", "URI", "js/views/container",
return requests;
};
dragHandleVertically = function (index, dy) {
var handle = containerView.$(".drag-handle:eq(" + index + ")");
getComponent = function(locator) {
return containerView.$('[data-locator="' + locator + '"]');
};
getDragHandle = function(locator) {
var component = getComponent(locator);
return component.prev();
};
dragComponentVertically = function (locator, dy) {
var handle = getDragHandle(locator);
handle.simulate("drag", {dy: dy});
};
dragHandleOver = function (index, targetElement) {
var handle = containerView.$(".drag-handle:eq(" + index + ")"),
dy = handle.y - targetElement.y;
dragComponentToY = function (locator, y) {
var handle = getDragHandle(locator),
handleY = handle.offset().top + (handle.height() / 2),
dy = y - handleY;
handle.simulate("drag", {dy: dy});
};
dragComponentAbove = function (sourceLocator, targetLocator) {
var targetElement = getComponent(targetLocator);
dragComponentToY(sourceLocator, targetElement.offset().top + 1);
};
dragComponentBelow = function (sourceLocator, targetLocator) {
var targetElement = containerView.$('[data-locator="' + targetLocator + '"]');
dragComponentToY(sourceLocator, targetElement.offset().top + targetElement.height() - 1);
};
verifyRequest = function (requests, reorderCallIndex, expectedURL, expectedChildren) {
var request, children, i;
var actualIndex, request, children, i;
// 0th call is the response to the initial render call to get HTML.
request = requests[reorderCallIndex + 1];
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);
@@ -96,79 +118,62 @@ define([ "jquery", "js/spec_helpers/create_sinon", "URI", "js/views/container",
};
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.
requests[reorderCallIndex + 1].respond(status);
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 thing in Group A (text component) down very slightly, but not past second thing.
dragHandleVertically(2, 5);
// 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 first component in Group A to the end
dragHandleVertically(2, 80);
// Drag the third component in Group A to be the first
dragComponentAbove(groupAComponent3, groupAComponent1);
respondToRequest(requests, 0, 200);
verifyNumReorderCalls(requests, 1);
verifyRequest(requests, 0, groupAUrl, [groupAComponent2, groupAComponent3, groupAComponent1]);
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 A into the second group.
dragHandleVertically(2, 300);
// Drag the first component in Group B to the first group.
dragComponentAbove(groupBComponent1, groupAComponent1);
// Respond to the first request which will trigger a request to make the move
respondToRequest(requests, 0, 200);
respondToRequest(requests, 1, 200);
// Will get an event to move into Group B and an event to remove from Group A.
verifyNumReorderCalls(requests, 2);
verifyRequest(requests, 0, groupBUrl,
[groupBComponent1, groupBComponent2, groupAComponent1, groupBComponent3]);
verifyRequest(requests, 1, groupAUrl, [groupAComponent2, groupAComponent3]);
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 A into the second group.
dragHandleVertically(2, 300);
// 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.
// 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);
verifyRequest(requests, 0, groupBUrl,
[groupBComponent1, groupBComponent2, groupAComponent1, groupBComponent3]);
});
it('can swap group A and group B', function () {
var requests = init(this);
// Drag Group B before group A.
dragHandleVertically(5, -300);
dragComponentAbove(groupB, groupA);
respondToRequest(requests, 0, 200);
verifyNumReorderCalls(requests, 1);
verifyRequest(requests, 0, containerTestUrl, [groupB, groupA]);
});
it('can drag a component to the top level, and nest one group in another', function () {
var requests = init(this);
// Drag text item in Group A to the top level (in first position).
dragHandleVertically(2, -40);
respondToRequest(requests, 0, 200);
respondToRequest(requests, 1, 200);
verifyNumReorderCalls(requests, 2);
verifyRequest(requests, 0, containerTestUrl, [groupAComponent1, groupA, groupB]);
verifyRequest(requests, 1, groupAUrl, [groupAComponent2, groupAComponent3]);
// Drag Group A into Group B.
dragHandleVertically(1, 150);
respondToRequest(requests, 2, 200);
respondToRequest(requests, 3, 200);
verifyNumReorderCalls(requests, 4);
verifyRequest(requests, 2, groupBUrl, [groupBComponent1, groupA, groupBComponent2]);
verifyRequest(requests, 3, containerTestUrl, [groupAComponent1, groupB]);
});
describe("Shows a saving message", function () {
var savingSpies;
@@ -182,8 +187,8 @@ define([ "jquery", "js/spec_helpers/create_sinon", "URI", "js/views/container",
var requests, savingOptions;
requests = init(this);
// Drag the first component in Group A into the second group.
dragHandleVertically(2, 200);
// Drag the first component in Group B to the first group.
dragComponentAbove(groupBComponent1, groupAComponent1);
expect(savingSpies.constructor).toHaveBeenCalled();
expect(savingSpies.show).toHaveBeenCalled();
@@ -195,14 +200,13 @@ define([ "jquery", "js/spec_helpers/create_sinon", "URI", "js/views/container",
expect(savingSpies.hide).not.toHaveBeenCalled();
respondToRequest(requests, 1, 200);
expect(savingSpies.hide).toHaveBeenCalled();
verifyNumReorderCalls(requests, 2);
});
it('does not hide saving message if failure', function () {
var requests = init(this);
// Drag the first component in Group A into the second group.
dragHandleVertically(2, 200);
// Drag the first component in Group B to the first group.
dragComponentAbove(groupBComponent1, groupAComponent1);
expect(savingSpies.constructor).toHaveBeenCalled();
expect(savingSpies.show).toHaveBeenCalled();
@@ -210,6 +214,7 @@ define([ "jquery", "js/spec_helpers/create_sinon", "URI", "js/views/container",
respondToRequest(requests, 0, 500);
expect(savingSpies.hide).not.toHaveBeenCalled();
// Since the first reorder call failed, the removal will not be called.
verifyNumReorderCalls(requests, 1);
});
@@ -217,4 +222,3 @@ define([ "jquery", "js/spec_helpers/create_sinon", "URI", "js/views/container",
});
});
});
147

View File

@@ -1,8 +1,8 @@
/**
* Provides helper methods for invoking Studio modal windows in Jasmine tests.
*/
define(["jquery"],
function($) {
define(["jquery", "js/spec_helpers/view_helpers"],
function($, view_helpers) {
var basicModalTemplate = readFixtures('basic-modal.underscore'),
modalButtonTemplate = readFixtures('modal-button.underscore'),
feedbackTemplate = readFixtures('system-feedback.underscore'),
@@ -14,11 +14,7 @@ define(["jquery"],
cancelModalIfShowing;
installModalTemplates = function(append) {
if (append) {
appendSetFixtures($("<script>", { id: "system-feedback-tpl", type: "text/template" }).text(feedbackTemplate));
} else {
setFixtures($("<script>", { id: "system-feedback-tpl", type: "text/template" }).text(feedbackTemplate));
}
view_helpers.installViewTemplates(append);
appendSetFixtures($("<script>", { id: "basic-modal-tpl", type: "text/template" }).text(basicModalTemplate));
appendSetFixtures($("<script>", { id: "modal-button-tpl", type: "text/template" }).text(modalButtonTemplate));
};
@@ -58,11 +54,11 @@ define(["jquery"],
}
};
return {
return $.extend(view_helpers, {
'installModalTemplates': installModalTemplates,
'isShowingModal': isShowingModal,
'hideModalIfShowing': hideModalIfShowing,
'cancelModal': cancelModal,
'cancelModalIfShowing': cancelModalIfShowing
};
});
});

View File

@@ -0,0 +1,20 @@
/**
* Provides helper methods for invoking Studio modal windows in Jasmine tests.
*/
define(["jquery"],
function($) {
var feedbackTemplate = readFixtures('system-feedback.underscore'),
installViewTemplates;
installViewTemplates = function(append) {
if (append) {
appendSetFixtures($("<script>", { id: "system-feedback-tpl", type: "text/template" }).text(feedbackTemplate));
} else {
setFixtures($("<script>", { id: "system-feedback-tpl", type: "text/template" }).text(feedbackTemplate));
}
};
return {
'installViewTemplates': installViewTemplates
};
});

View File

@@ -18,8 +18,6 @@ define(["jquery", "underscore", "js/views/xblock", "js/utils/module", "gettext",
stop: function (event, ui) {
var saving, hideSaving, removeFromParent;
console.log('stop');
if (oldParent === undefined) {
// If no actual change occurred,
// oldParent will never have been set.
@@ -81,8 +79,6 @@ define(["jquery", "underscore", "js/views/xblock", "js/utils/module", "gettext",
reorder: function (targetParent, successCallback) {
var children, childLocators;
console.log('calling reorder for ' + targetParent.data('locator'));
// Find descendants with class "wrapper-xblock" whose parent == targetParent.
// This is necessary to filter our grandchildren, great-grandchildren, etc.
children = targetParent.find('.wrapper-xblock').filter(function () {
@@ -106,7 +102,6 @@ define(["jquery", "underscore", "js/views/xblock", "js/utils/module", "gettext",
}),
success: function () {
// change data-parent on the element moved.
console.log('SAVED! ' + targetParent.data('locator') + " with " + childLocators.length + " children");
if (successCallback) {
successCallback();
}