+ Provide identifying information for this re-run of the course. The original course is not affected in any way by a re-run. + Note: Together, the organization, course number, and course run must uniquely identify this new course instance. +
+
diff --git a/cms/static/coffee/spec/main.coffee b/cms/static/coffee/spec/main.coffee index 2854eabe34..d80ab05764 100644 --- a/cms/static/coffee/spec/main.coffee +++ b/cms/static/coffee/spec/main.coffee @@ -233,6 +233,7 @@ define([ "js/spec/views/pages/container_subviews_spec", "js/spec/views/pages/group_configurations_spec", "js/spec/views/pages/course_outline_spec", + "js/spec/views/pages/course_rerun_spec", "js/spec/views/modals/base_modal_spec", "js/spec/views/modals/edit_xblock_spec", diff --git a/cms/static/js/spec/views/pages/course_rerun_spec.js b/cms/static/js/spec/views/pages/course_rerun_spec.js new file mode 100644 index 0000000000..077c395313 --- /dev/null +++ b/cms/static/js/spec/views/pages/course_rerun_spec.js @@ -0,0 +1,133 @@ +define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers", "js/views/course_rerun"], + function ($, create_sinon, view_helpers, CourseRerunPage) { + describe("Create course rerun page", function () { + var selectors = { + courseOrg: '.rerun-course-org', + courseNumber: '.rerun-course-number', + courseRun: '.rerun-course-run', + courseName: '.rerun-course-name', + errorField: '.tip-error', + saveButton: '.rerun-course-save', + cancelButton: '.rerun-course-cancel', + errorMessage: '.wrapper-error' + }, + classes = { + hidden: 'is-hidden', + error: 'error', + disabled: 'is-disabled', + processing: 'is-processing' + }, + mockCreateCourseRerunHTML = readFixtures('mock/mock-create-course-rerun.underscore'); + + var fillInFields = function (org, number, run, name) { + $(selectors.courseOrg).val(org); + $(selectors.courseNumber).val(number); + $(selectors.courseRun).val(run); + $(selectors.courseName).val(name); + }; + + beforeEach(function () { + view_helpers.installMockAnalytics(); + window.source_course_key = 'test_course_key'; + appendSetFixtures(mockCreateCourseRerunHTML); + CourseRerunPage.onReady(); + }); + + afterEach(function () { + view_helpers.removeMockAnalytics(); + delete window.source_course_key; + }); + + describe("validateRequiredField", function () { + it("has a message for an empty string", function () { + var message = CourseRerunPage.validateRequiredField(''); + expect(message).not.toBe(''); + }); + + it("does not have a message for a non empty string", function () { + var message = CourseRerunPage.validateRequiredField('edX'); + expect(message).toBe(''); + }); + }); + + describe("setNewCourseFieldInErr", function () { + var setErrorMessage = function(selector, message) { + var element = $(selector).parent(); + CourseRerunPage.setNewCourseFieldInErr(element, message); + return element; + }; + + it("can show an error message", function () { + var element = setErrorMessage(selectors.courseOrg, 'error message'); + expect(element).toHaveClass(classes.error); + expect(element.children(selectors.errorField)).not.toHaveClass(classes.hidden); + expect(element.children(selectors.errorField)).toContainText('error message'); + }); + + it("can hide an error message", function () { + var element = setErrorMessage(selectors.courseOrg, ''); + expect(element).not.toHaveClass(classes.error); + expect(element.children(selectors.errorField)).toHaveClass(classes.hidden); + }); + + it("disables the save button", function () { + setErrorMessage(selectors.courseOrg, 'error message'); + expect($(selectors.saveButton)).toHaveClass(classes.disabled); + }); + + it("enables the save button when all errors are removed", function () { + setErrorMessage(selectors.courseOrg, 'error message 1'); + setErrorMessage(selectors.courseNumber, 'error message 2'); + expect($(selectors.saveButton)).toHaveClass(classes.disabled); + setErrorMessage(selectors.courseOrg, ''); + setErrorMessage(selectors.courseNumber, ''); + expect($(selectors.saveButton)).not.toHaveClass(classes.disabled); + }); + + it("does not enable the save button when errors remain", function () { + setErrorMessage(selectors.courseOrg, 'error message 1'); + setErrorMessage(selectors.courseNumber, 'error message 2'); + expect($(selectors.saveButton)).toHaveClass(classes.disabled); + setErrorMessage(selectors.courseOrg, ''); + expect($(selectors.saveButton)).toHaveClass(classes.disabled); + }); + }); + + it("can save course reruns", function () { + var requests = create_sinon.requests(this); + window.source_course_key = 'test_course_key'; + fillInFields('DemoX', 'DM101', '2014', 'Demo course'); + $(selectors.saveButton).click(); + create_sinon.expectJsonRequest(requests, 'POST', '/course/', { + source_course_key: 'test_course_key', + org: 'DemoX', + number: 'DM101', + run: '2014', + display_name: 'Demo course' + }); + expect($(selectors.saveButton)).toHaveClass(classes.disabled); + expect($(selectors.saveButton)).toHaveClass(classes.processing); + expect($(selectors.cancelButton)).toHaveClass(classes.hidden); + }); + + it("displays an error when saving fails", function () { + var requests = create_sinon.requests(this); + fillInFields('DemoX', 'DM101', '2014', 'Demo course'); + $(selectors.saveButton).click(); + create_sinon.respondWithJson(requests, { + ErrMsg: 'error message' + }); + expect($(selectors.errorMessage)).not.toHaveClass(classes.hidden); + expect($(selectors.errorMessage)).toContainText('error message'); + expect($(selectors.saveButton)).not.toHaveClass(classes.processing); + expect($(selectors.cancelButton)).not.toHaveClass(classes.hidden); + }); + + it("does not save if there are validation errors", function () { + var requests = create_sinon.requests(this); + fillInFields('DemoX', 'DM101', '', 'Demo course'); + $(selectors.saveButton).click(); + expect(requests.length).toBe(0); + }); + }); + }); diff --git a/cms/static/js/views/course_rerun.js b/cms/static/js/views/course_rerun.js index 7361a8303a..57bba6351c 100644 --- a/cms/static/js/views/course_rerun.js +++ b/cms/static/js/views/course_rerun.js @@ -1,4 +1,4 @@ -require(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"], +define(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"], function (domReady, $, _, CancelOnEscape) { var saveRerunCourse = function (e) { @@ -87,7 +87,7 @@ require(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"], } }; - domReady(function () { + var onReady = function () { var $cancelButton = $('.rerun-course-cancel'); var $courseRun = $('.rerun-course-run'); $courseRun.focus().select(); @@ -175,5 +175,16 @@ require(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"], $('.rerun-course-save').addClass('is-disabled'); } }); - }); + }; + + domReady(onReady); + + // Return these functions so that they can be tested + return { + saveRerunCourse: saveRerunCourse, + cancelRerunCourse: cancelRerunCourse, + validateRequiredField: validateRequiredField, + setNewCourseFieldInErr: setNewCourseFieldInErr, + onReady: onReady + }; }); diff --git a/cms/templates/js/mock/mock-create-course-rerun.underscore b/cms/templates/js/mock/mock-create-course-rerun.underscore new file mode 100644 index 0000000000..43b9ff0b26 --- /dev/null +++ b/cms/templates/js/mock/mock-create-course-rerun.underscore @@ -0,0 +1,116 @@ +
+ Provide identifying information for this re-run of the course. The original course is not affected in any way by a re-run. + Note: Together, the organization, course number, and course run must uniquely identify this new course instance. +
+