');
+ programCollection = new ProgramCollection(context.programsData);
+ view = new CollectionListView({
+ el: '.program-cards-container',
+ childView: ProgramCardView,
+ context,
+ collection: programCollection,
+ titleContext,
+ });
+ view.render();
+ const $title = view.$el.parent().find('.collection-title');
+ expect($title.html()).toBe(titleContext.title);
+ });
+});
diff --git a/lms/static/js/learner_dashboard/spec/course_card_view_spec.js b/lms/static/js/learner_dashboard/spec/course_card_view_spec.js
new file mode 100644
index 0000000000..726dc2b70b
--- /dev/null
+++ b/lms/static/js/learner_dashboard/spec/course_card_view_spec.js
@@ -0,0 +1,267 @@
+/* globals setFixtures */
+
+import CourseCardModel from '../models/course_card_model';
+import CourseCardView from '../views/course_card_view';
+
+describe('Course Card View', () => {
+ let view = null;
+ let courseCardModel;
+ let course;
+ const startDate = 'Feb 28, 2017';
+ const endDate = 'May 30, 2017';
+
+ const setupView = (data, isEnrolled, collectionCourseStatus) => {
+ const programData = $.extend({}, data);
+ const context = {
+ courseData: {
+ grades: {
+ 'course-v1:WageningenX+FFESx+1T2017': 0.8,
+ },
+ },
+ collectionCourseStatus,
+ };
+
+ if (typeof collectionCourseStatus === 'undefined') {
+ context.collectionCourseStatus = 'completed';
+ }
+
+ programData.course_runs[0].is_enrolled = isEnrolled;
+ setFixtures('');
+ courseCardModel = new CourseCardModel(programData);
+ view = new CourseCardView({
+ model: courseCardModel,
+ context,
+ });
+ };
+
+ const validateCourseInfoDisplay = () => {
+ // DRY validation for course card in enrolled state
+ expect(view.$('.course-details .course-title-link').text().trim()).toEqual(course.title);
+ expect(view.$('.course-details .course-title-link').attr('href')).toEqual(
+ course.course_runs[0].marketing_url,
+ );
+ expect(view.$('.course-details .course-text .run-period').html()).toEqual(
+ `${startDate} - ${endDate}`,
+ );
+ };
+
+ beforeEach(() => {
+ // NOTE: This data is redefined prior to each test case so that tests
+ // can't break each other by modifying data copied by reference.
+ course = {
+ key: 'WageningenX+FFESx',
+ uuid: '9f8562eb-f99b-45c7-b437-799fd0c15b6a',
+ title: 'Systems thinking and environmental sustainability',
+ course_runs: [
+ {
+ key: 'course-v1:WageningenX+FFESx+1T2017',
+ title: 'Food Security and Sustainability: Systems thinking and environmental sustainability',
+ image: {
+ src: 'https://example.com/9f8562eb-f99b-45c7-b437-799fd0c15b6a.jpg',
+ },
+ marketing_url: 'https://www.edx.org/course/food-security-sustainability',
+ start: '2017-02-28T05:00:00Z',
+ end: '2017-05-30T23:00:00Z',
+ enrollment_start: '2017-01-18T00:00:00Z',
+ enrollment_end: null,
+ type: 'verified',
+ certificate_url: '',
+ course_url: 'https://courses.example.com/courses/course-v1:WageningenX+FFESx+1T2017',
+ enrollment_open_date: 'Jan 18, 2016',
+ is_course_ended: false,
+ is_enrolled: true,
+ is_enrollment_open: true,
+ status: 'published',
+ upgrade_url: '',
+ },
+ ],
+ };
+
+ setupView(course, true);
+ });
+
+ afterEach(() => {
+ view.remove();
+ });
+
+ it('should exist', () => {
+ expect(view).toBeDefined();
+ });
+
+ it('should render final grade if course is completed', () => {
+ view.remove();
+ setupView(course, true);
+ expect(view.$('.grade-display').text()).toEqual('80%');
+ });
+
+ it('should not render final grade if course has not been completed', () => {
+ view.remove();
+ setupView(course, true, 'in_progress');
+ expect(view.$('.final-grade').length).toEqual(0);
+ });
+
+ it('should render the course card based on the data not enrolled', () => {
+ view.remove();
+ setupView(course, false);
+ validateCourseInfoDisplay();
+ });
+
+ it('should update render if the course card is_enrolled updated', () => {
+ setupView(course, false);
+ courseCardModel.set({
+ is_enrolled: true,
+ });
+ validateCourseInfoDisplay();
+ });
+
+ it('should show the course advertised start date', () => {
+ const advertisedStart = 'A long time ago...';
+ course.course_runs[0].advertised_start = advertisedStart;
+
+ setupView(course, false);
+
+ expect(view.$('.course-details .course-text .run-period').html()).toEqual(
+ `${advertisedStart} - ${endDate}`,
+ );
+ });
+
+ it('should only show certificate status section if a certificate has been earned', () => {
+ const certUrl = 'sample-certificate';
+
+ expect(view.$('.course-certificate .certificate-status').length).toEqual(0);
+ view.remove();
+
+ course.course_runs[0].certificate_url = certUrl;
+ setupView(course, false);
+ expect(view.$('.course-certificate .certificate-status').length).toEqual(1);
+ });
+
+ it('should only show upgrade message section if an upgrade is required', () => {
+ const upgradeUrl = '/path/to/upgrade';
+
+ expect(view.$('.upgrade-message').length).toEqual(0);
+ view.remove();
+
+ course.course_runs[0].upgrade_url = upgradeUrl;
+ setupView(course, false);
+ expect(view.$('.upgrade-message').length).toEqual(1);
+ expect(view.$('.upgrade-message .cta-primary').attr('href')).toEqual(upgradeUrl);
+ });
+
+ it('should not show both the upgrade message and certificate status sections', () => {
+ // Verify that no empty elements are left in the DOM.
+ course.course_runs[0].upgrade_url = '';
+ course.course_runs[0].certificate_url = '';
+ setupView(course, false);
+ expect(view.$('.upgrade-message').length).toEqual(0);
+ expect(view.$('.course-certificate .certificate-status').length).toEqual(0);
+ view.remove();
+
+ // Verify that the upgrade message takes priority.
+ course.course_runs[0].upgrade_url = '/path/to/upgrade';
+ course.course_runs[0].certificate_url = '/path/to/certificate';
+ setupView(course, false);
+ expect(view.$('.upgrade-message').length).toEqual(1);
+ expect(view.$('.course-certificate .certificate-status').length).toEqual(0);
+ });
+
+ it('should allow enrollment in future runs when the user has an expired enrollment', () => {
+ const newRun = $.extend({}, course.course_runs[0]);
+ const newRunKey = 'course-v1:foo+bar+baz';
+ const advertisedStart = 'Summer';
+
+ newRun.key = newRunKey;
+ newRun.is_enrolled = false;
+ newRun.advertised_start = advertisedStart;
+ course.course_runs.push(newRun);
+
+ course.expired = true;
+
+ setupView(course, true);
+
+ expect(courseCardModel.get('course_run_key')).toEqual(newRunKey);
+ expect(view.$('.course-details .course-text .run-period').html()).toEqual(
+ `${advertisedStart} - ${endDate}`,
+ );
+ });
+
+ it('should show a message if an there is an upcoming course run', () => {
+ course.course_runs[0].is_enrollment_open = false;
+
+ setupView(course, false);
+
+ expect(view.$('.course-details .course-title').text().trim()).toEqual(course.title);
+ expect(view.$('.course-details .course-text .run-period').length).toBe(0);
+ expect(view.$('.no-action-message').text().trim()).toBe('Coming Soon');
+ expect(view.$('.enrollment-open-date').text().trim()).toEqual(
+ course.course_runs[0].enrollment_open_date,
+ );
+ });
+
+ it('should show a message if there are no upcoming course runs', () => {
+ course.course_runs[0].is_enrollment_open = false;
+ course.course_runs[0].is_course_ended = true;
+
+ setupView(course, false);
+
+ expect(view.$('.course-details .course-title').text().trim()).toEqual(course.title);
+ expect(view.$('.course-details .course-text .run-period').length).toBe(0);
+ expect(view.$('.no-action-message').text().trim()).toBe('Not Currently Available');
+ expect(view.$('.enrollment-opens').length).toEqual(0);
+ });
+
+ it('should link to the marketing site when the user is not enrolled', () => {
+ setupView(course, false);
+ expect(view.$('.course-title-link').attr('href')).toEqual(course.course_runs[0].marketing_url);
+ });
+
+ it('should link to the course home when the user is enrolled', () => {
+ setupView(course, true);
+ expect(view.$('.course-title-link').attr('href')).toEqual(course.course_runs[0].course_url);
+ });
+
+ it('should not link to the marketing site if the URL is not available', () => {
+ course.course_runs[0].marketing_url = null;
+ setupView(course, false);
+
+ expect(view.$('.course-title-link').length).toEqual(0);
+ });
+
+ it('should not link to the course home if the URL is not available', () => {
+ course.course_runs[0].course_url = null;
+ setupView(course, true);
+
+ expect(view.$('.course-title-link').length).toEqual(0);
+ });
+
+ it('should show an unfulfilled user entitlement allows you to select a session', () => {
+ course.user_entitlement = {
+ uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
+ course_uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
+ expiration_date: '2017-12-05 01:06:12',
+ };
+ setupView(course, false);
+ expect(view.$('.info-expires-at').text().trim()).toContain('You must select a session by');
+ });
+
+ it('should show a fulfilled expired user entitlement does not allow the changing of sessions', () => {
+ course.user_entitlement = {
+ uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
+ course_uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
+ expired_at: '2017-12-06 01:06:12',
+ expiration_date: '2017-12-05 01:06:12',
+ };
+ setupView(course, true);
+ expect(view.$('.info-expires-at').text().trim()).toContain('You can no longer change sessions.');
+ });
+
+ it('should show a fulfilled user entitlement allows the changing of sessions', () => {
+ course.user_entitlement = {
+ uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
+ course_uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
+ expiration_date: '2017-12-05 01:06:12',
+ };
+ setupView(course, true);
+ expect(view.$('.info-expires-at').text().trim()).toContain('You can change sessions until');
+ });
+});
diff --git a/lms/static/js/learner_dashboard/spec/course_enroll_view_spec.js b/lms/static/js/learner_dashboard/spec/course_enroll_view_spec.js
new file mode 100644
index 0000000000..4f07849843
--- /dev/null
+++ b/lms/static/js/learner_dashboard/spec/course_enroll_view_spec.js
@@ -0,0 +1,303 @@
+/* globals setFixtures */
+
+import Backbone from 'backbone';
+
+import CourseCardModel from '../models/course_card_model';
+import CourseEnrollModel from '../models/course_enroll_model';
+import CourseEnrollView from '../views/course_enroll_view';
+
+describe('Course Enroll View', () => {
+ let view = null;
+ let courseCardModel;
+ let courseEnrollModel;
+ let urlModel;
+ let singleCourseRunList;
+ let multiCourseRunList;
+ const course = {
+ key: 'WageningenX+FFESx',
+ uuid: '9f8562eb-f99b-45c7-b437-799fd0c15b6a',
+ title: 'Systems thinking and environmental sustainability',
+ owners: [
+ {
+ uuid: '0c6e5fa2-96e8-40b2-9ebe-c8b0df2a3b22',
+ key: 'WageningenX',
+ name: 'Wageningen University & Research',
+ },
+ ],
+ };
+ const urls = {
+ commerce_api_url: '/commerce',
+ track_selection_url: '/select_track/course/',
+ };
+
+ beforeEach(() => {
+ // Stub analytics tracking
+ window.analytics = jasmine.createSpyObj('analytics', ['track']);
+
+ // NOTE: This data is redefined prior to each test case so that tests
+ // can't break each other by modifying data copied by reference.
+ singleCourseRunList = [{
+ key: 'course-v1:WageningenX+FFESx+1T2017',
+ uuid: '2f2edf03-79e6-4e39-aef0-65436a6ee344',
+ title: 'Food Security and Sustainability: Systems thinking and environmental sustainability',
+ image: {
+ src: 'https://example.com/2f2edf03-79e6-4e39-aef0-65436a6ee344.jpg',
+ },
+ marketing_url: 'https://www.edx.org/course/food-security-sustainability-systems-wageningenx-ffesx',
+ start: '2017-02-28T05:00:00Z',
+ end: '2017-05-30T23:00:00Z',
+ enrollment_start: '2017-01-18T00:00:00Z',
+ enrollment_end: null,
+ type: 'verified',
+ certificate_url: '',
+ course_url: 'https://courses.example.com/courses/course-v1:edX+DemoX+Demo_Course',
+ enrollment_open_date: 'Jan 18, 2016',
+ is_course_ended: false,
+ is_enrolled: false,
+ is_enrollment_open: true,
+ status: 'published',
+ upgrade_url: '',
+ }];
+
+ multiCourseRunList = [{
+ key: 'course-v1:WageningenX+FFESx+2T2016',
+ uuid: '9bbb7844-4848-44ab-8e20-0be6604886e9',
+ title: 'Food Security and Sustainability: Systems thinking and environmental sustainability',
+ image: {
+ src: 'https://example.com/9bbb7844-4848-44ab-8e20-0be6604886e9.jpg',
+ },
+ short_description: 'Learn how to apply systems thinking to improve food production systems.',
+ marketing_url: 'https://www.edx.org/course/food-security-sustainability-systems-wageningenx-stesx',
+ start: '2016-09-08T04:00:00Z',
+ end: '2016-11-11T00:00:00Z',
+ enrollment_start: null,
+ enrollment_end: null,
+ pacing_type: 'instructor_paced',
+ type: 'verified',
+ certificate_url: '',
+ course_url: 'https://courses.example.com/courses/course-v1:WageningenX+FFESx+2T2016',
+ enrollment_open_date: 'Jan 18, 2016',
+ is_course_ended: false,
+ is_enrolled: false,
+ is_enrollment_open: true,
+ status: 'published',
+ }, {
+ key: 'course-v1:WageningenX+FFESx+1T2017',
+ uuid: '2f2edf03-79e6-4e39-aef0-65436a6ee344',
+ title: 'Food Security and Sustainability: Systems thinking and environmental sustainability',
+ image: {
+ src: 'https://example.com/2f2edf03-79e6-4e39-aef0-65436a6ee344.jpg',
+ },
+ marketing_url: 'https://www.edx.org/course/food-security-sustainability-systems-wageningenx-ffesx',
+ start: '2017-02-28T05:00:00Z',
+ end: '2017-05-30T23:00:00Z',
+ enrollment_start: '2017-01-18T00:00:00Z',
+ enrollment_end: null,
+ type: 'verified',
+ certificate_url: '',
+ course_url: 'https://courses.example.com/courses/course-v1:WageningenX+FFESx+1T2017',
+ enrollment_open_date: 'Jan 18, 2016',
+ is_course_ended: false,
+ is_enrolled: false,
+ is_enrollment_open: true,
+ status: 'published',
+ }];
+ });
+
+ const setupView = (courseRuns, urlMap) => {
+ course.course_runs = courseRuns;
+ setFixtures('');
+ courseCardModel = new CourseCardModel(course);
+ courseEnrollModel = new CourseEnrollModel({}, {
+ courseId: courseCardModel.get('course_run_key'),
+ });
+ if (urlMap) {
+ urlModel = new Backbone.Model(urlMap);
+ }
+ view = new CourseEnrollView({
+ $parentEl: $('.course-actions'),
+ model: courseCardModel,
+ enrollModel: courseEnrollModel,
+ urlModel,
+ });
+ };
+
+ afterEach(() => {
+ view.remove();
+ urlModel = null;
+ courseCardModel = null;
+ courseEnrollModel = null;
+ });
+
+ it('should exist', () => {
+ setupView(singleCourseRunList);
+ expect(view).toBeDefined();
+ });
+
+ it('should render the course enroll view when not enrolled', () => {
+ setupView(singleCourseRunList);
+ expect(view.$('.enroll-button').text().trim()).toEqual('Enroll Now');
+ expect(view.$('.run-select').length).toBe(0);
+ });
+
+ it('should render the course enroll view when enrolled', () => {
+ singleCourseRunList[0].is_enrolled = true;
+
+ setupView(singleCourseRunList);
+ expect(view.$('.view-course-button').text().trim()).toEqual('View Course');
+ expect(view.$('.run-select').length).toBe(0);
+ });
+
+ it('should not render anything if course runs are empty', () => {
+ setupView([]);
+
+ expect(view.$('.run-select').length).toBe(0);
+ expect(view.$('.enroll-button').length).toBe(0);
+ });
+
+ it('should render run selection dropdown if multiple course runs are available', () => {
+ setupView(multiCourseRunList);
+
+ expect(view.$('.run-select').length).toBe(1);
+ expect(view.$('.run-select').val()).toEqual(multiCourseRunList[0].key);
+ expect(view.$('.run-select option').length).toBe(2);
+ });
+
+ it('should not allow enrollment in unpublished course runs', () => {
+ multiCourseRunList[0].status = 'unpublished';
+
+ setupView(multiCourseRunList);
+ expect(view.$('.run-select').length).toBe(0);
+ expect(view.$('.enroll-button').length).toBe(1);
+ });
+
+ it('should not allow enrollment in course runs with a null status', () => {
+ multiCourseRunList[0].status = null;
+
+ setupView(multiCourseRunList);
+ expect(view.$('.run-select').length).toBe(0);
+ expect(view.$('.enroll-button').length).toBe(1);
+ });
+
+ it('should enroll learner when enroll button is clicked with one course run available', () => {
+ setupView(singleCourseRunList);
+
+ expect(view.$('.enroll-button').length).toBe(1);
+
+ spyOn(courseEnrollModel, 'save');
+
+ view.$('.enroll-button').click();
+
+ expect(courseEnrollModel.save).toHaveBeenCalled();
+ });
+
+ it('should enroll learner when enroll button is clicked with multiple course runs available', () => {
+ setupView(multiCourseRunList);
+
+ spyOn(courseEnrollModel, 'save');
+
+ view.$('.run-select').val(multiCourseRunList[1].key);
+ view.$('.run-select').trigger('change');
+ view.$('.enroll-button').click();
+
+ expect(courseEnrollModel.save).toHaveBeenCalled();
+ });
+
+ it('should redirect to track selection when audit enrollment succeeds', () => {
+ singleCourseRunList[0].is_enrolled = false;
+ singleCourseRunList[0].mode_slug = 'audit';
+
+ setupView(singleCourseRunList, urls);
+
+ expect(view.$('.enroll-button').length).toBe(1);
+ expect(view.trackSelectionUrl).toBeDefined();
+
+ spyOn(CourseEnrollView, 'redirect');
+
+ view.enrollSuccess();
+
+ expect(CourseEnrollView.redirect).toHaveBeenCalledWith(
+ view.trackSelectionUrl + courseCardModel.get('course_run_key'));
+ });
+
+ it('should redirect to track selection when enrollment in an unspecified mode is attempted', () => {
+ singleCourseRunList[0].is_enrolled = false;
+ singleCourseRunList[0].mode_slug = null;
+
+ setupView(singleCourseRunList, urls);
+
+ expect(view.$('.enroll-button').length).toBe(1);
+ expect(view.trackSelectionUrl).toBeDefined();
+
+ spyOn(CourseEnrollView, 'redirect');
+
+ view.enrollSuccess();
+
+ expect(CourseEnrollView.redirect).toHaveBeenCalledWith(
+ view.trackSelectionUrl + courseCardModel.get('course_run_key'),
+ );
+ });
+
+ it('should not redirect when urls are not provided', () => {
+ singleCourseRunList[0].is_enrolled = false;
+ singleCourseRunList[0].mode_slug = 'verified';
+
+ setupView(singleCourseRunList);
+
+ expect(view.$('.enroll-button').length).toBe(1);
+ expect(view.verificationUrl).not.toBeDefined();
+ expect(view.dashboardUrl).not.toBeDefined();
+ expect(view.trackSelectionUrl).not.toBeDefined();
+
+ spyOn(CourseEnrollView, 'redirect');
+
+ view.enrollSuccess();
+
+ expect(CourseEnrollView.redirect).not.toHaveBeenCalled();
+ });
+
+ it('should redirect to track selection on error', () => {
+ setupView(singleCourseRunList, urls);
+
+ expect(view.$('.enroll-button').length).toBe(1);
+ expect(view.trackSelectionUrl).toBeDefined();
+
+ spyOn(CourseEnrollView, 'redirect');
+
+ view.enrollError(courseEnrollModel, { status: 500 });
+ expect(CourseEnrollView.redirect).toHaveBeenCalledWith(
+ view.trackSelectionUrl + courseCardModel.get('course_run_key'),
+ );
+ });
+
+ it('should redirect to login on 403 error', () => {
+ const response = {
+ status: 403,
+ responseJSON: {
+ user_message_url: 'redirect/to/this',
+ },
+ };
+
+ setupView(singleCourseRunList, urls);
+
+ expect(view.$('.enroll-button').length).toBe(1);
+ expect(view.trackSelectionUrl).toBeDefined();
+
+ spyOn(CourseEnrollView, 'redirect');
+
+ view.enrollError(courseEnrollModel, response);
+
+ expect(CourseEnrollView.redirect).toHaveBeenCalledWith(
+ response.responseJSON.user_message_url,
+ );
+ });
+
+ it('sends analytics event when enrollment succeeds', () => {
+ setupView(singleCourseRunList, urls);
+ spyOn(CourseEnrollView, 'redirect');
+ view.enrollSuccess();
+ expect(window.analytics.track).toHaveBeenCalledWith(
+ 'edx.bi.user.program-details.enrollment',
+ );
+ });
+});
diff --git a/lms/static/js/learner_dashboard/spec/course_entitlement_view_spec.js b/lms/static/js/learner_dashboard/spec/course_entitlement_view_spec.js
new file mode 100644
index 0000000000..253a6acfaa
--- /dev/null
+++ b/lms/static/js/learner_dashboard/spec/course_entitlement_view_spec.js
@@ -0,0 +1,178 @@
+/* globals setFixtures */
+
+import _ from 'underscore';
+
+import CourseEntitlementView from '../views/course_entitlement_view';
+
+describe('Course Entitlement View', () => {
+ let view = null;
+ let sessionIndex;
+ let selectOptions;
+ let entitlementAvailableSessions;
+ let initialSessionId;
+ let alreadyEnrolled;
+ let hasSessions;
+ const entitlementUUID = 'a9aiuw76a4ijs43u18';
+ const testSessionIds = ['test_session_id_1', 'test_session_id_2'];
+
+ const setupView = (isAlreadyEnrolled, hasAvailableSessions, specificSessionIndex) => {
+ setFixtures('');
+ alreadyEnrolled = (typeof isAlreadyEnrolled !== 'undefined') ? isAlreadyEnrolled : true;
+ hasSessions = (typeof hasAvailableSessions !== 'undefined') ? hasAvailableSessions : true;
+ sessionIndex = (typeof specificSessionIndex !== 'undefined') ? specificSessionIndex : 0;
+
+ initialSessionId = alreadyEnrolled ? testSessionIds[sessionIndex] : '';
+ entitlementAvailableSessions = [];
+ if (hasSessions) {
+ entitlementAvailableSessions = [{
+ enrollment_end: null,
+ start: '2016-02-05T05:00:00+00:00',
+ pacing_type: 'instructor_paced',
+ session_id: testSessionIds[0],
+ end: null,
+ }, {
+ enrollment_end: '2019-12-22T03:30:00Z',
+ start: '2020-01-03T13:00:00+00:00',
+ pacing_type: 'self_paced',
+ session_id: testSessionIds[1],
+ end: '2020-03-09T21:30:00+00:00',
+ }];
+ }
+
+ view = new CourseEntitlementView({
+ el: '.course-entitlement-selection-container',
+ triggerOpenBtn: '#course-card-0 .change-session',
+ courseCardMessages: '#course-card-0 .messages-list > .message',
+ courseTitleLink: '#course-card-0 .course-title a',
+ courseImageLink: '#course-card-0 .wrapper-course-image > a',
+ dateDisplayField: '#course-card-0 .info-date-block',
+ enterCourseBtn: '#course-card-0 .enter-course',
+ availableSessions: JSON.stringify(entitlementAvailableSessions),
+ entitlementUUID,
+ currentSessionId: initialSessionId,
+ userId: '1',
+ enrollUrl: '/api/enrollment/v1/enrollment',
+ courseHomeUrl: '/courses/course-v1:edX+DemoX+Demo_Course/course/',
+ });
+ };
+
+ afterEach(() => {
+ if (view) view.remove();
+ });
+
+ describe('Initialization of view', () => {
+ it('Should create a entitlement view element', () => {
+ setupView(false);
+ expect(view).toBeDefined();
+ });
+ });
+
+ describe('Available Sessions Select - Unfulfilled Entitlement', () => {
+ beforeEach(() => {
+ setupView(false);
+ selectOptions = view.$('.session-select').find('option');
+ });
+
+ it('Select session dropdown should show all available course runs and a coming soon option.', () => {
+ expect(selectOptions.length).toEqual(entitlementAvailableSessions.length + 1);
+ });
+
+ it('Self paced courses should have visual indication in the selection option.', () => {
+ const selfPacedOptionIndex = _.findIndex(entitlementAvailableSessions, session => session.pacing_type === 'self_paced');
+ const selfPacedOption = selectOptions[selfPacedOptionIndex];
+ expect(selfPacedOption && selfPacedOption.text.includes('(Self-paced)')).toBe(true);
+ });
+
+ it('Courses with an an enroll by date should indicate so on the selection option.', () => {
+ const enrollEndSetOptionIndex = _.findIndex(entitlementAvailableSessions,
+ session => session.enrollment_end !== null);
+ const enrollEndSetOption = selectOptions[enrollEndSetOptionIndex];
+ expect(enrollEndSetOption && enrollEndSetOption.text.includes('Open until')).toBe(true);
+ });
+
+ it('Title element should correctly indicate the expected behavior.', () => {
+ expect(view.$('.action-header').text().includes(
+ 'To access the course, select a session.',
+ )).toBe(true);
+ });
+ });
+
+ describe('Available Sessions Select - Unfulfilled Entitlement without available sessions', () => {
+ beforeEach(() => {
+ setupView(false, false);
+ });
+
+ it('Should notify user that more sessions are coming soon if none available.', () => {
+ expect(view.$('.action-header').text().includes('More sessions coming soon.')).toBe(true);
+ });
+ });
+
+ describe('Available Sessions Select - Fulfilled Entitlement', () => {
+ beforeEach(() => {
+ setupView(true);
+ selectOptions = view.$('.session-select').find('option');
+ });
+
+ it('Select session dropdown should show available course runs, coming soon and leave options.', () => {
+ expect(selectOptions.length).toEqual(entitlementAvailableSessions.length + 2);
+ });
+
+ it('Select session dropdown should allow user to leave the current session.', () => {
+ const leaveSessionOption = selectOptions[selectOptions.length - 1];
+ expect(leaveSessionOption.text.includes('Leave the current session and decide later')).toBe(true);
+ });
+
+ it('Currently selected session should be specified in the dropdown options.', () => {
+ const selectedSessionIndex = _.findIndex(entitlementAvailableSessions,
+ session => initialSessionId === session.session_id);
+ expect(selectOptions[selectedSessionIndex].text.includes('Currently Selected')).toBe(true);
+ });
+
+ it('Title element should correctly indicate the expected behavior.', () => {
+ expect(view.$('.action-header').text().includes(
+ 'Change to a different session or leave the current session.',
+ )).toBe(true);
+ });
+ });
+
+ describe('Available Sessions Select - Fulfilled Entitlement (session in the future)', () => {
+ beforeEach(() => {
+ setupView(true, true, 1);
+ });
+
+ it('Currently selected session should initialize to selected in the dropdown options.', () => {
+ const selectedOption = view.$('.session-select').find('option:selected');
+ expect(selectedOption.data('session_id')).toEqual(testSessionIds[1]);
+ });
+ });
+
+ describe('Select Session Action Button and popover behavior - Unfulfilled Entitlement', () => {
+ beforeEach(() => {
+ setupView(false);
+ });
+
+ it('Change session button should have the correct text.', () => {
+ expect(view.$('.enroll-btn-initial').text() === 'Select Session').toBe(true);
+ });
+
+ it('Select session button should show popover when clicked.', () => {
+ view.$('.enroll-btn-initial').click();
+ expect(view.$('.verification-modal').length > 0).toBe(true);
+ });
+ });
+
+ describe('Change Session Action Button and popover behavior - Fulfilled Entitlement', () => {
+ beforeEach(() => {
+ setupView(true);
+ selectOptions = view.$('.session-select').find('option');
+ });
+
+ it('Change session button should show correct text.', () => {
+ expect(view.$('.enroll-btn-initial').text().trim() === 'Change Session').toBe(true);
+ });
+
+ it('Switch session button should be disabled when on the currently enrolled session.', () => {
+ expect(view.$('.enroll-btn-initial')).toHaveClass('disabled');
+ });
+ });
+});
diff --git a/lms/static/js/learner_dashboard/spec/entitlement_unenrollment_view_spec.js b/lms/static/js/learner_dashboard/spec/entitlement_unenrollment_view_spec.js
new file mode 100644
index 0000000000..26149b31a3
--- /dev/null
+++ b/lms/static/js/learner_dashboard/spec/entitlement_unenrollment_view_spec.js
@@ -0,0 +1,186 @@
+/* globals setFixtures */
+
+import EntitlementUnenrollmentView from '../views/entitlement_unenrollment_view';
+
+describe('EntitlementUnenrollmentView', () => {
+ let view = null;
+ const options = {
+ dashboardPath: '/dashboard',
+ signInPath: '/login',
+ };
+
+ const initView = () => new EntitlementUnenrollmentView(options);
+
+ const modalHtml = 'Unenroll ' +
+ 'Unenroll ' +
+ '
' +
+ ' ' +
+ ' ' +
+ ' ' +
+ '
';
+
+ beforeEach(() => {
+ setFixtures(modalHtml);
+ view = initView();
+ });
+
+ afterEach(() => {
+ view.remove();
+ });
+
+ describe('when an unenroll link is clicked', () => {
+ it('should reset the modal and set the correct values for header/submit', () => {
+ const $link1 = $('#link1');
+ const $link2 = $('#link2');
+ const $headerTxt = $('.js-entitlement-unenrollment-modal-header-text');
+ const $errorTxt = $('.js-entitlement-unenrollment-modal-error-text');
+ const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
+
+ $link1.trigger('click');
+ expect($headerTxt.html().startsWith('Are you sure you want to unenroll from Test Course 1')).toBe(true);
+ expect($submitBtn.data()).toEqual({ entitlementApiEndpoint: '/test/api/endpoint/1' });
+ expect($submitBtn.prop('disabled')).toBe(false);
+ expect($errorTxt.html()).toEqual('');
+ expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(false);
+
+ // Set an error so that we can see that the modal is reset properly when clicked again
+ view.setError('This is an error');
+ expect($errorTxt.html()).toEqual('This is an error');
+ expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(true);
+ expect($submitBtn.prop('disabled')).toBe(true);
+
+ $link2.trigger('click');
+ expect($headerTxt.html().startsWith('Are you sure you want to unenroll from Test Course 2')).toBe(true);
+ expect($submitBtn.data()).toEqual({ entitlementApiEndpoint: '/test/api/endpoint/2' });
+ expect($submitBtn.prop('disabled')).toBe(false);
+ expect($errorTxt.html()).toEqual('');
+ expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(false);
+ });
+ });
+
+ describe('when the unenroll submit button is clicked', () => {
+ it('should send a DELETE request to the configured apiEndpoint', () => {
+ const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
+ const apiEndpoint = '/test/api/endpoint/1';
+
+ view.setSubmitData(apiEndpoint);
+
+ spyOn($, 'ajax').and.callFake((opts) => {
+ expect(opts.url).toEqual(apiEndpoint);
+ expect(opts.method).toEqual('DELETE');
+ expect(opts.complete).toBeTruthy();
+ });
+
+ $submitBtn.trigger('click');
+ expect($.ajax).toHaveBeenCalled();
+ });
+
+ it('should set an error and disable submit if the apiEndpoint has not been properly set', () => {
+ const $errorTxt = $('.js-entitlement-unenrollment-modal-error-text');
+ const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
+
+ expect($submitBtn.data()).toEqual({});
+ expect($submitBtn.prop('disabled')).toBe(false);
+ expect($errorTxt.html()).toEqual('');
+ expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(false);
+
+ spyOn($, 'ajax');
+ $submitBtn.trigger('click');
+ expect($.ajax).not.toHaveBeenCalled();
+
+ expect($submitBtn.data()).toEqual({});
+ expect($submitBtn.prop('disabled')).toBe(true);
+ expect($errorTxt.html()).toEqual(view.genericErrorMsg);
+ expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(true);
+ });
+
+ describe('when the unenroll request is complete', () => {
+ it('should redirect to the dashboard if the request was successful', () => {
+ const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
+ const apiEndpoint = '/test/api/endpoint/1';
+
+ view.setSubmitData(apiEndpoint);
+
+ spyOn($, 'ajax').and.callFake((opts) => {
+ expect(opts.url).toEqual(apiEndpoint);
+ expect(opts.method).toEqual('DELETE');
+ expect(opts.complete).toBeTruthy();
+
+ opts.complete({
+ status: 204,
+ responseJSON: { detail: 'success' },
+ });
+ });
+ spyOn(EntitlementUnenrollmentView, 'redirectTo');
+
+ $submitBtn.trigger('click');
+ expect($.ajax).toHaveBeenCalled();
+ expect(EntitlementUnenrollmentView.redirectTo).toHaveBeenCalledWith(view.dashboardPath);
+ });
+
+ it('should redirect to the login page if the request failed with an auth error', () => {
+ const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
+ const apiEndpoint = '/test/api/endpoint/1';
+
+ view.setSubmitData(apiEndpoint);
+
+ spyOn($, 'ajax').and.callFake((opts) => {
+ expect(opts.url).toEqual(apiEndpoint);
+ expect(opts.method).toEqual('DELETE');
+ expect(opts.complete).toBeTruthy();
+
+ opts.complete({
+ status: 401,
+ responseJSON: { detail: 'Authentication credentials were not provided.' },
+ });
+ });
+ spyOn(EntitlementUnenrollmentView, 'redirectTo');
+
+ $submitBtn.trigger('click');
+ expect($.ajax).toHaveBeenCalled();
+ expect(EntitlementUnenrollmentView.redirectTo).toHaveBeenCalledWith(
+ `${view.signInPath}?next=${encodeURIComponent(view.dashboardPath)}`,
+ );
+ });
+
+ it('should set an error and disable submit if a non-auth error occurs', () => {
+ const $errorTxt = $('.js-entitlement-unenrollment-modal-error-text');
+ const $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
+ const apiEndpoint = '/test/api/endpoint/1';
+
+ view.setSubmitData(apiEndpoint);
+
+ spyOn($, 'ajax').and.callFake((opts) => {
+ expect(opts.url).toEqual(apiEndpoint);
+ expect(opts.method).toEqual('DELETE');
+ expect(opts.complete).toBeTruthy();
+
+ opts.complete({
+ status: 400,
+ responseJSON: { detail: 'Bad request.' },
+ });
+ });
+ spyOn(EntitlementUnenrollmentView, 'redirectTo');
+
+ expect($submitBtn.prop('disabled')).toBe(false);
+ expect($errorTxt.html()).toEqual('');
+ expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(false);
+
+ $submitBtn.trigger('click');
+
+ expect($submitBtn.prop('disabled')).toBe(true);
+ expect($errorTxt.html()).toEqual(view.genericErrorMsg);
+ expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(true);
+
+ expect($.ajax).toHaveBeenCalled();
+ expect(EntitlementUnenrollmentView.redirectTo).not.toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/lms/static/js/learner_dashboard/spec/program_card_view_spec.js b/lms/static/js/learner_dashboard/spec/program_card_view_spec.js
new file mode 100644
index 0000000000..e08e5778d2
--- /dev/null
+++ b/lms/static/js/learner_dashboard/spec/program_card_view_spec.js
@@ -0,0 +1,130 @@
+/* globals setFixtures */
+
+import ProgramCardView from '../views/program_card_view';
+import ProgramModel from '../models/program_model';
+import ProgressCollection from '../collections/program_progress_collection';
+
+describe('Program card View', () => {
+ let view = null;
+ let programModel;
+ const program = {
+ uuid: 'a87e5eac-3c93-45a1-a8e1-4c79ca8401c8',
+ title: 'Food Security and Sustainability',
+ subtitle: 'Learn how to feed all people in the world in a sustainable way.',
+ type: 'XSeries',
+ detail_url: 'https://www.edx.org/foo/bar',
+ banner_image: {
+ medium: {
+ height: 242,
+ width: 726,
+ url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.medium.jpg',
+ },
+ 'x-small': {
+ height: 116,
+ width: 348,
+ url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.x-small.jpg',
+ },
+ small: {
+ height: 145,
+ width: 435,
+ url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.small.jpg',
+ },
+ large: {
+ height: 480,
+ width: 1440,
+ url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.large.jpg',
+ },
+ },
+ authoring_organizations: [
+ {
+ uuid: '0c6e5fa2-96e8-40b2-9ebe-c8b0df2a3b22',
+ key: 'WageningenX',
+ name: 'Wageningen University & Research',
+ },
+ ],
+ };
+ const userProgress = [
+ {
+ uuid: 'a87e5eac-3c93-45a1-a8e1-4c79ca8401c8',
+ completed: 4,
+ in_progress: 2,
+ not_started: 4,
+ },
+ {
+ uuid: '91d144d2-1bb1-4afe-90df-d5cff63fa6e2',
+ completed: 1,
+ in_progress: 0,
+ not_started: 3,
+ },
+ ];
+ const progressCollection = new ProgressCollection();
+ const cardRenders = ($card) => {
+ expect($card).toBeDefined();
+ expect($card.find('.title').html().trim()).toEqual(program.title);
+ expect($card.find('.category span').html().trim()).toEqual(program.type);
+ expect($card.find('.organization').html().trim()).toEqual(program.authoring_organizations[0].key);
+ expect($card.find('.card-link').attr('href')).toEqual(program.detail_url);
+ };
+
+ beforeEach(() => {
+ setFixtures('');
+ programModel = new ProgramModel(program);
+ progressCollection.set(userProgress);
+ view = new ProgramCardView({
+ model: programModel,
+ context: {
+ progressCollection,
+ },
+ });
+ });
+
+ afterEach(() => {
+ view.remove();
+ });
+
+ it('should exist', () => {
+ expect(view).toBeDefined();
+ });
+
+ it('should load the program-card based on passed in context', () => {
+ cardRenders(view.$el);
+ });
+
+ it('should call reEvaluatePicture if reLoadBannerImage is called', () => {
+ spyOn(ProgramCardView, 'reEvaluatePicture');
+ view.reLoadBannerImage();
+ expect(ProgramCardView.reEvaluatePicture).toHaveBeenCalled();
+ });
+
+ it('should handle exceptions from reEvaluatePicture', () => {
+ const message = 'Picturefill had exceptions';
+
+ spyOn(ProgramCardView, 'reEvaluatePicture').and.callFake(() => {
+ const error = { name: message };
+
+ throw error;
+ });
+ view.reLoadBannerImage();
+ expect(ProgramCardView.reEvaluatePicture).toHaveBeenCalled();
+ expect(view.reLoadBannerImage).not.toThrow(message);
+ });
+
+ it('should show the right number of progress bar segments', () => {
+ expect(view.$('.progress-bar .completed').length).toEqual(4);
+ expect(view.$('.progress-bar .enrolled').length).toEqual(2);
+ });
+
+ it('should display the correct course status numbers', () => {
+ expect(view.$('.number-circle').text()).toEqual('424');
+ });
+
+ it('should render cards if there is no progressData', () => {
+ view.remove();
+ view = new ProgramCardView({
+ model: programModel,
+ context: {},
+ });
+ cardRenders(view.$el);
+ expect(view.$('.progress').length).toEqual(0);
+ });
+});
diff --git a/lms/static/js/learner_dashboard/spec/program_details_header_spec.js b/lms/static/js/learner_dashboard/spec/program_details_header_spec.js
new file mode 100644
index 0000000000..3be603accd
--- /dev/null
+++ b/lms/static/js/learner_dashboard/spec/program_details_header_spec.js
@@ -0,0 +1,74 @@
+/* globals setFixtures */
+
+import Backbone from 'backbone';
+
+import ProgramHeaderView from '../views/program_header_view';
+
+describe('Program Details Header View', () => {
+ let view = null;
+ const context = {
+ programData: {
+ uuid: 'a87e5eac-3c93-45a1-a8e1-4c79ca8401c8',
+ title: 'Food Security and Sustainability',
+ subtitle: 'Learn how to feed all people in the world in a sustainable way.',
+ type: 'XSeries',
+ detail_url: 'https://www.edx.org/foo/bar',
+ banner_image: {
+ medium: {
+ height: 242,
+ width: 726,
+ url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.medium.jpg',
+ },
+ 'x-small': {
+ height: 116,
+ width: 348,
+ url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.x-small.jpg',
+ },
+ small: {
+ height: 145,
+ width: 435,
+ url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.small.jpg',
+ },
+ large: {
+ height: 480,
+ width: 1440,
+ url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.large.jpg',
+ },
+ },
+ authoring_organizations: [
+ {
+ uuid: '0c6e5fa2-96e8-40b2-9ebe-c8b0df2a3b22',
+ key: 'WageningenX',
+ name: 'Wageningen University & Research',
+ certificate_logo_image_url: 'https://example.com/org-certificate-logo.jpg',
+ logo_image_url: 'https://example.com/org-logo.jpg',
+ },
+ ],
+ },
+ };
+
+ beforeEach(() => {
+ setFixtures('');
+ view = new ProgramHeaderView({
+ model: new Backbone.Model(context),
+ });
+ view.render();
+ });
+
+ afterEach(() => {
+ view.remove();
+ });
+
+ it('should exist', () => {
+ expect(view).toBeDefined();
+ });
+
+ it('should render the header based on the passed in model', () => {
+ expect(view.$('.program-title').html()).toEqual(context.programData.title);
+ expect(view.$('.org-logo').length).toEqual(context.programData.authoring_organizations.length);
+ expect(view.$('.org-logo').attr('src'))
+ .toEqual(context.programData.authoring_organizations[0].certificate_logo_image_url);
+ expect(view.$('.org-logo').attr('alt'))
+ .toEqual(`${context.programData.authoring_organizations[0].name}'s logo`);
+ });
+});
diff --git a/lms/static/js/learner_dashboard/spec/program_details_sidebar_view_spec.js b/lms/static/js/learner_dashboard/spec/program_details_sidebar_view_spec.js
new file mode 100644
index 0000000000..77f884f065
--- /dev/null
+++ b/lms/static/js/learner_dashboard/spec/program_details_sidebar_view_spec.js
@@ -0,0 +1,118 @@
+/* globals setFixtures */
+
+import Backbone from 'backbone';
+
+import ProgramSidebarView from '../views/program_details_sidebar_view';
+
+describe('Program Progress View', () => {
+ let view = null;
+ // Don't bother linting the format of the test data
+ /* eslint-disable */
+ const data = {
+ programData: {"subtitle": "Explore water management concepts and technologies.", "overview": "\u003ch3\u003eXSeries Program Overview\u003c/h3\u003e\n\u003cp\u003eSafe water supply and hygienic water treatment are prerequisites for the well-being of communities all over the world. This Water XSeries, offered by the water management experts of TU Delft, will give you a unique opportunity to gain access to world-class knowledge and expertise in this field.\u003c/p\u003e\n\u003cp\u003eThis 3-course series will cover questions such as: How does climate change affect water cycle and public safety? How to use existing technologies to treat groundwater and surface water so we have safe drinking water? How do we take care of sewage produced in the cities on a daily basis? You will learn what are the physical, chemical and biological processes involved; carry out simple experiments at home; and have the chance to make a basic design of a drinking water treatment plant\u003c/p\u003e", "weeks_to_complete": null, "corporate_endorsements": [], "video": null, "type": "XSeries", "applicable_seat_types": ["verified", "professional", "credit"], "max_hours_effort_per_week": null, "transcript_languages": ["en-us"], "expected_learning_items": [], "uuid": "988e7ea8-f5e2-4d2e-998a-eae4ad3af322", "title": "Water Management", "languages": ["en-us"], "subjects": [{"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/engineering.jpg", "name": "Engineering", "subtitle": "Learn about engineering and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/engineering-1440x210.jpg", "slug": "engineering", "description": "Enroll in an online introduction to engineering course or explore specific areas such as structural, mechanical, electrical, software or aeronautical engineering. EdX offers free online courses in thermodynamics, robot mechanics, aerodynamics and more from top engineering universities."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/biology.jpg", "name": "Biology \u0026 Life Sciences", "subtitle": "Learn about biology and life sciences and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/plant-stomas-1440x210.jpg", "slug": "biology-life-sciences", "description": "Take free online biology courses in genetics, biotechnology, biochemistry, neurobiology and other disciplines. Courses include Fundamentals of Neuroscience from Harvard University, Molecular Biology from MIT and an Introduction to Bioethics from Georgetown."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/science.jpg", "name": "Science", "subtitle": "Learn about science and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/neuron-1440x210.jpg", "slug": "science", "description": "Science is one of the most popular subjects on edX and online courses range from beginner to advanced levels. Areas of study include neuroscience, genotyping, DNA methylation, innovations in environmental science, modern astrophysics and more from top universities and institutions worldwide."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/physics.jpg", "name": "Physics", "subtitle": "Learn about physics and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/header-bg-physics.png", "slug": "physics", "description": "Find online courses in quantum mechanics and magnetism the likes of MIT and Rice University or get an introduction to the violent universe from Australian National University."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/engery.jpg", "name": "Energy \u0026 Earth Sciences", "subtitle": "Learn about energy and earth sciences and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/energy-1440x210.jpg", "slug": "energy-earth-sciences", "description": "EdX\u2019s online Earth sciences courses cover very timely and important issues such as climate change and energy sustainability. Learn about natural disasters and our ability to predict them. Explore the universe with online courses in astrophysics, space plasmas and fusion energy."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/environmental-studies.jpg", "name": "Environmental Studies", "subtitle": "Learn about environmental studies, and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/environment-studies-1440x210.jpg", "slug": "environmental-studies", "description": "Take online courses in environmental science, natural resource management, environmental policy and civic ecology. Learn how to solve complex problems related to pollution control, water treatment and environmental sustainability with free online courses from leading universities worldwide."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/health.jpg", "name": "Health \u0026 Safety", "subtitle": "Learn about health and safety and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/health-and-safety-1440x210.jpg", "slug": "health-safety", "description": "From public health initiatives to personal wellbeing, find online courses covering a wide variety of health and medical subjects. Enroll in free courses from major universities on topics like epidemics, global healthcare and the fundamentals of clinical trials."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/electronics.jpg", "name": "Electronics", "subtitle": "Learn about electronics and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/electronics-a-1440x210.jpg", "slug": "electronics", "description": "The online courses in electrical engineering explore computation structures, electronic interfaces and the principles of electric circuits. Learn the engineering behind drones and autonomous robots or find out how organic electronic devices are changing the way humans interact with machines."}], "individual_endorsements": [], "staff": [{"family_name": "Smets", "uuid": "6078b3dd-ade4-457d-9262-7439a5f4b07e", "bio": "Dr. Arno H.M. Smets is Professor in Solar Energy in the Photovoltaics Material and Devices group at the faculty of Electrical Engineering, Mathematics and Computer Science, Delft University of Technology. From 2005-2010 he worked at the Research Center for Photovoltaics at the National Institute of Advanced Industrial Science and Technology (AIST) in Tsukuba Japan. His research work is focused on processing of thin silicon films, innovative materials and new concepts for photovoltaic applications. He is lecturer for BSc and MSc courses on Photovoltaics and Sustainable Energy at TU Delft. His online edX course on Solar Energy attracted over 150,000 students worldwide. He is co-author of the book \u003cem\u003e\u201cSolar Energy. The physics and engineering of photovoltaic conversion technologies and systems.\u201d\u003c/em\u003e", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/arno-smets_x110.jpg", "given_name": "Arno", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Professor, Electrical Engineering, Mathematics and Computer Science"}, "works": [], "slug": "arno-smets"}, {"family_name": "van de Giesen", "uuid": "0e28153f-4e9f-4080-b56f-43480600ecd7", "bio": "Since July 2004, Nick van de Giesen has held the Van Kuffeler Chair of Water Resources Management of the Faculty of Civil Engineering and Geosciences. He teaches Integrated Water Resources Management and Water Management. His main interests are the modeling of complex water resources systems and the development of science-based decision support systems. The interaction between water systems and their users is the core theme in both research portfolio and teaching curriculum. Since 1 April 2009, he is chairman of the \u003ca href=\"http://www.environment.tudelft.nl\"\u003eDelft Research Initiative Environment\u003c/a\u003e.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/giesen_vd_nick_110p.jpg", "given_name": "Nick", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "nick-van-de-giesen"}, {"family_name": "Russchenberg", "uuid": "8a94bdb9-ac44-4bc1-a3d2-306f391682b4", "bio": "Herman Russchenberg is engaged in intensive and extensive research into the causes of climate change. His own research involves investigating the role played by clouds and dust particles in the atmosphere, but he is also head of the TU Delft Climate Institute, established in March 2012 to bring together TU Delft researchers working on all aspects of climate and climate change. Russchenberg started out in the faculty of Electrical Engineering, conducting research into the influence of the atmosphere (rain, clouds) on satellite signals. After obtaining his PhD in 1992, he shifted his attention to the physics of water vapour, water droplets, dust particles, sunlight, radiation and emissions in the atmosphere. He is now based in the faculty of Civil Engineering and Geosciences.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/russchenberg_herman_110p.jpg", "given_name": "Herman", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "herman-russchenberg"}, {"family_name": "Savenije", "uuid": "4ebdcd93-bb4e-4c0c-9faf-4e513b1a2e33", "bio": "Prof. Savenije was born in 1952 in the Netherlands and studied at the Delft University of Technology, in the Netherlands, where he obtained his MSc in 1977 in Hydrology. As a young graduate hydrologist he worked for six years in Mozambique where he developed a theory on salt intrusion in estuaries and studied the hydrology of international rivers. From 1985-1990 he worked as an international consultant mostly in Asia and Africa. He joined academia in 1990 to complete his PhD in 1992. In 1994 he was appointed Professor of Water Resources Management at the IHE (now UNESCO-IHE, Institute for Water Education) in Delft, the Netherlands. Since 1999, he is Professor of Hydrology at the Delft University of Technology, where he is the head of the Water Resources Section. He is President of the International Association of Hydrological Sciences and Executive Editor of the journal Hydrology and Earth System Sciences.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/savenije_hubert_110p.jpg", "given_name": "Hubert", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "hubert-savenije"}, {"family_name": "Stive", "uuid": "a7364bab-8e9c-4265-bd14-598afac1f086", "bio": "Marcel Stive studied Civil engineering at the Delft University of Technology, where he graduated in 1977 and received his doctorate in 1988. After graduating in 1977 Stive started working at WL-Delft Hydraulics, where he worked until 1992. In 1992 he became a professor at the Polytechnic University of Catalonia in Barcelona, Spain. In 1994 her returned to WL-Delft Hydraulics and at the same time began to work as a professor of Coastal Morphodynamics at the Delft University of Technology. Since 2001 Stive is a professor of Coastal Engineering at Delft University of Technology and he is the scientific director of the Water Research Centre Delft since 2003.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/stive_marcel_110p.jpg", "given_name": "Marcel", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "TU Delft", "title": "Professor"}, "works": [], "slug": "marcel-stive"}, {"family_name": "Rietveld", "uuid": "1b70c71d-20cc-487d-be10-4b31baeff559", "bio": "\u003cp\u003eLuuk Rietveld is professor of Urban Water Cycle Technology at Delft University of Technology. After finalizing his studies in Civil Engineering at Delft University of Technology in 1987, he worked, until 1991, as lecturer/researcher in Sanitary Engineering at the Eduardo Mondlane University, Maputo, Mozambique. Between 1991 and 1994, he was employed at the Management Centre for International Co-operation, and since 1994 he has had an appointment at the Department of Water Management of Delft University of Technology. In 2005, he defended his PhD thesis entitled \"Improving Operation of Drinking Water Treatment through Modelling\".\u003c/p\u003e\n\u003cp\u003eLuuk Rietveld\u2019s main research interests are modelling and optimisation of processes in the urban water cycle, and technological innovations in drinking water treatment and water reclamation for industrial purposes. In addition, he has extensive experience in education, in various cultural contexts, and is interested to explore the use of new ways of teaching through activated and blended learning and MOOCs.\u003c/p\u003e", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/rietveld_luuk_110p.jpg", "given_name": "Luuk", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "luuk-rietveld-0"}, {"family_name": "van Halem", "uuid": "4ce9ef2a-19e9-46de-9f34-5d755f26736a", "bio": "Doris van Halem is a tenure track Assistant Professor within the Department of Water Management, section Sanitary Engineering of Delft University of Technology. She graduated from Delft University of Technology in Civil Engineering and Geosciences with a cum laude MSc degree (2007). During her studies she developed an interest in global drinking water challenges, illustrated by her internships in Sri Lanka and Benin, resulting in an MSc thesis \u201cCeramic silver impregnated pot filter for household drinking water treatment in developing countries\u201d. In 2011 she completed her PhD research (with honours) on subsurface iron and arsenic removal for drinking water supply in Bangladesh under the guidance of prof. J.C. van Dijk (TU Delft) and prof. dr. G.L. Amy (Unesco-IHE). Currently she supervises BSc, MSc and PhD students, focusing on inorganic constituent behaviour and trace compound removal during soil passage and drinking water treatment - with a particular interest in smart, pro-poor drinking water solutions.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/doris_van_halem_1.jpg", "given_name": "Doris", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Assistant Professor, Sanitary Engineering"}, "works": [], "slug": "doris-van-halem-0"}, {"family_name": "Grefte", "uuid": "463c3f1a-95fc-45aa-b7c0-d01b14126f02", "bio": "Anke Grefte is project manager open, online and blended education for the Faculty of Civil Engineering and Geosciences, Delft University of Technology. She graduated from Delft University of Technology in Civil Engineering with a master\u2019s thesis entitled \"Behaviour of particles in a drinking water distribution network; test rig results\". For this thesis Anke was awarded the Gijs Oskam award for best young researcher. In November 2013, she finished her Ph.D. research on the removal of Natural Organic Matter (NOM) fractions by ion exchange and the impact on drinking water treatment processes and biological stability.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/grefte_anke_110p.jpg", "given_name": "Anke", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "anke-grefte-0"}, {"family_name": "Lier", "uuid": "349aa2cc-0107-4632-ad10-869f23966049", "bio": "Jules van Lier is full professor of Environmental Engineering and Wastewater Treatment at the Sanitary Engineering Section of Delft University of Technology and has a 1 day per week posted position at the Unesco-IHE Institute for Water Education, also in Delft Jules van Lier accomplished his PhD on Thermophilic Anaerobic Wastewater Treatment under the supervision of Prof. Gatze Lettinga (1995) at Wageningen University. Throughout his career he has been involved as a senior researcher / project manager in various (inter)national research projects, working on cost-effective water treatment for resource recovery (water, nutrients, biogas, elements). His research projects are focused on closing water cycles in industries and sewage water recovery for irrigated agriculture. The further development of anaerobic treatment technology is his prime focus. In addition to university work he is an Executive Board Member and Scientific Advisor to the LeAF Foundation; regional representative for Western Europe Anaerobic Digestion Specialist group of the International Water Association (IWA); editor of scientific journals (e.g Water Science Technology and Advances in Environmental Research and Development); member of the Paques Technological Advisory Commission; and member of the Advisory Board of World-Waternet, Amsterdam.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/lier_van_jules_110p.jpg", "given_name": "Jules van", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Professor, Sanitary Engineering"}, "works": [], "slug": "jules-van-lier"}, {"family_name": "Kreuk", "uuid": "c1e50a84-1b09-47b5-b704-5e16309d0cba", "bio": "Merle de Kreuk is a wastewater Associate Professor at the Sanitary Engineering department of the Delft University of Technology. Her research focus is on (municipal and industrial) wastewater treatment systems and anaerobic processes, aiming to link the world of Biotechnology to the Civil Engineering, as well as fundamental research to industrial applications. Her main research topics are hydrolysis processes in anaerobic treatment and granule formation and deterioration. Merle\u2019s PhD and Post-Doc research involved the development of aerobic granular sludge technology and up scaling the technology from a three litre lab scale reactor to the full scale Nereda\u00ae process\u00ae. The first application of aerobic granular sludge technology in the Netherlands was opened in May 2012, and currently many more installations are being built, due to its compactness, low energy use and good effluent characteristics. Her previous work experience also involved the position of water treatment technology innovator at Water authority Hollandse Delta on projects such as the Energy Factory in which 14 water authorities cooperated to develop an energy producing sewage treatment plant.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/kreuk_de_merle_110p.jpg", "given_name": "Merle de", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Associate Professor, Sanitary Engineering"}, "works": [], "slug": "merle-de-kreuk"}], "marketing_slug": "water-management", "marketing_url": "https://stage.edx.org/xseries/water-management", "status": "active", "credit_redemption_overview": "These courses can be taken in any order.", "card_image_url": "https://stage.edx.org/sites/default/files/card/images/waterxseries_course0.png", "faq": [], "price_ranges": [{"currency": "USD", "max": 15.0, "total": 35.0, "min": 10.0}], "banner_image": {"small": {"url": "https://d385l2sek0vys7.cloudfront.net/media/programs/banner_images/988e7ea8-f5e2-4d2e-998a-eae4ad3af322.small.jpg", "width": 435, "height": 145}, "large": {"url": "https://d385l2sek0vys7.cloudfront.net/media/programs/banner_images/988e7ea8-f5e2-4d2e-998a-eae4ad3af322.large.jpg", "width": 1440, "height": 480}, "medium": {"url": "https://d385l2sek0vys7.cloudfront.net/media/programs/banner_images/988e7ea8-f5e2-4d2e-998a-eae4ad3af322.medium.jpg", "width": 726, "height": 242}, "x-small": {"url": "https://d385l2sek0vys7.cloudfront.net/media/programs/banner_images/988e7ea8-f5e2-4d2e-998a-eae4ad3af322.x-small.jpg", "width": 348, "height": 116}}, "authoring_organizations": [{"description": "Delft University of Technology is the largest and oldest technological university in the Netherlands. Our research is inspired by the desire to increase fundamental understanding, as well as by societal challenges. We encourage our students to be independent thinkers so they will become engineers capable of solving complex problems. Our students have chosen Delft University of Technology because of our reputation for quality education and research.", "tags": ["charter", "contributor"], "name": "Delft University of Technology (TU Delft)", "homepage_url": null, "key": "DelftX", "certificate_logo_image_url": null, "marketing_url": "https://stage.edx.org/school/delftx", "logo_image_url": "https://stage.edx.org/sites/default/files/school/image/banner/delft_logo_200x101_0.png", "uuid": "c484a523-d396-4aff-90f4-bb7e82e16bf6"}], "job_outlook_items": [], "credit_backing_organizations": [], "weeks_to_complete_min": 4, "weeks_to_complete_max": 8, "min_hours_effort_per_week": null},
+ courseData: {
+ "completed": [{"owners": [{"uuid": "c484a523-d396-4aff-90f4-bb7e82e16bf6", "key": "DelftX", "name": "Delft University of Technology (TU Delft)"}], "uuid": "4ce7a648-3172-475a-84f3-9f843b2157f3", "title": "Introduction to Water and Climate", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/wc_home_378x225.jpg", "height": null, "description": null, "width": null}, "key": "Delftx+CTB3300WCx", "course_runs": [{"upgrade_url": null, "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/wc_home_378x225.jpg", "height": null, "description": null, "width": null}, "max_effort": null, "is_enrollment_open": true, "course": "Delftx+CTB3300WCx", "content_language": "en-us", "eligible_for_financial_aid": true, "seats": [{"sku": "18AC1BC", "credit_hours": null, "price": "0.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "honor"}, {"sku": "86A734B", "credit_hours": null, "price": "10.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "verified"}], "course_url": "/courses/course-v1:Delftx+CTB3300WCx+2015_T3/", "availability": "Archived", "transcript_languages": ["en-us"], "staff": [{"family_name": "van de Giesen", "uuid": "0e28153f-4e9f-4080-b56f-43480600ecd7", "bio": "Since July 2004, Nick van de Giesen has held the Van Kuffeler Chair of Water Resources Management of the Faculty of Civil Engineering and Geosciences. He teaches Integrated Water Resources Management and Water Management. His main interests are the modeling of complex water resources systems and the development of science-based decision support systems. The interaction between water systems and their users is the core theme in both research portfolio and teaching curriculum. Since 1 April 2009, he is chairman of the \u003ca href=\"http://www.environment.tudelft.nl\"\u003eDelft Research Initiative Environment\u003c/a\u003e.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/giesen_vd_nick_110p.jpg", "given_name": "Nick", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "nick-van-de-giesen"}, {"family_name": "Russchenberg", "uuid": "8a94bdb9-ac44-4bc1-a3d2-306f391682b4", "bio": "Herman Russchenberg is engaged in intensive and extensive research into the causes of climate change. His own research involves investigating the role played by clouds and dust particles in the atmosphere, but he is also head of the TU Delft Climate Institute, established in March 2012 to bring together TU Delft researchers working on all aspects of climate and climate change. Russchenberg started out in the faculty of Electrical Engineering, conducting research into the influence of the atmosphere (rain, clouds) on satellite signals. After obtaining his PhD in 1992, he shifted his attention to the physics of water vapour, water droplets, dust particles, sunlight, radiation and emissions in the atmosphere. He is now based in the faculty of Civil Engineering and Geosciences.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/russchenberg_herman_110p.jpg", "given_name": "Herman", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "herman-russchenberg"}, {"family_name": "Savenije", "uuid": "4ebdcd93-bb4e-4c0c-9faf-4e513b1a2e33", "bio": "Prof. Savenije was born in 1952 in the Netherlands and studied at the Delft University of Technology, in the Netherlands, where he obtained his MSc in 1977 in Hydrology. As a young graduate hydrologist he worked for six years in Mozambique where he developed a theory on salt intrusion in estuaries and studied the hydrology of international rivers. From 1985-1990 he worked as an international consultant mostly in Asia and Africa. He joined academia in 1990 to complete his PhD in 1992. In 1994 he was appointed Professor of Water Resources Management at the IHE (now UNESCO-IHE, Institute for Water Education) in Delft, the Netherlands. Since 1999, he is Professor of Hydrology at the Delft University of Technology, where he is the head of the Water Resources Section. He is President of the International Association of Hydrological Sciences and Executive Editor of the journal Hydrology and Earth System Sciences.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/savenije_hubert_110p.jpg", "given_name": "Hubert", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "hubert-savenije"}, {"family_name": "Stive", "uuid": "a7364bab-8e9c-4265-bd14-598afac1f086", "bio": "Marcel Stive studied Civil engineering at the Delft University of Technology, where he graduated in 1977 and received his doctorate in 1988. After graduating in 1977 Stive started working at WL-Delft Hydraulics, where he worked until 1992. In 1992 he became a professor at the Polytechnic University of Catalonia in Barcelona, Spain. In 1994 her returned to WL-Delft Hydraulics and at the same time began to work as a professor of Coastal Morphodynamics at the Delft University of Technology. Since 2001 Stive is a professor of Coastal Engineering at Delft University of Technology and he is the scientific director of the Water Research Centre Delft since 2003.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/stive_marcel_110p.jpg", "given_name": "Marcel", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "TU Delft", "title": "Professor"}, "works": [], "slug": "marcel-stive"}], "announcement": "2015-06-09T00:00:00Z", "end": "2015-11-04T12:00:00Z", "uuid": "a36f5673-6637-11e6-a8e3-22000bdde520", "title": "Introduction to Water and Climate", "certificate_url": "/certificates/a37c59143d9d422eb6ab11e1053b8eb5", "enrollment_start": null, "start": "2015-09-01T04:00:00Z", "min_effort": null, "short_description": "Explore how climate change, water availability, and engineering innovation are key challenges for our planet.", "hidden": false, "level_type": "Intermediate", "type": "verified", "enrollment_open_date": "Jan 01, 1900", "marketing_url": "https://stage.edx.org/course/introduction-water-climate-delftx-ctb3300wcx-0", "is_course_ended": true, "instructors": [], "full_description": "\u003cp\u003eWater is essential for life on earth and of crucial importance for society. Cycling across the planet and the atmosphere, it also has a major influence on our climate.\u003c/p\u003e\n\u003cp\u003eWeekly modules are hosted by four different professors, all of them being international experts in their field. The course consists of knowledge clips, movies, exercises, discussion and homework assignments. It finishes with an examination.\u003c/p\u003e\n\u003cp\u003eThis course combined with the courses \"Introduction to Drinking Water Treatment\" (new edition to start in January 2016) and \"Introduction to the Treatment of Urban Sewage\" (new edition to start in April 2016) forms the Water XSeries, Faculty of Civil Engineering and Geosciences, TU Delft.\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e\u003cstrong\u003eLICENSE\u003c/strong\u003e\u003cbr /\u003e\nThe course materials of this course are Copyright Delft University of Technology and are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike (CC-BY-NC-SA) 4.0 International License.\u003c/em\u003e\u003c/p\u003e", "key": "course-v1:Delftx+CTB3300WCx+2015_T3", "enrollment_end": null, "reporting_type": "mooc", "advertised_start": null, "mobile_available": true, "modified": "2017-04-06T12:26:52.594942Z", "is_enrolled": false, "pacing_type": "instructor_paced", "video": {"src": "http://www.youtube.com/watch?v=dJEhwq0sXiQ", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/featured-card/wc_home_378x225.jpg", "width": null, "description": null, "height": null}, "description": null}}]}, {"owners": [{"uuid": "c484a523-d396-4aff-90f4-bb7e82e16bf6", "key": "DelftX", "name": "Delft University of Technology (TU Delft)"}], "uuid": "a0aade38-7a50-4afb-97cd-2214c572cc86", "title": "Urban Sewage Treatment", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/sewage_home_378x225.jpg", "height": null, "description": null, "width": null}, "key": "DelftX+CTB3365STx", "course_runs": [{"upgrade_url": null, "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/sewage_home_378x225.jpg", "height": null, "description": null, "width": null}, "max_effort": null, "is_enrollment_open": true, "course": "DelftX+CTB3365STx", "content_language": "en-us", "eligible_for_financial_aid": true, "seats": [{"sku": "01CDD4F", "credit_hours": null, "price": "0.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "honor"}, {"sku": "B4F253D", "credit_hours": null, "price": "10.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "verified"}], "course_url": "/courses/course-v1:Delftx+CTB3365STx+1T2016/", "availability": "Archived", "transcript_languages": ["en-us"], "staff": [{"family_name": "Lier", "uuid": "349aa2cc-0107-4632-ad10-869f23966049", "bio": "Jules van Lier is full professor of Environmental Engineering and Wastewater Treatment at the Sanitary Engineering Section of Delft University of Technology and has a 1 day per week posted position at the Unesco-IHE Institute for Water Education, also in Delft Jules van Lier accomplished his PhD on Thermophilic Anaerobic Wastewater Treatment under the supervision of Prof. Gatze Lettinga (1995) at Wageningen University. Throughout his career he has been involved as a senior researcher / project manager in various (inter)national research projects, working on cost-effective water treatment for resource recovery (water, nutrients, biogas, elements). His research projects are focused on closing water cycles in industries and sewage water recovery for irrigated agriculture. The further development of anaerobic treatment technology is his prime focus. In addition to university work he is an Executive Board Member and Scientific Advisor to the LeAF Foundation; regional representative for Western Europe Anaerobic Digestion Specialist group of the International Water Association (IWA); editor of scientific journals (e.g Water Science Technology and Advances in Environmental Research and Development); member of the Paques Technological Advisory Commission; and member of the Advisory Board of World-Waternet, Amsterdam.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/lier_van_jules_110p.jpg", "given_name": "Jules van", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Professor, Sanitary Engineering"}, "works": [], "slug": "jules-van-lier"}, {"family_name": "Kreuk", "uuid": "c1e50a84-1b09-47b5-b704-5e16309d0cba", "bio": "Merle de Kreuk is a wastewater Associate Professor at the Sanitary Engineering department of the Delft University of Technology. Her research focus is on (municipal and industrial) wastewater treatment systems and anaerobic processes, aiming to link the world of Biotechnology to the Civil Engineering, as well as fundamental research to industrial applications. Her main research topics are hydrolysis processes in anaerobic treatment and granule formation and deterioration. Merle\u2019s PhD and Post-Doc research involved the development of aerobic granular sludge technology and up scaling the technology from a three litre lab scale reactor to the full scale Nereda\u00ae process\u00ae. The first application of aerobic granular sludge technology in the Netherlands was opened in May 2012, and currently many more installations are being built, due to its compactness, low energy use and good effluent characteristics. Her previous work experience also involved the position of water treatment technology innovator at Water authority Hollandse Delta on projects such as the Energy Factory in which 14 water authorities cooperated to develop an energy producing sewage treatment plant.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/kreuk_de_merle_110p.jpg", "given_name": "Merle de", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Associate Professor, Sanitary Engineering"}, "works": [], "slug": "merle-de-kreuk"}], "announcement": "2015-07-24T00:00:00Z", "end": "2016-07-01T22:30:00Z", "uuid": "a36f70c1-6637-11e6-a8e3-22000bdde520", "title": "Introduction to the Treatment of Urban Sewage", "certificate_url": "/certificates/bed3980e67ca40f0b31e309d9dfe9e7e", "enrollment_start": null, "start": "2016-04-12T04:00:00Z", "min_effort": null, "short_description": "Learn about urban water services, focusing on basic sewage treatment technologies.", "hidden": false, "level_type": "Intermediate", "type": "verified", "enrollment_open_date": "Jan 01, 1900", "marketing_url": "https://stage.edx.org/course/introduction-treatment-urban-sewage-delftx-ctb3365stx-0", "is_course_ended": true, "instructors": [], "full_description": "\u003cp\u003eThis course will focus on basic technologies for the treatment of urban sewage. Unit processes involved in the treatment chain will be described as well as the physical, chemical and biological processes involved. There will be an emphasis on water quality and the functionality of each unit process within the treatment chain. After the course one should be able to recognise the process units, describe their function and make simple design calculations on urban sewage treatment plants.\u003c/p\u003e\n\u003cp\u003eThe course consists of 6 modules:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eSewage treatment plant overview. In this module you will learn what major pollutants are present in the sewage and why we need to treat sewage prior to discharge to surface waters. The functional units will be briefly discussed\u003c/li\u003e\n\u003cli\u003ePrimary treatment. In this module you learn how coarse material, sand \u0026 grit are removed from the sewage and how to design primary clarification tanks\u003c/li\u003e\n\u003cli\u003eBiological treatment. In this module you learn the basics of the carbon, nitrogen and phosphorous cycle and how biological processes are used to treat the main pollutants of concern.\u003c/li\u003e\n\u003cli\u003eActivated sludge process. In this module you learn the design principles of conventional activated sludge processes including the secondary clarifiers and aeration demand of aeration tanks.\u003c/li\u003e\n\u003cli\u003eNitrogen and phosphorus removal. In this module you learn the principles of biological nitrogen removal as well as phosphorus removal by biological and/or chemical means.\u003c/li\u003e\n\u003cli\u003eSludge treatment. In this module you will the design principles of sludge thickeners, digesters and dewatering facilities for the concentration and stabilisation of excess sewage sludge. Potentials for energy recovery via the produced biogas will be discussed as well as the direct anaerobic treatment of urban sewage in UASB reactors when climate conditions allow.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThis course in combination with the courses \"\u003ca href=\"https://www.edx.org/course/introduction-water-climate-delftx-ctb3300wcx-0\"\u003eIntroduction to Water and Climate\u003c/a\u003e\" and \"\u003ca href=\"https://www.edx.org/course/introduction-drinking-water-treatment-delftx-ctb3365dwx-0\"\u003eIntroduction to Drinking Water Treatment\u003c/a\u003e\" forms the Water XSeries, by DelftX.\u003c/p\u003e\n\u003chr /\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cem\u003eLICENSE\u003c/em\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eThe course materials of this course are Copyright Delft University of Technology and are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike (CC-BY-NC-SA) 4.0 International License.\u003c/em\u003e\u003c/p\u003e", "key": "course-v1:Delftx+CTB3365STx+1T2016", "enrollment_end": null, "reporting_type": "mooc", "advertised_start": null, "mobile_available": true, "modified": "2017-04-06T12:26:52.679900Z", "is_enrolled": true, "pacing_type": "instructor_paced", "video": {"src": "http://www.youtube.com/watch?v=pcSsOE-F4e8", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/featured-card/sewage_home_378x225.jpg", "width": null, "description": null, "height": null}, "description": null}}]}],
+ "in_progress": [], "uuid": "988e7ea8-f5e2-4d2e-998a-eae4ad3af322",
+ "not_started": [{"owners": [{"uuid": "c484a523-d396-4aff-90f4-bb7e82e16bf6", "key": "DelftX", "name": "Delft University of Technology (TU Delft)"}], "uuid": "51275d00-1f3f-462f-8231-ce42821cc1dd", "title": "Solar Energy", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/solar-energy_378x225.jpg", "height": null, "description": null, "width": null}, "key": "DelftX+ET3034TUx", "course_runs": [{"upgrade_url": null, "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/solar-energy_378x225.jpg", "height": null, "description": null, "width": null}, "max_effort": null, "is_enrollment_open": true, "course": "DelftX+ET3034TUx", "content_language": null, "eligible_for_financial_aid": true, "seats": [{"sku": "E433FA8", "credit_hours": null, "price": "0.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "honor"}], "course_url": "/courses/DelftX/ET3034TUx/2013_Fall/", "availability": "Archived", "transcript_languages": [], "staff": [{"family_name": "Smets", "uuid": "6078b3dd-ade4-457d-9262-7439a5f4b07e", "bio": "Dr. Arno H.M. Smets is Professor in Solar Energy in the Photovoltaics Material and Devices group at the faculty of Electrical Engineering, Mathematics and Computer Science, Delft University of Technology. From 2005-2010 he worked at the Research Center for Photovoltaics at the National Institute of Advanced Industrial Science and Technology (AIST) in Tsukuba Japan. His research work is focused on processing of thin silicon films, innovative materials and new concepts for photovoltaic applications. He is lecturer for BSc and MSc courses on Photovoltaics and Sustainable Energy at TU Delft. His online edX course on Solar Energy attracted over 150,000 students worldwide. He is co-author of the book \u003cem\u003e\u201cSolar Energy. The physics and engineering of photovoltaic conversion technologies and systems.\u201d\u003c/em\u003e", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/arno-smets_x110.jpg", "given_name": "Arno", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Professor, Electrical Engineering, Mathematics and Computer Science"}, "works": [], "slug": "arno-smets"}], "announcement": "2013-05-08T00:00:00Z", "end": "2013-12-06T10:30:00Z", "uuid": "f33a9660-b5d0-47a9-9bfa-a326d9ed4ef2", "title": "Solar Energy", "certificate_url": null, "enrollment_start": null, "start": "2013-09-16T04:00:00Z", "min_effort": null, "short_description": "Discover the power of solar energy and design a complete photovoltaic system.", "hidden": false, "level_type": null, "type": "honor", "enrollment_open_date": "Jan 01, 1900", "marketing_url": "https://stage.edx.org/course/solar-energy-delftx-et3034tux", "is_course_ended": true, "instructors": [], "full_description": "", "key": "DelftX/ET3034TUx/2013_Fall", "enrollment_end": null, "reporting_type": "mooc", "advertised_start": null, "mobile_available": false, "modified": "2017-04-06T12:26:54.345710Z", "is_enrolled": false, "pacing_type": "instructor_paced", "video": {"src": "http://www.youtube.com/watch?v=LLiNzrIubF0", "image": null, "description": null}}]}, {"owners": [{"uuid": "c484a523-d396-4aff-90f4-bb7e82e16bf6", "key": "DelftX", "name": "Delft University of Technology (TU Delft)"}], "uuid": "7c430382-d477-4bac-9c29-f36c24f1935f", "title": "Drinking Water Treatment", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/drinking_water_home_378x225.jpg", "height": null, "description": null, "width": null}, "key": "DelftX+CTB3365DWx", "course_runs": [{"upgrade_url": null, "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/drinking_water_home_378x225.jpg", "height": null, "description": null, "width": null}, "max_effort": null, "is_enrollment_open": true, "course": "DelftX+CTB3365DWx", "content_language": "en-us", "eligible_for_financial_aid": true, "seats": [{"sku": "74AC06B", "credit_hours": 100, "price": "15.00", "currency": "USD", "upgrade_deadline": "2016-04-30T00:00:00Z", "credit_provider": "mit", "type": "credit"}, {"sku": "0BBAE34", "credit_hours": null, "price": "0.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "honor"}, {"sku": "8E52FAE", "credit_hours": null, "price": "10.00", "currency": "USD", "upgrade_deadline": "2016-03-25T01:06:00Z", "credit_provider": null, "type": "verified"}], "course_url": "/courses/course-v1:DelftX+CTB3365DWx+1T2016/", "availability": "Current", "transcript_languages": ["en-us"], "staff": [{"family_name": "Rietveld", "uuid": "1b70c71d-20cc-487d-be10-4b31baeff559", "bio": "\u003cp\u003eLuuk Rietveld is professor of Urban Water Cycle Technology at Delft University of Technology. After finalizing his studies in Civil Engineering at Delft University of Technology in 1987, he worked, until 1991, as lecturer/researcher in Sanitary Engineering at the Eduardo Mondlane University, Maputo, Mozambique. Between 1991 and 1994, he was employed at the Management Centre for International Co-operation, and since 1994 he has had an appointment at the Department of Water Management of Delft University of Technology. In 2005, he defended his PhD thesis entitled \"Improving Operation of Drinking Water Treatment through Modelling\".\u003c/p\u003e\n\u003cp\u003eLuuk Rietveld\u2019s main research interests are modelling and optimisation of processes in the urban water cycle, and technological innovations in drinking water treatment and water reclamation for industrial purposes. In addition, he has extensive experience in education, in various cultural contexts, and is interested to explore the use of new ways of teaching through activated and blended learning and MOOCs.\u003c/p\u003e", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/rietveld_luuk_110p.jpg", "given_name": "Luuk", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "luuk-rietveld-0"}, {"family_name": "van Halem", "uuid": "4ce9ef2a-19e9-46de-9f34-5d755f26736a", "bio": "Doris van Halem is a tenure track Assistant Professor within the Department of Water Management, section Sanitary Engineering of Delft University of Technology. She graduated from Delft University of Technology in Civil Engineering and Geosciences with a cum laude MSc degree (2007). During her studies she developed an interest in global drinking water challenges, illustrated by her internships in Sri Lanka and Benin, resulting in an MSc thesis \u201cCeramic silver impregnated pot filter for household drinking water treatment in developing countries\u201d. In 2011 she completed her PhD research (with honours) on subsurface iron and arsenic removal for drinking water supply in Bangladesh under the guidance of prof. J.C. van Dijk (TU Delft) and prof. dr. G.L. Amy (Unesco-IHE). Currently she supervises BSc, MSc and PhD students, focusing on inorganic constituent behaviour and trace compound removal during soil passage and drinking water treatment - with a particular interest in smart, pro-poor drinking water solutions.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/doris_van_halem_1.jpg", "given_name": "Doris", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Assistant Professor, Sanitary Engineering"}, "works": [], "slug": "doris-van-halem-0"}, {"family_name": "Grefte", "uuid": "463c3f1a-95fc-45aa-b7c0-d01b14126f02", "bio": "Anke Grefte is project manager open, online and blended education for the Faculty of Civil Engineering and Geosciences, Delft University of Technology. She graduated from Delft University of Technology in Civil Engineering with a master\u2019s thesis entitled \"Behaviour of particles in a drinking water distribution network; test rig results\". For this thesis Anke was awarded the Gijs Oskam award for best young researcher. In November 2013, she finished her Ph.D. research on the removal of Natural Organic Matter (NOM) fractions by ion exchange and the impact on drinking water treatment processes and biological stability.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/grefte_anke_110p.jpg", "given_name": "Anke", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "anke-grefte-0"}], "announcement": "2015-07-24T00:00:00Z", "end": "2017-07-20T21:30:00Z", "uuid": "a36ed16a-6637-11e6-a8e3-22000bdde520", "title": "Introduction to Drinking Water Treatment", "certificate_url": null, "enrollment_start": "2016-06-15T00:00:00Z", "start": "2016-01-12T05:00:00Z", "min_effort": null, "short_description": "Learn about urban water services, focusing on conventional technologies for drinking water treatment.", "hidden": false, "level_type": "Intermediate", "type": "credit", "enrollment_open_date": "Jun 15, 2016", "marketing_url": "https://stage.edx.org/course/introduction-drinking-water-treatment-delftx-ctb3365dwx-0", "is_course_ended": false, "instructors": [], "full_description": "\u003cp\u003eThis course focuses on conventional technologies for drinking water treatment. Unit processes, involved in the treatment chain, are discussed as well as the physical, chemical and biological processes involved. The emphasis is on the effect of treatment on water quality and the dimensions of the unit processes in the treatment chain. After the course one should be able to recognise the process units, describe their function, and make basic calculations for a preliminary design of a drinking water treatment plant.\u003c/p\u003e\n\u003cp\u003eThe course consists of 4 modules:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eIntroduction to drinking water treatment. In this module you learn to describe the important disciplines, schemes and evaluation criteria involved in the design phase.\u003c/li\u003e\n\u003cli\u003eWater quality. In this module you learn to identify the drinking water quality parameters to be improved and explain what treatment train or scheme is needed.\u003c/li\u003e\n\u003cli\u003eGroundwater treatment. In this module you learn to calculate the dimensions of the groundwater treatment processes and draw groundwater treatment schemes.\u003c/li\u003e\n\u003cli\u003eSurface water treatment. In this module you learn to calculate the dimensions of the surface water treatment processes and draw surface water treatment schemes.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThis course in combination with the courses \"\u003ca href=\"https://www.edx.org/course/introduction-water-climate-delftx-ctb3300wcx-0\"\u003eIntroduction to Water and Climate\u003c/a\u003e\" and \"\u003ca href=\"https://www.edx.org/course/introduction-treatment-urban-sewage-delftx-ctb3365stx\"\u003eIntroduction to the Treatment of Urban Sewage\u003c/a\u003e\" forms the Water XSeries, by DelftX.\u003c/p\u003e\n\u003chr /\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cem\u003eLICENSE\u003c/em\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eThe course materials of this course are Copyright Delft University of Technology and are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike (CC-BY-NC-SA) 4.0 International License.\u003c/em\u003e\u003c/p\u003e", "key": "course-v1:DelftX+CTB3365DWx+1T2016", "enrollment_end": null, "reporting_type": "mooc", "advertised_start": null, "mobile_available": true, "modified": "2017-04-06T12:26:52.652365Z", "is_enrolled": false, "pacing_type": "instructor_paced", "video": {"src": "http://www.youtube.com/watch?v=0xPZXLHtRJw", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/featured-card/h20_new_378x225.jpg", "width": null, "description": null, "height": null}, "description": null}}]}]},
+ certificateData: [
+ {
+ "url": "/certificates/a37c59143d9d422eb6ab11e1053b8eb5", "type": "course", "title": "Introduction to Water and Climate"
+ }, {
+ "url": "/certificates/bed3980e67ca40f0b31e309d9dfe9e7e", "type": "course", "title": "Introduction to the Treatment of Urban Sewage"
+ }
+ ],
+ urls: {"program_listing_url": "/dashboard/programs/", "commerce_api_url": "/api/commerce/v0/baskets/", "track_selection_url": "/course_modes/choose/"},
+ userPreferences: {"pref-lang": "en"}
+ };
+ /* eslint-enable */
+ let programModel;
+ let courseData;
+ let certificateCollection;
+
+ const testCircle = (progress) => {
+ const $circle = view.$('.progress-circle');
+ const incomplete = progress.in_progress.length + progress.not_started.length;
+
+ expect($circle.find('.complete').length).toEqual(progress.completed.length);
+ expect($circle.find('.incomplete').length).toEqual(incomplete);
+ };
+
+ const testText = (progress) => {
+ const $numbers = view.$('.numbers');
+ const total = progress.completed.length + progress.in_progress.length +
+ progress.not_started.length;
+
+ expect(view.$('.progress-heading').html()).toEqual('XSeries Progress');
+ expect(parseInt($numbers.find('.complete').html(), 10)).toEqual(progress.completed.length);
+ expect(parseInt($numbers.find('.total').html(), 10)).toEqual(total);
+ };
+
+ const initView = () => new ProgramSidebarView({
+ el: '.js-program-sidebar',
+ model: programModel,
+ courseModel: courseData,
+ certificateCollection,
+ });
+
+ beforeEach(() => {
+ setFixtures('');
+ programModel = new Backbone.Model(data.programData);
+ courseData = new Backbone.Model(data.courseData);
+ certificateCollection = new Backbone.Collection(data.certificateData);
+ });
+
+ afterEach(() => {
+ view.remove();
+ });
+
+ it('should exist', () => {
+ view = initView();
+ expect(view).toBeDefined();
+ });
+
+ it('should render the progress view if there is no program certificate', () => {
+ view = initView();
+ testCircle(data.courseData);
+ testText(data.courseData);
+ });
+
+ it('should render the program certificate if earned', () => {
+ const programCert = {
+ url: '/program-cert',
+ type: 'program',
+ title: 'And Justice For All...',
+ };
+ const altText = `Open the certificate you earned for the ${programCert.title} program.`;
+
+ certificateCollection.add(programCert);
+ view = initView();
+ expect(view.$('.progress-circle-wrapper')[0]).not.toBeInDOM();
+ const $certLink = view.$('.program-cert-link');
+ expect($certLink[0]).toBeInDOM();
+ expect($certLink.attr('href')).toEqual(programCert.url);
+ expect($certLink.find('.program-cert').attr('alt')).toEqual(altText);
+ expect(view.$('.certificate-heading')).toHaveText('Your XSeries Certificate');
+ });
+
+ it('should render the course certificate list', () => {
+ view = initView();
+ const $certificates = view.$('.certificate-list .certificate');
+
+ expect(view.$('.course-list-heading').html()).toEqual('Earned Certificates');
+ expect($certificates).toHaveLength(certificateCollection.length);
+ $certificates.each((i, el) => {
+ const $link = $(el).find('.certificate-link');
+ const model = certificateCollection.at(i);
+
+ expect($link.attr('href')).toEqual(model.get('url'));
+ expect($link.html()).toEqual(model.get('title'));
+ });
+ });
+
+ it('should not render the course certificate view if no certificates have been earned', () => {
+ certificateCollection.reset();
+ view = initView();
+ expect(view).toBeDefined();
+ expect(view.$('.js-course-certificates')).toBeEmpty();
+ });
+});
diff --git a/lms/static/js/learner_dashboard/spec/program_details_view_spec.js b/lms/static/js/learner_dashboard/spec/program_details_view_spec.js
new file mode 100644
index 0000000000..7f70193ee3
--- /dev/null
+++ b/lms/static/js/learner_dashboard/spec/program_details_view_spec.js
@@ -0,0 +1,626 @@
+/* globals setFixtures */
+
+import ProgramDetailsView from '../views/program_details_view';
+
+describe('Program Details Header View', () => {
+ let view = null;
+ const options = {
+ programData: {
+ subtitle: '',
+ overview: '',
+ weeks_to_complete: null,
+ corporate_endorsements: [],
+ video: null,
+ type: 'Test',
+ max_hours_effort_per_week: null,
+ transcript_languages: [
+ 'en-us',
+ ],
+ expected_learning_items: [],
+ uuid: '0ffff5d6-0177-4690-9a48-aa2fecf94610',
+ title: 'Test Course Title',
+ languages: [
+ 'en-us',
+ ],
+ subjects: [],
+ individual_endorsements: [],
+ staff: [
+ {
+ family_name: 'Tester',
+ uuid: '11ee1afb-5750-4185-8434-c9ae8297f0f1',
+ bio: 'Dr. Tester, PhD, RD, is an Associate Professor at the School of Nutrition.',
+ profile_image: {},
+ profile_image_url: 'some image',
+ given_name: 'Bob',
+ urls: {
+ blog: null,
+ twitter: null,
+ facebook: null,
+ },
+ position: {
+ organization_name: 'Test University',
+ title: 'Associate Professor of Nutrition',
+ },
+ works: [],
+ slug: 'dr-tester',
+ },
+ ],
+ marketing_slug: 'testing',
+ marketing_url: 'someurl',
+ status: 'active',
+ credit_redemption_overview: '',
+ discount_data: {
+ currency: 'USD',
+ discount_value: 0,
+ is_discounted: false,
+ total_incl_tax: 300,
+ total_incl_tax_excl_discounts: 300,
+ },
+ full_program_price: 300,
+ card_image_url: 'some image',
+ faq: [],
+ price_ranges: [
+ {
+ max: 378,
+ total: 109,
+ min: 10,
+ currency: 'USD',
+ },
+ ],
+ banner_image: {
+ large: {
+ url: 'someurl',
+ width: 1440,
+ height: 480,
+ },
+ small: {
+ url: 'someurl',
+ width: 435,
+ height: 145,
+ },
+ medium: {
+ url: 'someurl',
+ width: 726,
+ height: 242,
+ },
+ 'x-small': {
+ url: 'someurl',
+ width: 348,
+ height: 116,
+ },
+ },
+ authoring_organizations: [
+ {
+ description: '
Learning University is home to leading creators, entrepreneurs.
')
- ).text
- );
- this.$courseTitleLink.replaceWith( // xss-lint: disable=javascript-jquery-insertion
- HtmlUtils.joinHtml(
- HtmlUtils.HTML(''),
- this.$courseTitleLink.text(),
- HtmlUtils.HTML('')
- ).text
- );
- },
+ unenrollSuccess() {
+ /*
+ Update external elements on the course card to represent the unenrolled state.
- enrollError: function() {
- // Display a success indicator
- var errorMsgEl = HtmlUtils.joinHtml(
- HtmlUtils.HTML(''),
- gettext('There was an error. Please reload the page and try again.'),
- HtmlUtils.HTML('')
- ).text;
+ 1) Hide the change session button and the date field.
+ 2) Hide the 'View Course' button.
+ 3) Remove the messages associated with the enrolled state.
+ 4) Remove the link from the course card image and title.
+ */
+ // With a containing backbone view, we can simply re-render the parent card
+ if (this.$parentEl) {
+ this.courseCardModel.setUnselected();
+ return;
+ }
- this.$dateDisplayField
- .find('.fa.fa-spin')
- .removeClass('fa-spin fa-spinner')
- .addClass('fa-close');
+ // Update the model with the new session Id;
+ this.entitlementModel.set({ currentSessionId: this.currentSessionSelection });
- this.$dateDisplayField.append(errorMsgEl);
- this.hideDialog(this.$('.enroll-btn-initial'));
- },
+ // Reset the card contents to the unenrolled state
+ this.$triggerOpenBtn.addClass('hidden');
+ this.$enterCourseBtn.addClass('hidden');
+ // Remove all message except for related programs, which should always be shown
+ // (Even other messages might need to be shown again in future: LEARNER-3523.)
+ this.$courseCardMessages.filter(':not(.message-related-programs)').remove();
+ this.$policyMsg.remove();
+ this.$('.enroll-btn-initial').focus();
+ HtmlUtils.setHtml(
+ this.$dateDisplayField,
+ HtmlUtils.joinHtml(
+ HtmlUtils.HTML(''),
+ HtmlUtils.HTML(gettext('You must select a session to access the course.')),
+ ),
+ );
- updateEnrollBtn: function() {
- /*
- This function is invoked on load, on opening the view and on changing the option on the session
- selection dropdown. It plays three roles:
- 1) Enables and disables enroll button
- 2) Changes text to describe the action taken
- 3) Formats the confirmation popover to allow for two step authentication
- */
- var enrollText,
- currentSessionId = this.entitlementModel.get('currentSessionId'),
- newSessionId = this.$('.session-select').find('option:selected').data('session_id'),
- enrollBtnInitial = this.$('.enroll-btn-initial');
+ // Remove links to previously enrolled sessions
+ this.$courseImageLink.replaceWith( // xss-lint: disable=javascript-jquery-insertion
+ HtmlUtils.joinHtml(
+ HtmlUtils.HTML('
');
- programCollection = new ProgramCollection(context.programsData);
- view = new CollectionListView({
- el: '.program-cards-container',
- childView: ProgramCardView,
- context: context,
- collection: programCollection,
- titleContext: titleContext
- });
- view.render();
- $title = view.$el.parent().find('.collection-title');
- expect($title.html()).toBe(titleContext.title);
- });
- });
-}
-);
diff --git a/lms/static/js/spec/learner_dashboard/course_card_view_spec.js b/lms/static/js/spec/learner_dashboard/course_card_view_spec.js
deleted file mode 100644
index ea7030b3b2..0000000000
--- a/lms/static/js/spec/learner_dashboard/course_card_view_spec.js
+++ /dev/null
@@ -1,272 +0,0 @@
-define([
- 'backbone',
- 'jquery',
- 'js/learner_dashboard/models/course_card_model',
- 'js/learner_dashboard/views/course_card_view'
-], function(Backbone, $, CourseCardModel, CourseCardView) {
- 'use strict';
-
- describe('Course Card View', function() {
- var view = null,
- courseCardModel,
- course,
- startDate = 'Feb 28, 2017',
- endDate = 'May 30, 2017',
-
- setupView = function(data, isEnrolled, collectionCourseStatus) {
- var programData = $.extend({}, data),
- context = {
- courseData: {
- grades: {
- 'course-v1:WageningenX+FFESx+1T2017': 0.8
- }
- },
- collectionCourseStatus: collectionCourseStatus
- };
-
- if (typeof collectionCourseStatus === 'undefined') {
- context.collectionCourseStatus = 'completed';
- }
-
- programData.course_runs[0].is_enrolled = isEnrolled;
- setFixtures('');
- courseCardModel = new CourseCardModel(programData);
- view = new CourseCardView({
- model: courseCardModel,
- context: context
- });
- },
-
- validateCourseInfoDisplay = function() {
- // DRY validation for course card in enrolled state
- expect(view.$('.course-details .course-title-link').text().trim()).toEqual(course.title);
- expect(view.$('.course-details .course-title-link').attr('href')).toEqual(
- course.course_runs[0].marketing_url
- );
- expect(view.$('.course-details .course-text .run-period').html()).toEqual(
- startDate + ' - ' + endDate
- );
- };
-
- beforeEach(function() {
- // NOTE: This data is redefined prior to each test case so that tests
- // can't break each other by modifying data copied by reference.
- course = {
- key: 'WageningenX+FFESx',
- uuid: '9f8562eb-f99b-45c7-b437-799fd0c15b6a',
- title: 'Systems thinking and environmental sustainability',
- course_runs: [
- {
- key: 'course-v1:WageningenX+FFESx+1T2017',
- title: 'Food Security and Sustainability: Systems thinking and environmental sustainability',
- image: {
- src: 'https://example.com/9f8562eb-f99b-45c7-b437-799fd0c15b6a.jpg'
- },
- marketing_url: 'https://www.edx.org/course/food-security-sustainability',
- start: '2017-02-28T05:00:00Z',
- end: '2017-05-30T23:00:00Z',
- enrollment_start: '2017-01-18T00:00:00Z',
- enrollment_end: null,
- type: 'verified',
- certificate_url: '',
- course_url: 'https://courses.example.com/courses/course-v1:WageningenX+FFESx+1T2017',
- enrollment_open_date: 'Jan 18, 2016',
- is_course_ended: false,
- is_enrolled: true,
- is_enrollment_open: true,
- status: 'published',
- upgrade_url: ''
- }
- ]
- };
-
- setupView(course, true);
- });
-
- afterEach(function() {
- view.remove();
- });
-
- it('should exist', function() {
- expect(view).toBeDefined();
- });
-
- it('should render final grade if course is completed', function() {
- view.remove();
- setupView(course, true);
- expect(view.$('.grade-display').text()).toEqual('80%');
- });
-
- it('should not render final grade if course has not been completed', function() {
- view.remove();
- setupView(course, true, 'in_progress');
- expect(view.$('.final-grade').length).toEqual(0);
- });
-
- it('should render the course card based on the data not enrolled', function() {
- view.remove();
- setupView(course, false);
- validateCourseInfoDisplay();
- });
-
- it('should update render if the course card is_enrolled updated', function() {
- setupView(course, false);
- courseCardModel.set({
- is_enrolled: true
- });
- validateCourseInfoDisplay();
- });
-
- it('should show the course advertised start date', function() {
- var advertisedStart = 'A long time ago...';
- course.course_runs[0].advertised_start = advertisedStart;
-
- setupView(course, false);
-
- expect(view.$('.course-details .course-text .run-period').html()).toEqual(
- advertisedStart + ' - ' + endDate
- );
- });
-
- it('should only show certificate status section if a certificate has been earned', function() {
- var certUrl = 'sample-certificate';
-
- expect(view.$('.course-certificate .certificate-status').length).toEqual(0);
- view.remove();
-
- course.course_runs[0].certificate_url = certUrl;
- setupView(course, false);
- expect(view.$('.course-certificate .certificate-status').length).toEqual(1);
- });
-
- it('should only show upgrade message section if an upgrade is required', function() {
- var upgradeUrl = '/path/to/upgrade';
-
- expect(view.$('.upgrade-message').length).toEqual(0);
- view.remove();
-
- course.course_runs[0].upgrade_url = upgradeUrl;
- setupView(course, false);
- expect(view.$('.upgrade-message').length).toEqual(1);
- expect(view.$('.upgrade-message .cta-primary').attr('href')).toEqual(upgradeUrl);
- });
-
- it('should not show both the upgrade message and certificate status sections', function() {
- // Verify that no empty elements are left in the DOM.
- course.course_runs[0].upgrade_url = '';
- course.course_runs[0].certificate_url = '';
- setupView(course, false);
- expect(view.$('.upgrade-message').length).toEqual(0);
- expect(view.$('.course-certificate .certificate-status').length).toEqual(0);
- view.remove();
-
- // Verify that the upgrade message takes priority.
- course.course_runs[0].upgrade_url = '/path/to/upgrade';
- course.course_runs[0].certificate_url = '/path/to/certificate';
- setupView(course, false);
- expect(view.$('.upgrade-message').length).toEqual(1);
- expect(view.$('.course-certificate .certificate-status').length).toEqual(0);
- });
-
- it('should allow enrollment in future runs when the user has an expired enrollment', function() {
- var newRun = $.extend({}, course.course_runs[0]),
- newRunKey = 'course-v1:foo+bar+baz',
- advertisedStart = 'Summer';
-
- newRun.key = newRunKey;
- newRun.is_enrolled = false;
- newRun.advertised_start = advertisedStart;
- course.course_runs.push(newRun);
-
- course.expired = true;
-
- setupView(course, true);
-
- expect(courseCardModel.get('course_run_key')).toEqual(newRunKey);
- expect(view.$('.course-details .course-text .run-period').html()).toEqual(
- advertisedStart + ' - ' + endDate
- );
- });
-
- it('should show a message if an there is an upcoming course run', function() {
- course.course_runs[0].is_enrollment_open = false;
-
- setupView(course, false);
-
- expect(view.$('.course-details .course-title').text().trim()).toEqual(course.title);
- expect(view.$('.course-details .course-text .run-period').length).toBe(0);
- expect(view.$('.no-action-message').text().trim()).toBe('Coming Soon');
- expect(view.$('.enrollment-open-date').text().trim()).toEqual(
- course.course_runs[0].enrollment_open_date
- );
- });
-
- it('should show a message if there are no upcoming course runs', function() {
- course.course_runs[0].is_enrollment_open = false;
- course.course_runs[0].is_course_ended = true;
-
- setupView(course, false);
-
- expect(view.$('.course-details .course-title').text().trim()).toEqual(course.title);
- expect(view.$('.course-details .course-text .run-period').length).toBe(0);
- expect(view.$('.no-action-message').text().trim()).toBe('Not Currently Available');
- expect(view.$('.enrollment-opens').length).toEqual(0);
- });
-
- it('should link to the marketing site when the user is not enrolled', function() {
- setupView(course, false);
- expect(view.$('.course-title-link').attr('href')).toEqual(course.course_runs[0].marketing_url);
- });
-
- it('should link to the course home when the user is enrolled', function() {
- setupView(course, true);
- expect(view.$('.course-title-link').attr('href')).toEqual(course.course_runs[0].course_url);
- });
-
- it('should not link to the marketing site if the URL is not available', function() {
- course.course_runs[0].marketing_url = null;
- setupView(course, false);
-
- expect(view.$('.course-title-link').length).toEqual(0);
- });
-
- it('should not link to the course home if the URL is not available', function() {
- course.course_runs[0].course_url = null;
- setupView(course, true);
-
- expect(view.$('.course-title-link').length).toEqual(0);
- });
-
- it('should show an unfulfilled user entitlement allows you to select a session', function() {
- course.user_entitlement = {
- uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
- course_uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
- expiration_date: '2017-12-05 01:06:12'
- };
- setupView(course, false);
- expect(view.$('.info-expires-at').text().trim()).toContain('You must select a session by');
- });
-
- it('should show a fulfilled expired user entitlement does not allow the changing of sessions', function() {
- course.user_entitlement = {
- uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
- course_uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
- expired_at: '2017-12-06 01:06:12',
- expiration_date: '2017-12-05 01:06:12'
- };
- setupView(course, true);
- expect(view.$('.info-expires-at').text().trim()).toContain('You can no longer change sessions.');
- });
-
- it('should show a fulfilled user entitlement allows the changing of sessions', function() {
- course.user_entitlement = {
- uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
- course_uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
- expiration_date: '2017-12-05 01:06:12'
- };
- setupView(course, true);
- expect(view.$('.info-expires-at').text().trim()).toContain('You can change sessions until');
- });
- });
-}
-);
diff --git a/lms/static/js/spec/learner_dashboard/course_enroll_view_spec.js b/lms/static/js/spec/learner_dashboard/course_enroll_view_spec.js
deleted file mode 100644
index 7a2610f7ad..0000000000
--- a/lms/static/js/spec/learner_dashboard/course_enroll_view_spec.js
+++ /dev/null
@@ -1,307 +0,0 @@
-define([
- 'backbone',
- 'jquery',
- 'js/learner_dashboard/models/course_card_model',
- 'js/learner_dashboard/models/course_enroll_model',
- 'js/learner_dashboard/views/course_enroll_view'
-], function(Backbone, $, CourseCardModel, CourseEnrollModel, CourseEnrollView) {
- 'use strict';
-
- describe('Course Enroll View', function() {
- var view = null,
- courseCardModel,
- courseEnrollModel,
- urlModel,
- setupView,
- singleCourseRunList,
- multiCourseRunList,
- course = {
- key: 'WageningenX+FFESx',
- uuid: '9f8562eb-f99b-45c7-b437-799fd0c15b6a',
- title: 'Systems thinking and environmental sustainability',
- owners: [
- {
- uuid: '0c6e5fa2-96e8-40b2-9ebe-c8b0df2a3b22',
- key: 'WageningenX',
- name: 'Wageningen University & Research'
- }
- ]
- },
- urls = {
- commerce_api_url: '/commerce',
- track_selection_url: '/select_track/course/'
- };
-
- beforeEach(function() {
- // Stub analytics tracking
- window.analytics = jasmine.createSpyObj('analytics', ['track']);
-
- // NOTE: This data is redefined prior to each test case so that tests
- // can't break each other by modifying data copied by reference.
- singleCourseRunList = [{
- key: 'course-v1:WageningenX+FFESx+1T2017',
- uuid: '2f2edf03-79e6-4e39-aef0-65436a6ee344',
- title: 'Food Security and Sustainability: Systems thinking and environmental sustainability',
- image: {
- src: 'https://example.com/2f2edf03-79e6-4e39-aef0-65436a6ee344.jpg'
- },
- marketing_url: 'https://www.edx.org/course/food-security-sustainability-systems-wageningenx-ffesx',
- start: '2017-02-28T05:00:00Z',
- end: '2017-05-30T23:00:00Z',
- enrollment_start: '2017-01-18T00:00:00Z',
- enrollment_end: null,
- type: 'verified',
- certificate_url: '',
- course_url: 'https://courses.example.com/courses/course-v1:edX+DemoX+Demo_Course',
- enrollment_open_date: 'Jan 18, 2016',
- is_course_ended: false,
- is_enrolled: false,
- is_enrollment_open: true,
- status: 'published',
- upgrade_url: ''
- }];
-
- multiCourseRunList = [{
- key: 'course-v1:WageningenX+FFESx+2T2016',
- uuid: '9bbb7844-4848-44ab-8e20-0be6604886e9',
- title: 'Food Security and Sustainability: Systems thinking and environmental sustainability',
- image: {
- src: 'https://example.com/9bbb7844-4848-44ab-8e20-0be6604886e9.jpg'
- },
- short_description: 'Learn how to apply systems thinking to improve food production systems.',
- marketing_url: 'https://www.edx.org/course/food-security-sustainability-systems-wageningenx-stesx',
- start: '2016-09-08T04:00:00Z',
- end: '2016-11-11T00:00:00Z',
- enrollment_start: null,
- enrollment_end: null,
- pacing_type: 'instructor_paced',
- type: 'verified',
- certificate_url: '',
- course_url: 'https://courses.example.com/courses/course-v1:WageningenX+FFESx+2T2016',
- enrollment_open_date: 'Jan 18, 2016',
- is_course_ended: false,
- is_enrolled: false,
- is_enrollment_open: true,
- status: 'published'
- }, {
- key: 'course-v1:WageningenX+FFESx+1T2017',
- uuid: '2f2edf03-79e6-4e39-aef0-65436a6ee344',
- title: 'Food Security and Sustainability: Systems thinking and environmental sustainability',
- image: {
- src: 'https://example.com/2f2edf03-79e6-4e39-aef0-65436a6ee344.jpg'
- },
- marketing_url: 'https://www.edx.org/course/food-security-sustainability-systems-wageningenx-ffesx',
- start: '2017-02-28T05:00:00Z',
- end: '2017-05-30T23:00:00Z',
- enrollment_start: '2017-01-18T00:00:00Z',
- enrollment_end: null,
- type: 'verified',
- certificate_url: '',
- course_url: 'https://courses.example.com/courses/course-v1:WageningenX+FFESx+1T2017',
- enrollment_open_date: 'Jan 18, 2016',
- is_course_ended: false,
- is_enrolled: false,
- is_enrollment_open: true,
- status: 'published'
- }];
- });
-
- setupView = function(courseRuns, urlMap) {
- course.course_runs = courseRuns;
- setFixtures('');
- courseCardModel = new CourseCardModel(course);
- courseEnrollModel = new CourseEnrollModel({}, {
- courseId: courseCardModel.get('course_run_key')
- });
- if (urlMap) {
- urlModel = new Backbone.Model(urlMap);
- }
- view = new CourseEnrollView({
- $parentEl: $('.course-actions'),
- model: courseCardModel,
- enrollModel: courseEnrollModel,
- urlModel: urlModel
- });
- };
-
- afterEach(function() {
- view.remove();
- urlModel = null;
- courseCardModel = null;
- courseEnrollModel = null;
- });
-
- it('should exist', function() {
- setupView(singleCourseRunList);
- expect(view).toBeDefined();
- });
-
- it('should render the course enroll view when not enrolled', function() {
- setupView(singleCourseRunList);
- expect(view.$('.enroll-button').text().trim()).toEqual('Enroll Now');
- expect(view.$('.run-select').length).toBe(0);
- });
-
- it('should render the course enroll view when enrolled', function() {
- singleCourseRunList[0].is_enrolled = true;
-
- setupView(singleCourseRunList);
- expect(view.$('.view-course-button').text().trim()).toEqual('View Course');
- expect(view.$('.run-select').length).toBe(0);
- });
-
- it('should not render anything if course runs are empty', function() {
- setupView([]);
-
- expect(view.$('.run-select').length).toBe(0);
- expect(view.$('.enroll-button').length).toBe(0);
- });
-
- it('should render run selection dropdown if multiple course runs are available', function() {
- setupView(multiCourseRunList);
-
- expect(view.$('.run-select').length).toBe(1);
- expect(view.$('.run-select').val()).toEqual(multiCourseRunList[0].key);
- expect(view.$('.run-select option').length).toBe(2);
- });
-
- it('should not allow enrollment in unpublished course runs', function() {
- multiCourseRunList[0].status = 'unpublished';
-
- setupView(multiCourseRunList);
- expect(view.$('.run-select').length).toBe(0);
- expect(view.$('.enroll-button').length).toBe(1);
- });
-
- it('should not allow enrollment in course runs with a null status', function() {
- multiCourseRunList[0].status = null;
-
- setupView(multiCourseRunList);
- expect(view.$('.run-select').length).toBe(0);
- expect(view.$('.enroll-button').length).toBe(1);
- });
-
- it('should enroll learner when enroll button is clicked with one course run available', function() {
- setupView(singleCourseRunList);
-
- expect(view.$('.enroll-button').length).toBe(1);
-
- spyOn(courseEnrollModel, 'save');
-
- view.$('.enroll-button').click();
-
- expect(courseEnrollModel.save).toHaveBeenCalled();
- });
-
- it('should enroll learner when enroll button is clicked with multiple course runs available', function() {
- setupView(multiCourseRunList);
-
- spyOn(courseEnrollModel, 'save');
-
- view.$('.run-select').val(multiCourseRunList[1].key);
- view.$('.run-select').trigger('change');
- view.$('.enroll-button').click();
-
- expect(courseEnrollModel.save).toHaveBeenCalled();
- });
-
- it('should redirect to track selection when audit enrollment succeeds', function() {
- singleCourseRunList[0].is_enrolled = false;
- singleCourseRunList[0].mode_slug = 'audit';
-
- setupView(singleCourseRunList, urls);
-
- expect(view.$('.enroll-button').length).toBe(1);
- expect(view.trackSelectionUrl).toBeDefined();
-
- spyOn(view, 'redirect');
-
- view.enrollSuccess();
-
- expect(view.redirect).toHaveBeenCalledWith(
- view.trackSelectionUrl + courseCardModel.get('course_run_key'));
- });
-
- it('should redirect to track selection when enrollment in an unspecified mode is attempted', function() {
- singleCourseRunList[0].is_enrolled = false;
- singleCourseRunList[0].mode_slug = null;
-
- setupView(singleCourseRunList, urls);
-
- expect(view.$('.enroll-button').length).toBe(1);
- expect(view.trackSelectionUrl).toBeDefined();
-
- spyOn(view, 'redirect');
-
- view.enrollSuccess();
-
- expect(view.redirect).toHaveBeenCalledWith(
- view.trackSelectionUrl + courseCardModel.get('course_run_key')
- );
- });
-
- it('should not redirect when urls are not provided', function() {
- singleCourseRunList[0].is_enrolled = false;
- singleCourseRunList[0].mode_slug = 'verified';
-
- setupView(singleCourseRunList);
-
- expect(view.$('.enroll-button').length).toBe(1);
- expect(view.verificationUrl).not.toBeDefined();
- expect(view.dashboardUrl).not.toBeDefined();
- expect(view.trackSelectionUrl).not.toBeDefined();
-
- spyOn(view, 'redirect');
-
- view.enrollSuccess();
-
- expect(view.redirect).not.toHaveBeenCalled();
- });
-
- it('should redirect to track selection on error', function() {
- setupView(singleCourseRunList, urls);
-
- expect(view.$('.enroll-button').length).toBe(1);
- expect(view.trackSelectionUrl).toBeDefined();
-
- spyOn(view, 'redirect');
-
- view.enrollError(courseEnrollModel, {status: 500});
- expect(view.redirect).toHaveBeenCalledWith(
- view.trackSelectionUrl + courseCardModel.get('course_run_key')
- );
- });
-
- it('should redirect to login on 403 error', function() {
- var response = {
- status: 403,
- responseJSON: {
- user_message_url: 'redirect/to/this'
- }
- };
-
- setupView(singleCourseRunList, urls);
-
- expect(view.$('.enroll-button').length).toBe(1);
- expect(view.trackSelectionUrl).toBeDefined();
-
- spyOn(view, 'redirect');
-
- view.enrollError(courseEnrollModel, response);
-
- expect(view.redirect).toHaveBeenCalledWith(
- response.responseJSON.user_message_url
- );
- });
-
- it('sends analytics event when enrollment succeeds', function() {
- setupView(singleCourseRunList, urls);
- spyOn(view, 'redirect');
- view.enrollSuccess();
- expect(window.analytics.track).toHaveBeenCalledWith(
- 'edx.bi.user.program-details.enrollment'
- );
- });
- });
-}
-);
diff --git a/lms/static/js/spec/learner_dashboard/course_entitlement_view_spec.js b/lms/static/js/spec/learner_dashboard/course_entitlement_view_spec.js
deleted file mode 100644
index c04e935628..0000000000
--- a/lms/static/js/spec/learner_dashboard/course_entitlement_view_spec.js
+++ /dev/null
@@ -1,188 +0,0 @@
-define([
- 'backbone',
- 'underscore',
- 'jquery',
- 'js/learner_dashboard/models/course_entitlement_model',
- 'js/learner_dashboard/views/course_entitlement_view'
-], function(Backbone, _, $, CourseEntitlementModel, CourseEntitlementView) {
- 'use strict';
-
- describe('Course Entitlement View', function() {
- var view = null,
- setupView,
- sessionIndex,
- selectOptions,
- entitlementAvailableSessions,
- initialSessionId,
- alreadyEnrolled,
- hasSessions,
- entitlementUUID = 'a9aiuw76a4ijs43u18',
- testSessionIds = ['test_session_id_1', 'test_session_id_2'];
-
- setupView = function(isAlreadyEnrolled, hasAvailableSessions, specificSessionIndex) {
- setFixtures('');
- alreadyEnrolled = (typeof isAlreadyEnrolled !== 'undefined') ? isAlreadyEnrolled : true;
- hasSessions = (typeof hasAvailableSessions !== 'undefined') ? hasAvailableSessions : true;
- sessionIndex = (typeof specificSessionIndex !== 'undefined') ? specificSessionIndex : 0;
-
- initialSessionId = alreadyEnrolled ? testSessionIds[sessionIndex] : '';
- entitlementAvailableSessions = [];
- if (hasSessions) {
- entitlementAvailableSessions = [{
- enrollment_end: null,
- start: '2016-02-05T05:00:00+00:00',
- pacing_type: 'instructor_paced',
- session_id: testSessionIds[0],
- end: null
- }, {
- enrollment_end: '2019-12-22T03:30:00Z',
- start: '2020-01-03T13:00:00+00:00',
- pacing_type: 'self_paced',
- session_id: testSessionIds[1],
- end: '2020-03-09T21:30:00+00:00'
- }];
- }
-
- view = new CourseEntitlementView({
- el: '.course-entitlement-selection-container',
- triggerOpenBtn: '#course-card-0 .change-session',
- courseCardMessages: '#course-card-0 .messages-list > .message',
- courseTitleLink: '#course-card-0 .course-title a',
- courseImageLink: '#course-card-0 .wrapper-course-image > a',
- dateDisplayField: '#course-card-0 .info-date-block',
- enterCourseBtn: '#course-card-0 .enter-course',
- availableSessions: JSON.stringify(entitlementAvailableSessions),
- entitlementUUID: entitlementUUID,
- currentSessionId: initialSessionId,
- userId: '1',
- enrollUrl: '/api/enrollment/v1/enrollment',
- courseHomeUrl: '/courses/course-v1:edX+DemoX+Demo_Course/course/'
- });
- };
-
- afterEach(function() {
- if (view) view.remove();
- });
-
- describe('Initialization of view', function() {
- it('Should create a entitlement view element', function() {
- setupView(false);
- expect(view).toBeDefined();
- });
- });
-
- describe('Available Sessions Select - Unfulfilled Entitlement', function() {
- beforeEach(function() {
- setupView(false);
- selectOptions = view.$('.session-select').find('option');
- });
-
- it('Select session dropdown should show all available course runs and a coming soon option.', function() {
- expect(selectOptions.length).toEqual(entitlementAvailableSessions.length + 1);
- });
-
- it('Self paced courses should have visual indication in the selection option.', function() {
- var selfPacedOptionIndex = _.findIndex(entitlementAvailableSessions, function(session) {
- return session.pacing_type === 'self_paced';
- });
- var selfPacedOption = selectOptions[selfPacedOptionIndex];
- expect(selfPacedOption && selfPacedOption.text.includes('(Self-paced)')).toBe(true);
- });
-
- it('Courses with an an enroll by date should indicate so on the selection option.', function() {
- var enrollEndSetOptionIndex = _.findIndex(entitlementAvailableSessions, function(session) {
- return session.enrollment_end !== null;
- });
- var enrollEndSetOption = selectOptions[enrollEndSetOptionIndex];
- expect(enrollEndSetOption && enrollEndSetOption.text.includes('Open until')).toBe(true);
- });
-
- it('Title element should correctly indicate the expected behavior.', function() {
- expect(view.$('.action-header').text().includes(
- 'To access the course, select a session.'
- )).toBe(true);
- });
- });
-
- describe('Available Sessions Select - Unfulfilled Entitlement without available sessions', function() {
- beforeEach(function() {
- setupView(false, false);
- });
-
- it('Should notify user that more sessions are coming soon if none available.', function() {
- expect(view.$('.action-header').text().includes('More sessions coming soon.')).toBe(true);
- });
- });
-
- describe('Available Sessions Select - Fulfilled Entitlement', function() {
- beforeEach(function() {
- setupView(true);
- selectOptions = view.$('.session-select').find('option');
- });
-
- it('Select session dropdown should show available course runs, coming soon and leave options.', function() {
- expect(selectOptions.length).toEqual(entitlementAvailableSessions.length + 2);
- });
-
- it('Select session dropdown should allow user to leave the current session.', function() {
- var leaveSessionOption = selectOptions[selectOptions.length - 1];
- expect(leaveSessionOption.text.includes('Leave the current session and decide later')).toBe(true);
- });
-
- it('Currently selected session should be specified in the dropdown options.', function() {
- var selectedSessionIndex = _.findIndex(entitlementAvailableSessions, function(session) {
- return initialSessionId === session.session_id;
- });
- expect(selectOptions[selectedSessionIndex].text.includes('Currently Selected')).toBe(true);
- });
-
- it('Title element should correctly indicate the expected behavior.', function() {
- expect(view.$('.action-header').text().includes(
- 'Change to a different session or leave the current session.'
- )).toBe(true);
- });
- });
-
- describe('Available Sessions Select - Fulfilled Entitlement (session in the future)', function() {
- beforeEach(function() {
- setupView(true, true, 1);
- });
-
- it('Currently selected session should initialize to selected in the dropdown options.', function() {
- var selectedOption = view.$('.session-select').find('option:selected');
- expect(selectedOption.data('session_id')).toEqual(testSessionIds[1]);
- });
- });
-
- describe('Select Session Action Button and popover behavior - Unfulfilled Entitlement', function() {
- beforeEach(function() {
- setupView(false);
- });
-
- it('Change session button should have the correct text.', function() {
- expect(view.$('.enroll-btn-initial').text() === 'Select Session').toBe(true);
- });
-
- it('Select session button should show popover when clicked.', function() {
- view.$('.enroll-btn-initial').click();
- expect(view.$('.verification-modal').length > 0).toBe(true);
- });
- });
-
- describe('Change Session Action Button and popover behavior - Fulfilled Entitlement', function() {
- beforeEach(function() {
- setupView(true);
- selectOptions = view.$('.session-select').find('option');
- });
-
- it('Change session button should show correct text.', function() {
- expect(view.$('.enroll-btn-initial').text().trim() === 'Change Session').toBe(true);
- });
-
- it('Switch session button should be disabled when on the currently enrolled session.', function() {
- expect(view.$('.enroll-btn-initial')).toHaveClass('disabled');
- });
- });
- });
-}
-);
diff --git a/lms/static/js/spec/learner_dashboard/entitlement_unenrollment_view_spec.js b/lms/static/js/spec/learner_dashboard/entitlement_unenrollment_view_spec.js
deleted file mode 100644
index 672d2e543b..0000000000
--- a/lms/static/js/spec/learner_dashboard/entitlement_unenrollment_view_spec.js
+++ /dev/null
@@ -1,193 +0,0 @@
-define([
- 'backbone',
- 'jquery',
- 'js/learner_dashboard/views/entitlement_unenrollment_view'
-], function(Backbone, $, EntitlementUnenrollmentView) {
- 'use strict';
-
- describe('EntitlementUnenrollmentView', function() {
- var view = null,
- options = {
- dashboardPath: '/dashboard',
- signInPath: '/login'
- },
-
- initView = function() {
- return new EntitlementUnenrollmentView(options);
- },
-
- modalHtml = 'Unenroll ' +
- 'Unenroll ' +
- '
' +
- ' ' +
- ' ' +
- ' ' +
- '
';
-
- beforeEach(function() {
- setFixtures(modalHtml);
- view = initView();
- });
-
- afterEach(function() {
- view.remove();
- });
-
- describe('when an unenroll link is clicked', function() {
- it('should reset the modal and set the correct values for header/submit', function() {
- var $link1 = $('#link1'),
- $link2 = $('#link2'),
- $headerTxt = $('.js-entitlement-unenrollment-modal-header-text'),
- $errorTxt = $('.js-entitlement-unenrollment-modal-error-text'),
- $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
-
- $link1.trigger('click');
- expect($headerTxt.html().startsWith('Are you sure you want to unenroll from Test Course 1')).toBe(true);
- expect($submitBtn.data()).toEqual({entitlementApiEndpoint: '/test/api/endpoint/1'});
- expect($submitBtn.prop('disabled')).toBe(false);
- expect($errorTxt.html()).toEqual('');
- expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(false);
-
- // Set an error so that we can see that the modal is reset properly when clicked again
- view.setError('This is an error');
- expect($errorTxt.html()).toEqual('This is an error');
- expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(true);
- expect($submitBtn.prop('disabled')).toBe(true);
-
- $link2.trigger('click');
- expect($headerTxt.html().startsWith('Are you sure you want to unenroll from Test Course 2')).toBe(true);
- expect($submitBtn.data()).toEqual({entitlementApiEndpoint: '/test/api/endpoint/2'});
- expect($submitBtn.prop('disabled')).toBe(false);
- expect($errorTxt.html()).toEqual('');
- expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(false);
- });
- });
-
- describe('when the unenroll submit button is clicked', function() {
- it('should send a DELETE request to the configured apiEndpoint', function() {
- var $submitBtn = $('.js-entitlement-unenrollment-modal-submit'),
- apiEndpoint = '/test/api/endpoint/1';
-
- view.setSubmitData(apiEndpoint);
-
- spyOn($, 'ajax').and.callFake(function(opts) {
- expect(opts.url).toEqual(apiEndpoint);
- expect(opts.method).toEqual('DELETE');
- expect(opts.complete).toBeTruthy();
- });
-
- $submitBtn.trigger('click');
- expect($.ajax).toHaveBeenCalled();
- });
-
- it('should set an error and disable submit if the apiEndpoint has not been properly set', function() {
- var $errorTxt = $('.js-entitlement-unenrollment-modal-error-text'),
- $submitBtn = $('.js-entitlement-unenrollment-modal-submit');
-
- expect($submitBtn.data()).toEqual({});
- expect($submitBtn.prop('disabled')).toBe(false);
- expect($errorTxt.html()).toEqual('');
- expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(false);
-
- spyOn($, 'ajax');
- $submitBtn.trigger('click');
- expect($.ajax).not.toHaveBeenCalled();
-
- expect($submitBtn.data()).toEqual({});
- expect($submitBtn.prop('disabled')).toBe(true);
- expect($errorTxt.html()).toEqual(view.genericErrorMsg);
- expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(true);
- });
-
- describe('when the unenroll request is complete', function() {
- it('should redirect to the dashboard if the request was successful', function() {
- var $submitBtn = $('.js-entitlement-unenrollment-modal-submit'),
- apiEndpoint = '/test/api/endpoint/1';
-
- view.setSubmitData(apiEndpoint);
-
- spyOn($, 'ajax').and.callFake(function(opts) {
- expect(opts.url).toEqual(apiEndpoint);
- expect(opts.method).toEqual('DELETE');
- expect(opts.complete).toBeTruthy();
-
- opts.complete({
- status: 204,
- responseJSON: {detail: 'success'}
- });
- });
- spyOn(view, 'redirectTo');
-
- $submitBtn.trigger('click');
- expect($.ajax).toHaveBeenCalled();
- expect(view.redirectTo).toHaveBeenCalledWith(view.dashboardPath);
- });
-
- it('should redirect to the login page if the request failed with an auth error', function() {
- var $submitBtn = $('.js-entitlement-unenrollment-modal-submit'),
- apiEndpoint = '/test/api/endpoint/1';
-
- view.setSubmitData(apiEndpoint);
-
- spyOn($, 'ajax').and.callFake(function(opts) {
- expect(opts.url).toEqual(apiEndpoint);
- expect(opts.method).toEqual('DELETE');
- expect(opts.complete).toBeTruthy();
-
- opts.complete({
- status: 401,
- responseJSON: {detail: 'Authentication credentials were not provided.'}
- });
- });
- spyOn(view, 'redirectTo');
-
- $submitBtn.trigger('click');
- expect($.ajax).toHaveBeenCalled();
- expect(view.redirectTo).toHaveBeenCalledWith(
- view.signInPath + '?next=' + encodeURIComponent(view.dashboardPath)
- );
- });
-
- it('should set an error and disable submit if a non-auth error occurs', function() {
- var $errorTxt = $('.js-entitlement-unenrollment-modal-error-text'),
- $submitBtn = $('.js-entitlement-unenrollment-modal-submit'),
- apiEndpoint = '/test/api/endpoint/1';
-
- view.setSubmitData(apiEndpoint);
-
- spyOn($, 'ajax').and.callFake(function(opts) {
- expect(opts.url).toEqual(apiEndpoint);
- expect(opts.method).toEqual('DELETE');
- expect(opts.complete).toBeTruthy();
-
- opts.complete({
- status: 400,
- responseJSON: {detail: 'Bad request.'}
- });
- });
- spyOn(view, 'redirectTo');
-
- expect($submitBtn.prop('disabled')).toBe(false);
- expect($errorTxt.html()).toEqual('');
- expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(false);
-
- $submitBtn.trigger('click');
-
- expect($submitBtn.prop('disabled')).toBe(true);
- expect($errorTxt.html()).toEqual(view.genericErrorMsg);
- expect($errorTxt.hasClass('entitlement-unenrollment-modal-error-text-visible')).toBe(true);
-
- expect($.ajax).toHaveBeenCalled();
- expect(view.redirectTo).not.toHaveBeenCalled();
- });
- });
- });
- });
-}
-);
diff --git a/lms/static/js/spec/learner_dashboard/program_card_view_spec.js b/lms/static/js/spec/learner_dashboard/program_card_view_spec.js
deleted file mode 100644
index 66b68bae4d..0000000000
--- a/lms/static/js/spec/learner_dashboard/program_card_view_spec.js
+++ /dev/null
@@ -1,137 +0,0 @@
-define([
- 'backbone',
- 'underscore',
- 'jquery',
- 'js/learner_dashboard/collections/program_progress_collection',
- 'js/learner_dashboard/models/program_model',
- 'js/learner_dashboard/views/program_card_view'
-], function(Backbone, _, $, ProgressCollection, ProgramModel, ProgramCardView) {
- 'use strict';
- /* jslint maxlen: 500 */
-
- describe('Program card View', function() {
- var view = null,
- programModel,
- program = {
- uuid: 'a87e5eac-3c93-45a1-a8e1-4c79ca8401c8',
- title: 'Food Security and Sustainability',
- subtitle: 'Learn how to feed all people in the world in a sustainable way.',
- type: 'XSeries',
- detail_url: 'https://www.edx.org/foo/bar',
- banner_image: {
- medium: {
- height: 242,
- width: 726,
- url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.medium.jpg'
- },
- 'x-small': {
- height: 116,
- width: 348,
- url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.x-small.jpg'
- },
- small: {
- height: 145,
- width: 435,
- url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.small.jpg'
- },
- large: {
- height: 480,
- width: 1440,
- url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.large.jpg'
- }
- },
- authoring_organizations: [
- {
- uuid: '0c6e5fa2-96e8-40b2-9ebe-c8b0df2a3b22',
- key: 'WageningenX',
- name: 'Wageningen University & Research'
- }
- ]
- },
- userProgress = [
- {
- uuid: 'a87e5eac-3c93-45a1-a8e1-4c79ca8401c8',
- completed: 4,
- in_progress: 2,
- not_started: 4
- },
- {
- uuid: '91d144d2-1bb1-4afe-90df-d5cff63fa6e2',
- completed: 1,
- in_progress: 0,
- not_started: 3
- }
- ],
- progressCollection = new ProgressCollection(),
- cardRenders = function($card) {
- expect($card).toBeDefined();
- expect($card.find('.title').html().trim()).toEqual(program.title);
- expect($card.find('.category span').html().trim()).toEqual(program.type);
- expect($card.find('.organization').html().trim()).toEqual(program.authoring_organizations[0].key);
- expect($card.find('.card-link').attr('href')).toEqual(program.detail_url);
- };
-
- beforeEach(function() {
- setFixtures('');
- programModel = new ProgramModel(program);
- progressCollection.set(userProgress);
- view = new ProgramCardView({
- model: programModel,
- context: {
- progressCollection: progressCollection
- }
- });
- });
-
- afterEach(function() {
- view.remove();
- });
-
- it('should exist', function() {
- expect(view).toBeDefined();
- });
-
- it('should load the program-card based on passed in context', function() {
- cardRenders(view.$el);
- });
-
- it('should call reEvaluatePicture if reLoadBannerImage is called', function() {
- spyOn(view, 'reEvaluatePicture');
- view.reLoadBannerImage();
- expect(view.reEvaluatePicture).toHaveBeenCalled();
- });
-
- it('should handle exceptions from reEvaluatePicture', function() {
- var message = 'Picturefill had exceptions';
-
- spyOn(view, 'reEvaluatePicture').and.callFake(function() {
- var error = {name: message};
-
- throw error;
- });
- view.reLoadBannerImage();
- expect(view.reEvaluatePicture).toHaveBeenCalled();
- expect(view.reLoadBannerImage).not.toThrow(message);
- });
-
- it('should show the right number of progress bar segments', function() {
- expect(view.$('.progress-bar .completed').length).toEqual(4);
- expect(view.$('.progress-bar .enrolled').length).toEqual(2);
- });
-
- it('should display the correct course status numbers', function() {
- expect(view.$('.number-circle').text()).toEqual('424');
- });
-
- it('should render cards if there is no progressData', function() {
- view.remove();
- view = new ProgramCardView({
- model: programModel,
- context: {}
- });
- cardRenders(view.$el);
- expect(view.$('.progress').length).toEqual(0);
- });
- });
-}
-);
diff --git a/lms/static/js/spec/learner_dashboard/program_details_header_spec.js b/lms/static/js/spec/learner_dashboard/program_details_header_spec.js
deleted file mode 100644
index 7829e0be1e..0000000000
--- a/lms/static/js/spec/learner_dashboard/program_details_header_spec.js
+++ /dev/null
@@ -1,77 +0,0 @@
-define([
- 'backbone',
- 'jquery',
- 'js/learner_dashboard/views/program_header_view'
-], function(Backbone, $, ProgramHeaderView) {
- 'use strict';
-
- describe('Program Details Header View', function() {
- var view = null,
- context = {
- programData: {
- uuid: 'a87e5eac-3c93-45a1-a8e1-4c79ca8401c8',
- title: 'Food Security and Sustainability',
- subtitle: 'Learn how to feed all people in the world in a sustainable way.',
- type: 'XSeries',
- detail_url: 'https://www.edx.org/foo/bar',
- banner_image: {
- medium: {
- height: 242,
- width: 726,
- url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.medium.jpg'
- },
- 'x-small': {
- height: 116,
- width: 348,
- url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.x-small.jpg'
- },
- small: {
- height: 145,
- width: 435,
- url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.small.jpg'
- },
- large: {
- height: 480,
- width: 1440,
- url: 'https://example.com/a87e5eac-3c93-45a1-a8e1-4c79ca8401c8.large.jpg'
- }
- },
- authoring_organizations: [
- {
- uuid: '0c6e5fa2-96e8-40b2-9ebe-c8b0df2a3b22',
- key: 'WageningenX',
- name: 'Wageningen University & Research',
- certificate_logo_image_url: 'https://example.com/org-certificate-logo.jpg',
- logo_image_url: 'https://example.com/org-logo.jpg'
- }
- ]
- }
- };
-
- beforeEach(function() {
- setFixtures('');
- view = new ProgramHeaderView({
- model: new Backbone.Model(context)
- });
- view.render();
- });
-
- afterEach(function() {
- view.remove();
- });
-
- it('should exist', function() {
- expect(view).toBeDefined();
- });
-
- it('should render the header based on the passed in model', function() {
- expect(view.$('.program-title').html()).toEqual(context.programData.title);
- expect(view.$('.org-logo').length).toEqual(context.programData.authoring_organizations.length);
- expect(view.$('.org-logo').attr('src'))
- .toEqual(context.programData.authoring_organizations[0].certificate_logo_image_url);
- expect(view.$('.org-logo').attr('alt'))
- .toEqual(context.programData.authoring_organizations[0].name + '\'s logo');
- });
- });
-}
-);
diff --git a/lms/static/js/spec/learner_dashboard/program_details_sidebar_view_spec.js b/lms/static/js/spec/learner_dashboard/program_details_sidebar_view_spec.js
deleted file mode 100644
index d4f9408e65..0000000000
--- a/lms/static/js/spec/learner_dashboard/program_details_sidebar_view_spec.js
+++ /dev/null
@@ -1,127 +0,0 @@
-define([
- 'backbone',
- 'js/learner_dashboard/views/program_details_sidebar_view'
-], function(Backbone, ProgramSidebarView) {
- 'use strict';
-
- describe('Program Progress View', function() {
- /* jslint maxlen: 500 */
- var view = null,
- // Don't bother linting the format of the test data
- /* eslint-disable */
- data = {
- programData: {"subtitle": "Explore water management concepts and technologies.", "overview": "\u003ch3\u003eXSeries Program Overview\u003c/h3\u003e\n\u003cp\u003eSafe water supply and hygienic water treatment are prerequisites for the well-being of communities all over the world. This Water XSeries, offered by the water management experts of TU Delft, will give you a unique opportunity to gain access to world-class knowledge and expertise in this field.\u003c/p\u003e\n\u003cp\u003eThis 3-course series will cover questions such as: How does climate change affect water cycle and public safety? How to use existing technologies to treat groundwater and surface water so we have safe drinking water? How do we take care of sewage produced in the cities on a daily basis? You will learn what are the physical, chemical and biological processes involved; carry out simple experiments at home; and have the chance to make a basic design of a drinking water treatment plant\u003c/p\u003e", "weeks_to_complete": null, "corporate_endorsements": [], "video": null, "type": "XSeries", "applicable_seat_types": ["verified", "professional", "credit"], "max_hours_effort_per_week": null, "transcript_languages": ["en-us"], "expected_learning_items": [], "uuid": "988e7ea8-f5e2-4d2e-998a-eae4ad3af322", "title": "Water Management", "languages": ["en-us"], "subjects": [{"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/engineering.jpg", "name": "Engineering", "subtitle": "Learn about engineering and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/engineering-1440x210.jpg", "slug": "engineering", "description": "Enroll in an online introduction to engineering course or explore specific areas such as structural, mechanical, electrical, software or aeronautical engineering. EdX offers free online courses in thermodynamics, robot mechanics, aerodynamics and more from top engineering universities."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/biology.jpg", "name": "Biology \u0026 Life Sciences", "subtitle": "Learn about biology and life sciences and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/plant-stomas-1440x210.jpg", "slug": "biology-life-sciences", "description": "Take free online biology courses in genetics, biotechnology, biochemistry, neurobiology and other disciplines. Courses include Fundamentals of Neuroscience from Harvard University, Molecular Biology from MIT and an Introduction to Bioethics from Georgetown."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/science.jpg", "name": "Science", "subtitle": "Learn about science and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/neuron-1440x210.jpg", "slug": "science", "description": "Science is one of the most popular subjects on edX and online courses range from beginner to advanced levels. Areas of study include neuroscience, genotyping, DNA methylation, innovations in environmental science, modern astrophysics and more from top universities and institutions worldwide."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/physics.jpg", "name": "Physics", "subtitle": "Learn about physics and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/header-bg-physics.png", "slug": "physics", "description": "Find online courses in quantum mechanics and magnetism the likes of MIT and Rice University or get an introduction to the violent universe from Australian National University."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/engery.jpg", "name": "Energy \u0026 Earth Sciences", "subtitle": "Learn about energy and earth sciences and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/energy-1440x210.jpg", "slug": "energy-earth-sciences", "description": "EdX\u2019s online Earth sciences courses cover very timely and important issues such as climate change and energy sustainability. Learn about natural disasters and our ability to predict them. Explore the universe with online courses in astrophysics, space plasmas and fusion energy."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/environmental-studies.jpg", "name": "Environmental Studies", "subtitle": "Learn about environmental studies, and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/environment-studies-1440x210.jpg", "slug": "environmental-studies", "description": "Take online courses in environmental science, natural resource management, environmental policy and civic ecology. Learn how to solve complex problems related to pollution control, water treatment and environmental sustainability with free online courses from leading universities worldwide."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/health.jpg", "name": "Health \u0026 Safety", "subtitle": "Learn about health and safety and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/health-and-safety-1440x210.jpg", "slug": "health-safety", "description": "From public health initiatives to personal wellbeing, find online courses covering a wide variety of health and medical subjects. Enroll in free courses from major universities on topics like epidemics, global healthcare and the fundamentals of clinical trials."}, {"card_image_url": "https://stage.edx.org/sites/default/files/subject/image/card/electronics.jpg", "name": "Electronics", "subtitle": "Learn about electronics and more from the best universities and institutions around the world.", "banner_image_url": "https://stage.edx.org/sites/default/files/electronics-a-1440x210.jpg", "slug": "electronics", "description": "The online courses in electrical engineering explore computation structures, electronic interfaces and the principles of electric circuits. Learn the engineering behind drones and autonomous robots or find out how organic electronic devices are changing the way humans interact with machines."}], "individual_endorsements": [], "staff": [{"family_name": "Smets", "uuid": "6078b3dd-ade4-457d-9262-7439a5f4b07e", "bio": "Dr. Arno H.M. Smets is Professor in Solar Energy in the Photovoltaics Material and Devices group at the faculty of Electrical Engineering, Mathematics and Computer Science, Delft University of Technology. From 2005-2010 he worked at the Research Center for Photovoltaics at the National Institute of Advanced Industrial Science and Technology (AIST) in Tsukuba Japan. His research work is focused on processing of thin silicon films, innovative materials and new concepts for photovoltaic applications. He is lecturer for BSc and MSc courses on Photovoltaics and Sustainable Energy at TU Delft. His online edX course on Solar Energy attracted over 150,000 students worldwide. He is co-author of the book \u003cem\u003e\u201cSolar Energy. The physics and engineering of photovoltaic conversion technologies and systems.\u201d\u003c/em\u003e", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/arno-smets_x110.jpg", "given_name": "Arno", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Professor, Electrical Engineering, Mathematics and Computer Science"}, "works": [], "slug": "arno-smets"}, {"family_name": "van de Giesen", "uuid": "0e28153f-4e9f-4080-b56f-43480600ecd7", "bio": "Since July 2004, Nick van de Giesen has held the Van Kuffeler Chair of Water Resources Management of the Faculty of Civil Engineering and Geosciences. He teaches Integrated Water Resources Management and Water Management. His main interests are the modeling of complex water resources systems and the development of science-based decision support systems. The interaction between water systems and their users is the core theme in both research portfolio and teaching curriculum. Since 1 April 2009, he is chairman of the \u003ca href=\"http://www.environment.tudelft.nl\"\u003eDelft Research Initiative Environment\u003c/a\u003e.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/giesen_vd_nick_110p.jpg", "given_name": "Nick", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "nick-van-de-giesen"}, {"family_name": "Russchenberg", "uuid": "8a94bdb9-ac44-4bc1-a3d2-306f391682b4", "bio": "Herman Russchenberg is engaged in intensive and extensive research into the causes of climate change. His own research involves investigating the role played by clouds and dust particles in the atmosphere, but he is also head of the TU Delft Climate Institute, established in March 2012 to bring together TU Delft researchers working on all aspects of climate and climate change. Russchenberg started out in the faculty of Electrical Engineering, conducting research into the influence of the atmosphere (rain, clouds) on satellite signals. After obtaining his PhD in 1992, he shifted his attention to the physics of water vapour, water droplets, dust particles, sunlight, radiation and emissions in the atmosphere. He is now based in the faculty of Civil Engineering and Geosciences.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/russchenberg_herman_110p.jpg", "given_name": "Herman", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "herman-russchenberg"}, {"family_name": "Savenije", "uuid": "4ebdcd93-bb4e-4c0c-9faf-4e513b1a2e33", "bio": "Prof. Savenije was born in 1952 in the Netherlands and studied at the Delft University of Technology, in the Netherlands, where he obtained his MSc in 1977 in Hydrology. As a young graduate hydrologist he worked for six years in Mozambique where he developed a theory on salt intrusion in estuaries and studied the hydrology of international rivers. From 1985-1990 he worked as an international consultant mostly in Asia and Africa. He joined academia in 1990 to complete his PhD in 1992. In 1994 he was appointed Professor of Water Resources Management at the IHE (now UNESCO-IHE, Institute for Water Education) in Delft, the Netherlands. Since 1999, he is Professor of Hydrology at the Delft University of Technology, where he is the head of the Water Resources Section. He is President of the International Association of Hydrological Sciences and Executive Editor of the journal Hydrology and Earth System Sciences.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/savenije_hubert_110p.jpg", "given_name": "Hubert", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "hubert-savenije"}, {"family_name": "Stive", "uuid": "a7364bab-8e9c-4265-bd14-598afac1f086", "bio": "Marcel Stive studied Civil engineering at the Delft University of Technology, where he graduated in 1977 and received his doctorate in 1988. After graduating in 1977 Stive started working at WL-Delft Hydraulics, where he worked until 1992. In 1992 he became a professor at the Polytechnic University of Catalonia in Barcelona, Spain. In 1994 her returned to WL-Delft Hydraulics and at the same time began to work as a professor of Coastal Morphodynamics at the Delft University of Technology. Since 2001 Stive is a professor of Coastal Engineering at Delft University of Technology and he is the scientific director of the Water Research Centre Delft since 2003.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/stive_marcel_110p.jpg", "given_name": "Marcel", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "TU Delft", "title": "Professor"}, "works": [], "slug": "marcel-stive"}, {"family_name": "Rietveld", "uuid": "1b70c71d-20cc-487d-be10-4b31baeff559", "bio": "\u003cp\u003eLuuk Rietveld is professor of Urban Water Cycle Technology at Delft University of Technology. After finalizing his studies in Civil Engineering at Delft University of Technology in 1987, he worked, until 1991, as lecturer/researcher in Sanitary Engineering at the Eduardo Mondlane University, Maputo, Mozambique. Between 1991 and 1994, he was employed at the Management Centre for International Co-operation, and since 1994 he has had an appointment at the Department of Water Management of Delft University of Technology. In 2005, he defended his PhD thesis entitled \"Improving Operation of Drinking Water Treatment through Modelling\".\u003c/p\u003e\n\u003cp\u003eLuuk Rietveld\u2019s main research interests are modelling and optimisation of processes in the urban water cycle, and technological innovations in drinking water treatment and water reclamation for industrial purposes. In addition, he has extensive experience in education, in various cultural contexts, and is interested to explore the use of new ways of teaching through activated and blended learning and MOOCs.\u003c/p\u003e", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/rietveld_luuk_110p.jpg", "given_name": "Luuk", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "luuk-rietveld-0"}, {"family_name": "van Halem", "uuid": "4ce9ef2a-19e9-46de-9f34-5d755f26736a", "bio": "Doris van Halem is a tenure track Assistant Professor within the Department of Water Management, section Sanitary Engineering of Delft University of Technology. She graduated from Delft University of Technology in Civil Engineering and Geosciences with a cum laude MSc degree (2007). During her studies she developed an interest in global drinking water challenges, illustrated by her internships in Sri Lanka and Benin, resulting in an MSc thesis \u201cCeramic silver impregnated pot filter for household drinking water treatment in developing countries\u201d. In 2011 she completed her PhD research (with honours) on subsurface iron and arsenic removal for drinking water supply in Bangladesh under the guidance of prof. J.C. van Dijk (TU Delft) and prof. dr. G.L. Amy (Unesco-IHE). Currently she supervises BSc, MSc and PhD students, focusing on inorganic constituent behaviour and trace compound removal during soil passage and drinking water treatment - with a particular interest in smart, pro-poor drinking water solutions.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/doris_van_halem_1.jpg", "given_name": "Doris", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Assistant Professor, Sanitary Engineering"}, "works": [], "slug": "doris-van-halem-0"}, {"family_name": "Grefte", "uuid": "463c3f1a-95fc-45aa-b7c0-d01b14126f02", "bio": "Anke Grefte is project manager open, online and blended education for the Faculty of Civil Engineering and Geosciences, Delft University of Technology. She graduated from Delft University of Technology in Civil Engineering with a master\u2019s thesis entitled \"Behaviour of particles in a drinking water distribution network; test rig results\". For this thesis Anke was awarded the Gijs Oskam award for best young researcher. In November 2013, she finished her Ph.D. research on the removal of Natural Organic Matter (NOM) fractions by ion exchange and the impact on drinking water treatment processes and biological stability.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/grefte_anke_110p.jpg", "given_name": "Anke", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "anke-grefte-0"}, {"family_name": "Lier", "uuid": "349aa2cc-0107-4632-ad10-869f23966049", "bio": "Jules van Lier is full professor of Environmental Engineering and Wastewater Treatment at the Sanitary Engineering Section of Delft University of Technology and has a 1 day per week posted position at the Unesco-IHE Institute for Water Education, also in Delft Jules van Lier accomplished his PhD on Thermophilic Anaerobic Wastewater Treatment under the supervision of Prof. Gatze Lettinga (1995) at Wageningen University. Throughout his career he has been involved as a senior researcher / project manager in various (inter)national research projects, working on cost-effective water treatment for resource recovery (water, nutrients, biogas, elements). His research projects are focused on closing water cycles in industries and sewage water recovery for irrigated agriculture. The further development of anaerobic treatment technology is his prime focus. In addition to university work he is an Executive Board Member and Scientific Advisor to the LeAF Foundation; regional representative for Western Europe Anaerobic Digestion Specialist group of the International Water Association (IWA); editor of scientific journals (e.g Water Science Technology and Advances in Environmental Research and Development); member of the Paques Technological Advisory Commission; and member of the Advisory Board of World-Waternet, Amsterdam.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/lier_van_jules_110p.jpg", "given_name": "Jules van", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Professor, Sanitary Engineering"}, "works": [], "slug": "jules-van-lier"}, {"family_name": "Kreuk", "uuid": "c1e50a84-1b09-47b5-b704-5e16309d0cba", "bio": "Merle de Kreuk is a wastewater Associate Professor at the Sanitary Engineering department of the Delft University of Technology. Her research focus is on (municipal and industrial) wastewater treatment systems and anaerobic processes, aiming to link the world of Biotechnology to the Civil Engineering, as well as fundamental research to industrial applications. Her main research topics are hydrolysis processes in anaerobic treatment and granule formation and deterioration. Merle\u2019s PhD and Post-Doc research involved the development of aerobic granular sludge technology and up scaling the technology from a three litre lab scale reactor to the full scale Nereda\u00ae process\u00ae. The first application of aerobic granular sludge technology in the Netherlands was opened in May 2012, and currently many more installations are being built, due to its compactness, low energy use and good effluent characteristics. Her previous work experience also involved the position of water treatment technology innovator at Water authority Hollandse Delta on projects such as the Energy Factory in which 14 water authorities cooperated to develop an energy producing sewage treatment plant.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/kreuk_de_merle_110p.jpg", "given_name": "Merle de", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Associate Professor, Sanitary Engineering"}, "works": [], "slug": "merle-de-kreuk"}], "marketing_slug": "water-management", "marketing_url": "https://stage.edx.org/xseries/water-management", "status": "active", "credit_redemption_overview": "These courses can be taken in any order.", "card_image_url": "https://stage.edx.org/sites/default/files/card/images/waterxseries_course0.png", "faq": [], "price_ranges": [{"currency": "USD", "max": 15.0, "total": 35.0, "min": 10.0}], "banner_image": {"small": {"url": "https://d385l2sek0vys7.cloudfront.net/media/programs/banner_images/988e7ea8-f5e2-4d2e-998a-eae4ad3af322.small.jpg", "width": 435, "height": 145}, "large": {"url": "https://d385l2sek0vys7.cloudfront.net/media/programs/banner_images/988e7ea8-f5e2-4d2e-998a-eae4ad3af322.large.jpg", "width": 1440, "height": 480}, "medium": {"url": "https://d385l2sek0vys7.cloudfront.net/media/programs/banner_images/988e7ea8-f5e2-4d2e-998a-eae4ad3af322.medium.jpg", "width": 726, "height": 242}, "x-small": {"url": "https://d385l2sek0vys7.cloudfront.net/media/programs/banner_images/988e7ea8-f5e2-4d2e-998a-eae4ad3af322.x-small.jpg", "width": 348, "height": 116}}, "authoring_organizations": [{"description": "Delft University of Technology is the largest and oldest technological university in the Netherlands. Our research is inspired by the desire to increase fundamental understanding, as well as by societal challenges. We encourage our students to be independent thinkers so they will become engineers capable of solving complex problems. Our students have chosen Delft University of Technology because of our reputation for quality education and research.", "tags": ["charter", "contributor"], "name": "Delft University of Technology (TU Delft)", "homepage_url": null, "key": "DelftX", "certificate_logo_image_url": null, "marketing_url": "https://stage.edx.org/school/delftx", "logo_image_url": "https://stage.edx.org/sites/default/files/school/image/banner/delft_logo_200x101_0.png", "uuid": "c484a523-d396-4aff-90f4-bb7e82e16bf6"}], "job_outlook_items": [], "credit_backing_organizations": [], "weeks_to_complete_min": 4, "weeks_to_complete_max": 8, "min_hours_effort_per_week": null},
- courseData: {
- "completed": [{"owners": [{"uuid": "c484a523-d396-4aff-90f4-bb7e82e16bf6", "key": "DelftX", "name": "Delft University of Technology (TU Delft)"}], "uuid": "4ce7a648-3172-475a-84f3-9f843b2157f3", "title": "Introduction to Water and Climate", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/wc_home_378x225.jpg", "height": null, "description": null, "width": null}, "key": "Delftx+CTB3300WCx", "course_runs": [{"upgrade_url": null, "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/wc_home_378x225.jpg", "height": null, "description": null, "width": null}, "max_effort": null, "is_enrollment_open": true, "course": "Delftx+CTB3300WCx", "content_language": "en-us", "eligible_for_financial_aid": true, "seats": [{"sku": "18AC1BC", "credit_hours": null, "price": "0.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "honor"}, {"sku": "86A734B", "credit_hours": null, "price": "10.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "verified"}], "course_url": "/courses/course-v1:Delftx+CTB3300WCx+2015_T3/", "availability": "Archived", "transcript_languages": ["en-us"], "staff": [{"family_name": "van de Giesen", "uuid": "0e28153f-4e9f-4080-b56f-43480600ecd7", "bio": "Since July 2004, Nick van de Giesen has held the Van Kuffeler Chair of Water Resources Management of the Faculty of Civil Engineering and Geosciences. He teaches Integrated Water Resources Management and Water Management. His main interests are the modeling of complex water resources systems and the development of science-based decision support systems. The interaction between water systems and their users is the core theme in both research portfolio and teaching curriculum. Since 1 April 2009, he is chairman of the \u003ca href=\"http://www.environment.tudelft.nl\"\u003eDelft Research Initiative Environment\u003c/a\u003e.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/giesen_vd_nick_110p.jpg", "given_name": "Nick", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "nick-van-de-giesen"}, {"family_name": "Russchenberg", "uuid": "8a94bdb9-ac44-4bc1-a3d2-306f391682b4", "bio": "Herman Russchenberg is engaged in intensive and extensive research into the causes of climate change. His own research involves investigating the role played by clouds and dust particles in the atmosphere, but he is also head of the TU Delft Climate Institute, established in March 2012 to bring together TU Delft researchers working on all aspects of climate and climate change. Russchenberg started out in the faculty of Electrical Engineering, conducting research into the influence of the atmosphere (rain, clouds) on satellite signals. After obtaining his PhD in 1992, he shifted his attention to the physics of water vapour, water droplets, dust particles, sunlight, radiation and emissions in the atmosphere. He is now based in the faculty of Civil Engineering and Geosciences.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/russchenberg_herman_110p.jpg", "given_name": "Herman", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "herman-russchenberg"}, {"family_name": "Savenije", "uuid": "4ebdcd93-bb4e-4c0c-9faf-4e513b1a2e33", "bio": "Prof. Savenije was born in 1952 in the Netherlands and studied at the Delft University of Technology, in the Netherlands, where he obtained his MSc in 1977 in Hydrology. As a young graduate hydrologist he worked for six years in Mozambique where he developed a theory on salt intrusion in estuaries and studied the hydrology of international rivers. From 1985-1990 he worked as an international consultant mostly in Asia and Africa. He joined academia in 1990 to complete his PhD in 1992. In 1994 he was appointed Professor of Water Resources Management at the IHE (now UNESCO-IHE, Institute for Water Education) in Delft, the Netherlands. Since 1999, he is Professor of Hydrology at the Delft University of Technology, where he is the head of the Water Resources Section. He is President of the International Association of Hydrological Sciences and Executive Editor of the journal Hydrology and Earth System Sciences.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/savenije_hubert_110p.jpg", "given_name": "Hubert", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "hubert-savenije"}, {"family_name": "Stive", "uuid": "a7364bab-8e9c-4265-bd14-598afac1f086", "bio": "Marcel Stive studied Civil engineering at the Delft University of Technology, where he graduated in 1977 and received his doctorate in 1988. After graduating in 1977 Stive started working at WL-Delft Hydraulics, where he worked until 1992. In 1992 he became a professor at the Polytechnic University of Catalonia in Barcelona, Spain. In 1994 her returned to WL-Delft Hydraulics and at the same time began to work as a professor of Coastal Morphodynamics at the Delft University of Technology. Since 2001 Stive is a professor of Coastal Engineering at Delft University of Technology and he is the scientific director of the Water Research Centre Delft since 2003.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/stive_marcel_110p.jpg", "given_name": "Marcel", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "TU Delft", "title": "Professor"}, "works": [], "slug": "marcel-stive"}], "announcement": "2015-06-09T00:00:00Z", "end": "2015-11-04T12:00:00Z", "uuid": "a36f5673-6637-11e6-a8e3-22000bdde520", "title": "Introduction to Water and Climate", "certificate_url": "/certificates/a37c59143d9d422eb6ab11e1053b8eb5", "enrollment_start": null, "start": "2015-09-01T04:00:00Z", "min_effort": null, "short_description": "Explore how climate change, water availability, and engineering innovation are key challenges for our planet.", "hidden": false, "level_type": "Intermediate", "type": "verified", "enrollment_open_date": "Jan 01, 1900", "marketing_url": "https://stage.edx.org/course/introduction-water-climate-delftx-ctb3300wcx-0", "is_course_ended": true, "instructors": [], "full_description": "\u003cp\u003eWater is essential for life on earth and of crucial importance for society. Cycling across the planet and the atmosphere, it also has a major influence on our climate.\u003c/p\u003e\n\u003cp\u003eWeekly modules are hosted by four different professors, all of them being international experts in their field. The course consists of knowledge clips, movies, exercises, discussion and homework assignments. It finishes with an examination.\u003c/p\u003e\n\u003cp\u003eThis course combined with the courses \"Introduction to Drinking Water Treatment\" (new edition to start in January 2016) and \"Introduction to the Treatment of Urban Sewage\" (new edition to start in April 2016) forms the Water XSeries, Faculty of Civil Engineering and Geosciences, TU Delft.\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e\u003cstrong\u003eLICENSE\u003c/strong\u003e\u003cbr /\u003e\nThe course materials of this course are Copyright Delft University of Technology and are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike (CC-BY-NC-SA) 4.0 International License.\u003c/em\u003e\u003c/p\u003e", "key": "course-v1:Delftx+CTB3300WCx+2015_T3", "enrollment_end": null, "reporting_type": "mooc", "advertised_start": null, "mobile_available": true, "modified": "2017-04-06T12:26:52.594942Z", "is_enrolled": false, "pacing_type": "instructor_paced", "video": {"src": "http://www.youtube.com/watch?v=dJEhwq0sXiQ", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/featured-card/wc_home_378x225.jpg", "width": null, "description": null, "height": null}, "description": null}}]}, {"owners": [{"uuid": "c484a523-d396-4aff-90f4-bb7e82e16bf6", "key": "DelftX", "name": "Delft University of Technology (TU Delft)"}], "uuid": "a0aade38-7a50-4afb-97cd-2214c572cc86", "title": "Urban Sewage Treatment", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/sewage_home_378x225.jpg", "height": null, "description": null, "width": null}, "key": "DelftX+CTB3365STx", "course_runs": [{"upgrade_url": null, "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/sewage_home_378x225.jpg", "height": null, "description": null, "width": null}, "max_effort": null, "is_enrollment_open": true, "course": "DelftX+CTB3365STx", "content_language": "en-us", "eligible_for_financial_aid": true, "seats": [{"sku": "01CDD4F", "credit_hours": null, "price": "0.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "honor"}, {"sku": "B4F253D", "credit_hours": null, "price": "10.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "verified"}], "course_url": "/courses/course-v1:Delftx+CTB3365STx+1T2016/", "availability": "Archived", "transcript_languages": ["en-us"], "staff": [{"family_name": "Lier", "uuid": "349aa2cc-0107-4632-ad10-869f23966049", "bio": "Jules van Lier is full professor of Environmental Engineering and Wastewater Treatment at the Sanitary Engineering Section of Delft University of Technology and has a 1 day per week posted position at the Unesco-IHE Institute for Water Education, also in Delft Jules van Lier accomplished his PhD on Thermophilic Anaerobic Wastewater Treatment under the supervision of Prof. Gatze Lettinga (1995) at Wageningen University. Throughout his career he has been involved as a senior researcher / project manager in various (inter)national research projects, working on cost-effective water treatment for resource recovery (water, nutrients, biogas, elements). His research projects are focused on closing water cycles in industries and sewage water recovery for irrigated agriculture. The further development of anaerobic treatment technology is his prime focus. In addition to university work he is an Executive Board Member and Scientific Advisor to the LeAF Foundation; regional representative for Western Europe Anaerobic Digestion Specialist group of the International Water Association (IWA); editor of scientific journals (e.g Water Science Technology and Advances in Environmental Research and Development); member of the Paques Technological Advisory Commission; and member of the Advisory Board of World-Waternet, Amsterdam.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/lier_van_jules_110p.jpg", "given_name": "Jules van", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Professor, Sanitary Engineering"}, "works": [], "slug": "jules-van-lier"}, {"family_name": "Kreuk", "uuid": "c1e50a84-1b09-47b5-b704-5e16309d0cba", "bio": "Merle de Kreuk is a wastewater Associate Professor at the Sanitary Engineering department of the Delft University of Technology. Her research focus is on (municipal and industrial) wastewater treatment systems and anaerobic processes, aiming to link the world of Biotechnology to the Civil Engineering, as well as fundamental research to industrial applications. Her main research topics are hydrolysis processes in anaerobic treatment and granule formation and deterioration. Merle\u2019s PhD and Post-Doc research involved the development of aerobic granular sludge technology and up scaling the technology from a three litre lab scale reactor to the full scale Nereda\u00ae process\u00ae. The first application of aerobic granular sludge technology in the Netherlands was opened in May 2012, and currently many more installations are being built, due to its compactness, low energy use and good effluent characteristics. Her previous work experience also involved the position of water treatment technology innovator at Water authority Hollandse Delta on projects such as the Energy Factory in which 14 water authorities cooperated to develop an energy producing sewage treatment plant.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/kreuk_de_merle_110p.jpg", "given_name": "Merle de", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Associate Professor, Sanitary Engineering"}, "works": [], "slug": "merle-de-kreuk"}], "announcement": "2015-07-24T00:00:00Z", "end": "2016-07-01T22:30:00Z", "uuid": "a36f70c1-6637-11e6-a8e3-22000bdde520", "title": "Introduction to the Treatment of Urban Sewage", "certificate_url": "/certificates/bed3980e67ca40f0b31e309d9dfe9e7e", "enrollment_start": null, "start": "2016-04-12T04:00:00Z", "min_effort": null, "short_description": "Learn about urban water services, focusing on basic sewage treatment technologies.", "hidden": false, "level_type": "Intermediate", "type": "verified", "enrollment_open_date": "Jan 01, 1900", "marketing_url": "https://stage.edx.org/course/introduction-treatment-urban-sewage-delftx-ctb3365stx-0", "is_course_ended": true, "instructors": [], "full_description": "\u003cp\u003eThis course will focus on basic technologies for the treatment of urban sewage. Unit processes involved in the treatment chain will be described as well as the physical, chemical and biological processes involved. There will be an emphasis on water quality and the functionality of each unit process within the treatment chain. After the course one should be able to recognise the process units, describe their function and make simple design calculations on urban sewage treatment plants.\u003c/p\u003e\n\u003cp\u003eThe course consists of 6 modules:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eSewage treatment plant overview. In this module you will learn what major pollutants are present in the sewage and why we need to treat sewage prior to discharge to surface waters. The functional units will be briefly discussed\u003c/li\u003e\n\u003cli\u003ePrimary treatment. In this module you learn how coarse material, sand \u0026 grit are removed from the sewage and how to design primary clarification tanks\u003c/li\u003e\n\u003cli\u003eBiological treatment. In this module you learn the basics of the carbon, nitrogen and phosphorous cycle and how biological processes are used to treat the main pollutants of concern.\u003c/li\u003e\n\u003cli\u003eActivated sludge process. In this module you learn the design principles of conventional activated sludge processes including the secondary clarifiers and aeration demand of aeration tanks.\u003c/li\u003e\n\u003cli\u003eNitrogen and phosphorus removal. In this module you learn the principles of biological nitrogen removal as well as phosphorus removal by biological and/or chemical means.\u003c/li\u003e\n\u003cli\u003eSludge treatment. In this module you will the design principles of sludge thickeners, digesters and dewatering facilities for the concentration and stabilisation of excess sewage sludge. Potentials for energy recovery via the produced biogas will be discussed as well as the direct anaerobic treatment of urban sewage in UASB reactors when climate conditions allow.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThis course in combination with the courses \"\u003ca href=\"https://www.edx.org/course/introduction-water-climate-delftx-ctb3300wcx-0\"\u003eIntroduction to Water and Climate\u003c/a\u003e\" and \"\u003ca href=\"https://www.edx.org/course/introduction-drinking-water-treatment-delftx-ctb3365dwx-0\"\u003eIntroduction to Drinking Water Treatment\u003c/a\u003e\" forms the Water XSeries, by DelftX.\u003c/p\u003e\n\u003chr /\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cem\u003eLICENSE\u003c/em\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eThe course materials of this course are Copyright Delft University of Technology and are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike (CC-BY-NC-SA) 4.0 International License.\u003c/em\u003e\u003c/p\u003e", "key": "course-v1:Delftx+CTB3365STx+1T2016", "enrollment_end": null, "reporting_type": "mooc", "advertised_start": null, "mobile_available": true, "modified": "2017-04-06T12:26:52.679900Z", "is_enrolled": true, "pacing_type": "instructor_paced", "video": {"src": "http://www.youtube.com/watch?v=pcSsOE-F4e8", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/featured-card/sewage_home_378x225.jpg", "width": null, "description": null, "height": null}, "description": null}}]}],
- "in_progress": [], "uuid": "988e7ea8-f5e2-4d2e-998a-eae4ad3af322",
- "not_started": [{"owners": [{"uuid": "c484a523-d396-4aff-90f4-bb7e82e16bf6", "key": "DelftX", "name": "Delft University of Technology (TU Delft)"}], "uuid": "51275d00-1f3f-462f-8231-ce42821cc1dd", "title": "Solar Energy", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/solar-energy_378x225.jpg", "height": null, "description": null, "width": null}, "key": "DelftX+ET3034TUx", "course_runs": [{"upgrade_url": null, "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/solar-energy_378x225.jpg", "height": null, "description": null, "width": null}, "max_effort": null, "is_enrollment_open": true, "course": "DelftX+ET3034TUx", "content_language": null, "eligible_for_financial_aid": true, "seats": [{"sku": "E433FA8", "credit_hours": null, "price": "0.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "honor"}], "course_url": "/courses/DelftX/ET3034TUx/2013_Fall/", "availability": "Archived", "transcript_languages": [], "staff": [{"family_name": "Smets", "uuid": "6078b3dd-ade4-457d-9262-7439a5f4b07e", "bio": "Dr. Arno H.M. Smets is Professor in Solar Energy in the Photovoltaics Material and Devices group at the faculty of Electrical Engineering, Mathematics and Computer Science, Delft University of Technology. From 2005-2010 he worked at the Research Center for Photovoltaics at the National Institute of Advanced Industrial Science and Technology (AIST) in Tsukuba Japan. His research work is focused on processing of thin silicon films, innovative materials and new concepts for photovoltaic applications. He is lecturer for BSc and MSc courses on Photovoltaics and Sustainable Energy at TU Delft. His online edX course on Solar Energy attracted over 150,000 students worldwide. He is co-author of the book \u003cem\u003e\u201cSolar Energy. The physics and engineering of photovoltaic conversion technologies and systems.\u201d\u003c/em\u003e", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/arno-smets_x110.jpg", "given_name": "Arno", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Professor, Electrical Engineering, Mathematics and Computer Science"}, "works": [], "slug": "arno-smets"}], "announcement": "2013-05-08T00:00:00Z", "end": "2013-12-06T10:30:00Z", "uuid": "f33a9660-b5d0-47a9-9bfa-a326d9ed4ef2", "title": "Solar Energy", "certificate_url": null, "enrollment_start": null, "start": "2013-09-16T04:00:00Z", "min_effort": null, "short_description": "Discover the power of solar energy and design a complete photovoltaic system.", "hidden": false, "level_type": null, "type": "honor", "enrollment_open_date": "Jan 01, 1900", "marketing_url": "https://stage.edx.org/course/solar-energy-delftx-et3034tux", "is_course_ended": true, "instructors": [], "full_description": "", "key": "DelftX/ET3034TUx/2013_Fall", "enrollment_end": null, "reporting_type": "mooc", "advertised_start": null, "mobile_available": false, "modified": "2017-04-06T12:26:54.345710Z", "is_enrolled": false, "pacing_type": "instructor_paced", "video": {"src": "http://www.youtube.com/watch?v=LLiNzrIubF0", "image": null, "description": null}}]}, {"owners": [{"uuid": "c484a523-d396-4aff-90f4-bb7e82e16bf6", "key": "DelftX", "name": "Delft University of Technology (TU Delft)"}], "uuid": "7c430382-d477-4bac-9c29-f36c24f1935f", "title": "Drinking Water Treatment", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/drinking_water_home_378x225.jpg", "height": null, "description": null, "width": null}, "key": "DelftX+CTB3365DWx", "course_runs": [{"upgrade_url": null, "image": {"src": "https://stage.edx.org/sites/default/files/course/image/promoted/drinking_water_home_378x225.jpg", "height": null, "description": null, "width": null}, "max_effort": null, "is_enrollment_open": true, "course": "DelftX+CTB3365DWx", "content_language": "en-us", "eligible_for_financial_aid": true, "seats": [{"sku": "74AC06B", "credit_hours": 100, "price": "15.00", "currency": "USD", "upgrade_deadline": "2016-04-30T00:00:00Z", "credit_provider": "mit", "type": "credit"}, {"sku": "0BBAE34", "credit_hours": null, "price": "0.00", "currency": "USD", "upgrade_deadline": null, "credit_provider": null, "type": "honor"}, {"sku": "8E52FAE", "credit_hours": null, "price": "10.00", "currency": "USD", "upgrade_deadline": "2016-03-25T01:06:00Z", "credit_provider": null, "type": "verified"}], "course_url": "/courses/course-v1:DelftX+CTB3365DWx+1T2016/", "availability": "Current", "transcript_languages": ["en-us"], "staff": [{"family_name": "Rietveld", "uuid": "1b70c71d-20cc-487d-be10-4b31baeff559", "bio": "\u003cp\u003eLuuk Rietveld is professor of Urban Water Cycle Technology at Delft University of Technology. After finalizing his studies in Civil Engineering at Delft University of Technology in 1987, he worked, until 1991, as lecturer/researcher in Sanitary Engineering at the Eduardo Mondlane University, Maputo, Mozambique. Between 1991 and 1994, he was employed at the Management Centre for International Co-operation, and since 1994 he has had an appointment at the Department of Water Management of Delft University of Technology. In 2005, he defended his PhD thesis entitled \"Improving Operation of Drinking Water Treatment through Modelling\".\u003c/p\u003e\n\u003cp\u003eLuuk Rietveld\u2019s main research interests are modelling and optimisation of processes in the urban water cycle, and technological innovations in drinking water treatment and water reclamation for industrial purposes. In addition, he has extensive experience in education, in various cultural contexts, and is interested to explore the use of new ways of teaching through activated and blended learning and MOOCs.\u003c/p\u003e", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/rietveld_luuk_110p.jpg", "given_name": "Luuk", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "luuk-rietveld-0"}, {"family_name": "van Halem", "uuid": "4ce9ef2a-19e9-46de-9f34-5d755f26736a", "bio": "Doris van Halem is a tenure track Assistant Professor within the Department of Water Management, section Sanitary Engineering of Delft University of Technology. She graduated from Delft University of Technology in Civil Engineering and Geosciences with a cum laude MSc degree (2007). During her studies she developed an interest in global drinking water challenges, illustrated by her internships in Sri Lanka and Benin, resulting in an MSc thesis \u201cCeramic silver impregnated pot filter for household drinking water treatment in developing countries\u201d. In 2011 she completed her PhD research (with honours) on subsurface iron and arsenic removal for drinking water supply in Bangladesh under the guidance of prof. J.C. van Dijk (TU Delft) and prof. dr. G.L. Amy (Unesco-IHE). Currently she supervises BSc, MSc and PhD students, focusing on inorganic constituent behaviour and trace compound removal during soil passage and drinking water treatment - with a particular interest in smart, pro-poor drinking water solutions.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/doris_van_halem_1.jpg", "given_name": "Doris", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": {"organization_name": "Delft University of Technology", "title": "Assistant Professor, Sanitary Engineering"}, "works": [], "slug": "doris-van-halem-0"}, {"family_name": "Grefte", "uuid": "463c3f1a-95fc-45aa-b7c0-d01b14126f02", "bio": "Anke Grefte is project manager open, online and blended education for the Faculty of Civil Engineering and Geosciences, Delft University of Technology. She graduated from Delft University of Technology in Civil Engineering with a master\u2019s thesis entitled \"Behaviour of particles in a drinking water distribution network; test rig results\". For this thesis Anke was awarded the Gijs Oskam award for best young researcher. In November 2013, she finished her Ph.D. research on the removal of Natural Organic Matter (NOM) fractions by ion exchange and the impact on drinking water treatment processes and biological stability.", "profile_image": {}, "profile_image_url": "https://stage.edx.org/sites/default/files/person/image/grefte_anke_110p.jpg", "given_name": "Anke", "urls": {"blog": null, "twitter": null, "facebook": null}, "position": null, "works": [], "slug": "anke-grefte-0"}], "announcement": "2015-07-24T00:00:00Z", "end": "2017-07-20T21:30:00Z", "uuid": "a36ed16a-6637-11e6-a8e3-22000bdde520", "title": "Introduction to Drinking Water Treatment", "certificate_url": null, "enrollment_start": "2016-06-15T00:00:00Z", "start": "2016-01-12T05:00:00Z", "min_effort": null, "short_description": "Learn about urban water services, focusing on conventional technologies for drinking water treatment.", "hidden": false, "level_type": "Intermediate", "type": "credit", "enrollment_open_date": "Jun 15, 2016", "marketing_url": "https://stage.edx.org/course/introduction-drinking-water-treatment-delftx-ctb3365dwx-0", "is_course_ended": false, "instructors": [], "full_description": "\u003cp\u003eThis course focuses on conventional technologies for drinking water treatment. Unit processes, involved in the treatment chain, are discussed as well as the physical, chemical and biological processes involved. The emphasis is on the effect of treatment on water quality and the dimensions of the unit processes in the treatment chain. After the course one should be able to recognise the process units, describe their function, and make basic calculations for a preliminary design of a drinking water treatment plant.\u003c/p\u003e\n\u003cp\u003eThe course consists of 4 modules:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eIntroduction to drinking water treatment. In this module you learn to describe the important disciplines, schemes and evaluation criteria involved in the design phase.\u003c/li\u003e\n\u003cli\u003eWater quality. In this module you learn to identify the drinking water quality parameters to be improved and explain what treatment train or scheme is needed.\u003c/li\u003e\n\u003cli\u003eGroundwater treatment. In this module you learn to calculate the dimensions of the groundwater treatment processes and draw groundwater treatment schemes.\u003c/li\u003e\n\u003cli\u003eSurface water treatment. In this module you learn to calculate the dimensions of the surface water treatment processes and draw surface water treatment schemes.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThis course in combination with the courses \"\u003ca href=\"https://www.edx.org/course/introduction-water-climate-delftx-ctb3300wcx-0\"\u003eIntroduction to Water and Climate\u003c/a\u003e\" and \"\u003ca href=\"https://www.edx.org/course/introduction-treatment-urban-sewage-delftx-ctb3365stx\"\u003eIntroduction to the Treatment of Urban Sewage\u003c/a\u003e\" forms the Water XSeries, by DelftX.\u003c/p\u003e\n\u003chr /\u003e\n\u003cp\u003e\u003cstrong\u003e\u003cem\u003eLICENSE\u003c/em\u003e\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eThe course materials of this course are Copyright Delft University of Technology and are licensed under a Creative Commons Attribution-NonCommercial-ShareAlike (CC-BY-NC-SA) 4.0 International License.\u003c/em\u003e\u003c/p\u003e", "key": "course-v1:DelftX+CTB3365DWx+1T2016", "enrollment_end": null, "reporting_type": "mooc", "advertised_start": null, "mobile_available": true, "modified": "2017-04-06T12:26:52.652365Z", "is_enrolled": false, "pacing_type": "instructor_paced", "video": {"src": "http://www.youtube.com/watch?v=0xPZXLHtRJw", "image": {"src": "https://stage.edx.org/sites/default/files/course/image/featured-card/h20_new_378x225.jpg", "width": null, "description": null, "height": null}, "description": null}}]}]},
- certificateData: [
- {
- "url": "/certificates/a37c59143d9d422eb6ab11e1053b8eb5", "type": "course", "title": "Introduction to Water and Climate"
- }, {
- "url": "/certificates/bed3980e67ca40f0b31e309d9dfe9e7e", "type": "course", "title": "Introduction to the Treatment of Urban Sewage"
- }
- ],
- urls: {"program_listing_url": "/dashboard/programs/", "commerce_api_url": "/api/commerce/v0/baskets/", "track_selection_url": "/course_modes/choose/"},
- userPreferences: {"pref-lang": "en"}
- },
- /* eslint-enable */
- programModel,
- courseData,
- certificateCollection,
- testCircle,
- testText,
- initView;
-
- testCircle = function(progress) {
- var $circle = view.$('.progress-circle'),
- incomplete = progress.in_progress.length + progress.not_started.length;
-
- expect($circle.find('.complete').length).toEqual(progress.completed.length);
- expect($circle.find('.incomplete').length).toEqual(incomplete);
- };
-
- testText = function(progress) {
- var $numbers = view.$('.numbers'),
- total = progress.completed.length + progress.in_progress.length + progress.not_started.length;
-
- expect(view.$('.progress-heading').html()).toEqual('XSeries Progress');
- expect(parseInt($numbers.find('.complete').html(), 10)).toEqual(progress.completed.length);
- expect(parseInt($numbers.find('.total').html(), 10)).toEqual(total);
- };
-
- initView = function() {
- return new ProgramSidebarView({
- el: '.js-program-sidebar',
- model: programModel,
- courseModel: courseData,
- certificateCollection: certificateCollection
- });
- };
-
- beforeEach(function() {
- setFixtures('');
- programModel = new Backbone.Model(data.programData);
- courseData = new Backbone.Model(data.courseData);
- certificateCollection = new Backbone.Collection(data.certificateData);
- });
-
- afterEach(function() {
- view.remove();
- });
-
- it('should exist', function() {
- view = initView();
- expect(view).toBeDefined();
- });
-
- it('should render the progress view if there is no program certificate', function() {
- view = initView();
- testCircle(data.courseData);
- testText(data.courseData);
- });
-
- it('should render the program certificate if earned', function() {
- var $certLink,
- programCert = {
- url: '/program-cert',
- type: 'program',
- title: 'And Justice For All...'
- },
- altText = 'Open the certificate you earned for the ' + programCert.title + ' program.';
-
- certificateCollection.add(programCert);
- view = initView();
- expect(view.$('.progress-circle-wrapper')[0]).not.toBeInDOM();
- $certLink = view.$('.program-cert-link');
- expect($certLink[0]).toBeInDOM();
- expect($certLink.attr('href')).toEqual(programCert.url);
- expect($certLink.find('.program-cert').attr('alt')).toEqual(altText);
- expect(view.$('.certificate-heading')).toHaveText('Your XSeries Certificate');
- });
-
- it('should render the course certificate list', function() {
- var $certificates;
-
- view = initView();
- $certificates = view.$('.certificate-list .certificate');
-
- expect(view.$('.course-list-heading').html()).toEqual('Earned Certificates');
- expect($certificates).toHaveLength(certificateCollection.length);
- $certificates.each(function(i, el) {
- var $link = $(el).find('.certificate-link'),
- model = certificateCollection.at(i);
-
- expect($link.attr('href')).toEqual(model.get('url'));
- expect($link.html()).toEqual(model.get('title'));
- });
- });
-
- it('should not render the course certificate view if no certificates have been earned', function() {
- certificateCollection.reset();
- view = initView();
- expect(view).toBeDefined();
- expect(view.$('.js-course-certificates')).toBeEmpty();
- });
- });
-});
diff --git a/lms/static/js/spec/learner_dashboard/program_details_view_spec.js b/lms/static/js/spec/learner_dashboard/program_details_view_spec.js
deleted file mode 100644
index 290f7db864..0000000000
--- a/lms/static/js/spec/learner_dashboard/program_details_view_spec.js
+++ /dev/null
@@ -1,632 +0,0 @@
-define([
- 'backbone',
- 'jquery',
- 'js/learner_dashboard/views/program_details_view'
-], function(Backbone, $, ProgramDetailsView) {
- 'use strict';
-
- describe('Program Details Header View', function() {
- var view = null,
- options = {
- programData: {
- subtitle: '',
- overview: '',
- weeks_to_complete: null,
- corporate_endorsements: [],
- video: null,
- type: 'Test',
- max_hours_effort_per_week: null,
- transcript_languages: [
- 'en-us'
- ],
- expected_learning_items: [],
- uuid: '0ffff5d6-0177-4690-9a48-aa2fecf94610',
- title: 'Test Course Title',
- languages: [
- 'en-us'
- ],
- subjects: [],
- individual_endorsements: [],
- staff: [
- {
- family_name: 'Tester',
- uuid: '11ee1afb-5750-4185-8434-c9ae8297f0f1',
- bio: 'Dr. Tester, PhD, RD, is an Associate Professor at the School of Nutrition.',
- profile_image: {},
- profile_image_url: 'some image',
- given_name: 'Bob',
- urls: {
- blog: null,
- twitter: null,
- facebook: null
- },
- position: {
- organization_name: 'Test University',
- title: 'Associate Professor of Nutrition'
- },
- works: [],
- slug: 'dr-tester'
- }
- ],
- marketing_slug: 'testing',
- marketing_url: 'someurl',
- status: 'active',
- credit_redemption_overview: '',
- discount_data: {
- currency: 'USD',
- discount_value: 0,
- is_discounted: false,
- total_incl_tax: 300,
- total_incl_tax_excl_discounts: 300
- },
- full_program_price: 300,
- card_image_url: 'some image',
- faq: [],
- price_ranges: [
- {
- max: 378,
- total: 109,
- min: 10,
- currency: 'USD'
- }
- ],
- banner_image: {
- large: {
- url: 'someurl',
- width: 1440,
- height: 480
- },
- small: {
- url: 'someurl',
- width: 435,
- height: 145
- },
- medium: {
- url: 'someurl',
- width: 726,
- height: 242
- },
- 'x-small': {
- url: 'someurl',
- width: 348,
- height: 116
- }
- },
- authoring_organizations: [
- {
- description: '
Learning University is home to leading creators, entrepreneurs.