diff --git a/.gitignore b/.gitignore index 74ae5c0..0da3a13 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ __diff_output__ # build build/ +*.tgz diff --git a/README.md b/README.md index 13d8804..51b482a 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,11 @@ Want to get paid for your contributions to `react-seo`? ```bash npm install @americanexpress/react-seo ``` + +
+ +Let's start with a minimal example of basic usage: + ```javascript import React from 'react'; import SEO from '@americanexpress/react-seo'; @@ -32,19 +37,75 @@ import SEO from '@americanexpress/react-seo'; const MyModule = () => (
+
+); + +export default MyModule; +``` + +This will result in the following tags being added to the `head` element: + +```html + + Lorem Ipsum + + + + + + + + + + + + +``` + +Notice in the example above that the Open Graph and Twitter Card metadata is constructed from the `title`, `description`, and `image` props. To override these values or add additional tags not provided by default, you may use the `openGraph` and `twitterCard` props. + +```javascript +import React from 'react'; +import SEO from '@americanexpress/react-seo'; + +const MyModule = () => ( +
+
); export default MyModule; ``` +
## 🎛️ API @@ -53,19 +114,96 @@ The interface for `react-seo` is denoted below: ```javascript SEO.propTypes = { - article: PropTypes.bool, - author: PropTypes.string, - description: PropTypes.string, - image: PropTypes.shape({ - src: PropTypes.string, + title: string, + description: string, + canonical: string, + image: shape({ + src: string, + secureUrl: string, + type: string, + width: number, + height: number, + alt: string, + }), + video: shape({ + src: string, + secureUrl: string, + type: string, + width: number, + height: number, + alt: string, + }), + openGraph: shape({ + type: string, + url: string, + title: string, + description: string, + determiner: string, + locale: string, + localeAlternate: string, + siteName: string, + image: shape({ + src: string, + secureUrl: string, + type: string, + width: number, + height: number, + alt: string, + }), + video: shape({ + src: string, + secureUrl: string, + type: string, + width: number, + height: number, + alt: string, + }), + audio: shape({ + src: string, + secureUrl: string, + type: string, + }), + }), + twitterCard: shape({ + card: string, + title: string, + description: string, + image: shape({ + src: string, + alt: string, + }), + site: string, + siteId: string, + creator: string, + creatorId: string, + app: shape({ + country: string, + iphone: shape({ + id: string, + url: string, + name: string, + }), + ipad: shape({ + id: string, + url: string, + name: string, + }), + googlePlay: shape({ + id: string, + url: string, + name: string, + }), + }), + player: shape({ + src: string, + width: number, + height: number, + }), }), - keywords: PropTypes.arrayOf(PropTypes.string), - locale: PropTypes.string, - meta: PropTypes.arrayOf(PropTypes.object), - pathname: PropTypes.string, - siteUrl: PropTypes.string, - title: PropTypes.string, - canonical: PropTypes.string, + keywords: arrayOf(string), + locale: string, + meta: arrayOf(object), + siteUrl: string, }; SEO.defaultProps = { diff --git a/__tests__/index.spec.jsx b/__tests__/components/SEO.spec.jsx similarity index 61% rename from __tests__/index.spec.jsx rename to __tests__/components/SEO.spec.jsx index a072269..cca5088 100644 --- a/__tests__/index.spec.jsx +++ b/__tests__/components/SEO.spec.jsx @@ -14,81 +14,104 @@ import React from 'react'; import { shallow } from 'enzyme'; -import SEO from '../src'; +import SEO from '../../src'; jest.mock('react-helmet', () => ({ Helmet: 'Helmet' })); describe('SEO', () => { - it('should render the snapshot correctly', () => { + it('should render correctly with the minimal tags', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + }); + + it('should provide the canonical URL', () => { const component = shallow( ); - expect(component).toMatchSnapshot(); + + const helmet = component.find('Helmet'); + const { link } = helmet.props(); + + expect(link).toEqual([{ + rel: 'canonical', href: 'https://example.com/index.html', + }]); }); - it('should render articles correctly', () => { + it('should render image tags correctly', () => { const component = shallow( ); expect(component).toMatchSnapshot(); }); - it('should render images correctly', () => { + it('should render video tags correctly', () => { const component = shallow( ); expect(component).toMatchSnapshot(); }); - it('should render images pathnames correctly', () => { + it('should render Open Graph tags correctly', () => { const component = shallow( ); expect(component).toMatchSnapshot(); }); - it('should render children correctly', () => { + it('should render Twitter Card tags correctly', () => { const component = shallow( -