Compare commits

...

7 Commits

Author SHA1 Message Date
Adam Butterworth
349a458617 Merge pull request #8 from edx/abutterworth/unique-ids
fix: add unique ids to Icon components
2019-03-08 14:00:06 -05:00
Adam Butterworth
abe3d03f58 fix: update snapshot to reflect new ids 2019-03-08 12:44:00 -05:00
Adam Butterworth
7af4b71faa fix: add unique ids to Icon components 2019-03-08 12:35:35 -05:00
Robert Raposa
7f2c5b32b1 Merge pull request #7 from edx/robrap/update-readme
Update README.rst
2019-03-08 09:44:26 -05:00
Robert Raposa
6e0f9cf30a fix(docs): update README.rst
Add a note to clarify that this component is not really
a flexible site footer at this time.
2019-03-06 09:36:43 -05:00
Robert Raposa
3dc70a890f Merge pull request #6 from edx/robrap/ARCH-378-add-test
fix(analytics): add test and fix youtube
2019-01-22 16:26:43 -05:00
Robert Raposa
a37ef7f701 fix(analytics): add test and fix youtube
Adds unit testing and fixes analytics for youtube.
2019-01-22 16:18:14 -05:00
6 changed files with 138 additions and 92 deletions

View File

@@ -7,6 +7,9 @@ frontend-component-footer
frontend-component-footer is a library containing a site footer
component for use when building edX frontend applications.
At this time, this componenet is hard-coded to match the legacy LMS site footer, including all of its links.
Note: As implemented, it should really be called the ``frontend-component-lms-footer``.
Usage
-----

16
package-lock.json generated
View File

@@ -21666,6 +21666,16 @@
"snapdragon": "^0.8.1",
"to-regex": "^3.0.2"
}
},
"watch": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz",
"integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=",
"dev": true,
"requires": {
"exec-sh": "^0.2.0",
"minimist": "^1.2.0"
}
}
}
},
@@ -24627,9 +24637,9 @@
}
},
"watch": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz",
"integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz",
"integrity": "sha1-NApxe952Vyb6CqB9ch4BR6VR3ww=",
"dev": true,
"requires": {
"exec-sh": "^0.2.0",

View File

@@ -78,7 +78,6 @@
"peerDependencies": {
"@edx/paragon": "^3.8.0",
"clean-webpack-plugin": "^0.1.19",
"copy-webpack-plugin": "^4.6.0",
"html-webpack-plugin": "^3.2.0",
"prop-types": "^15.5.10",
"react": "^16.4.2",

View File

@@ -1,81 +1,112 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { mount } from 'enzyme';
import FooterLogo from '../../../edx-footer.png';
import SiteFooter from '../../index';
import SiteFooter, { EVENT_NAMES } from './index';
const completeSiteFooterComponent = mockHandleAllTrackEvents =>
(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
handleAllTrackEvents={mockHandleAllTrackEvents}
/>);
describe('<SiteFooter />', () => {
it('renders correctly', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
/>)
.toJSON();
expect(tree).toMatchSnapshot();
describe('renders correctly', () => {
it('renders with social and mobile links', () => {
const mockHandleAllTrackEvents = jest.fn();
const tree = renderer
.create(completeSiteFooterComponent(mockHandleAllTrackEvents))
.toJSON();
expect(tree).toMatchSnapshot();
});
it('does not render social links', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
handleAllTrackEvents={jest.fn()}
showSocialLinks={false}
/>)
.toJSON();
expect(tree).toMatchSnapshot();
});
it('does not render mobile links', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
handleAllTrackEvents={jest.fn()}
showMobileLinks={false}
/>)
.toJSON();
expect(tree).toMatchSnapshot();
});
});
it('does not render social links', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
showSocialLinks={false}
/>)
.toJSON();
expect(tree).toMatchSnapshot();
});
describe('handles analytics', () => {
it('calls handleAllTrackEvents prop when external links clicked', () => {
const mockHandleAllTrackEvents = jest.fn();
const footer = mount((completeSiteFooterComponent(mockHandleAllTrackEvents)));
const externalLinks = footer.find("a[target='_blank']");
it('does not render mobile links', () => {
const tree = renderer
.create(<SiteFooter
siteName="example"
siteLogo={FooterLogo}
marketingSiteBaseUrl="https://www.example.com"
supportUrl="https://www.example.com/support"
contactUrl="https://www.example.com/contact"
openSourceUrl="https://www.example.com/open"
termsOfServiceUrl="https://www.example.com/terms-of-service"
privacyPolicyUrl="https://www.example.com/privacy-policy"
facebookUrl="https://www.facebook.com"
twitterUrl="https://www.twitter.com"
youTubeUrl="https://www.youtube.com"
linkedInUrl="https://www.linkedin.com"
googlePlusUrl="https://plus.google.com"
redditUrl="https://reddit.com"
appleAppStoreUrl="https://store.apple.com"
googlePlayUrl="https://play.google.com"
showMobileLinks={false}
/>)
.toJSON();
expect(tree).toMatchSnapshot();
expect(externalLinks).toHaveLength(8);
externalLinks.forEach((externalLink) => {
const callIndex = mockHandleAllTrackEvents.mock.calls.length;
externalLink.simulate('click');
expect(mockHandleAllTrackEvents.mock.calls[callIndex]).toEqual([
EVENT_NAMES.FOOTER_LINK,
{
category: 'outbound_link',
label: externalLink.prop('href'),
},
]);
});
});
});
});

View File

@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<SiteFooter /> does not render mobile links 1`] = `
exports[`<SiteFooter /> renders correctly does not render mobile links 1`] = `
<footer
aria-label="Page Footer"
className="footer d-flex justify-content-center border-top py-3 px-4"
@@ -188,7 +188,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<span
aria-hidden={true}
className="fa fa-facebook-square fa-2x"
id="Icon1"
id="edx-footer-icon-facebook"
/>
<span
className="sr-only"
@@ -208,7 +208,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<span
aria-hidden={true}
className="fa fa-twitter-square fa-2x"
id="Icon1"
id="edx-footer-icon-twitter"
/>
<span
className="sr-only"
@@ -220,6 +220,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<li>
<a
href="https://www.youtube.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Youtube"
@@ -227,7 +228,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<span
aria-hidden={true}
className="fa fa-youtube-square fa-2x"
id="Icon1"
id="edx-footer-icon-youtube"
/>
<span
className="sr-only"
@@ -247,7 +248,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<span
aria-hidden={true}
className="fa fa-linkedin-square fa-2x"
id="Icon1"
id="edx-footer-icon-linkedin"
/>
<span
className="sr-only"
@@ -267,7 +268,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
<span
aria-hidden={true}
className="fa fa-google-plus-square fa-2x"
id="Icon1"
id="edx-footer-icon-google"
/>
<span
className="sr-only"
@@ -311,7 +312,7 @@ exports[`<SiteFooter /> does not render mobile links 1`] = `
</footer>
`;
exports[`<SiteFooter /> does not render social links 1`] = `
exports[`<SiteFooter /> renders correctly does not render social links 1`] = `
<footer
aria-label="Page Footer"
className="footer d-flex justify-content-center border-top py-3 px-4"
@@ -531,7 +532,7 @@ exports[`<SiteFooter /> does not render social links 1`] = `
</footer>
`;
exports[`<SiteFooter /> renders correctly 1`] = `
exports[`<SiteFooter /> renders correctly renders with social and mobile links 1`] = `
<footer
aria-label="Page Footer"
className="footer d-flex justify-content-center border-top py-3 px-4"
@@ -719,7 +720,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<span
aria-hidden={true}
className="fa fa-facebook-square fa-2x"
id="Icon1"
id="edx-footer-icon-facebook"
/>
<span
className="sr-only"
@@ -739,7 +740,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<span
aria-hidden={true}
className="fa fa-twitter-square fa-2x"
id="Icon1"
id="edx-footer-icon-twitter"
/>
<span
className="sr-only"
@@ -751,6 +752,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<li>
<a
href="https://www.youtube.com"
onClick={[Function]}
rel="noopener noreferrer"
target="_blank"
title="Youtube"
@@ -758,7 +760,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<span
aria-hidden={true}
className="fa fa-youtube-square fa-2x"
id="Icon1"
id="edx-footer-icon-youtube"
/>
<span
className="sr-only"
@@ -778,7 +780,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<span
aria-hidden={true}
className="fa fa-linkedin-square fa-2x"
id="Icon1"
id="edx-footer-icon-linkedin"
/>
<span
className="sr-only"
@@ -798,7 +800,7 @@ exports[`<SiteFooter /> renders correctly 1`] = `
<span
aria-hidden={true}
className="fa fa-google-plus-square fa-2x"
id="Icon1"
id="edx-footer-icon-google"
/>
<span
className="sr-only"

View File

@@ -59,7 +59,7 @@ class SiteFooter extends React.Component {
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon className={['fa', 'fa-facebook-square', 'fa-2x']} screenReaderText={`Like ${siteName} on Facebook`} />
<Icon id="edx-footer-icon-facebook" className={['fa', 'fa-facebook-square', 'fa-2x']} screenReaderText={`Like ${siteName} on Facebook`} />
</a>
</li>
@@ -72,7 +72,7 @@ class SiteFooter extends React.Component {
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon className={['fa', 'fa-twitter-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on Twitter`} />
<Icon id="edx-footer-icon-twitter" className={['fa', 'fa-twitter-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on Twitter`} />
</a>
</li>
<li>
@@ -81,8 +81,9 @@ class SiteFooter extends React.Component {
title="Youtube"
rel="noopener noreferrer"
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon className={['fa', 'fa-youtube-square', 'fa-2x']} screenReaderText={`Subscribe to the ${siteName} YouTube channel`} />
<Icon id="edx-footer-icon-youtube" className={['fa', 'fa-youtube-square', 'fa-2x']} screenReaderText={`Subscribe to the ${siteName} YouTube channel`} />
</a>
</li>
<li>
@@ -93,7 +94,7 @@ class SiteFooter extends React.Component {
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon className={['fa', 'fa-linkedin-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on LinkedIn`} />
<Icon id="edx-footer-icon-linkedin" className={['fa', 'fa-linkedin-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on LinkedIn`} />
</a>
</li>
<li>
@@ -104,7 +105,7 @@ class SiteFooter extends React.Component {
target="_blank"
onClick={this.externalLinkClickHandler}
>
<Icon className={['fa', 'fa-google-plus-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on Google+`} />
<Icon id="edx-footer-icon-google" className={['fa', 'fa-google-plus-square', 'fa-2x']} screenReaderText={`Follow ${siteName} on Google+`} />
</a>
</li>
<li>