diff --git a/cms/static/js/index.js b/cms/static/js/index.js index 26206859eb..70f036012f 100644 --- a/cms/static/js/index.js +++ b/cms/static/js/index.js @@ -82,7 +82,7 @@ define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape", "js/vie var onReady = function () { $('.new-course-button').bind('click', addNewCourse); $('.dismiss-button').bind('click', ViewUtils.deleteNotificationHandler(function () { - window.location.reload(); + ViewUtils.reload(); })); }; 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 5d5204148d..5a9eb0b87b 100644 --- a/cms/static/js/spec/views/pages/course_rerun_spec.js +++ b/cms/static/js/spec/views/pages/course_rerun_spec.js @@ -1,6 +1,6 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers", "js/views/course_rerun", - "js/views/utils/create_course_utils", "jquery.simulate"], - function ($, create_sinon, view_helpers, CourseRerunUtils, CreateCourseUtilsFactory) { + "js/views/utils/create_course_utils", "js/views/utils/view_utils", "jquery.simulate"], + function ($, create_sinon, view_helpers, CourseRerunUtils, CreateCourseUtilsFactory, ViewUtils) { describe("Create course rerun page", function () { var selectors = { org: '.rerun-course-org', @@ -66,6 +66,11 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers" return element; }; + var type = function (input, value) { + input.val(value); + input.simulate("keyup", { keyCode: $.simulate.keyCode.SPACE }); + }; + it("shows an error message", function () { var element = setErrorMessage(selectors.org, 'error message'); expect(element).toHaveClass(classes.error); @@ -104,15 +109,55 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers" it("shows an error message when non URL characters are entered", function () { var input = $(selectors.org); expect(input.parent()).not.toHaveClass(classes.error); - input.val("%") + type(input, "%"); + expect(input.parent()).toHaveClass(classes.error); + }); + + it("does not show an error message when tabbing into a field", function () { + var input = $(selectors.number); + input.val(''); + expect(input.parent()).not.toHaveClass(classes.error); + input.simulate("keyup", { keyCode: $.simulate.keyCode.TAB }); + expect(input.parent()).not.toHaveClass(classes.error); + }); + + it("shows an error message when a required field is empty", function () { + var input = $(selectors.org); + input.val(''); + expect(input.parent()).not.toHaveClass(classes.error); input.simulate("keyup", { keyCode: $.simulate.keyCode.ENTER }); expect(input.parent()).toHaveClass(classes.error); }); + + it("shows an error message when spaces are entered and unicode is allowed", function () { + var input = $(selectors.org); + $(selectors.allowUnicode).val('True'); + expect(input.parent()).not.toHaveClass(classes.error); + type(input, ' '); + expect(input.parent()).toHaveClass(classes.error); + }); + + it("shows an error message when total length exceeds 65 characters", function () { + expect($(selectors.errorWrapper)).not.toHaveClass(classes.shown); + type($(selectors.org), 'ThisIsAVeryLongNameThatWillExceedTheSixtyFiveCharacterLimit'); + type($(selectors.number), 'ThisIsAVeryLongNameThatWillExceedTheSixtyFiveCharacterLimit'); + type($(selectors.run), 'ThisIsAVeryLongNameThatWillExceedTheSixtyFiveCharacterLimit'); + expect($(selectors.errorWrapper)).toHaveClass(classes.shown); + }); + + describe("Name field", function () { + it("does not show an error message when non URL characters are entered", function () { + var input = $(selectors.name); + expect(input.parent()).not.toHaveClass(classes.error); + type(input, "%"); + expect(input.parent()).not.toHaveClass(classes.error); + }); + }); }); it("saves course reruns", function () { var requests = create_sinon.requests(this); - window.source_course_key = 'test_course_key'; + var redirectSpy = spyOn(ViewUtils, 'redirect') fillInFields('DemoX', 'DM101', '2014', 'Demo course'); $(selectors.save).click(); create_sinon.expectJsonRequest(requests, 'POST', '/course/', { @@ -125,6 +170,10 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers" expect($(selectors.save)).toHaveClass(classes.disabled); expect($(selectors.save)).toHaveClass(classes.processing); expect($(selectors.cancel)).toHaveClass(classes.hidden); + create_sinon.respondWithJson(requests, { + url: 'dummy_test_url' + }); + expect(redirectSpy).toHaveBeenCalledWith('dummy_test_url'); }); it("displays an error when saving fails", function () { @@ -146,5 +195,11 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers" $(selectors.save).click(); expect(requests.length).toBe(0); }); + + it("can be canceled", function () { + var redirectSpy = spyOn(ViewUtils, 'redirect'); + $(selectors.cancel).click(); + expect(redirectSpy).toHaveBeenCalledWith('/course/'); + }); }); }); diff --git a/cms/static/js/spec/views/pages/index_spec.js b/cms/static/js/spec/views/pages/index_spec.js index 5eafbc476d..cadba58a22 100644 --- a/cms/static/js/spec/views/pages/index_spec.js +++ b/cms/static/js/spec/views/pages/index_spec.js @@ -1,7 +1,15 @@ -define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers", "js/index"], - function ($, create_sinon, view_helpers, IndexUtils) { +define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers", "js/index", + "js/views/utils/view_utils"], + function ($, create_sinon, view_helpers, IndexUtils, ViewUtils) { describe("Course listing page", function () { - var mockIndexPageHTML = readFixtures('mock/mock-index-page.underscore'); + var mockIndexPageHTML = readFixtures('mock/mock-index-page.underscore'), fillInFields; + + var fillInFields = function (org, number, run, name) { + $('.new-course-org').val(org); + $('.new-course-number').val(number); + $('.new-course-run').val(run); + $('.new-course-name').val(name); + }; beforeEach(function () { view_helpers.installMockAnalytics(); @@ -16,8 +24,29 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers" it("can dismiss notifications", function () { var requests = create_sinon.requests(this); + var reloadSpy = spyOn(ViewUtils, 'reload'); $('.dismiss-button').click(); create_sinon.expectJsonRequest(requests, 'DELETE', 'dummy_dismiss_url'); + create_sinon.respondToDelete(requests); + expect(reloadSpy).toHaveBeenCalled(); + }); + + it("saves new courses", function () { + var requests = create_sinon.requests(this); + var redirectSpy = spyOn(ViewUtils, 'redirect'); + $('.new-course-button').click() + fillInFields('DemoX', 'DM101', '2014', 'Demo course'); + $('.new-course-save').click(); + create_sinon.expectJsonRequest(requests, 'POST', '/course/', { + org: 'DemoX', + number: 'DM101', + run: '2014', + display_name: 'Demo course' + }); + create_sinon.respondWithJson(requests, { + url: 'dummy_test_url' + }); + expect(redirectSpy).toHaveBeenCalledWith('dummy_test_url'); }); }); - }); \ No newline at end of file + }); diff --git a/cms/static/js/views/course_rerun.js b/cms/static/js/views/course_rerun.js index 60fd88fd7d..bfa6370d1b 100644 --- a/cms/static/js/views/course_rerun.js +++ b/cms/static/js/views/course_rerun.js @@ -1,5 +1,5 @@ -define(["domReady", "jquery", "underscore", "js/views/utils/create_course_utils"], - function (domReady, $, _, CreateCourseUtilsFactory) { +define(["domReady", "jquery", "underscore", "js/views/utils/create_course_utils", "js/views/utils/view_utils"], + function (domReady, $, _, CreateCourseUtilsFactory, ViewUtils) { var CreateCourseUtils = CreateCourseUtilsFactory({ name: '.rerun-course-name', org: '.rerun-course-org', @@ -62,7 +62,7 @@ define(["domReady", "jquery", "underscore", "js/views/utils/create_course_utils" $('#course_rerun_error').html(''); $('wrapper-error').removeClass('is-shown').addClass('is-hidden'); $('.rerun-course-save').off('click'); - window.location.href = '/course/'; + ViewUtils.redirect('/course/'); }; var onReady = function () { diff --git a/cms/static/js/views/utils/create_course_utils.js b/cms/static/js/views/utils/create_course_utils.js index a8959fa247..c712e649d2 100644 --- a/cms/static/js/views/utils/create_course_utils.js +++ b/cms/static/js/views/utils/create_course_utils.js @@ -1,8 +1,8 @@ /** * Provides utilities for validating courses during creation, for both new courses and reruns. */ -define(["jquery", "underscore", "gettext"], - function ($, _, gettext) { +define(["jquery", "underscore", "gettext", "js/views/utils/view_utils"], + function ($, _, gettext, ViewUtils) { return function (selectors, classes) { var validateRequiredField, validateCourseItemEncoding, validateTotalCourseItemsLength, setNewCourseFieldInErr, hasInvalidRequiredFields, createCourse, validateFilledFields, configureHandlers; @@ -84,7 +84,7 @@ define(["jquery", "underscore", "gettext"], courseInfo, function (data) { if (data.url !== undefined) { - window.location = data.url; + ViewUtils.redirect(data.url); } else if (data.ErrMsg !== undefined) { errorHandler(data.ErrMsg); } diff --git a/cms/static/js/views/utils/view_utils.js b/cms/static/js/views/utils/view_utils.js index 9719ea9247..27d969f523 100644 --- a/cms/static/js/views/utils/view_utils.js +++ b/cms/static/js/views/utils/view_utils.js @@ -5,7 +5,7 @@ define(["jquery", "underscore", "gettext", "js/views/feedback_notification", "js function ($, _, gettext, NotificationView, PromptView) { var toggleExpandCollapse, showLoadingIndicator, hideLoadingIndicator, confirmThenRunOperation, runOperationShowingMessage, disableElementWhileRunning, getScrollOffset, setScrollOffset, - setScrollTop, redirect, hasChangedAttributes, deleteNotificationHandler; + setScrollTop, redirect, reload, hasChangedAttributes, deleteNotificationHandler; /** * Toggles the expanded state of the current element. @@ -147,6 +147,13 @@ define(["jquery", "underscore", "gettext", "js/views/feedback_notification", "js window.location = url; }; + /** + * Reloads the page. This is broken out as its own function for unit testing. + */ + reload = function() { + window.location.reload(); + }; + /** * Returns true if a model has changes to at least one of the specified attributes. * @param model The model in question. @@ -178,6 +185,7 @@ define(["jquery", "underscore", "gettext", "js/views/feedback_notification", "js 'getScrollOffset': getScrollOffset, 'setScrollOffset': setScrollOffset, 'redirect': redirect, + 'reload': reload, 'hasChangedAttributes': hasChangedAttributes }; });