diff --git a/cms/static/coffee/spec/views/assets_spec.coffee b/cms/static/coffee/spec/views/assets_spec.coffee index 0c0a5f42c9..8a795b63b6 100644 --- a/cms/static/coffee/spec/views/assets_spec.coffee +++ b/cms/static/coffee/spec/views/assets_spec.coffee @@ -290,6 +290,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], it "should remove the deleted asset from the view", -> {view: @view, requests: requests} = @createAssetsView(this) + AjaxHelpers.respondWithJson(requests, @mockAssetsResponse) setup.call(this, requests) # Delete the 2nd asset with success from server. @view.$(".remove-asset-button")[1].click() diff --git a/cms/static/js/spec/utils/drag_and_drop_spec.js b/cms/static/js/spec/utils/drag_and_drop_spec.js index a1db0401d7..e53a07e3f5 100644 --- a/cms/static/js/spec/utils/drag_and_drop_spec.js +++ b/cms/static/js/spec/utils/drag_and_drop_spec.js @@ -309,7 +309,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat this.clock.restore(); }); it("should send an update on reorder from one parent to another", function () { - var requests, savingOptions; + var requests, request, savingOptions; requests = AjaxHelpers["requests"](this); ContentDragger.dragState.dropDestination = $('#unit-4'); ContentDragger.dragState.attachMethod = "after"; @@ -323,15 +323,15 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat }, null, { clientX: $('#unit-1').offset().left }); - expect(requests.length).toEqual(1); + request = AjaxHelpers.currentRequest(requests); expect(this.savingSpies.constructor).toHaveBeenCalled(); expect(this.savingSpies.show).toHaveBeenCalled(); expect(this.savingSpies.hide).not.toHaveBeenCalled(); savingOptions = this.savingSpies.constructor.mostRecentCall.args[0]; expect(savingOptions.title).toMatch(/Saving/); expect($('#unit-1')).toHaveClass('was-dropped'); - expect(requests[0].requestBody).toEqual('{"children":["fourth-unit-id","first-unit-id"]}'); - requests[0].respond(200); + expect(request.requestBody).toEqual('{"children":["fourth-unit-id","first-unit-id"]}'); + request.respond(200); expect(this.savingSpies.hide).toHaveBeenCalled(); this.clock.tick(1001); expect($('#unit-1')).not.toHaveClass('was-dropped'); @@ -341,7 +341,8 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat expect($('#subsection-2').data('refresh')).toHaveBeenCalled(); }); it("should send an update on reorder within the same parent", function () { - var requests = AjaxHelpers["requests"](this); + var requests = AjaxHelpers["requests"](this), + request; ContentDragger.dragState.dropDestination = $('#unit-2'); ContentDragger.dragState.attachMethod = "after"; ContentDragger.dragState.parentList = $('#subsection-1'); @@ -354,12 +355,12 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat }, null, { clientX: $('#unit-1').offset().left }); - expect(requests.length).toEqual(1); + request = AjaxHelpers.currentRequest(requests); expect($('#unit-1')).toHaveClass('was-dropped'); - expect(requests[0].requestBody).toEqual( + expect(request.requestBody).toEqual( '{"children":["second-unit-id","first-unit-id","third-unit-id"]}' ); - requests[0].respond(200); + request.respond(200); this.clock.tick(1001); expect($('#unit-1')).not.toHaveClass('was-dropped'); // parent diff --git a/cms/static/js/spec/views/assets_spec.js b/cms/static/js/spec/views/assets_spec.js index 1d85367ffd..87c5006bc2 100644 --- a/cms/static/js/spec/views/assets_spec.js +++ b/cms/static/js/spec/views/assets_spec.js @@ -119,13 +119,12 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset }; var respondWithMockAssets = function(requests) { - var requestIndex = requests.length - 1; - var request = requests[requestIndex]; + var request = AjaxHelpers.currentRequest(requests); var url = new URI(request.url); var queryParameters = url.query(true); // Returns an object with each query parameter stored as a value var asset_type = queryParameters.asset_type; var response = asset_type !== '' ? mockExampleFilteredAssetsResponse : mockExampleAssetsResponse; - AjaxHelpers.respondWithJson(requests, response, requestIndex); + AjaxHelpers.respondWithJson(requests, response); }; var event = {}; diff --git a/cms/static/js/spec/views/container_spec.js b/cms/static/js/spec/views/container_spec.js index 4cbb0f91d4..919e27a885 100644 --- a/cms/static/js/spec/views/container_spec.js +++ b/cms/static/js/spec/views/container_spec.js @@ -7,7 +7,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "js/spec_helpers/edit_ describe("Supports reordering components", function () { - var model, containerView, mockContainerHTML, respondWithMockXBlockFragment, init, getComponent, + var model, containerView, mockContainerHTML, init, getComponent, getDragHandle, dragComponentVertically, dragComponentAbove, verifyRequest, verifyNumReorderCalls, respondToRequest, notificationSpy, @@ -28,11 +28,6 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "js/spec_helpers/edit_ mockContainerHTML = readFixtures('mock/mock-container-xblock.underscore'); - respondWithMockXBlockFragment = function (requests, response) { - var requestIndex = requests.length - 1; - AjaxHelpers.respondWithJson(requests, response, requestIndex); - }; - beforeEach(function () { EditHelpers.installMockXBlock(); EditHelpers.installViewTemplates(); @@ -60,7 +55,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "js/spec_helpers/edit_ var requests = AjaxHelpers.requests(caller); containerView.render(); - respondWithMockXBlockFragment(requests, { + AjaxHelpers.respondWithJson(requests, { html: mockContainerHTML, "resources": [] }); diff --git a/cms/static/js/spec/views/group_configuration_spec.js b/cms/static/js/spec/views/group_configuration_spec.js index 430c47e2f9..29488b551b 100644 --- a/cms/static/js/spec/views/group_configuration_spec.js +++ b/cms/static/js/spec/views/group_configuration_spec.js @@ -443,19 +443,19 @@ define([ 'Group Configuration name is required' ); // No request - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); // Set correct value setValuesToInputs(this.view, { inputName: 'New Configuration' }); // Try to save this.view.$('form').submit(); - requests[0].respond(200); + AjaxHelpers.respondWithJson(requests, {}); // Model is updated expect(this.model).toBeCorrectValuesInModel({ name: 'New Configuration' }); // Error message disappear expect(this.view.$(SELECTORS.errorMessage)).not.toExist(); - expect(requests.length).toBe(1); + AjaxHelpers.expectNoRequests(requests); }); it('should have appropriate class names on focus/blur', function () { @@ -733,9 +733,9 @@ define([ }; respondToSave = function(requests, view) { - expect(requests.length).toBe(1); - expect(requests[0].method).toBe('POST'); - expect(requests[0].url).toBe('/mock_url/0'); + var request = AjaxHelpers.currentRequest(requests); + expect(request.method).toBe('POST'); + expect(request.url).toBe('/mock_url/0'); AjaxHelpers.respondWithJson(requests, { name: 'Content Group Configuration', groups: view.collection.map(function(groupModel, index) { @@ -803,7 +803,7 @@ define([ newGroupName = 'New Group Name', view = renderView(); editNewGroup(view, {newName: newGroupName, cancel: true}); - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); verifyEditingGroup(view, false); expect(view.$()).not.toContainText(newGroupName); }); @@ -814,7 +814,7 @@ define([ view = renderView([originalGroupName]); editExistingGroup(view, {newName: 'New Group Name', cancel: true}); verifyEditingGroup(view, false); - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); expect(view.collection.at(0).get('name')).toBe(originalGroupName); }); @@ -823,7 +823,7 @@ define([ newGroupName = 'New Group Name', view = renderView(); editNewGroup(view, {newName: '', save: true}); - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); correctValidationError(view, requests, newGroupName); }); @@ -832,7 +832,7 @@ define([ oldGroupName = 'Old Group Name', view = renderView([oldGroupName]); editExistingGroup(view, {newName: '', save: true}); - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); correctValidationError(view, requests, oldGroupName); }); diff --git a/cms/static/js/spec/views/paged_container_spec.js b/cms/static/js/spec/views/paged_container_spec.js index 6a636555a4..fd55c3e2be 100644 --- a/cms/static/js/spec/views/paged_container_spec.js +++ b/cms/static/js/spec/views/paged_container_spec.js @@ -54,15 +54,14 @@ define(["jquery", "underscore", "common/js/spec_helpers/ajax_helpers", "URI", "j }); var respondWithMockPage = function(requests, mockPage) { - var requestIndex = requests.length - 1; + var request = AjaxHelpers.currentRequest(requests); if (typeof mockPage == 'undefined') { - var request = requests[requestIndex]; var url = new URI(request.url); var queryParameters = url.query(true); // Returns an object with each query parameter stored as a value var page = queryParameters.page_number; mockPage = page === "0" ? mockFirstPage : mockSecondPage; } - AjaxHelpers.respondWithJson(requests, mockPage, requestIndex); + AjaxHelpers.respondWithJson(requests, mockPage); }; var MockPagingView = PagedContainer.extend({ @@ -140,7 +139,7 @@ define(["jquery", "underscore", "common/js/spec_helpers/ajax_helpers", "URI", "j pagingContainer.setPage(1); respondWithMockPage(requests); pagingContainer.nextPage(); - expect(requests.length).toBe(1); + AjaxHelpers.expectNoRequests(requests); }); }); @@ -159,7 +158,7 @@ define(["jquery", "underscore", "common/js/spec_helpers/ajax_helpers", "URI", "j pagingContainer.setPage(0); respondWithMockPage(requests); pagingContainer.previousPage(); - expect(requests.length).toBe(1); + AjaxHelpers.expectNoRequests(requests); }); it('does not move back after a server error', function () { diff --git a/cms/static/js/spec/views/pages/container_spec.js b/cms/static/js/spec/views/pages/container_spec.js index c9eb7c270d..fe78638a57 100644 --- a/cms/static/js/spec/views/pages/container_spec.js +++ b/cms/static/js/spec/views/pages/container_spec.js @@ -2,22 +2,23 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja "common/js/spec_helpers/template_helpers", "js/spec_helpers/edit_helpers", "js/views/pages/container", "js/views/pages/paged_container", "js/models/xblock_info", "jquery.simulate"], function ($, _, str, AjaxHelpers, TemplateHelpers, EditHelpers, ContainerPage, PagedContainerPage, XBlockInfo) { + 'use strict'; - function parameterized_suite(label, global_page_options, fixtures) { + function parameterized_suite(label, globalPageOptions) { describe(label + " ContainerPage", function () { - var lastRequest, getContainerPage, renderContainerPage, expectComponents, respondWithHtml, - model, containerPage, requests, initialDisplayName, + var getContainerPage, renderContainerPage, handleContainerPageRefresh, expectComponents, + respondWithHtml, model, containerPage, requests, initialDisplayName, mockContainerPage = readFixtures('mock/mock-container-page.underscore'), - mockContainerXBlockHtml = readFixtures(fixtures.initial), - mockXBlockHtml = readFixtures(fixtures.add_response), + mockContainerXBlockHtml = readFixtures(globalPageOptions.initial), + mockXBlockHtml = readFixtures(globalPageOptions.addResponse), mockBadContainerXBlockHtml = readFixtures('mock/mock-bad-javascript-container-xblock.underscore'), mockBadXBlockContainerXBlockHtml = readFixtures('mock/mock-bad-xblock-container-xblock.underscore'), mockUpdatedContainerXBlockHtml = readFixtures('mock/mock-updated-container-xblock.underscore'), mockXBlockEditorHtml = readFixtures('mock/mock-xblock-editor.underscore'), mockXBlockVisibilityEditorHtml = readFixtures('mock/mock-xblock-visibility-editor.underscore'), - PageClass = fixtures.page, - pagedSpecificTests = fixtures.paged_specific_tests, - hasVisibilityEditor = fixtures.has_visibility_editor; + PageClass = globalPageOptions.page, + pagedSpecificTests = globalPageOptions.pagedSpecificTests, + hasVisibilityEditor = globalPageOptions.hasVisibilityEditor; beforeEach(function () { var newDisplayName = 'New Display Name'; @@ -47,16 +48,10 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja EditHelpers.uninstallMockXBlock(); }); - lastRequest = function () { - return requests[requests.length - 1]; - }; - respondWithHtml = function (html) { - var requestIndex = requests.length - 1; AjaxHelpers.respondWithJson( requests, - { html: html, "resources": [] }, - requestIndex + { html: html, "resources": [] } ); }; @@ -66,7 +61,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja templates: EditHelpers.mockComponentTemplates, el: $('#content') }; - return new PageClass(_.extend(options || {}, global_page_options, default_options)); + return new PageClass(_.extend(options || {}, globalPageOptions, default_options)); }; renderContainerPage = function (test, html, options) { @@ -74,6 +69,18 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja containerPage = getContainerPage(options); containerPage.render(); respondWithHtml(html); + AjaxHelpers.expectJsonRequest(requests, 'GET', '/xblock/locator-container'); + AjaxHelpers.respondWithJson(requests, options); + }; + + handleContainerPageRefresh = function(requests) { + var request = AjaxHelpers.currentRequest(requests); + expect(str.startsWith(request.url, + '/xblock/locator-container/container_preview')).toBeTruthy(); + AjaxHelpers.respondWithJson(requests, { + html: mockUpdatedContainerXBlockHtml, + resources: [] + }); }; expectComponents = function (container, locators) { @@ -136,7 +143,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja }; it('can edit itself', function () { - var editButtons, displayNameElement; + var editButtons, displayNameElement, request; renderContainerPage(this, mockContainerXBlockHtml); displayNameElement = containerPage.$('.page-header-title'); @@ -145,7 +152,8 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja editButtons.first().click(); // Expect a request to be made to show the studio view for the container - expect(str.startsWith(lastRequest().url, '/xblock/locator-container/studio_view')).toBeTruthy(); + request = AjaxHelpers.currentRequest(requests); + expect(str.startsWith(request.url, '/xblock/locator-container/studio_view')).toBeTruthy(); AjaxHelpers.respondWithJson(requests, { html: mockContainerXBlockHtml, resources: [] @@ -161,12 +169,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja expect(EditHelpers.isShowingModal()).toBeFalsy(); // Expect the last request be to refresh the container page - expect(str.startsWith(lastRequest().url, - '/xblock/locator-container/container_preview')).toBeTruthy(); - AjaxHelpers.respondWithJson(requests, { - html: mockUpdatedContainerXBlockHtml, - resources: [] - }); + handleContainerPageRefresh(requests); // Respond to the subsequent xblock info fetch request. AjaxHelpers.respondWithJson(requests, {"display_name": updatedDisplayName}); @@ -196,14 +199,15 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja }); it('can show an edit modal for a child xblock', function () { - var editButtons; + var editButtons, request; renderContainerPage(this, mockContainerXBlockHtml); editButtons = containerPage.$('.wrapper-xblock .edit-button'); // The container should have rendered six mock xblocks expect(editButtons.length).toBe(6); editButtons[0].click(); // Make sure that the correct xblock is requested to be edited - expect(str.startsWith(lastRequest().url, '/xblock/locator-component-A1/studio_view')).toBeTruthy(); + request = AjaxHelpers.currentRequest(requests); + expect(str.startsWith(request.url, '/xblock/locator-component-A1/studio_view')).toBeTruthy(); AjaxHelpers.respondWithJson(requests, { html: mockXBlockEditorHtml, resources: [] @@ -224,13 +228,14 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja }); it('can show a visibility modal for a child xblock if supported for the page', function() { - var visibilityButtons; + var visibilityButtons, request; renderContainerPage(this, mockContainerXBlockHtml); visibilityButtons = containerPage.$('.wrapper-xblock .visibility-button'); if (hasVisibilityEditor) { expect(visibilityButtons.length).toBe(6); visibilityButtons[0].click(); - expect(str.startsWith(lastRequest().url, '/xblock/locator-component-A1/visibility_view')) + request = AjaxHelpers.currentRequest(requests); + expect(str.startsWith(request.url, '/xblock/locator-component-A1/visibility_view')) .toBeTruthy(); AjaxHelpers.respondWithJson(requests, { html: mockXBlockVisibilityEditorHtml, @@ -297,7 +302,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja }); describe("xblock operations", function () { - var getGroupElement, paginated, getDeleteOffset, + var getGroupElement, NUM_COMPONENTS_PER_GROUP = 3, GROUP_TO_TEST = "A", allComponentsInGroup = _.map( _.range(NUM_COMPONENTS_PER_GROUP), @@ -306,11 +311,6 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja } ); - getDeleteOffset = function () { - // Paginated containers will make an additional AJAX request. - return pagedSpecificTests ? 3 : 2; - }; - getGroupElement = function () { return containerPage.$("[data-locator='locator-group-" + GROUP_TO_TEST + "']"); }; @@ -337,28 +337,35 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja EditHelpers.confirmPrompt(promptSpy, clickNo); }; - deleteComponent = function (componentIndex, requestOffset) { + deleteComponent = function (componentIndex) { clickDelete(componentIndex); - AjaxHelpers.respondWithJson(requests, {}); + + // first request to delete the component AjaxHelpers.expectJsonRequest(requests, 'DELETE', - '/xblock/locator-component-' + GROUP_TO_TEST + (componentIndex + 1), - null, requests.length - requestOffset); + '/xblock/locator-component-' + GROUP_TO_TEST + (componentIndex + 1), + null); + AjaxHelpers.respondWithNoContent(requests); + + // then handle the request to refresh the preview + if (globalPageOptions.requiresPageRefresh) { + handleContainerPageRefresh(requests); + } // final request to refresh the xblock info AjaxHelpers.expectJsonRequest(requests, 'GET', '/xblock/locator-container'); + AjaxHelpers.respondWithJson(requests, {}); }; deleteComponentWithSuccess = function (componentIndex) { - var deleteOffset; + deleteComponent(componentIndex); - deleteOffset = getDeleteOffset(); - deleteComponent(componentIndex, deleteOffset); - - // verify the new list of components within the group - expectComponents( - getGroupElement(), - _.without(allComponentsInGroup, allComponentsInGroup[componentIndex]) - ); + // verify the new list of components within the group (unless reloading) + if (!globalPageOptions.requiresPageRefresh) { + expectComponents( + getGroupElement(), + _.without(allComponentsInGroup, allComponentsInGroup[componentIndex]) + ); + } }; it("can delete the first xblock", function () { @@ -377,24 +384,25 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja }); it("can delete an xblock with broken JavaScript", function () { - var deleteOffset = getDeleteOffset(); renderContainerPage(this, mockBadContainerXBlockHtml); containerPage.$('.delete-button').first().click(); EditHelpers.confirmPrompt(promptSpy); - AjaxHelpers.respondWithJson(requests, {}); // expect the second to last request to be a delete of the xblock - AjaxHelpers.expectJsonRequest(requests, 'DELETE', '/xblock/locator-broken-javascript', - null, requests.length - deleteOffset); + AjaxHelpers.expectJsonRequest(requests, 'DELETE', '/xblock/locator-broken-javascript'); + AjaxHelpers.respondWithNoContent(requests); + + // handle the refresh request for pages that require a full refresh on delete + if (globalPageOptions.requiresPageRefresh) { + handleContainerPageRefresh(requests); + } + // expect the last request to be a fetch of the xblock info for the parent container AjaxHelpers.expectJsonRequest(requests, 'GET', '/xblock/locator-container'); }); it('does not delete when clicking No in prompt', function () { - var numRequests; - renderContainerPage(this, mockContainerXBlockHtml); - numRequests = requests.length; // click delete on the first component but press no clickDelete(0, true); @@ -403,7 +411,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja expectComponents(getGroupElement(), allComponentsInGroup); // no requests should have been sent to the server - expect(requests.length).toBe(numRequests); + AjaxHelpers.expectNoRequests(requests); }); it('shows a notification during the delete operation', function () { @@ -526,13 +534,13 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja expect(getButtonText(containerPage)).toBe(""); }); - function updatePreviewButtonTest(show_previews, expected_text) { + var updatePreviewButtonTest = function(show_previews, expected_text) { it('can set preview button to "' + expected_text + '"', function () { containerPage = getContainerPage(); containerPage.updatePreviewButton(show_previews); expect(getButtonText(containerPage)).toBe(expected_text); }); - } + }; updatePreviewButtonTest(true, 'Hide Previews'); updatePreviewButtonTest(false, 'Show Previews'); @@ -603,13 +611,11 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja }); it('does not insert component upon failure', function () { - var requestCount; renderContainerPage(this, mockContainerXBlockHtml); clickNewComponent(0); - requestCount = requests.length; AjaxHelpers.respondWithError(requests); // No new requests should be made to refresh the view - expect(requests.length).toBe(requestCount); + AjaxHelpers.expectNoRequests(requests); expectComponents(getGroupElement(), allComponentsInGroup); }); @@ -649,31 +655,31 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja }); }); }); - }); } // Create a suite for a non-paged container that includes 'edit visibility' buttons parameterized_suite("Non paged", - { }, { page: ContainerPage, + requiresPageRefresh: false, initial: 'mock/mock-container-xblock.underscore', - add_response: 'mock/mock-xblock.underscore', - has_visibility_editor: true, - paged_specific_tests: false + addResponse: 'mock/mock-xblock.underscore', + hasVisibilityEditor: true, + pagedSpecificTests: false } ); // Create a suite for a paged container that does not include 'edit visibility' buttons parameterized_suite("Paged", - { page_size: 42 }, { page: PagedContainerPage, + page_size: 42, + requiresPageRefresh: true, initial: 'mock/mock-container-paged-xblock.underscore', - add_response: 'mock/mock-xblock-paged.underscore', - has_visibility_editor: false, - paged_specific_tests: true + addResponse: 'mock/mock-xblock-paged.underscore', + hasVisibilityEditor: false, + pagedSpecificTests: true } ); }); diff --git a/cms/static/js/spec/views/pages/container_subviews_spec.js b/cms/static/js/spec/views/pages/container_subviews_spec.js index 97bf656e26..744b991e6b 100644 --- a/cms/static/js/spec/views/pages/container_subviews_spec.js +++ b/cms/static/js/spec/views/pages/container_subviews_spec.js @@ -8,7 +8,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja describe("Container Subviews", function() { var model, containerPage, requests, createContainerPage, renderContainerPage, - respondWithHtml, respondWithJson, fetch, + respondWithHtml, fetch, disabledCss = "is-disabled", defaultXBlockInfo, createXBlockInfo, mockContainerPage = readFixtures('mock/mock-container-page.underscore'), mockContainerXBlockHtml = readFixtures('mock/mock-empty-container-xblock.underscore'); @@ -52,30 +52,23 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja renderContainerPage = function (test, html, options) { createContainerPage(test, options); containerPage.render(); - respondWithHtml(html); + respondWithHtml(html, options); }; - respondWithHtml = function(html) { - var requestIndex = requests.length - 1; + respondWithHtml = function(html, options) { AjaxHelpers.respondWithJson( requests, - { html: html, "resources": [] }, - requestIndex - ); - }; - - respondWithJson = function(json, requestIndex) { - AjaxHelpers.respondWithJson( - requests, - json, - requestIndex + { html: html, "resources": [] } ); + AjaxHelpers.expectJsonRequest(requests, 'GET', '/xblock/locator-container'); + AjaxHelpers.respondWithJson(requests, createXBlockInfo(options)); }; fetch = function (json) { json = createXBlockInfo(json); model.fetch(); - respondWithJson(json); + AjaxHelpers.expectJsonRequest(requests, 'GET', '/xblock/locator-container'); + AjaxHelpers.respondWithJson(requests, json); }; describe("ViewLiveButtonController", function () { @@ -236,14 +229,17 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja ); // Response to publish call - respondWithJson({"id": "locator-container", "data": null, "metadata":{}}); + AjaxHelpers.respondWithJson(requests, {"id": "locator-container", "data": null, "metadata":{}}); EditHelpers.verifyNotificationHidden(notificationSpy); AjaxHelpers.expectJsonRequest(requests, "GET", "/xblock/locator-container"); // Response to fetch - respondWithJson(createXBlockInfo({ - published: true, has_changes: false, visibility_state: VisibilityState.ready - })); + AjaxHelpers.respondWithJson( + requests, + createXBlockInfo({ + published: true, has_changes: false, visibility_state: VisibilityState.ready + }) + ); // Verify updates displayed expect(containerPage.$(bitPublishingCss)).toHaveClass(readyClass); @@ -258,11 +254,9 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja // Click publish containerPage.$(publishButtonCss).click(); - var numRequests = requests.length; // Respond with failure AjaxHelpers.respondWithError(requests); - - expect(requests.length).toEqual(numRequests); + AjaxHelpers.expectNoRequests(requests); // Verify still in draft (unscheduled) state. verifyPublishingBitUnscheduled(); @@ -280,7 +274,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja numRequests = requests.length; // Respond with success. - respondWithJson({"id": "locator-container"}); + AjaxHelpers.respondWithJson(requests, {"id": "locator-container"}); EditHelpers.verifyNotificationHidden(notificationSpy); // Verify other requests are sent to the server to update page state. @@ -296,12 +290,10 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja renderPageSpy = spyOn(containerPage.xblockPublisher, 'renderPage').andCallThrough(); sendDiscardChangesToServer(); - numRequests = requests.length; // Respond with failure AjaxHelpers.respondWithError(requests); - - expect(requests.length).toEqual(numRequests); + AjaxHelpers.expectNoRequests(requests); expect(containerPage.$(discardChangesButtonCss)).not.toHaveClass('is-disabled'); expect(containerPage.model.get("publish")).toBeNull(); expect(renderPageSpy).not.toHaveBeenCalled(); @@ -310,7 +302,6 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja it('does not discard changes on cancel', function () { renderContainerPage(this, mockContainerXBlockHtml); fetch({published: true, has_changes: true, visibility_state: VisibilityState.needsAttention}); - var numRequests = requests.length; // Click discard changes expect(containerPage.$(discardChangesButtonCss)).not.toHaveClass('is-disabled'); @@ -319,8 +310,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja // Click cancel to confirmation. expect(promptSpies.constructor).toHaveBeenCalled(); promptSpies.constructor.mostRecentCall.args[0].actions.secondary.click(promptSpies); - - expect(requests.length).toEqual(numRequests); + AjaxHelpers.expectNoRequests(requests); expect(containerPage.$(discardChangesButtonCss)).not.toHaveClass('is-disabled'); }); @@ -534,28 +524,24 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja }); it("does not refresh if removing staff only is canceled", function() { - var requestCount; promptSpy = EditHelpers.createPromptSpy(); renderContainerPage(this, mockContainerXBlockHtml, { visibility_state: VisibilityState.staffOnly, has_explicit_staff_lock: true, ancestor_has_staff_lock: false }); - requestCount = requests.length; containerPage.$('.action-staff-lock').click(); EditHelpers.confirmPrompt(promptSpy, true); // Click 'No' to cancel - expect(requests.length).toBe(requestCount); + AjaxHelpers.expectNoRequests(requests); verifyExplicitStaffOnly(true); verifyStaffOnly(true); }); it("does not refresh when failing to set staff only", function() { - var requestCount; renderContainerPage(this, mockContainerXBlockHtml); - containerPage.$('.lock-checkbox').click(); - requestCount = requests.length; + containerPage.$('.action-staff-lock').click(); AjaxHelpers.respondWithError(requests); - expect(requests.length).toBe(requestCount); + AjaxHelpers.expectNoRequests(requests); verifyStaffOnly(false); }); }); diff --git a/cms/static/js/spec/views/pages/course_outline_spec.js b/cms/static/js/spec/views/pages/course_outline_spec.js index f69bf31e8e..02860f4e3f 100644 --- a/cms/static/js/spec/views/pages/course_outline_spec.js +++ b/cms/static/js/spec/views/pages/course_outline_spec.js @@ -401,9 +401,8 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u 'display_name': 'Section', 'parent_locator': 'mock-course' }); - requestCount = requests.length; AjaxHelpers.respondWithError(requests); - expect(requests.length).toBe(requestCount); // No additional requests should be made + AjaxHelpers.expectNoRequests(requests); expect(outlinePage.$('.no-content')).not.toHaveClass('is-hidden'); expect(outlinePage.$('.no-content .button-new')).toExist(); }); @@ -424,10 +423,9 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u ])); getItemHeaders('section').find('.delete-button').first().click(); EditHelpers.confirmPrompt(promptSpy); - requestCount = requests.length; AjaxHelpers.expectJsonRequest(requests, 'DELETE', '/xblock/mock-section'); AjaxHelpers.respondWithJson(requests, {}); - expect(requests.length).toBe(requestCount); // No fetch should be performed + AjaxHelpers.expectNoRequests(requests); // No fetch should be performed expect(outlinePage.$('[data-locator="mock-section"]')).not.toExist(); expect(outlinePage.$('[data-locator="mock-section-2"]')).toExist(); }); @@ -452,9 +450,8 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u getItemHeaders('section').find('.delete-button').click(); EditHelpers.confirmPrompt(promptSpy); AjaxHelpers.expectJsonRequest(requests, 'DELETE', '/xblock/mock-section'); - requestCount = requests.length; AjaxHelpers.respondWithError(requests); - expect(requests.length).toBe(requestCount); // No additional requests should be made + AjaxHelpers.expectNoRequests(requests); expect(outlinePage.$('.list-sections li.outline-section').data('locator')).toEqual('mock-section'); }); @@ -534,10 +531,8 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u ]) ]); AjaxHelpers.expectJsonRequest(requests, 'GET', '/xblock/outline/mock-section'); - expect(requests.length).toBe(2); - // This is the response for the subsequent fetch operation for the section. AjaxHelpers.respondWithJson(requests, mockResponseSectionJSON); - + AjaxHelpers.expectNoRequests(requests); expect($(".outline-section .status-release-value")).toContainText("Jan 02, 2015 at 00:00 UTC"); }); @@ -713,13 +708,11 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u } }); expect(requests[0].requestHeaders['X-HTTP-Method-Override']).toBe('PATCH'); - - // This is the response for the change operation. AjaxHelpers.respondWithJson(requests, {}); + AjaxHelpers.expectJsonRequest(requests, 'GET', '/xblock/outline/mock-section'); - expect(requests.length).toBe(2); - // This is the response for the subsequent fetch operation for the section. AjaxHelpers.respondWithJson(requests, mockServerValuesJson); + AjaxHelpers.expectNoRequests(requests); expect($(".outline-subsection .status-release-value")).toContainText( "Jul 09, 2014 at 00:00 UTC" diff --git a/cms/static/js/spec/views/pages/course_rerun_spec.js b/cms/static/js/spec/views/pages/course_rerun_spec.js index 08c45c53de..f9d62ed2ba 100644 --- a/cms/static/js/spec/views/pages/course_rerun_spec.js +++ b/cms/static/js/spec/views/pages/course_rerun_spec.js @@ -193,7 +193,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers var requests = AjaxHelpers.requests(this); fillInFields('DemoX', 'DM101', '', 'Demo course'); $(selectors.save).click(); - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); }); it("can be canceled", function () { diff --git a/cms/static/js/spec/views/pages/index_spec.js b/cms/static/js/spec/views/pages/index_spec.js index 1a06273f26..e9a1d4310a 100644 --- a/cms/static/js/spec/views/pages/index_spec.js +++ b/cms/static/js/spec/views/pages/index_spec.js @@ -88,7 +88,6 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers it("displays an error when a required field is blank", function () { var requests = AjaxHelpers.requests(this); - var requests_count = requests.length; $('.new-library-button').click(); var values = ['DemoX', 'DM101', 'Demo library']; // Try making each of these three values empty one at a time and ensure the form won't submit: @@ -100,7 +99,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers expect($('.new-library-save')).toHaveClass('is-disabled'); expect($('.new-library-save')).toHaveAttr('aria-disabled', 'true'); $('.new-library-save').click(); - expect(requests.length).toEqual(requests_count); // Expect no new requests + AjaxHelpers.expectNoRequests(requests); } }); diff --git a/cms/static/js/spec/views/pages/library_users_spec.js b/cms/static/js/spec/views/pages/library_users_spec.js index 876a6fe30e..3a747d97c2 100644 --- a/cms/static/js/spec/views/pages/library_users_spec.js +++ b/cms/static/js/spec/views/pages/library_users_spec.js @@ -84,7 +84,7 @@ function ($, AjaxHelpers, ViewHelpers, ManageUsersFactory, ViewUtils) { $('.form-create.create-user .action-primary').click(); expect($(errorPromptSelector).length).toEqual(1); expect($(errorPromptSelector)).toContainText('You must enter a valid email address'); - expect(requests.length).toEqual(0); + AjaxHelpers.expectNoRequests(requests); }); it("displays an error when the user has already been added", function () { @@ -94,7 +94,7 @@ function ($, AjaxHelpers, ViewHelpers, ManageUsersFactory, ViewUtils) { $('.user-email-input').val('honor@example.com'); $('.form-create.create-user .action-primary').click(); ViewHelpers.verifyPromptShowing(promptSpy, 'Already a library team member'); - expect(requests.length).toEqual(0); + AjaxHelpers.expectNoRequests(requests); }); diff --git a/cms/static/js/spec/views/paging_spec.js b/cms/static/js/spec/views/paging_spec.js index ff9c7a865a..19e1dfedec 100644 --- a/cms/static/js/spec/views/paging_spec.js +++ b/cms/static/js/spec/views/paging_spec.js @@ -51,13 +51,12 @@ define([ }; var respondWithMockItems = function(requests) { - var requestIndex = requests.length - 1; - var request = requests[requestIndex]; + var request = AjaxHelpers.currentRequest(requests); var url = new URI(request.url); var queryParameters = url.query(true); // Returns an object with each query parameter stored as a value var page = queryParameters.page; var response = page === "0" ? mockFirstPage : mockSecondPage; - AjaxHelpers.respondWithJson(requests, response, requestIndex); + AjaxHelpers.respondWithJson(requests, response); }; var MockPagingView = PagingView.extend({ @@ -124,7 +123,7 @@ define([ pagingView.setPage(2); respondWithMockItems(requests); pagingView.nextPage(); - expect(requests.length).toBe(1); + AjaxHelpers.expectNoRequests(requests); }); }); @@ -144,7 +143,7 @@ define([ pagingView.setPage(1); respondWithMockItems(requests); pagingView.previousPage(); - expect(requests.length).toBe(1); + AjaxHelpers.expectNoRequests(requests); }); it('does not move back after a server error', function () { diff --git a/cms/static/js/spec/views/xblock_editor_spec.js b/cms/static/js/spec/views/xblock_editor_spec.js index 5dcafb443e..701c71c499 100644 --- a/cms/static/js/spec/views/xblock_editor_spec.js +++ b/cms/static/js/spec/views/xblock_editor_spec.js @@ -86,7 +86,7 @@ define([ "jquery", "underscore", "common/js/spec_helpers/ajax_helpers", "js/spec // Give the mock xblock a save method... editor.xblock.save = window.MockDescriptor.save; editor.model.save(editor.getXBlockFieldData()); - request = requests[requests.length - 1]; + request = AjaxHelpers.currentRequest(requests); response = JSON.parse(request.requestBody); expect(response.metadata.display_name).toBe(testDisplayName); expect(response.metadata.custom_field).toBe('Custom Value'); diff --git a/cms/static/js/spec/views/xblock_spec.js b/cms/static/js/spec/views/xblock_spec.js index 5e0c1fe246..6eb9753b63 100644 --- a/cms/static/js/spec/views/xblock_spec.js +++ b/cms/static/js/spec/views/xblock_spec.js @@ -3,7 +3,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/xbloc function ($, AjaxHelpers, URI, XBlockView, XBlockInfo) { describe("XBlockView", function() { - var model, xblockView, mockXBlockHtml, respondWithMockXBlockFragment; + var model, xblockView, mockXBlockHtml; beforeEach(function () { model = new XBlockInfo({ @@ -18,15 +18,10 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/xbloc mockXBlockHtml = readFixtures('mock/mock-xblock.underscore'); - respondWithMockXBlockFragment = function(requests, response) { - var requestIndex = requests.length - 1; - AjaxHelpers.respondWithJson(requests, response, requestIndex); - }; - it('can render a nested xblock', function() { var requests = AjaxHelpers.requests(this); xblockView.render(); - respondWithMockXBlockFragment(requests, { + AjaxHelpers.respondWithJson(requests, { html: mockXBlockHtml, resources: [] }); @@ -48,7 +43,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/xbloc }); // Note: this mock response will call the AJAX success function synchronously // so the promise variable defined above will be available. - respondWithMockXBlockFragment(requests, { + AjaxHelpers.respondWithJson(requests, { html: mockXBlockHtml, resources: resources }); diff --git a/cms/static/js/spec/views/xblock_string_field_editor_spec.js b/cms/static/js/spec/views/xblock_string_field_editor_spec.js index 883e32a207..b3fa04a7db 100644 --- a/cms/static/js/spec/views/xblock_string_field_editor_spec.js +++ b/cms/static/js/spec/views/xblock_string_field_editor_spec.js @@ -52,7 +52,6 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers expectEditCanceled = function (test, fieldEditorView, options) { var requests, initialRequests, displayNameInput; requests = AjaxHelpers.requests(test); - initialRequests = requests.length; displayNameInput = EditHelpers.inlineEdit(fieldEditorView.$el, options.newTitle); if (options.pressEscape) { displayNameInput.simulate("keydown", { keyCode: $.simulate.keyCode.ESCAPE }); @@ -63,7 +62,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers displayNameInput.change(); } // No requests should be made when the edit is cancelled client-side - expect(initialRequests).toBe(requests.length); + AjaxHelpers.expectNoRequests(requests); EditHelpers.verifyInlineEditChange(fieldEditorView.$el, initialDisplayName); expect(fieldEditorView.model.get('display_name')).toBe(initialDisplayName); }; @@ -85,14 +84,13 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers it('does not change the title when a display name update fails', function () { var requests, fieldEditorView, initialRequests; requests = AjaxHelpers.requests(this); - initialRequests = requests.length; fieldEditorView = getFieldEditorView().render(); EditHelpers.inlineEdit(fieldEditorView.$el, updatedDisplayName); fieldEditorView.$('button[name=submit]').click(); expectPostedNewDisplayName(requests, updatedDisplayName); AjaxHelpers.respondWithError(requests); // No fetch operation should occur. - expect(initialRequests + 1).toBe(requests.length); + AjaxHelpers.expectNoRequests(requests); EditHelpers.verifyInlineEditChange(fieldEditorView.$el, initialDisplayName, updatedDisplayName); }); diff --git a/cms/static/js/spec_helpers/edit_helpers.js b/cms/static/js/spec_helpers/edit_helpers.js index 6f1359d43e..fa100d7907 100644 --- a/cms/static/js/spec_helpers/edit_helpers.js +++ b/cms/static/js/spec_helpers/edit_helpers.js @@ -98,7 +98,7 @@ define(["jquery", "underscore", "common/js/spec_helpers/ajax_helpers", "common/j }; verifyXBlockRequest = function (requests, expectedJson) { - var request = requests[requests.length - 1], + var request = AjaxHelpers.currentRequest(requests), actualJson = JSON.parse(request.requestBody); expect(request.url).toEqual("/xblock/"); expect(request.method).toEqual("POST"); diff --git a/common/static/common/js/spec/components/paginated_view_spec.js b/common/static/common/js/spec/components/paginated_view_spec.js index 186f711af7..b7b0e4c396 100644 --- a/common/static/common/js/spec/components/paginated_view_spec.js +++ b/common/static/common/js/spec/components/paginated_view_spec.js @@ -109,9 +109,8 @@ define([ expectHeader('Showing 1-5 out of 6 total'); expectItems(initialItems); expectFooter({currentPage: 1, totalPages: 2, isHidden: false}); - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); testView.$(nextPageButtonCss).click(); - expect(requests.length).toBe(1); AjaxHelpers.respondWithJson(requests, { "count": 6, "num_pages": 2, diff --git a/common/static/common/js/spec/components/paging_collection_spec.js b/common/static/common/js/spec/components/paging_collection_spec.js index 0d5f668e97..6a49b787eb 100644 --- a/common/static/common/js/spec/components/paging_collection_spec.js +++ b/common/static/common/js/spec/components/paging_collection_spec.js @@ -15,7 +15,8 @@ define(['jquery', isZeroIndexed: false, count: 43, respond: function (requests) { - var params = (new URI(requests[requests.length - 1].url)).query(true), + var request = AjaxHelpers.currentRequest(requests), + params = (new URI(request.url)).query(true), page = parseInt(params['page'], 10), page_size = parseInt(params['page_size'], 10), page_count = Math.ceil(this.count / page_size); @@ -23,7 +24,7 @@ define(['jquery', // Make zeroPage consistently start at zero for ease of calculation var zeroPage = page - (this.isZeroIndexed ? 0 : 1); if (zeroPage < 0 || zeroPage > page_count) { - AjaxHelpers.respondWithError(requests, 404, {}, requests.length - 1); + AjaxHelpers.respondWithError(requests, 404); } else { AjaxHelpers.respondWithJson(requests, { 'count': this.count, @@ -31,12 +32,13 @@ define(['jquery', 'num_pages': page_count, 'start': zeroPage * page_size, 'results': [] - }, requests.length - 1); + }); } } }; var assertQueryParams = function (requests, params) { - var urlParams = (new URI(requests[requests.length - 1].url)).query(true); + var request = AjaxHelpers.currentRequest(requests), + urlParams = (new URI(request.url)).query(true); _.each(params, function (value, key) { expect(urlParams[key]).toBe(value); }); @@ -153,7 +155,7 @@ define(['jquery', expect(collection.getPage()).toBe(2); server.respond(requests); collection.setPage(3); - AjaxHelpers.respondWithError(requests, 500, {}, requests.length - 1); + AjaxHelpers.respondWithError(requests, 500); expect(errorTriggered).toBe(true); expect(collection.getPage()).toBe(2); }); diff --git a/common/static/common/js/spec_helpers/ajax_helpers.js b/common/static/common/js/spec_helpers/ajax_helpers.js index e699805512..c501f7006f 100644 --- a/common/static/common/js/spec_helpers/ajax_helpers.js +++ b/common/static/common/js/spec_helpers/ajax_helpers.js @@ -1,9 +1,17 @@ define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) { 'use strict'; - var fakeServer, fakeRequests, expectRequest, expectJsonRequest, expectPostRequest, expectRequestURL, + var XML_HTTP_READY_STATES, fakeServer, fakeRequests, currentRequest, expectRequest, expectNoRequests, + expectJsonRequest, expectPostRequest, expectRequestURL, skipResetRequest, respondWithJson, respondWithError, respondWithTextError, respondWithNoContent; + XML_HTTP_READY_STATES = { + UNSENT: 0, + OPENED: 1, + LOADING: 3, + DONE: 4 + }; + /* These utility methods are used by Jasmine tests to create a mock server or * get reference to mock requests. In either case, the cleanup (restore) is done with * an after function. @@ -37,6 +45,7 @@ define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) { fakeRequests = function (that) { var requests = [], xhr = sinon.useFakeXMLHttpRequest(); + requests.currentIndex = 0; xhr.onCreate = function(request) { requests.push(request); }; @@ -44,27 +53,38 @@ define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) { that.after(function() { xhr.restore(); }); - return requests; }; - expectRequest = function(requests, method, url, body, requestIndex) { - var request; - if (_.isUndefined(requestIndex)) { - requestIndex = requests.length - 1; - } - request = requests[requestIndex]; + /** + * Returns the request that has not yet been responded to. If no such request + * is available then the current test will fail. + * @param requests The Sinon requests list. + * @returns {*} The current request. + */ + currentRequest = function(requests) { + expect(requests.length).toBeGreaterThan(requests.currentIndex); + return requests[requests.currentIndex]; + }; + + expectRequest = function(requests, method, url, body) { + var request = currentRequest(requests); + expect(request.readyState).toEqual(XML_HTTP_READY_STATES.OPENED); expect(request.url).toEqual(url); expect(request.method).toEqual(method); expect(request.requestBody).toEqual(body); }; - expectJsonRequest = function(requests, method, url, jsonRequest, requestIndex) { - var request; - if (_.isUndefined(requestIndex)) { - requestIndex = requests.length - 1; - } - request = requests[requestIndex]; + /** + * Verifies the there are no unconsumed requests. + */ + expectNoRequests = function(requests) { + expect(requests.length).toEqual(requests.currentIndex); + }; + + expectJsonRequest = function(requests, method, url, jsonRequest) { + var request = currentRequest(requests); + expect(request.readyState).toEqual(XML_HTTP_READY_STATES.OPENED); expect(request.url).toEqual(url); expect(request.method).toEqual(method); expect(JSON.parse(request.requestBody)).toEqual(jsonRequest); @@ -75,14 +95,10 @@ define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) { * @param requests The collected requests * @param expectedUrl The expected URL excluding the parameters * @param expectedParameters An object representing the URL parameters - * @param requestIndex An optional index for the request (by default, the last request is used) */ - expectRequestURL = function(requests, expectedUrl, expectedParameters, requestIndex) { - var request, parameters; - if (_.isUndefined(requestIndex)) { - requestIndex = requests.length - 1; - } - request = requests[requestIndex]; + expectRequestURL = function(requests, expectedUrl, expectedParameters) { + var request = currentRequest(requests), + parameters; expect(new URI(request.url).path()).toEqual(expectedUrl); parameters = new URI(request.url).query(true); delete parameters._; // Ignore the cache-busting argument @@ -92,73 +108,82 @@ define(['sinon', 'underscore', 'URI'], function(sinon, _, URI) { /** * Intended for use with POST requests using application/x-www-form-urlencoded. */ - expectPostRequest = function(requests, url, body, requestIndex) { - var request; - if (_.isUndefined(requestIndex)) { - requestIndex = requests.length - 1; - } - request = requests[requestIndex]; + expectPostRequest = function(requests, url, body) { + var request = currentRequest(requests); + expect(request.readyState).toEqual(XML_HTTP_READY_STATES.OPENED); expect(request.url).toEqual(url); expect(request.method).toEqual("POST"); expect(_.difference(request.requestBody.split('&'), body.split('&'))).toEqual([]); }; - respondWithJson = function(requests, jsonResponse, requestIndex) { - if (_.isUndefined(requestIndex)) { - requestIndex = requests.length - 1; - } - requests[requestIndex].respond(200, - { 'Content-Type': 'application/json' }, - JSON.stringify(jsonResponse)); + /** + * Verify that the request was reset, and then skip it. + */ + skipResetRequest = function(requests) { + var request = currentRequest(requests); + expect(request.readyState).toEqual(XML_HTTP_READY_STATES.UNSENT); + requests.currentIndex++; }; - respondWithError = function(requests, statusCode, jsonResponse, requestIndex) { - if (_.isUndefined(requestIndex)) { - requestIndex = requests.length - 1; - } + respondWithJson = function(requests, jsonResponse) { + var request = currentRequest(requests); + request.respond(200, + { 'Content-Type': 'application/json' }, + JSON.stringify(jsonResponse)); + requests.currentIndex++; + }; + + respondWithError = function(requests, statusCode, jsonResponse) { + var request = currentRequest(requests); if (_.isUndefined(statusCode)) { statusCode = 500; } if (_.isUndefined(jsonResponse)) { jsonResponse = {}; } - requests[requestIndex].respond(statusCode, + request.respond( + statusCode, { 'Content-Type': 'application/json' }, JSON.stringify(jsonResponse) ); + requests.currentIndex++; }; - respondWithTextError = function(requests, statusCode, textResponse, requestIndex) { - if (_.isUndefined(requestIndex)) { - requestIndex = requests.length - 1; - } + respondWithTextError = function(requests, statusCode, textResponse) { + var request = currentRequest(requests); if (_.isUndefined(statusCode)) { statusCode = 500; } if (_.isUndefined(textResponse)) { textResponse = ""; } - requests[requestIndex].respond(statusCode, + request.respond( + statusCode, { 'Content-Type': 'text/plain' }, textResponse ); + requests.currentIndex++; }; - respondWithNoContent = function(requests, requestIndex) { - if (_.isUndefined(requestIndex)) { - requestIndex = requests.length - 1; - } - requests[requestIndex].respond(204, - { 'Content-Type': 'application/json' }); + respondWithNoContent = function(requests) { + var request = currentRequest(requests); + request.respond( + 204, + { 'Content-Type': 'application/json' } + ); + requests.currentIndex++; }; return { server: fakeServer, requests: fakeRequests, + currentRequest: currentRequest, expectRequest: expectRequest, + expectNoRequests: expectNoRequests, expectJsonRequest: expectJsonRequest, expectPostRequest: expectPostRequest, expectRequestURL: expectRequestURL, + skipResetRequest: skipResetRequest, respondWithJson: respondWithJson, respondWithError: respondWithError, respondWithTextError: respondWithTextError, diff --git a/lms/djangoapps/teams/static/teams/js/spec/collections/topic_collection_spec.js b/lms/djangoapps/teams/static/teams/js/spec/collections/topic_collection_spec.js index 241ef6bf03..272a1827dd 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/collections/topic_collection_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/collections/topic_collection_spec.js @@ -10,11 +10,12 @@ define(['backbone', 'URI', 'underscore', 'common/js/spec_helpers/ajax_helpers', var testRequestParam = function (self, param, value) { var requests = AjaxHelpers.requests(self), + request, url, params; topicCollection.fetch(); - expect(requests.length).toBe(1); - url = new URI(requests[0].url); + request = AjaxHelpers.currentRequest(requests); + url = new URI(request.url); params = url.query(true); expect(params[param]).toBe(value); }; diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_members_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_members_spec.js index aa241b6b5a..f2d28dd507 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_members_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_members_spec.js @@ -138,7 +138,7 @@ define([ verifyTeamMembersView(view); deleteTeamMemember(view, false); - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); expect(view.teamEvents.trigger).not.toHaveBeenCalled(); verifyTeamMembersView(view); }); diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js index f2ddf34382..70f0e59e82 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/edit_team_spec.js @@ -55,7 +55,8 @@ define([ } }); - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); + }, editTeamID = 'av', teamAction; diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/instructor_tools_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/instructor_tools_spec.js index 12bb27d8d1..a556dcab44 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/instructor_tools_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/instructor_tools_spec.js @@ -72,7 +72,7 @@ define([ it('can cancel team deletion', function () { var requests = AjaxHelpers.requests(this); deleteTeam(view, false); - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); expect(Backbone.history.navigate).not.toHaveBeenCalled(); }); diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_header_actions_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_header_actions_spec.js index af509310ba..5f50e216e1 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_header_actions_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_header_actions_spec.js @@ -168,7 +168,7 @@ define([ expect(view.$('.join-team-message').text().trim()).toBe(view.teamFullMessage); // there should be no request made - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); }); it('shows correct error message if user fails to join team', function () { diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js index 8e295fb611..7483e64a6f 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js @@ -85,10 +85,9 @@ define([ AjaxHelpers.expectJsonRequest(requests, 'GET', '/api/team/v0/teams/test-team'); AjaxHelpers.respondWithJson(requests, createTeamModelData({country: 'US', language: 'en'})); } else { - var requestCount = requests.length; // click on Cancel button on dialog $('.prompt.warning .action-secondary').click(); - expect(requests.length).toBe(requestCount); + AjaxHelpers.expectNoRequests(requests); } }; diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/teams_tab_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/teams_tab_spec.js index 0665d50e28..e366d004f7 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/teams_tab_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/teams_tab_spec.js @@ -174,7 +174,7 @@ define([ userInfo: TeamSpecHelpers.createMockUserInfo({staff: true}) }); teamsTabView.router.navigate(url, {trigger: true}); - if (requests.length) { + if (AjaxHelpers.currentRequest(requests)) { AjaxHelpers.respondWithJson(requests, {}); } expect(Logger.log).toHaveBeenCalledWith('edx.team.page_viewed', expectedEvent); @@ -229,24 +229,22 @@ define([ text_search: 'foo' }); AjaxHelpers.respondWithJson(requests, TeamSpecHelpers.createMockTeamsResponse({results: []})); + + // Expect exactly one search request to be fired + AjaxHelpers.expectNoRequests(requests); }; it('can search teams', function () { - var teamsTabView = createTeamsTabView(this), - requestCountBeforeSearch; + var teamsTabView = createTeamsTabView(this); teamsTabView.browseTopic(TeamSpecHelpers.testTopicID); verifyTeamsRequest({ order_by: 'last_activity_at', text_search: '' }); AjaxHelpers.respondWithJson(requests, {}); - requestCountBeforeSearch = requests.length; performSearch(requests, teamsTabView); expect(teamsTabView.$('.page-title').text()).toBe('Team Search'); expect(teamsTabView.$('.page-description').text()).toBe('Showing results for "foo"'); - - // Expect exactly one search request to be fired - expect(requests.length).toBe(requestCountBeforeSearch + 1); }); it('can clear a search', function () { diff --git a/lms/static/js/spec/discovery/discovery_factory_spec.js b/lms/static/js/spec/discovery/discovery_factory_spec.js index cef435ed23..199323d0ea 100644 --- a/lms/static/js/spec/discovery/discovery_factory_spec.js +++ b/lms/static/js/spec/discovery/discovery_factory_spec.js @@ -130,6 +130,9 @@ define([ window.scroll(0, $(document).height()); $(window).trigger('scroll'); jasmine.Clock.tick(500); + + // TODO: determine why the search API is invoked twice + AjaxHelpers.respondWithJson(requests, JSON_RESPONSE); AjaxHelpers.respondWithJson(requests, JSON_RESPONSE); expect($('.courses-listing article').length).toEqual(2); }); diff --git a/lms/static/js/spec/edxnotes/views/notes_visibility_factory_spec.js b/lms/static/js/spec/edxnotes/views/notes_visibility_factory_spec.js index 2014d40d34..977b381c07 100644 --- a/lms/static/js/spec/edxnotes/views/notes_visibility_factory_spec.js +++ b/lms/static/js/spec/edxnotes/views/notes_visibility_factory_spec.js @@ -70,6 +70,16 @@ define([ expect(this.toggleMessage).toContainText('Notes visible'); expect(Annotator._instances).toHaveLength(2); + // TODO: why is the same search request made twice? + AjaxHelpers.expectJsonRequest(requests, 'GET', + '/test_endpoint/search/?user=a+user&usage_id=an+usage&course_id=a+course' + ); + AjaxHelpers.respondWithJson(requests, {}); + AjaxHelpers.expectJsonRequest(requests, 'GET', + '/test_endpoint/search/?user=a+user&usage_id=an+usage&course_id=a+course' + ); + AjaxHelpers.respondWithJson(requests, {}); + AjaxHelpers.expectJsonRequest(requests, 'PUT', '/test_url', { 'visibility': true }); @@ -90,6 +100,17 @@ define([ expect(errorContainer).toHaveClass('annotator-notice-error'); this.button.click(); + + // TODO: why is the same search request made twice? + AjaxHelpers.expectJsonRequest(requests, 'GET', + '/test_endpoint/search/?user=a+user&usage_id=an+usage&course_id=a+course' + ); + AjaxHelpers.respondWithJson(requests, {}); + AjaxHelpers.expectJsonRequest(requests, 'GET', + '/test_endpoint/search/?user=a+user&usage_id=an+usage&course_id=a+course' + ); + AjaxHelpers.respondWithJson(requests, {}); + AjaxHelpers.respondWithJson(requests, {}); expect(errorContainer).not.toHaveClass('annotator-notice-show'); }); diff --git a/lms/static/js/spec/edxnotes/views/tabs/search_results_spec.js b/lms/static/js/spec/edxnotes/views/tabs/search_results_spec.js index 3f01ca9cfe..f828e2d63a 100644 --- a/lms/static/js/spec/edxnotes/views/tabs/search_results_spec.js +++ b/lms/static/js/spec/edxnotes/views/tabs/search_results_spec.js @@ -9,30 +9,30 @@ define([ 'use strict'; describe('EdxNotes SearchResultsView', function() { var notes = [ - { - created: 'December 11, 2014 at 11:12AM', - updated: 'December 11, 2014 at 11:12AM', - text: 'Third added model', - quote: 'Should be listed first' + { + created: 'December 11, 2014 at 11:12AM', + updated: 'December 11, 2014 at 11:12AM', + text: 'Third added model', + quote: 'Should be listed first' + }, + { + created: 'December 11, 2014 at 11:11AM', + updated: 'December 11, 2014 at 11:11AM', + text: 'Second added model', + quote: 'Should be listed second' + }, + { + created: 'December 11, 2014 at 11:10AM', + updated: 'December 11, 2014 at 11:10AM', + text: 'First added model', + quote: 'Should be listed third' + } + ], + responseJson = { + total: 3, + rows: notes }, - { - created: 'December 11, 2014 at 11:11AM', - updated: 'December 11, 2014 at 11:11AM', - text: 'Second added model', - quote: 'Should be listed second' - }, - { - created: 'December 11, 2014 at 11:10AM', - updated: 'December 11, 2014 at 11:10AM', - text: 'First added model', - quote: 'Should be listed third' - } - ], - responseJson = { - total: 3, - rows: notes - }, - getView, submitForm; + getView, submitForm, respondToSearch; getView = function (tabsCollection, options) { options = _.defaults(options || {}, { @@ -50,6 +50,14 @@ define([ searchBox.$('.search-notes-submit').click(); }; + respondToSearch = function(requests, responseJson) { + // First respond to the analytics event + AjaxHelpers.respondWithNoContent(requests); + + // Now process the search request + AjaxHelpers.respondWithJson(requests, responseJson); + }; + beforeEach(function () { customMatchers(this); loadFixtures('js/fixtures/edxnotes/edxnotes.html'); @@ -71,7 +79,7 @@ define([ requests = AjaxHelpers.requests(this); submitForm(view.searchBox, 'second'); - AjaxHelpers.respondWithJson(requests, responseJson); + respondToSearch(requests, responseJson); expect(this.tabsCollection).toHaveLength(1); expect(this.tabsCollection.at(0).toJSON()).toEqual({ @@ -100,7 +108,7 @@ define([ expect(this.tabsCollection).toHaveLength(1); expect(view.searchResults).toBeNull(); expect(view.$('.tab-panel')).not.toExist(); - AjaxHelpers.respondWithJson(requests, responseJson); + respondToSearch(requests, responseJson); expect(view.$('.ui-loading')).toHaveClass('is-hidden'); }); @@ -109,7 +117,7 @@ define([ requests = AjaxHelpers.requests(this); submitForm(view.searchBox, 'some text'); - AjaxHelpers.respondWithJson(requests, { + respondToSearch(requests, { total: 0, rows: [] }); @@ -147,7 +155,7 @@ define([ requests = AjaxHelpers.requests(this); submitForm(view.searchBox, 'test_query'); - AjaxHelpers.respondWithJson(requests, responseJson); + respondToSearch(requests, responseJson); expect(view.searchResults).toBeDefined(); this.tabsCollection.at(0).destroy(); expect(view.searchResults).toBeNull(); @@ -158,6 +166,11 @@ define([ requests = AjaxHelpers.requests(this); submitForm(view.searchBox, 'test error'); + + // First respond to the analytics event + AjaxHelpers.respondWithNoContent(requests); + + // Now respond to the search with a 500 error AjaxHelpers.respondWithError(requests, 500, {error: 'test error message'}); expect(view.$('.wrapper-msg')).not.toHaveClass('is-hidden'); @@ -182,12 +195,12 @@ define([ }]; submitForm(view.searchBox, 'test_query'); - AjaxHelpers.respondWithJson(requests, responseJson); + respondToSearch(requests, responseJson); expect(view.$('.note')).toHaveLength(3); submitForm(view.searchBox, 'new_test_query'); - AjaxHelpers.respondWithJson(requests, { + respondToSearch(requests, { total: 1, rows: newNotes }); diff --git a/lms/static/js/spec/groups/views/cohorts_spec.js b/lms/static/js/spec/groups/views/cohorts_spec.js index 975dfa7491..44ad1d2d3f 100644 --- a/lms/static/js/spec/groups/views/cohorts_spec.js +++ b/lms/static/js/spec/groups/views/cohorts_spec.js @@ -247,8 +247,7 @@ define(['backbone', 'jquery', 'common/js/spec_helpers/ajax_helpers', 'common/js/ }; saveFormAndExpectErrors = function(action, errors) { - var requestCount = requests.length, - form, expectedTitle; + var form, expectedTitle; if (action === 'add') { expectedTitle = 'The cohort cannot be added'; form = getAddModal(); @@ -257,7 +256,7 @@ define(['backbone', 'jquery', 'common/js/spec_helpers/ajax_helpers', 'common/js/ form = cohortsView.$('.cohort-management-settings-form'); } form.find('.action-save').click(); - expect(requests.length).toBe(requestCount); + AjaxHelpers.expectNoRequests(requests); verifyDetailedMessage(expectedTitle, 'error', errors); }; @@ -360,6 +359,9 @@ define(['backbone', 'jquery', 'common/js/spec_helpers/ajax_helpers', 'common/js/ cohortsView.$(fileUploadForm).fileupload('add', {files: [{name: 'upload_file.txt'}]}); cohortsView.$('.submit-file-button').click(); + // Respond to the event request + AjaxHelpers.respondWithNoContent(requests); + // No file will actually be uploaded because "uploaded_file.txt" doesn't actually exist. AjaxHelpers.expectRequest(requests, 'POST', MOCK_UPLOAD_COHORTS_CSV_URL, new FormData()); AjaxHelpers.respondWithJson(requests, {}); @@ -706,7 +708,7 @@ define(['backbone', 'jquery', 'common/js/spec_helpers/ajax_helpers', 'common/js/ it('shows an error when adding with no students specified', function() { createCohortsView(this, {selectCohort: 1}); addStudents(' '); - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); verifyMessage('Enter a username or email.', 'error'); expect(getStudentInput().val()).toBe(''); }); diff --git a/lms/static/js/spec/search/search_spec.js b/lms/static/js/spec/search/search_spec.js index e907d88072..af76009741 100644 --- a/lms/static/js/spec/search/search_spec.js +++ b/lms/static/js/spec/search/search_spec.js @@ -162,16 +162,18 @@ define([ this.collection.performSearch('old search'); this.collection.performSearch('new search'); + AjaxHelpers.skipResetRequest(requests); AjaxHelpers.respondWithJson(requests, response); expect(this.onSearch.calls.length).toEqual(1); this.collection.performSearch('old search'); this.collection.cancelSearch(); - AjaxHelpers.respondWithJson(requests, response); + AjaxHelpers.skipResetRequest(requests); expect(this.onSearch.calls.length).toEqual(1); this.collection.loadNextPage(); this.collection.loadNextPage(); + AjaxHelpers.skipResetRequest(requests); AjaxHelpers.respondWithJson(requests, response); expect(this.onNext.calls.length).toEqual(1); }); diff --git a/lms/static/js/spec/student_account/account_settings_factory_spec.js b/lms/static/js/spec/student_account/account_settings_factory_spec.js index 12cdda51f5..656f696ae8 100644 --- a/lms/static/js/spec/student_account/account_settings_factory_spec.js +++ b/lms/static/js/spec/student_account/account_settings_factory_spec.js @@ -139,6 +139,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData()); AjaxHelpers.respondWithJson(requests, Helpers.createUserPreferencesData()); + AjaxHelpers.respondWithJson(requests, {}); // Page viewed analytics event var sectionsData = accountSettingsView.options.sectionsData; diff --git a/lms/static/js/spec/student_profile/learner_profile_factory_spec.js b/lms/static/js/spec/student_profile/learner_profile_factory_spec.js index c6bc477b38..638a51d48c 100644 --- a/lms/static/js/spec/student_profile/learner_profile_factory_spec.js +++ b/lms/static/js/spec/student_profile/learner_profile_factory_spec.js @@ -42,16 +42,13 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers }); }; - it("renders the full profile after data is successfully fetched", function() { + it("renders the full profile for a user", function() { requests = AjaxHelpers.requests(this); var context = createProfilePage(true), learnerProfileView = context.learnerProfileView; - AjaxHelpers.respondWithJson(requests, Helpers.createAccountSettingsData()); - AjaxHelpers.respondWithJson(requests, Helpers.createUserPreferencesData()); - // sets the profile for full view. context.accountPreferencesModel.set({account_privacy: 'all_users'}); LearnerProfileHelpers.expectProfileSectionsAndFieldsToBeRendered(learnerProfileView, false); diff --git a/lms/static/js/spec/student_profile/learner_profile_fields_spec.js b/lms/static/js/spec/student_profile/learner_profile_fields_spec.js index 694171335c..ab5a86c0e1 100644 --- a/lms/static/js/spec/student_profile/learner_profile_fields_spec.js +++ b/lms/static/js/spec/student_profile/learner_profile_fields_spec.js @@ -110,6 +110,9 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers // Verify image upload progress message verifyImageUploadButtonMessage(imageView, true); + // Respond to the analytics event + AjaxHelpers.respondWithJson(requests, {}); + // Verify if POST request received for image upload AjaxHelpers.expectRequest(requests, 'POST', Helpers.IMAGE_UPLOAD_API_URL, new FormData()); @@ -278,6 +281,9 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers // Verify image upload progress message verifyImageUploadButtonMessage(imageView, true); + // Respond to the analytics event + AjaxHelpers.respondWithJson(requests, {}); + // Verify if POST request received for image upload AjaxHelpers.expectRequest(requests, 'POST', Helpers.IMAGE_UPLOAD_API_URL, new FormData()); diff --git a/lms/static/js/spec/verify_student/make_payment_step_view_spec.js b/lms/static/js/spec/verify_student/make_payment_step_view_spec.js index 7e59684588..44d7403313 100644 --- a/lms/static/js/spec/verify_student/make_payment_step_view_spec.js +++ b/lms/static/js/spec/verify_student/make_payment_step_view_spec.js @@ -83,7 +83,7 @@ define([ // TODO put fixture responses in the right place AjaxHelpers.respondWithJson( requests, {payment_page_url: 'http://payment-page-url/', payment_form_data: {foo: 'bar'}} ); } else { - AjaxHelpers.respondWithTextError( requests, 400, SERVER_ERROR_MSG ); + AjaxHelpers.respondWithTextError( requests, 400, SERVER_ERROR_MSG); } }; @@ -102,7 +102,8 @@ define([ var $el = $( '.payment-button' ); expect($el.length).toEqual(_.size(buttons)); _.each(buttons, function( expectedText, expectedId ) { - var buttonEl = $( '#' + expectedId ); + var buttonEl = $( '#' + expectedId), + request; buttonEl.removeAttr('disabled'); expect( buttonEl.length ).toEqual( 1 ); @@ -112,7 +113,9 @@ define([ buttonEl[0].click(); expect( buttonEl[0] ).toHaveClass( 'is-selected' ); expectPaymentButtonEnabled( false ); - expect(requests[requests.length - 1].requestBody.split('&')).toContain('processor=' + expectedId); + request = AjaxHelpers.currentRequest(requests); + expect(request.requestBody.split('&')).toContain('processor=' + expectedId); + AjaxHelpers.respondWithJson(requests, {}); }); }; diff --git a/lms/static/js/spec/views/fields_helpers.js b/lms/static/js/spec/views/fields_helpers.js index 5d322d2c40..1fe74c2b48 100644 --- a/lms/static/js/spec/views/fields_helpers.js +++ b/lms/static/js/spec/views/fields_helpers.js @@ -154,7 +154,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers view.$(valueInputSelector).val(fieldData.validValue).change(); expect(view.fieldValue()).toBe(fieldData.validValue); expectMessageContains(view, view.helpMessage); - expect(requests.length).toBe(0); + AjaxHelpers.expectNoRequests(requests); }; var verifyEditableField = function (view, data, requests) { diff --git a/lms/static/js/spec/views/file_uploader_spec.js b/lms/static/js/spec/views/file_uploader_spec.js index 0e5e47322c..40d3c0b703 100644 --- a/lms/static/js/spec/views/file_uploader_spec.js +++ b/lms/static/js/spec/views/file_uploader_spec.js @@ -54,6 +54,9 @@ define(['backbone', 'jquery', 'js/views/file_uploader', 'common/js/spec_helpers/ verifySubmitButtonEnabled(true); fileUploaderView.$('.submit-file-button').click(); + // Respond to the analytics event first + AjaxHelpers.respondWithJson(requests, {}); + // No file will actually be uploaded because "uploaded_file.txt" doesn't actually exist. AjaxHelpers.expectRequest(requests, 'POST', url, new FormData()); return requests;