Jasmine tests for account settings page.
TNL-1499
This commit is contained in:
committed by
Andy Armstrong
parent
74bf7f239e
commit
9c2d18710c
@@ -123,7 +123,7 @@ define([
|
||||
|
||||
patchAndVerifyRequest(requests, url, notificationSpy);
|
||||
|
||||
AjaxHelpers.respondToDelete(requests);
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
ViewHelpers.verifyNotificationHidden(notificationSpy);
|
||||
expect($(SELECTORS.itemView)).not.toExist();
|
||||
};
|
||||
|
||||
@@ -281,7 +281,7 @@ define(["jquery", "sinon", "js/common_helpers/ajax_helpers", "js/views/utils/vie
|
||||
expect($('.wrapper-alert-announcement')).not.toHaveClass('is-hidden');
|
||||
$('.dismiss-button').click();
|
||||
AjaxHelpers.expectJsonRequest(requests, 'DELETE', 'dummy_dismiss_url');
|
||||
AjaxHelpers.respondToDelete(requests);
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
expect($('.wrapper-alert-announcement')).toHaveClass('is-hidden');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,7 +33,7 @@ define(["jquery", "js/common_helpers/ajax_helpers", "js/spec_helpers/view_helper
|
||||
var reloadSpy = spyOn(ViewUtils, 'reload');
|
||||
$('.dismiss-button').click();
|
||||
AjaxHelpers.expectJsonRequest(requests, 'DELETE', 'dummy_dismiss_url');
|
||||
AjaxHelpers.respondToDelete(requests);
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
expect(reloadSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
define(['sinon', 'underscore'], function(sinon, _) {
|
||||
var fakeServer, fakeRequests, expectRequest, expectJsonRequest,
|
||||
respondWithJson, respondWithError, respondWithTextError, respondToDelete;
|
||||
respondWithJson, respondWithError, respondWithTextError, responseWithNoContent;
|
||||
|
||||
/* These utility methods are used by Jasmine tests to create a mock server or
|
||||
* get reference to mock requests. In either case, the cleanup (restore) is done with
|
||||
@@ -109,7 +109,7 @@ define(['sinon', 'underscore'], function(sinon, _) {
|
||||
);
|
||||
};
|
||||
|
||||
respondToDelete = function(requests, requestIndex) {
|
||||
respondWithNoContent = function(requests, requestIndex) {
|
||||
if (_.isUndefined(requestIndex)) {
|
||||
requestIndex = requests.length - 1;
|
||||
}
|
||||
@@ -125,6 +125,6 @@ define(['sinon', 'underscore'], function(sinon, _) {
|
||||
'respondWithJson': respondWithJson,
|
||||
'respondWithError': respondWithError,
|
||||
'respondWithTextError': respondWithTextError,
|
||||
'respondToDelete': respondToDelete
|
||||
'respondWithNoContent': respondWithNoContent,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
|
||||
// Manually specify LMS files that are not converted to RequireJS
|
||||
'history': 'js/vendor/history',
|
||||
'js/mustache': 'js/mustache',
|
||||
'js/verify_student/photocapture': 'js/verify_student/photocapture',
|
||||
'js/staff_debug_actions': 'js/staff_debug_actions',
|
||||
'js/vendor/jquery.qubit': 'js/vendor/jquery.qubit',
|
||||
@@ -587,7 +588,11 @@
|
||||
'lms/include/js/spec/student_account/enrollment_spec.js',
|
||||
'lms/include/js/spec/student_account/emailoptin_spec.js',
|
||||
'lms/include/js/spec/student_account/shoppingcart_spec.js',
|
||||
'lms/include/js/spec/student_account/account_settings_factory_spec.js',
|
||||
'lms/include/js/spec/student_account/account_settings_fields_spec.js',
|
||||
'lms/include/js/spec/student_account/account_settings_view_spec.js',
|
||||
'lms/include/js/spec/student_profile/profile_spec.js',
|
||||
'lms/include/js/spec/views/fields_spec.js',
|
||||
'lms/include/js/spec/verify_student/pay_and_verify_view_spec.js',
|
||||
'lms/include/js/spec/verify_student/webcam_photo_view_spec.js',
|
||||
'lms/include/js/spec/verify_student/image_input_spec.js',
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'js/common_helpers/template_helpers',
|
||||
'js/spec/views/fields_helpers',
|
||||
'js/spec/student_account/helpers',
|
||||
'js/student_account/views/account_settings_factory',
|
||||
'js/student_account/views/account_settings_view'
|
||||
],
|
||||
function (Backbone, $, _, AjaxHelpers, TemplateHelpers, FieldViewsSpecHelpers, Helpers, AccountSettingsPage, AccountSettingsView) {
|
||||
'use strict';
|
||||
|
||||
describe("edx.user.AccountSettingsFactory", function () {
|
||||
|
||||
var FIELDS_DATA = {
|
||||
'country': {
|
||||
'options': Helpers.FIELD_OPTIONS,
|
||||
}, 'gender': {
|
||||
'options': Helpers.FIELD_OPTIONS,
|
||||
}, 'language': {
|
||||
'options': Helpers.FIELD_OPTIONS,
|
||||
}, 'level_of_education': {
|
||||
'options': Helpers.FIELD_OPTIONS,
|
||||
}, 'password': {
|
||||
'url': '/password_reset',
|
||||
}, 'year_of_birth': {
|
||||
'options': Helpers.FIELD_OPTIONS,
|
||||
}, 'preferred_language': {
|
||||
'options': Helpers.FIELD_OPTIONS,
|
||||
}
|
||||
};
|
||||
|
||||
var requests;
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures('<div class="wrapper-account-settings"></div>');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_readonly');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_dropdown');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_link');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_text');
|
||||
TemplateHelpers.installTemplate('templates/student_account/account_settings');
|
||||
});
|
||||
|
||||
it("shows loading error when UserAccountModel fails to load", function() {
|
||||
|
||||
requests = AjaxHelpers.requests(this);
|
||||
|
||||
var context = AccountSettingsPage(
|
||||
FIELDS_DATA, Helpers.USER_ACCOUNTS_API_URL, Helpers.USER_PREFERENCES_API_URL
|
||||
);
|
||||
var accountSettingsView = context.accountSettingsView;
|
||||
|
||||
Helpers.expectLoadingIndicatorIsVisible(accountSettingsView, true);
|
||||
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectSettingsSectionsButNotFieldsToBeRendered(accountSettingsView);
|
||||
|
||||
var request = requests[0];
|
||||
expect(request.method).toBe('GET');
|
||||
expect(request.url).toBe(Helpers.USER_ACCOUNTS_API_URL);
|
||||
|
||||
AjaxHelpers.respondWithError(requests, 500);
|
||||
Helpers.expectLoadingIndicatorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectLoadingErrorIsVisible(accountSettingsView, true);
|
||||
Helpers.expectSettingsSectionsButNotFieldsToBeRendered(accountSettingsView);
|
||||
});
|
||||
|
||||
|
||||
it("shows loading error when UserPreferencesModel fails to load", function() {
|
||||
|
||||
requests = AjaxHelpers.requests(this);
|
||||
|
||||
var context = AccountSettingsPage(
|
||||
FIELDS_DATA, Helpers.USER_ACCOUNTS_API_URL, Helpers.USER_PREFERENCES_API_URL
|
||||
);
|
||||
var accountSettingsView = context.accountSettingsView;
|
||||
|
||||
Helpers.expectLoadingIndicatorIsVisible(accountSettingsView, true);
|
||||
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectSettingsSectionsButNotFieldsToBeRendered(accountSettingsView);
|
||||
|
||||
var request = requests[0];
|
||||
expect(request.method).toBe('GET');
|
||||
expect(request.url).toBe(Helpers.USER_ACCOUNTS_API_URL);
|
||||
|
||||
AjaxHelpers.respondWithJson(requests, Helpers.USER_ACCOUNTS_DATA);
|
||||
Helpers.expectLoadingIndicatorIsVisible(accountSettingsView, true);
|
||||
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectSettingsSectionsButNotFieldsToBeRendered(accountSettingsView);
|
||||
|
||||
var request = requests[1];
|
||||
expect(request.method).toBe('GET');
|
||||
expect(request.url).toBe(Helpers.USER_PREFERENCES_API_URL);
|
||||
|
||||
AjaxHelpers.respondWithError(requests, 500);
|
||||
Helpers.expectLoadingIndicatorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectLoadingErrorIsVisible(accountSettingsView, true);
|
||||
Helpers.expectSettingsSectionsButNotFieldsToBeRendered(accountSettingsView);
|
||||
});
|
||||
|
||||
it("renders fields after the models are successfully fetched", function() {
|
||||
|
||||
requests = AjaxHelpers.requests(this);
|
||||
|
||||
var context = AccountSettingsPage(
|
||||
FIELDS_DATA, Helpers.USER_ACCOUNTS_API_URL, Helpers.USER_PREFERENCES_API_URL
|
||||
);
|
||||
var accountSettingsView = context.accountSettingsView;
|
||||
|
||||
Helpers.expectLoadingIndicatorIsVisible(accountSettingsView, true);
|
||||
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectSettingsSectionsButNotFieldsToBeRendered(accountSettingsView);
|
||||
|
||||
AjaxHelpers.respondWithJson(requests, Helpers.USER_ACCOUNTS_DATA);
|
||||
AjaxHelpers.respondWithJson(requests, Helpers.USER_PREFERENCES_DATA);
|
||||
|
||||
Helpers.expectLoadingIndicatorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectSettingsSectionsAndFieldsToBeRendered(accountSettingsView)
|
||||
});
|
||||
|
||||
it("expects all fields to behave correctly", function () {
|
||||
|
||||
requests = AjaxHelpers.requests(this);
|
||||
|
||||
var context = AccountSettingsPage(
|
||||
FIELDS_DATA, Helpers.USER_ACCOUNTS_API_URL, Helpers.USER_PREFERENCES_API_URL
|
||||
);
|
||||
var accountSettingsView = context.accountSettingsView;
|
||||
|
||||
AjaxHelpers.respondWithJson(requests, Helpers.USER_ACCOUNTS_DATA);
|
||||
AjaxHelpers.respondWithJson(requests, Helpers.USER_PREFERENCES_DATA);
|
||||
|
||||
var sectionsData = accountSettingsView.options.sectionsData;
|
||||
|
||||
expect(sectionsData[0].fields.length).toBe(5);
|
||||
|
||||
var textFields = [sectionsData[0].fields[1], sectionsData[0].fields[2]];
|
||||
for (var i = 0; i < textFields ; i++) {
|
||||
|
||||
var view = textFields[i].view;
|
||||
FieldViewsSpecHelpers.verifyTextField(view, {
|
||||
title: view.options.title,
|
||||
valueAttribute: view.options.valueAttribute,
|
||||
helpMessage: view.options.helpMessage,
|
||||
validValue: 'My Name',
|
||||
invalidValue1: '',
|
||||
invalidValue2: '@',
|
||||
validationError: "Think again!"
|
||||
}, requests);
|
||||
}
|
||||
|
||||
expect(sectionsData[1].fields.length).toBe(5);
|
||||
for (var i = 0; i < 4; i++) {
|
||||
|
||||
var view = sectionsData[1].fields[i].view;
|
||||
FieldViewsSpecHelpers.verifyDropDownField(view, {
|
||||
title: view.options.title,
|
||||
valueAttribute: view.options.valueAttribute,
|
||||
helpMessage: '',
|
||||
validValue: Helpers.FIELD_OPTIONS[0][0],
|
||||
invalidValue1: Helpers.FIELD_OPTIONS[1][0],
|
||||
invalidValue2: Helpers.FIELD_OPTIONS[2][0],
|
||||
validationError: "Nope, this will not do!"
|
||||
}, requests);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,96 @@
|
||||
define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'js/common_helpers/template_helpers',
|
||||
'js/views/fields',
|
||||
'js/spec/views/fields_helpers',
|
||||
'js/student_account/views/account_settings_fields',
|
||||
'js/student_account/models/user_account_model',
|
||||
'string_utils'],
|
||||
function (Backbone, $, _, AjaxHelpers, TemplateHelpers, FieldViews, FieldViewsSpecHelpers, AccountSettingsFieldViews, UserAccountModel) {
|
||||
'use strict';
|
||||
|
||||
describe("edx.AccountSettingsFieldViews", function () {
|
||||
|
||||
var requests,
|
||||
timerCallback;
|
||||
|
||||
var USERNAME = 'Legolas',
|
||||
FULLNAME = 'Legolas Thranduil',
|
||||
EMAIL = 'legolas@woodland.middlearth';
|
||||
|
||||
beforeEach(function () {
|
||||
TemplateHelpers.installTemplate('templates/fields/field_readonly');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_dropdown');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_link');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_text');
|
||||
|
||||
timerCallback = jasmine.createSpy('timerCallback');
|
||||
jasmine.Clock.useMock();
|
||||
});
|
||||
|
||||
it("sends request to reset password on clicking link in PasswordFieldView", function() {
|
||||
requests = AjaxHelpers.requests(this);
|
||||
|
||||
var fieldData = FieldViewsSpecHelpers.createFieldData(AccountSettingsFieldViews.PasswordFieldView, {
|
||||
linkHref: '/password_reset',
|
||||
emailAttribute: 'email'
|
||||
});
|
||||
|
||||
var view = new AccountSettingsFieldViews.PasswordFieldView(fieldData).render();
|
||||
view.$('.u-field-value > a').click();
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/password_reset', "email=legolas%40woodland.middlearth");
|
||||
AjaxHelpers.respondWithJson(requests, {"success": "true"})
|
||||
FieldViewsSpecHelpers.expectMessageContains(view,
|
||||
"We've sent a message to legolas@woodland.middlearth. Click the link in the message to reset your password."
|
||||
);
|
||||
});
|
||||
|
||||
it("sends request to /i18n/setlang/ after changing language preference in LanguagePreferenceFieldView", function() {
|
||||
requests = AjaxHelpers.requests(this);
|
||||
|
||||
var selector = '.u-field-value > select';
|
||||
var fieldData = FieldViewsSpecHelpers.createFieldData(AccountSettingsFieldViews.DropdownFieldView, {
|
||||
valueAttribute: 'language',
|
||||
options: FieldViewsSpecHelpers.SELECT_OPTIONS
|
||||
});
|
||||
|
||||
var view = new AccountSettingsFieldViews.LanguagePreferenceFieldView(fieldData).render();
|
||||
|
||||
var data = {'language': FieldViewsSpecHelpers.SELECT_OPTIONS[2][0]};
|
||||
view.$(selector).val(data[fieldData.valueAttribute]).change();
|
||||
FieldViewsSpecHelpers.expectAjaxRequestWithData(requests, data);
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/i18n/setlang/', 'language=' + data[fieldData.valueAttribute]);
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
FieldViewsSpecHelpers.expectMessageContains(view, "Your changes have been saved.");
|
||||
|
||||
var data = {'language': FieldViewsSpecHelpers.SELECT_OPTIONS[1][0]};
|
||||
view.$(selector).val(data[fieldData.valueAttribute]).change();
|
||||
FieldViewsSpecHelpers.expectAjaxRequestWithData(requests, data);
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
|
||||
AjaxHelpers.expectRequest(requests, 'POST', '/i18n/setlang/', 'language=' + data[fieldData.valueAttribute]);
|
||||
AjaxHelpers.respondWithError(requests, 500);
|
||||
FieldViewsSpecHelpers.expectMessageContains(view, "You must sign out of edX and sign back in before your language changes take effect.");
|
||||
});
|
||||
|
||||
it("reads and saves the value correctly for LanguageProficienciesFieldView", function() {
|
||||
requests = AjaxHelpers.requests(this);
|
||||
|
||||
var selector = '.u-field-value > select';
|
||||
var fieldData = FieldViewsSpecHelpers.createFieldData(AccountSettingsFieldViews.DropdownFieldView, {
|
||||
valueAttribute: 'language_proficiencies',
|
||||
options: FieldViewsSpecHelpers.SELECT_OPTIONS
|
||||
});
|
||||
fieldData.model.set({'language_proficiencies': [{'code': FieldViewsSpecHelpers.SELECT_OPTIONS[0][0]}]});
|
||||
|
||||
var view = new AccountSettingsFieldViews.LanguageProficienciesFieldView(fieldData).render();
|
||||
|
||||
expect(view.modelValue()).toBe(FieldViewsSpecHelpers.SELECT_OPTIONS[0][0]);
|
||||
|
||||
var data = {'language_proficiencies': [{'code': FieldViewsSpecHelpers.SELECT_OPTIONS[1][0]}]};
|
||||
view.$(selector).val(FieldViewsSpecHelpers.SELECT_OPTIONS[1][0]).change();
|
||||
FieldViewsSpecHelpers.expectAjaxRequestWithData(requests, data);
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
});
|
||||
});
|
||||
});
|
||||
101
lms/static/js/spec/student_account/account_settings_view_spec.js
Normal file
101
lms/static/js/spec/student_account/account_settings_view_spec.js
Normal file
@@ -0,0 +1,101 @@
|
||||
define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'js/common_helpers/template_helpers',
|
||||
'js/spec/student_account/helpers',
|
||||
'js/views/fields',
|
||||
'js/student_account/models/user_account_model',
|
||||
'js/student_account/views/account_settings_view'
|
||||
],
|
||||
function (Backbone, $, _, AjaxHelpers, TemplateHelpers, Helpers, FieldViews, UserAccountModel, AccountSettingsView) {
|
||||
'use strict';
|
||||
|
||||
describe("edx.user.AccountSettingsView", function () {
|
||||
|
||||
var createAccountSettingsView = function () {
|
||||
|
||||
var model = new UserAccountModel();
|
||||
model.set(Helpers.USER_ACCOUNTS_DATA);
|
||||
|
||||
var sectionsData = [
|
||||
{
|
||||
title: "Basic Account Information",
|
||||
fields: [
|
||||
{
|
||||
view: new FieldViews.ReadonlyFieldView({
|
||||
model: model,
|
||||
title: "Username",
|
||||
valueAttribute: "username"
|
||||
})
|
||||
},
|
||||
{
|
||||
view: new FieldViews.TextFieldView({
|
||||
model: model,
|
||||
title: "Full Name",
|
||||
valueAttribute: "name"
|
||||
})
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Additional Information",
|
||||
fields: [
|
||||
{
|
||||
view: new FieldViews.DropdownFieldView({
|
||||
model: model,
|
||||
title: "Education Completed",
|
||||
valueAttribute: "level_of_education",
|
||||
options: Helpers.FIELD_OPTIONS
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
var accountSettingsView = new AccountSettingsView({
|
||||
el: $('.wrapper-account-settings'),
|
||||
model: model,
|
||||
sectionsData : sectionsData
|
||||
});
|
||||
|
||||
return accountSettingsView;
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures('<div class="wrapper-account-settings"></div>');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_readonly');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_dropdown');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_link');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_text');
|
||||
TemplateHelpers.installTemplate('templates/student_account/account_settings');
|
||||
});
|
||||
|
||||
it("shows loading error correctly", function() {
|
||||
|
||||
var accountSettingsView = createAccountSettingsView();
|
||||
|
||||
accountSettingsView.render();
|
||||
Helpers.expectLoadingIndicatorIsVisible(accountSettingsView, true);
|
||||
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectSettingsSectionsButNotFieldsToBeRendered(accountSettingsView);
|
||||
|
||||
accountSettingsView.showLoadingError();
|
||||
Helpers.expectLoadingIndicatorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectLoadingErrorIsVisible(accountSettingsView, true);
|
||||
Helpers.expectSettingsSectionsButNotFieldsToBeRendered(accountSettingsView);
|
||||
});
|
||||
|
||||
it("renders all fields as expected", function() {
|
||||
|
||||
var accountSettingsView = createAccountSettingsView();
|
||||
|
||||
accountSettingsView.render();
|
||||
Helpers.expectLoadingIndicatorIsVisible(accountSettingsView, true);
|
||||
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectSettingsSectionsButNotFieldsToBeRendered(accountSettingsView);
|
||||
|
||||
accountSettingsView.renderFields();
|
||||
Helpers.expectLoadingIndicatorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectLoadingErrorIsVisible(accountSettingsView, false);
|
||||
Helpers.expectSettingsSectionsAndFieldsToBeRendered(accountSettingsView)
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
100
lms/static/js/spec/student_account/helpers.js
Normal file
100
lms/static/js/spec/student_account/helpers.js
Normal file
@@ -0,0 +1,100 @@
|
||||
define(['underscore'], function(_) {
|
||||
'use strict';
|
||||
|
||||
var USER_ACCOUNTS_API_URL = '/api/user/v0/accounts/student';
|
||||
var USER_PREFERENCES_API_URL = '/api/user/v0/preferences/student';
|
||||
|
||||
var USER_ACCOUNTS_DATA = {
|
||||
username: 'student',
|
||||
name: 'Student',
|
||||
email: 'student@edx.org',
|
||||
|
||||
level_of_education: '1',
|
||||
gender: '2',
|
||||
year_of_birth: '3',
|
||||
country: '1',
|
||||
language: '2'
|
||||
};
|
||||
|
||||
var USER_PREFERENCES_DATA = {
|
||||
'pref-lang': '2'
|
||||
};
|
||||
|
||||
var FIELD_OPTIONS = [
|
||||
['1', 'Option 1'],
|
||||
['2', 'Option 2'],
|
||||
['3', 'Option 3'],
|
||||
];
|
||||
|
||||
var expectLoadingIndicatorIsVisible = function (view, visible) {
|
||||
if (visible) {
|
||||
expect(view.$('.ui-loading-indicator')).not.toHaveClass('is-hidden');
|
||||
} else {
|
||||
expect(view.$('.ui-loading-indicator')).toHaveClass('is-hidden');
|
||||
}
|
||||
};
|
||||
|
||||
var expectLoadingErrorIsVisible = function (view, visible) {
|
||||
if (visible) {
|
||||
expect(view.$('.ui-loading-error')).not.toHaveClass('is-hidden');
|
||||
} else {
|
||||
expect(view.$('.ui-loading-error')).toHaveClass('is-hidden');
|
||||
}
|
||||
};
|
||||
|
||||
var expectElementContainsField = function(element, field) {
|
||||
var view = field.view;
|
||||
|
||||
var fieldTitle = $(element).find('.u-field-title').text().trim();
|
||||
expect(fieldTitle).toBe(view.options.title);
|
||||
|
||||
if ('fieldValue' in view) {
|
||||
expect(view.model.get(view.options.valueAttribute)).toBeTruthy();
|
||||
expect(view.fieldValue()).toBe(view.modelValue());
|
||||
} else if (view.fieldType === 'link') {
|
||||
expect($(element).find('a').length).toBe(1);
|
||||
} else {
|
||||
throw new Error('Unexpected field type: ' + view.fieldType);
|
||||
}
|
||||
};
|
||||
|
||||
var expectSettingsSectionsButNotFieldsToBeRendered = function (accountSettingsView) {
|
||||
expectSettingsSectionsAndFieldsToBeRendered(accountSettingsView, false)
|
||||
};
|
||||
|
||||
var expectSettingsSectionsAndFieldsToBeRendered = function (accountSettingsView, fieldsAreRendered) {
|
||||
var sectionsData = accountSettingsView.options.sectionsData;
|
||||
|
||||
var sectionElements = accountSettingsView.$('.section');
|
||||
expect(sectionElements.length).toBe(sectionsData.length);
|
||||
|
||||
_.each(sectionElements, function(sectionElement, sectionIndex) {
|
||||
expect($(sectionElement).find('.section-header').text().trim()).toBe(sectionsData[sectionIndex].title);
|
||||
|
||||
var sectionFieldElements = $(sectionElement).find('.u-field');
|
||||
|
||||
if (fieldsAreRendered === false) {
|
||||
expect(sectionFieldElements.length).toBe(0);
|
||||
} else {
|
||||
expect(sectionFieldElements.length).toBe(sectionsData[sectionIndex].fields.length);
|
||||
|
||||
_.each(sectionFieldElements, function (sectionFieldElement, fieldIndex) {
|
||||
expectElementContainsField(sectionFieldElement, sectionsData[sectionIndex].fields[fieldIndex]);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
USER_ACCOUNTS_API_URL: USER_ACCOUNTS_API_URL,
|
||||
USER_PREFERENCES_API_URL: USER_PREFERENCES_API_URL,
|
||||
USER_ACCOUNTS_DATA: USER_ACCOUNTS_DATA,
|
||||
USER_PREFERENCES_DATA: USER_PREFERENCES_DATA,
|
||||
FIELD_OPTIONS: FIELD_OPTIONS,
|
||||
expectLoadingIndicatorIsVisible: expectLoadingIndicatorIsVisible,
|
||||
expectLoadingErrorIsVisible: expectLoadingErrorIsVisible,
|
||||
expectElementContainsField: expectElementContainsField,
|
||||
expectSettingsSectionsButNotFieldsToBeRendered: expectSettingsSectionsButNotFieldsToBeRendered,
|
||||
expectSettingsSectionsAndFieldsToBeRendered: expectSettingsSectionsAndFieldsToBeRendered
|
||||
};
|
||||
});
|
||||
195
lms/static/js/spec/views/fields_helpers.js
Normal file
195
lms/static/js/spec/views/fields_helpers.js
Normal file
@@ -0,0 +1,195 @@
|
||||
define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'js/common_helpers/template_helpers',
|
||||
'js/views/fields',
|
||||
'string_utils'],
|
||||
function (Backbone, $, _, AjaxHelpers, TemplateHelpers, FieldViews) {
|
||||
'use strict';
|
||||
|
||||
var API_URL = '/api/end_point/v1';
|
||||
|
||||
var USERNAME = 'Legolas',
|
||||
FULLNAME = 'Legolas Thranduil',
|
||||
EMAIL = 'legolas@woodland.middlearth',
|
||||
SELECT_OPTIONS = [['si', 'sindarin'], ['el', 'elvish'], ['na', 'nandor']];
|
||||
|
||||
var UserAccountModel = Backbone.Model.extend({
|
||||
idAttribute: 'username',
|
||||
defaults: {
|
||||
username: USERNAME,
|
||||
name: FULLNAME,
|
||||
email: EMAIL,
|
||||
language: SELECT_OPTIONS[0][0]
|
||||
},
|
||||
url: API_URL
|
||||
});
|
||||
|
||||
var createFieldData = function (fieldType, fieldData) {
|
||||
var data = {
|
||||
model: fieldData.model || new UserAccountModel({}),
|
||||
title: fieldData.title || 'Field Title',
|
||||
valueAttribute: fieldData.valueAttribute,
|
||||
helpMessage: fieldData.helpMessage || 'I am a field message'
|
||||
};
|
||||
|
||||
switch (fieldType) {
|
||||
case FieldViews.DropdownFieldView:
|
||||
data['required'] = fieldData.required || false;
|
||||
data['options'] = fieldData.options || SELECT_OPTIONS;
|
||||
break;
|
||||
case FieldViews.LinkFieldView:
|
||||
case FieldViews.PasswordFieldView:
|
||||
data['linkTitle'] = fieldData.linkTitle || "Link Title";
|
||||
data['linkHref'] = fieldData.linkHref || "/path/to/resource";
|
||||
data['emailAttribute'] = 'email';
|
||||
break;
|
||||
}
|
||||
|
||||
_.extend(data, fieldData);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
var createErrorMessage = function(attribute, user_message) {
|
||||
var field_errors = {}
|
||||
field_errors[attribute] = {
|
||||
"user_message": user_message
|
||||
}
|
||||
return {
|
||||
"field_errors": field_errors
|
||||
}
|
||||
};
|
||||
|
||||
var expectTitleAndMessageToBe = function(view, expectedTitle, expectedMessage) {
|
||||
expect(view.$('.u-field-title').text().trim()).toBe(expectedTitle);
|
||||
expect(view.$('.u-field-message').text().trim()).toBe(expectedMessage);
|
||||
};
|
||||
|
||||
var expectMessageContains = function(view, expectedText) {
|
||||
expect(view.$('.u-field-message').html()).toContain(expectedText);
|
||||
};
|
||||
|
||||
var expectAjaxRequestWithData = function(requests, data) {
|
||||
AjaxHelpers.expectJsonRequest(
|
||||
requests, 'PATCH', API_URL, data
|
||||
);
|
||||
};
|
||||
|
||||
var verifyMessageUpdates = function (view, data, timerCallback) {
|
||||
|
||||
var message = 'Here to help!'
|
||||
|
||||
view.message(message);
|
||||
expectMessageContains(view, message);
|
||||
|
||||
view.showHelpMessage();
|
||||
expectMessageContains(view, view.helpMessage);
|
||||
|
||||
view.showInProgressMessage();
|
||||
expectMessageContains(view, view.indicators['inProgress']);
|
||||
expectMessageContains(view, view.messages['inProgress']);
|
||||
|
||||
view.showSuccessMessage();
|
||||
expectMessageContains(view, view.indicators['success']);
|
||||
expectMessageContains(view, view.getMessage('success'));
|
||||
|
||||
expect(timerCallback).not.toHaveBeenCalled();
|
||||
|
||||
view.showErrorMessage({
|
||||
responseText: JSON.stringify(createErrorMessage(data.valueAttribute, 'Ops, try again!.')),
|
||||
status: 400
|
||||
});
|
||||
expectMessageContains(view, view.indicators['validationError']);
|
||||
|
||||
view.showErrorMessage({status: 500});
|
||||
expectMessageContains(view, view.indicators['error']);
|
||||
expectMessageContains(view, view.indicators['error']);
|
||||
};
|
||||
|
||||
var verifySuccessMessageReset = function (view, data, timerCallback) {
|
||||
view.showHelpMessage();
|
||||
expectMessageContains(view, view.helpMessage);
|
||||
view.showSuccessMessage();
|
||||
expectMessageContains(view, view.indicators['success']);
|
||||
jasmine.Clock.tick(5000);
|
||||
// Message gets reset
|
||||
expectMessageContains(view, view.helpMessage);
|
||||
|
||||
view.showSuccessMessage();
|
||||
expectMessageContains(view, view.indicators['success']);
|
||||
// But if we change the message, it should not get reset.
|
||||
view.message("Do not reset this!");
|
||||
jasmine.Clock.tick(5000);
|
||||
expectMessageContains(view, "Do not reset this!");
|
||||
};
|
||||
|
||||
var verifyEditableField = function (view, data, requests) {
|
||||
var request_data = {};
|
||||
var url = view.model.url;
|
||||
|
||||
expectTitleAndMessageToBe(view, data.title, data.helpMessage);
|
||||
|
||||
view.$(data.valueElementSelector).val(data.validValue).change();
|
||||
// When the value in the field is changed
|
||||
expect(view.fieldValue()).toBe(data.validValue);
|
||||
expectMessageContains(view, view.indicators['inProgress']);
|
||||
expectMessageContains(view, view.messages['inProgress']);
|
||||
request_data[data.valueAttribute] = data.validValue;
|
||||
AjaxHelpers.expectJsonRequest(
|
||||
requests, 'PATCH', url, request_data
|
||||
);
|
||||
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
// When server returns success.
|
||||
expectMessageContains(view, view.indicators['success']);
|
||||
|
||||
view.$(data.valueElementSelector).val(data.invalidValue1).change();
|
||||
request_data[data.valueAttribute] = data.invalidValue1;
|
||||
AjaxHelpers.expectJsonRequest(
|
||||
requests, 'PATCH', url, request_data
|
||||
);
|
||||
AjaxHelpers.respondWithError(requests, 500);
|
||||
// When server returns a 500 error
|
||||
expectMessageContains(view, view.indicators['error']);
|
||||
expectMessageContains(view, view.messages['error']);
|
||||
|
||||
view.$(data.valueElementSelector).val(data.invalidValue2).change();
|
||||
request_data[data.valueAttribute] = data.invalidValue2;
|
||||
AjaxHelpers.expectJsonRequest(
|
||||
requests, 'PATCH', url, request_data
|
||||
);
|
||||
AjaxHelpers.respondWithError(requests, 400, createErrorMessage(data.valueAttribute, data.validationError));
|
||||
// When server returns a validation error
|
||||
expectMessageContains(view, view.indicators['validationError']);
|
||||
expectMessageContains(view, data.validationError);
|
||||
};
|
||||
|
||||
var verifyTextField = function (view, data, requests) {
|
||||
var selector = '.u-field-value > input';
|
||||
verifyEditableField(view, _.extend({
|
||||
valueElementSelector: selector,
|
||||
}, data
|
||||
), requests);
|
||||
}
|
||||
|
||||
var verifyDropDownField = function (view, data, requests) {
|
||||
var selector = '.u-field-value > select';
|
||||
verifyEditableField(view, _.extend({
|
||||
valueElementSelector: selector,
|
||||
}, data
|
||||
), requests);
|
||||
}
|
||||
|
||||
return {
|
||||
SELECT_OPTIONS: SELECT_OPTIONS,
|
||||
UserAccountModel: UserAccountModel,
|
||||
createFieldData: createFieldData,
|
||||
createErrorMessage: createErrorMessage,
|
||||
expectTitleAndMessageToBe: expectTitleAndMessageToBe,
|
||||
expectMessageContains: expectMessageContains,
|
||||
expectAjaxRequestWithData: expectAjaxRequestWithData,
|
||||
verifyMessageUpdates: verifyMessageUpdates,
|
||||
verifySuccessMessageReset: verifySuccessMessageReset,
|
||||
verifyEditableField: verifyEditableField,
|
||||
verifyTextField: verifyTextField,
|
||||
verifyDropDownField: verifyDropDownField
|
||||
};
|
||||
});
|
||||
161
lms/static/js/spec/views/fields_spec.js
Normal file
161
lms/static/js/spec/views/fields_spec.js
Normal file
@@ -0,0 +1,161 @@
|
||||
define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'js/common_helpers/template_helpers',
|
||||
'js/views/fields',
|
||||
'js/spec/views/fields_helpers',
|
||||
'string_utils'],
|
||||
function (Backbone, $, _, AjaxHelpers, TemplateHelpers, FieldViews, FieldViewsSpecHelpers) {
|
||||
'use strict';
|
||||
|
||||
var USERNAME = 'Legolas',
|
||||
FULLNAME = 'Legolas Thranduil',
|
||||
EMAIL = 'legolas@woodland.middlearth';
|
||||
|
||||
describe("edx.FieldViews", function () {
|
||||
|
||||
var requests,
|
||||
timerCallback;
|
||||
|
||||
var fieldViewClasses = [
|
||||
FieldViews.ReadonlyFieldView,
|
||||
FieldViews.TextFieldView,
|
||||
FieldViews.DropdownFieldView,
|
||||
FieldViews.LinkFieldView,
|
||||
];
|
||||
|
||||
beforeEach(function () {
|
||||
TemplateHelpers.installTemplate('templates/fields/field_readonly');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_dropdown');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_link');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_text');
|
||||
|
||||
timerCallback = jasmine.createSpy('timerCallback');
|
||||
jasmine.Clock.useMock();
|
||||
});
|
||||
|
||||
it("updates messages correctly for all fields", function() {
|
||||
|
||||
for (var i = 0; i < fieldViewClasses.length; i++) {
|
||||
|
||||
var fieldViewClass = fieldViewClasses[i];
|
||||
var fieldData = FieldViewsSpecHelpers.createFieldData(fieldViewClass, {
|
||||
title: 'Username',
|
||||
valueAttribute: 'username',
|
||||
helpMessage: 'The username that you use to sign in to edX.'
|
||||
});
|
||||
|
||||
var view = new fieldViewClass(fieldData).render();
|
||||
FieldViewsSpecHelpers.verifyMessageUpdates(view, fieldData, timerCallback);
|
||||
}
|
||||
});
|
||||
|
||||
it("resets to help message some time after success message is set", function() {
|
||||
|
||||
for (var i = 0; i < fieldViewClasses.length; i++) {
|
||||
var fieldViewClass = fieldViewClasses[i];
|
||||
var fieldData = FieldViewsSpecHelpers.createFieldData(fieldViewClass, {
|
||||
title: 'Username',
|
||||
valueAttribute: 'username',
|
||||
helpMessage: 'The username that you use to sign in to edX.'
|
||||
})
|
||||
|
||||
var view = new fieldViewClass(fieldData).render();
|
||||
FieldViewsSpecHelpers.verifySuccessMessageReset(view, fieldData, timerCallback);
|
||||
}
|
||||
});
|
||||
|
||||
it("sends a PATCH request when saveAttributes is called", function() {
|
||||
|
||||
requests = AjaxHelpers.requests(this);
|
||||
|
||||
var fieldViewClass = FieldViews.FieldView;
|
||||
var fieldData = FieldViewsSpecHelpers.createFieldData(fieldViewClass, {
|
||||
title: 'Preferred Language',
|
||||
valueAttribute: 'language',
|
||||
helpMessage: 'Your preferred language.'
|
||||
})
|
||||
|
||||
var view = new fieldViewClass(fieldData);
|
||||
view.saveAttributes(
|
||||
{'language': 'ur'},
|
||||
{'headers': {'Priority': 'Urgent'}}
|
||||
);
|
||||
|
||||
var request = requests[0];
|
||||
expect(request.method).toBe('PATCH');
|
||||
expect(request.requestHeaders['Content-Type']).toBe('application/merge-patch+json;charset=utf-8');
|
||||
expect(request.requestHeaders['Priority']).toBe('Urgent');
|
||||
expect(request.requestBody).toBe('{"language":"ur"}');
|
||||
});
|
||||
|
||||
it("correctly renders and updates ReadonlyFieldView", function() {
|
||||
var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.ReadonlyFieldView, {
|
||||
title: 'Username',
|
||||
valueAttribute: 'username',
|
||||
helpMessage: 'The username that you use to sign in to edX.'
|
||||
});
|
||||
var view = new FieldViews.ReadonlyFieldView(fieldData).render();
|
||||
|
||||
FieldViewsSpecHelpers.expectTitleAndMessageToBe(view, fieldData.title, fieldData.helpMessage);
|
||||
expect(view.$('.u-field-value input').val().trim()).toBe(USERNAME);
|
||||
|
||||
view.model.set({'username': 'bookworm'});
|
||||
expect(view.$('.u-field-value input').val().trim()).toBe('bookworm');
|
||||
});
|
||||
|
||||
it("correctly renders, updates and persists changes to TextFieldView", function() {
|
||||
|
||||
requests = AjaxHelpers.requests(this);
|
||||
|
||||
var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.TextFieldView, {
|
||||
title: 'Full Name',
|
||||
valueAttribute: 'name',
|
||||
helpMessage: 'How are you?'
|
||||
});
|
||||
var view = new FieldViews.TextFieldView(fieldData).render();
|
||||
|
||||
FieldViewsSpecHelpers.verifyTextField(view, {
|
||||
title: fieldData.title,
|
||||
valueAttribute: fieldData.valueAttribute,
|
||||
helpMessage: fieldData.helpMessage,
|
||||
validValue: 'My Name',
|
||||
invalidValue1: 'Your Name',
|
||||
invalidValue2: 'Her Name',
|
||||
validationError: "Think again!"
|
||||
}, requests);
|
||||
});
|
||||
|
||||
it("correctly renders, updates and persists changes to DropdownFieldView", function() {
|
||||
|
||||
requests = AjaxHelpers.requests(this);
|
||||
|
||||
var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.DropdownFieldView, {
|
||||
title: 'Full Name',
|
||||
valueAttribute: 'name',
|
||||
helpMessage: 'edX full name'
|
||||
});
|
||||
var view = new FieldViews.DropdownFieldView(fieldData).render();
|
||||
|
||||
FieldViewsSpecHelpers.verifyDropDownField(view, {
|
||||
title: fieldData.title,
|
||||
valueAttribute: fieldData.valueAttribute,
|
||||
helpMessage: fieldData.helpMessage,
|
||||
validValue: FieldViewsSpecHelpers.SELECT_OPTIONS[0][0],
|
||||
invalidValue1: FieldViewsSpecHelpers.SELECT_OPTIONS[1][0],
|
||||
invalidValue2: FieldViewsSpecHelpers.SELECT_OPTIONS[2][0],
|
||||
validationError: "Nope, this will not do!"
|
||||
}, requests);
|
||||
});
|
||||
|
||||
it("correctly renders LinkFieldView", function() {
|
||||
var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.LinkFieldView, {
|
||||
title: 'Title',
|
||||
linkTitle: 'Link title',
|
||||
helpMessage: 'Click the link.'
|
||||
});
|
||||
var view = new FieldViews.LinkFieldView(fieldData).render();
|
||||
|
||||
FieldViewsSpecHelpers.expectTitleAndMessageToBe(view, fieldData.title, fieldData.helpMessage);
|
||||
expect(view.$('.u-field-value > a').text().trim()).toBe(fieldData.linkTitle);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -29,7 +29,7 @@
|
||||
model: userAccountModel,
|
||||
title: gettext('Username'),
|
||||
valueAttribute: 'username',
|
||||
helpMessage: ''
|
||||
helpMessage: 'The name that identifies you on the edX site. You cannot change your username.'
|
||||
})
|
||||
},
|
||||
{
|
||||
@@ -37,13 +37,13 @@
|
||||
model: userAccountModel,
|
||||
title: gettext('Full Name'),
|
||||
valueAttribute: 'name',
|
||||
helpMessage: gettext('The name that appears on your edX certificates.')
|
||||
helpMessage: gettext('The name that appears on your edX certificates. Other learners never see your full name.')
|
||||
})
|
||||
},
|
||||
{
|
||||
view: new AccountSettingsFieldViews.EmailFieldView({
|
||||
model: userAccountModel,
|
||||
title: gettext('Email'),
|
||||
title: gettext('Email Address'),
|
||||
valueAttribute: 'email',
|
||||
helpMessage: gettext('The email address you use to sign in to edX. Communications from edX and your courses are sent to this address.')
|
||||
})
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
initialize: function (options) {
|
||||
|
||||
this.template = _.template($(this.templateSelector).text()),
|
||||
this.template = _.template($(this.templateSelector).text());
|
||||
|
||||
this.helpMessage = this.options.helpMessage || '';
|
||||
this.showMessages = _.isUndefined(this.options.showMessages) ? true : this.options.showMessages;
|
||||
@@ -221,9 +221,9 @@
|
||||
title: this.options.title,
|
||||
required: this.options.required,
|
||||
selectOptions: this.options.options,
|
||||
message: this.helpMessage,
|
||||
message: this.helpMessage
|
||||
}));
|
||||
this.updateValueInField()
|
||||
this.updateValueInField();
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ fixture_paths:
|
||||
- templates/instructor/instructor_dashboard_2
|
||||
- templates/dashboard
|
||||
- templates/edxnotes
|
||||
- templates/fields
|
||||
- templates/student_account
|
||||
- templates/student_profile
|
||||
- templates/verify_student
|
||||
|
||||
Reference in New Issue
Block a user