diff --git a/src/components/atoms/Button.test.jsx b/src/components/atoms/Button.test.jsx index c9ead8e..483dc12 100644 --- a/src/components/atoms/Button.test.jsx +++ b/src/components/atoms/Button.test.jsx @@ -5,15 +5,17 @@ import Button from './Button' describe('Button', () => { it('renders correctly', () => { - const { getByText } = render() + const { container } = render() - expect(getByText('Hello').nodeName).toBe('A') + expect(container.firstChild.nodeName).toBe('A') + expect(container.firstChild).toBeInTheDocument() }) it('renders children', () => { const children = Hello World - const { getByText } = render() + const { container } = render() - expect(getByText('Hello World')).toBeDefined() + expect(container.firstChild.nodeName).toBe('A') + expect(container.firstChild).toBeInTheDocument() }) }) diff --git a/src/components/atoms/HostnameCheck.test.jsx b/src/components/atoms/HostnameCheck.test.jsx index 3b51cba..4764907 100644 --- a/src/components/atoms/HostnameCheck.test.jsx +++ b/src/components/atoms/HostnameCheck.test.jsx @@ -12,6 +12,7 @@ describe('HostnameCheck', () => { const allowedHosts = ['hello.com'] const { container } = render() expect(container.firstChild).toHaveTextContent('do a remix') + expect(container.firstChild).toBeInTheDocument() }) it('does not render if on correct hostname', () => { diff --git a/src/components/molecules/Availability.jsx b/src/components/molecules/Availability.jsx index f0cc23a..a7671c5 100644 --- a/src/components/molecules/Availability.jsx +++ b/src/components/molecules/Availability.jsx @@ -1,48 +1,31 @@ -import React, { PureComponent } from 'react' +import React from 'react' import PropTypes from 'prop-types' -import { StaticQuery, graphql } from 'gatsby' import posed from 'react-pose' import { fadeIn } from '../atoms/Transitions' +import { useMeta } from '../../hooks/use-meta' import styles from './Availability.module.scss' -const query = graphql` - query { - contentYaml { - availability { - status - available - unavailable - } - } - } -` - const Animation = posed.aside(fadeIn) -export default class Availability extends PureComponent { - static propTypes = { hide: PropTypes.bool } +const Availability = ({ hide }) => { + const { availability } = useMeta() + const { status, available, unavailable } = availability + const className = status + ? `${styles.availability} ${styles.available}` + : `${styles.availability}` + const html = status ? available : unavailable - render() { - return ( - { - const { availability } = data.contentYaml - const { status, available, unavailable } = availability - const className = status - ? `${styles.availability} ${styles.available}` - : `${styles.availability}` - const html = status ? available : unavailable - - return ( - !this.props.hide && ( - -

- - ) - ) - }} - /> + return ( + !hide && ( + +

+ ) - } + ) } + +Availability.propTypes = { + hide: PropTypes.bool +} + +export default Availability diff --git a/src/components/molecules/Availability.test.jsx b/src/components/molecules/Availability.test.jsx new file mode 100644 index 0000000..b552111 --- /dev/null +++ b/src/components/molecules/Availability.test.jsx @@ -0,0 +1,56 @@ +import React from 'react' +import { render } from 'react-testing-library' +import Availability from './Availability' +import { useStaticQuery } from 'gatsby' +import data from '../../../jest/__fixtures__/meta.json' + +describe('Availability', () => { + it('renders correctly from data file values', () => { + useStaticQuery.mockImplementation(() => { + return { ...data } + }) + const { container } = render() + expect(container.firstChild).toBeInTheDocument() + }) + + it('renders correctly when status: true', () => { + useStaticQuery.mockImplementationOnce(() => { + return { + contentYaml: { + availability: { + status: true, + available: 'I am available.', + unavailable: 'Not available.' + } + } + } + }) + + const { container } = render() + expect(container.firstChild).toBeInTheDocument() + expect(container.firstChild).toHaveTextContent('I am available.') + }) + + it('renders correctly when status: false', () => { + useStaticQuery.mockImplementationOnce(() => { + return { + contentYaml: { + availability: { + status: false, + available: 'I am available.', + unavailable: 'Not available.' + } + } + } + }) + + const { container } = render() + expect(container.firstChild).toBeInTheDocument() + expect(container.firstChild).toHaveTextContent('Not available.') + }) + + it('can be hidden', () => { + const { container } = render() + expect(container.firstChild).not.toBeInTheDocument() + }) +}) diff --git a/src/components/molecules/LogoUnit.jsx b/src/components/molecules/LogoUnit.jsx index 252d3b2..1f8c67b 100644 --- a/src/components/molecules/LogoUnit.jsx +++ b/src/components/molecules/LogoUnit.jsx @@ -22,14 +22,15 @@ export default class LogoUnit extends PureComponent { } Animation = posed.div(moveInBottom) + + wrapClasses = classNames([styles.logounit], { + [styles.minimal]: this.props.minimal + }) + nameClasses = classNames('p-name', [styles.title]) descriptionClasses = classNames('p-job-title', [styles.description]) render() { - let wrapClasses = classNames([styles.logounit], { - [styles.minimal]: this.props.minimal - }) - return ( +

-

{title.toLowerCase()}

-

+

+ {title.toLowerCase()} +

+

{tagline.toLowerCase()}

diff --git a/src/components/molecules/LogoUnit.test.jsx b/src/components/molecules/LogoUnit.test.jsx new file mode 100644 index 0000000..190f710 --- /dev/null +++ b/src/components/molecules/LogoUnit.test.jsx @@ -0,0 +1,27 @@ +import React from 'react' +import { render } from 'react-testing-library' +import { StaticQuery } from 'gatsby' +import LogoUnit from './LogoUnit' +import data from '../../../jest/__fixtures__/meta.json' + +beforeEach(() => { + StaticQuery.mockImplementationOnce(({ render }) => render({ ...data })) +}) + +describe('LogoUnit', () => { + it('renders correctly from data file values', () => { + const { title, tagline } = data.contentYaml + const { container, getByTestId } = render() + + expect(container.firstChild).toBeInTheDocument() + expect(getByTestId('logo-title')).toHaveTextContent(title.toLowerCase()) + expect(getByTestId('logo-tagline')).toHaveTextContent(tagline.toLowerCase()) + }) + + it('renders in minimal variant', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + expect(container.firstChild.className).toMatch(/logounit minimal/) + }) +}) diff --git a/src/components/molecules/Networks.jsx b/src/components/molecules/Networks.jsx index cfa6332..4d64703 100644 --- a/src/components/molecules/Networks.jsx +++ b/src/components/molecules/Networks.jsx @@ -1,71 +1,51 @@ -import React, { PureComponent } from 'react' +import React from 'react' import PropTypes from 'prop-types' -import { StaticQuery, graphql } from 'gatsby' import posed from 'react-pose' import classNames from 'classnames' import { moveInTop } from '../atoms/Transitions' import LinkIcon from '../atoms/LinkIcon' +import { useMeta } from '../../hooks/use-meta' import icons from '../atoms/Icons.module.scss' import styles from './Networks.module.scss' -const query = graphql` - query { - contentYaml { - social { - Email - Blog - Twitter - GitHub - Dribbble - } - } - } -` +const Animation = posed.aside(moveInTop) -export default class Networks extends PureComponent { - static propTypes = { - minimal: PropTypes.bool, - hide: PropTypes.bool - } - - Animation = posed.aside(moveInTop) - - linkClasses = key => - classNames({ - 'u-url': key !== 'Email', - 'u-email': key === 'Email', - [styles.link]: true - }) - - wrapClasses = classNames([styles.networks], { - [styles.minimal]: this.props.minimal +const linkClasses = key => + classNames({ + 'u-url': key !== 'Email', + 'u-email': key === 'Email', + [styles.link]: true }) - render() { - return ( - { - const meta = data.contentYaml +const Networks = ({ small, hide }) => { + const { social } = useMeta() - return ( - !this.props.hide && ( - - {Object.keys(meta.social).map((key, i) => ( - - - {key} - - ))} - - ) - ) - }} - /> + const wrapClasses = classNames([styles.networks], { + [styles.small]: small + }) + + return ( + !hide && ( + + {Object.keys(social).map((key, i) => ( + + + {key} + + ))} + ) - } + ) } + +Networks.propTypes = { + small: PropTypes.bool, + hide: PropTypes.bool +} + +export default Networks diff --git a/src/components/molecules/Networks.module.scss b/src/components/molecules/Networks.module.scss index 412a10f..6695269 100644 --- a/src/components/molecules/Networks.module.scss +++ b/src/components/molecules/Networks.module.scss @@ -48,7 +48,7 @@ } } -.minimal { +.small { .link { padding: $spacer / 4; margin-left: $spacer / 4; diff --git a/src/components/molecules/Networks.test.jsx b/src/components/molecules/Networks.test.jsx new file mode 100644 index 0000000..9ef5674 --- /dev/null +++ b/src/components/molecules/Networks.test.jsx @@ -0,0 +1,39 @@ +import React from 'react' +import { render } from 'react-testing-library' +import { useStaticQuery } from 'gatsby' +import Networks from './Networks' +import data from '../../../jest/__fixtures__/meta.json' + +beforeEach(() => { + useStaticQuery.mockImplementationOnce(() => { + return { ...data } + }) +}) + +describe('Networks', () => { + it('renders correctly from data file values', () => { + const { social } = data.contentYaml + const { container, getByTestId } = render() + + expect(container.firstChild).toBeInTheDocument() + expect(container.firstChild.nodeName).toBe('ASIDE') + expect(getByTestId('network-email').href).toBe(social.Email) + expect(getByTestId('network-blog').href).toBe(social.Blog + '/') + expect(getByTestId('network-twitter').href).toBe(social.Twitter) + expect(getByTestId('network-github').href).toBe(social.GitHub) + expect(getByTestId('network-dribbble').href).toBe(social.Dribbble) + }) + + it('renders correctly in small variant', () => { + const { container } = render() + + expect(container.firstChild).toBeInTheDocument() + expect(container.firstChild.className).toMatch(/networks small/) + }) + + it('can be hidden', () => { + const { container } = render() + + expect(container.firstChild).not.toBeInTheDocument() + }) +}) diff --git a/src/components/molecules/ThemeSwitch.jsx b/src/components/molecules/ThemeSwitch.jsx index 1443ccb..8437f5e 100644 --- a/src/components/molecules/ThemeSwitch.jsx +++ b/src/components/molecules/ThemeSwitch.jsx @@ -1,4 +1,4 @@ -import React, { PureComponent, Fragment } from 'react' +import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import Helmet from 'react-helmet' import posed from 'react-pose' @@ -44,7 +44,7 @@ export default class ThemeSwitch extends PureComponent { return ( {({ dark, toggleDark }) => ( - + <> @@ -55,7 +55,7 @@ export default class ThemeSwitch extends PureComponent { - + )} ) diff --git a/src/hooks/use-meta.js b/src/hooks/use-meta.js new file mode 100644 index 0000000..47b0d9a --- /dev/null +++ b/src/hooks/use-meta.js @@ -0,0 +1,36 @@ +import { useStaticQuery, graphql } from 'gatsby' + +const query = graphql` + query Meta { + contentYaml { + title + tagline + description + url + email + social { + Email + Blog + Twitter + GitHub + Dribbble + } + availability { + status + available + unavailable + } + gpg + addressbook + typekitID + matomoUrl + matomoSite + allowedHosts + } + } +` + +export const useMeta = () => { + const { contentYaml } = useStaticQuery(query) + return contentYaml +} diff --git a/src/hooks/use-meta.test.js b/src/hooks/use-meta.test.js new file mode 100644 index 0000000..7ca0541 --- /dev/null +++ b/src/hooks/use-meta.test.js @@ -0,0 +1,20 @@ +import React from 'react' +import { render } from 'react-testing-library' +import { useStaticQuery } from 'gatsby' +import { useMeta } from './use-meta' +import data from '../../jest/__fixtures__/meta.json' + +beforeEach(() => { + useStaticQuery.mockImplementationOnce(() => { + return { ...data } + }) +}) + +describe('useMeta', () => { + it('renders correctly', () => { + const { social } = useMeta() + const { container } = render(
{social.Twitter}
) + + expect(container.textContent).toBe('https://twitter.com/kremalicious') + }) +})