define(['backbone', 'jquery', 'underscore', 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers', 'common/js/spec_helpers/template_helpers', 'js/views/fields', 'js/spec/views/fields_helpers', 'string_utils'], function(Backbone, $, _, AjaxHelpers, TemplateHelpers, FieldViews, FieldViewsSpecHelpers) { 'use strict'; var USERNAME = 'Legolas', BIO = "My Name is Theon Greyjoy. I'm member of House Greyjoy"; describe('edx.FieldViews', function() { var requests, timerCallback, dropdownSelectClass = '.u-field-value > select', dropdownButtonClass = '.u-field-value > button', textareaLinkClass = '.u-field-value .clickable'; var fieldViewClasses = [ FieldViews.ReadonlyFieldView, FieldViews.TextFieldView, FieldViews.DropdownFieldView, FieldViews.LinkFieldView, FieldViews.TextareaFieldView ]; beforeEach(function() { timerCallback = jasmine.createSpy('timerCallback'); jasmine.clock().install(); }); afterEach(function() { jasmine.clock().uninstall(); }); 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.EditableFieldView; var fieldData = FieldViewsSpecHelpers.createFieldData(fieldViewClass, { title: 'Preferred Language', valueAttribute: 'language', helpMessage: 'Your preferred language.', persistChanges: true }); 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.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage); expect(view.fieldValue()).toBe(USERNAME); view.model.set({username: 'bookworm'}); expect(view.fieldValue()).toBe('bookworm'); }); it('correctly renders, updates and persists changes to TextFieldView when editable == always', function() { requests = AjaxHelpers.requests(this); var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.TextFieldView, { title: 'Full Name', valueAttribute: 'name', helpMessage: 'How are you?', persistChanges: true }); 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!', defaultValue: '' }, requests); }); it('correctly renders and updates DropdownFieldView when editable == never', function() { requests = AjaxHelpers.requests(this); var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.DropdownFieldView, { title: 'Full Name', valueAttribute: 'name', helpMessage: 'edX full name', editable: 'never', persistChanges: true }); var view = new FieldViews.DropdownFieldView(fieldData).render(); var readOnlyDisplayClass = '.u-field-value-readonly'; FieldViewsSpecHelpers.expectDropdownSrTitleToContain(view, fieldData.title); FieldViewsSpecHelpers.expectMessageContains(view, fieldData.helpMessage); expect(view.el).toHaveClass('mode-hidden'); // Note that "name" will be retrieved from the model, but the options specified are // the languages options. Therefore initially the placeholder message will be shown because // the model value does not match any of the possible options. expect(view.fieldValue()).toBeNull(); expect(view.$(readOnlyDisplayClass).text()).toBe(fieldData.placeholderValue); // Make sure that the select and the button are not in the HTML. expect(view.$(dropdownSelectClass).length).toBe(0); expect(view.$(dropdownButtonClass).length).toBe(0); view.model.set({name: fieldData.options[1][0]}); expect(view.el).toHaveClass('mode-display'); expect(view.fieldValue()).toBe(fieldData.options[1][0]); expect(view.$(readOnlyDisplayClass).text()).toBe(fieldData.options[1][1]); view.$el.click(); expect(view.el).toHaveClass('mode-display'); // Make sure that the select and the button still are not in the HTML. expect(view.$(dropdownSelectClass).length).toBe(0); expect(view.$(dropdownButtonClass).length).toBe(0); }); it('correctly renders, updates and persists changes to DropdownFieldView when editable == always', function() { requests = AjaxHelpers.requests(this); var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.DropdownFieldView, { title: 'Full Name', valueAttribute: 'name', helpMessage: 'edX full name', persistChanges: true }); 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!', defaultValue: null }, requests); }); it('correctly renders, updates and persists changes to DropdownFieldView when editable == toggle', function() { requests = AjaxHelpers.requests(this); var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.DropdownFieldView, { title: 'Full Name', valueAttribute: 'name', helpMessage: 'edX full name', editable: 'toggle', persistChanges: true }); var view = new FieldViews.DropdownFieldView(fieldData).render(); FieldViewsSpecHelpers.verifyDropDownField(view, { title: fieldData.title, valueAttribute: fieldData.valueAttribute, helpMessage: fieldData.helpMessage, editable: 'toggle', validValue: FieldViewsSpecHelpers.SELECT_OPTIONS[0][0], invalidValue1: FieldViewsSpecHelpers.SELECT_OPTIONS[1][0], invalidValue2: FieldViewsSpecHelpers.SELECT_OPTIONS[2][0], validationError: 'Nope, this will not do!', defaultValue: null }, requests); }); it('only shows empty option in DropdownFieldView if required is false or model value is not set', function() { requests = AjaxHelpers.requests(this); var editableOptions = ['toggle', 'always']; _.each(editableOptions, function(editable) { var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.DropdownFieldView, { title: 'Drop Down Field', valueAttribute: 'drop-down', helpMessage: 'edX drop down', editable: editable, required: true, persistChanges: true }); var view = new FieldViews.DropdownFieldView(fieldData).render(); expect(view.modelValueIsSet()).toBe(false); expect(view.displayValue()).toBe(''); if (editable === 'toggle') { expect(view.$(dropdownButtonClass).length).toBe(1); view.showEditMode(true); } expect(view.$(dropdownSelectClass).length).toBe(1); view.$(dropdownSelectClass).val(FieldViewsSpecHelpers.SELECT_OPTIONS[0]).change(); view.$(dropdownSelectClass).focusout(); expect(view.fieldValue()).toBe(FieldViewsSpecHelpers.SELECT_OPTIONS[0][0]); AjaxHelpers.respondWithNoContent(requests); if (editable === 'toggle') { view.showEditMode(true); } // When server returns success, there should no longer be an empty option. expect($(view.$('.u-field-value option')[0]).val()).toBe('si'); }); }); it('correctly renders and updates TextAreaFieldView when editable == never', function() { var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.TextareaFieldView, { title: 'About me', valueAttribute: 'bio', helpMessage: 'Wicked is good', placeholderValue: 'Tell other edX learners a little about yourself: where you live, ' + 'what your interests are, why you’re taking courses on edX, or what you hope to learn.', editable: 'never', persistChanges: true, messagePosition: 'header' }); // set bio to empty to see the placeholder. fieldData.model.set({bio: ''}); var view = new FieldViews.TextareaFieldView(fieldData).render(); FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage); expect(view.el).toHaveClass('mode-hidden'); expect(view.fieldValue()).toBe(fieldData.placeholderValue); expect(view.$(textareaLinkClass).length).toBe(0); var bio = 'Too much to tell!'; view.model.set({bio: bio}); expect(view.el).toHaveClass('mode-display'); expect(view.fieldValue()).toBe(bio); view.$el.click(); expect(view.el).toHaveClass('mode-display'); expect(view.$(textareaLinkClass).length).toBe(0); }); it('correctly renders, updates and persists changes to TextAreaFieldView when editable == toggle', function() { requests = AjaxHelpers.requests(this); var valueInputSelector = '.u-field-value > textarea'; var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.TextareaFieldView, { title: 'About me', valueAttribute: 'bio', helpMessage: 'Wicked is good', placeholderValue: 'Tell other edX learners a little about yourself: where you live, ' + 'what your interests are, why you’re taking courses on edX, or what you hope to learn.', editable: 'toggle', persistChanges: true, messagePosition: 'header' }); fieldData.model.set({bio: ''}); var view = new FieldViews.TextareaFieldView(fieldData).render(); FieldViewsSpecHelpers.expectTitleToContain(view, fieldData.title); FieldViewsSpecHelpers.expectMessageContains(view, view.indicators.canEdit); expect(view.el).toHaveClass('mode-placeholder'); expect(view.fieldValue()).toBe(fieldData.placeholderValue); expect(view.$(textareaLinkClass).length).toBe(1); view.$('.wrapper-u-field').click(); expect(view.el).toHaveClass('mode-edit'); view.$(valueInputSelector).val(BIO).focusout(); expect(view.fieldValue()).toBe(BIO); expect(view.$(textareaLinkClass).length).toBe(0); AjaxHelpers.expectJsonRequest( requests, 'PATCH', view.model.url, {bio: BIO} ); AjaxHelpers.respondWithNoContent(requests); expect(view.el).toHaveClass('mode-display'); expect(view.$(textareaLinkClass).length).toBe(1); view.$('.wrapper-u-field').click(); view.$(valueInputSelector).val('').focusout(); AjaxHelpers.respondWithNoContent(requests); expect(view.el).toHaveClass('mode-placeholder'); expect(view.fieldValue()).toBe(fieldData.placeholderValue); }); it('correctly renders LinkFieldView', function() { var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.LinkFieldView, { title: 'Title', linkTitle: 'Link title', helpMessage: 'Click the link.', valueAttribute: 'password-reset' }); var view = new FieldViews.LinkFieldView(fieldData).render(); FieldViewsSpecHelpers.expectTitleAndMessageToContain(view, fieldData.title, fieldData.helpMessage); expect(view.$('.u-field-value > a .u-field-link-title-' + view.options.valueAttribute).text().trim()).toBe(fieldData.linkTitle); }); it("can't persist changes if persistChanges is off", function() { requests = AjaxHelpers.requests(this); var fieldClasses = [ FieldViews.TextFieldView, FieldViews.DropdownFieldView, FieldViews.TextareaFieldView ]; for (var i = 0; i < fieldClasses.length; i++) { FieldViewsSpecHelpers.verifyPersistence(fieldClasses[i], requests); } }); it('correctly renders DateFieldView', function() { var fieldData = FieldViewsSpecHelpers.createFieldData(FieldViews.DateFieldView, { title: 'Title', helpMessage: '', dateFormat: 'MMM YYYY', valueAttribute: 'date_joined', userLanguage: 'en-US', userTimezone: 'America/New_York' }), joinDate = new Date(1990, 0, 15), view; fieldData.model.set({date_joined: joinDate.toDateString()}); view = new FieldViews.DateFieldView(fieldData).render(); expect(view.$('.u-field-value').text().trim()).toBe('Jan 1990'); }); }); });