diff --git a/src/profile/AgeMessage.jsx b/src/profile/AgeMessage.jsx index 304cfd5fc..a5df158db 100644 --- a/src/profile/AgeMessage.jsx +++ b/src/profile/AgeMessage.jsx @@ -1,42 +1,36 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { StatusAlert } from '@edx/paragon'; +import { Alert } from '@edx/paragon'; import { FormattedMessage } from '@edx/frontend-platform/i18n'; import { getConfig } from '@edx/frontend-platform'; function AgeMessage({ accountSettingsUrl }) { return ( - - - - - - - - )} + + show + > + + Your profile cannot be shared. + + + + + + ); } diff --git a/src/profile/ProfilePage.jsx b/src/profile/ProfilePage.jsx index 6c0f29cac..0fcd03a63 100644 --- a/src/profile/ProfilePage.jsx +++ b/src/profile/ProfilePage.jsx @@ -6,7 +6,7 @@ import { sendTrackingLogEvent } from '@edx/frontend-platform/analytics'; import { ensureConfig, getConfig } from '@edx/frontend-platform'; import { AppContext } from '@edx/frontend-platform/react'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import { StatusAlert, Hyperlink } from '@edx/paragon'; +import { Alert, Hyperlink } from '@edx/paragon'; // Actions import { @@ -156,7 +156,9 @@ class ProfilePage extends React.Component { return (
- + + {photoUploadError.userMessage} +
); diff --git a/src/profile/ProfilePage.test.jsx b/src/profile/ProfilePage.test.jsx index c05068891..e82ba505d 100644 --- a/src/profile/ProfilePage.test.jsx +++ b/src/profile/ProfilePage.test.jsx @@ -167,6 +167,51 @@ describe('', () => { const tree = renderer.create(component).toJSON(); expect(tree).toMatchSnapshot(); }); + it('test age message alert', () => { + const storeData = JSON.parse(JSON.stringify(storeMocks.viewOwnProfile)); + storeData.userAccount.requiresParentalConsent = true; + storeData.profilePage.account.requiresParentalConsent = true; + const component = ( + + + + + + + + ); + const wrapper = mount(component); + wrapper.update(); + + expect(wrapper.find('.alert-info').hasClass('show')).toBe(true); + }); + it('test photo error alert', () => { + const storeData = JSON.parse(JSON.stringify(storeMocks.viewOwnProfile)); + storeData.profilePage.errors.photo = { userMessage: 'error' }; + const component = ( + + + + + + + + ); + const wrapper = mount(component); + wrapper.update(); + + expect(wrapper.find('.alert-danger').hasClass('show')).toBe(true); + }); }); describe('handles analytics', () => { diff --git a/src/profile/forms/SocialLinks.jsx b/src/profile/forms/SocialLinks.jsx index 389135ae6..4aa92e98d 100644 --- a/src/profile/forms/SocialLinks.jsx +++ b/src/profile/forms/SocialLinks.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { StatusAlert } from '@edx/paragon'; +import { Alert } from '@edx/paragon'; import { connect } from 'react-redux'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faTwitter, faFacebook, faLinkedin } from '@fortawesome/free-brands-svg-icons'; @@ -158,14 +158,19 @@ class SocialLinks extends React.Component { ), editing: (
-
+ {/* TODO: Replace this alert with per-field errors. Needs API update. */}
- {error !== null ? : null} + {error !== null + ? ( + + {error} + + ) : null}
    {socialLinks.map(({ platform, socialLink }) => ( diff --git a/src/profile/forms/SocialLinks.test.jsx b/src/profile/forms/SocialLinks.test.jsx new file mode 100644 index 000000000..735b40053 --- /dev/null +++ b/src/profile/forms/SocialLinks.test.jsx @@ -0,0 +1,152 @@ +import { mount } from 'enzyme'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { Provider } from 'react-redux'; +import renderer from 'react-test-renderer'; +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { configure as configureI18n, IntlProvider } from '@edx/frontend-platform/i18n'; +import { getConfig } from '@edx/frontend-platform'; +import { AppContext } from '@edx/frontend-platform/react'; + +import SocialLinks from './SocialLinks'; +import * as savingEditedBio from '../__mocks__/savingEditedBio.mockStore'; +import messages from '../../i18n'; + +const mockStore = configureMockStore([thunk]); + +const defaultProps = { + formId: 'socialLinks', + socialLinks: [ + { + platform: 'facebook', + socialLink: 'https://www.facebook.com/aloha', + }, + { + platform: 'twitter', + socialLink: 'https://www.twitter.com/ALOHA', + }, + ], + drafts: {}, + visibilitySocialLinks: 'private', + editMode: 'static', + saveState: null, + error: null, + changeHandler: jest.fn(), + submitHandler: jest.fn(), + closeHandler: jest.fn(), + openHandler: jest.fn(), +}; + +configureI18n({ + loggingService: { logError: jest.fn() }, + config: { + ENVIRONMENT: 'production', + LANGUAGE_PREFERENCE_COOKIE_NAME: 'yum', + }, + messages, +}); + +const SocialLinksWrapper = props => ( + + + + + + + +); + +SocialLinksWrapper.defaultProps = { + store: mockStore(savingEditedBio), +}; + +SocialLinksWrapper.propTypes = { + store: PropTypes.shape({}), +}; + +describe('', () => { + ['certificates', 'bio', 'goals', 'socialLinks'].forEach(editMode => ( + it(`calls social links with edit mode ${editMode}`, () => { + const component = ; + const tree = renderer.create(component).toJSON(); + expect(tree).toMatchSnapshot(); + }) + )); + + it('calls social links with editing', () => { + const changeHandler = jest.fn(); + const submitHandler = jest.fn(); + const closeHandler = jest.fn(); + const component = ( + + ); + const wrapper = mount(component); + const socialLink = wrapper.find(SocialLinks); + const { platform } = defaultProps.socialLinks[0]; + const inputField = socialLink.find(`#social-${platform}`); + inputField.simulate('change', { target: { value: 'test', name: platform } }); + expect(changeHandler).toHaveBeenCalledTimes(1); + + expect(socialLink.find('#visibilitySocialLinks select').props().value).toBe('private'); + const event = { target: { value: 'all_users', name: 'visibilitySocialLinks' } }; + socialLink.find('#visibilitySocialLinks select').simulate('change', event); + expect(changeHandler).toHaveBeenCalledTimes(2); + + socialLink.find('[aria-labelledby="editing-form"]').simulate('submit'); + expect(submitHandler).toHaveBeenCalledTimes(1); + + socialLink.find('[aria-labelledby="editing-form"]').find('Button .btn-link').simulate('click'); + expect(closeHandler).toHaveBeenCalledTimes(1); + }); + + it('calls social links with static', () => { + const openHandler = jest.fn(); + const component = ( + + ); + const wrapper = mount(component); + const socialLink = wrapper.find(SocialLinks); + + socialLink.find('EmptyContent button').first().simulate('click'); + expect(openHandler).toHaveBeenCalledTimes(1); + }); + + it('calls social links with error', () => { + const newStore = JSON.parse(JSON.stringify(savingEditedBio)); + newStore.profilePage.errors.bio = { userMessage: 'error' }; + const component = ( + + + + + + + + ); + const wrapper = mount(component); + const socialLink = wrapper.find(SocialLinks); + + expect(socialLink.find('.alert-danger').exists()).toBe(true); + }); +}); diff --git a/src/profile/forms/__snapshots__/SocialLinks.test.jsx.snap b/src/profile/forms/__snapshots__/SocialLinks.test.jsx.snap new file mode 100644 index 000000000..e9328f910 --- /dev/null +++ b/src/profile/forms/__snapshots__/SocialLinks.test.jsx.snap @@ -0,0 +1,590 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` calls social links with edit mode bio 1`] = ` +
    +
    +
    + +
    + +
    +
    +
      +
    • + + +
    • +
    • + + +
    • +
    +
    +
    + + + + + + + +
    +
    + + +
    +
    + +
    +
    +
    +`; + +exports[` calls social links with edit mode certificates 1`] = ` +
    +
    +
    +

    + Social Links + +

    +

    + + + + Just me + +

    +
    + +
    +
    +`; + +exports[` calls social links with edit mode goals 1`] = ` +
    +
    +
    +

    + Social Links +

    +
    +
      +
    • +
      + +
      +
    • +
    • +
      + +
      +
    • +
    +
    +
    +`; + +exports[` calls social links with edit mode socialLinks 1`] = ` +
    +
    +
    +

    + Social Links + +

    +

    + + + + Just me + +

    +
    + +
    +
    +`;