mirror of
https://github.com/kremalicious/portfolio.git
synced 2025-01-25 00:52:05 +01:00
more tests, hook for metadata
This commit is contained in:
parent
3e341140e6
commit
683ca4f710
@ -5,15 +5,17 @@ import Button from './Button'
|
|||||||
|
|
||||||
describe('Button', () => {
|
describe('Button', () => {
|
||||||
it('renders correctly', () => {
|
it('renders correctly', () => {
|
||||||
const { getByText } = render(<Button href="/somewhere">Hello</Button>)
|
const { container } = render(<Button href="/somewhere">Hello</Button>)
|
||||||
|
|
||||||
expect(getByText('Hello').nodeName).toBe('A')
|
expect(container.firstChild.nodeName).toBe('A')
|
||||||
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('renders children', () => {
|
it('renders children', () => {
|
||||||
const children = <span>Hello World</span>
|
const children = <span>Hello World</span>
|
||||||
const { getByText } = render(<Button href="/children">{children}</Button>)
|
const { container } = render(<Button href="/children">{children}</Button>)
|
||||||
|
|
||||||
expect(getByText('Hello World')).toBeDefined()
|
expect(container.firstChild.nodeName).toBe('A')
|
||||||
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -12,6 +12,7 @@ describe('HostnameCheck', () => {
|
|||||||
const allowedHosts = ['hello.com']
|
const allowedHosts = ['hello.com']
|
||||||
const { container } = render(<HostnameCheck allowedHosts={allowedHosts} />)
|
const { container } = render(<HostnameCheck allowedHosts={allowedHosts} />)
|
||||||
expect(container.firstChild).toHaveTextContent('do a remix')
|
expect(container.firstChild).toHaveTextContent('do a remix')
|
||||||
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does not render if on correct hostname', () => {
|
it('does not render if on correct hostname', () => {
|
||||||
|
@ -1,48 +1,31 @@
|
|||||||
import React, { PureComponent } from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { StaticQuery, graphql } from 'gatsby'
|
|
||||||
import posed from 'react-pose'
|
import posed from 'react-pose'
|
||||||
import { fadeIn } from '../atoms/Transitions'
|
import { fadeIn } from '../atoms/Transitions'
|
||||||
|
import { useMeta } from '../../hooks/use-meta'
|
||||||
import styles from './Availability.module.scss'
|
import styles from './Availability.module.scss'
|
||||||
|
|
||||||
const query = graphql`
|
|
||||||
query {
|
|
||||||
contentYaml {
|
|
||||||
availability {
|
|
||||||
status
|
|
||||||
available
|
|
||||||
unavailable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const Animation = posed.aside(fadeIn)
|
const Animation = posed.aside(fadeIn)
|
||||||
|
|
||||||
export default class Availability extends PureComponent {
|
const Availability = ({ hide }) => {
|
||||||
static propTypes = { hide: PropTypes.bool }
|
const { availability } = useMeta()
|
||||||
|
const { status, available, unavailable } = availability
|
||||||
|
const className = status
|
||||||
|
? `${styles.availability} ${styles.available}`
|
||||||
|
: `${styles.availability}`
|
||||||
|
const html = status ? available : unavailable
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
return (
|
!hide && (
|
||||||
<StaticQuery
|
<Animation className={className}>
|
||||||
query={query}
|
<p dangerouslySetInnerHTML={{ __html: html }} />
|
||||||
render={data => {
|
</Animation>
|
||||||
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 && (
|
|
||||||
<Animation className={className}>
|
|
||||||
<p dangerouslySetInnerHTML={{ __html: html }} />
|
|
||||||
</Animation>
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Availability.propTypes = {
|
||||||
|
hide: PropTypes.bool
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Availability
|
||||||
|
56
src/components/molecules/Availability.test.jsx
Normal file
56
src/components/molecules/Availability.test.jsx
Normal file
@ -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(<Availability />)
|
||||||
|
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(<Availability />)
|
||||||
|
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(<Availability />)
|
||||||
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
|
expect(container.firstChild).toHaveTextContent('Not available.')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can be hidden', () => {
|
||||||
|
const { container } = render(<Availability hide={true} />)
|
||||||
|
expect(container.firstChild).not.toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
@ -22,14 +22,15 @@ export default class LogoUnit extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Animation = posed.div(moveInBottom)
|
Animation = posed.div(moveInBottom)
|
||||||
|
|
||||||
|
wrapClasses = classNames([styles.logounit], {
|
||||||
|
[styles.minimal]: this.props.minimal
|
||||||
|
})
|
||||||
|
|
||||||
nameClasses = classNames('p-name', [styles.title])
|
nameClasses = classNames('p-name', [styles.title])
|
||||||
descriptionClasses = classNames('p-job-title', [styles.description])
|
descriptionClasses = classNames('p-job-title', [styles.description])
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let wrapClasses = classNames([styles.logounit], {
|
|
||||||
[styles.minimal]: this.props.minimal
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StaticQuery
|
<StaticQuery
|
||||||
query={query}
|
query={query}
|
||||||
@ -37,11 +38,16 @@ export default class LogoUnit extends PureComponent {
|
|||||||
const { title, tagline } = data.contentYaml
|
const { title, tagline } = data.contentYaml
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={wrapClasses}>
|
<div className={this.wrapClasses}>
|
||||||
<this.Animation>
|
<this.Animation>
|
||||||
<Logo className={styles.logo} />
|
<Logo className={styles.logo} />
|
||||||
<h1 className={this.nameClasses}>{title.toLowerCase()}</h1>
|
<h1 data-testid="logo-title" className={this.nameClasses}>
|
||||||
<p className={this.descriptionClasses}>
|
{title.toLowerCase()}
|
||||||
|
</h1>
|
||||||
|
<p
|
||||||
|
data-testid="logo-tagline"
|
||||||
|
className={this.descriptionClasses}
|
||||||
|
>
|
||||||
{tagline.toLowerCase()}
|
{tagline.toLowerCase()}
|
||||||
</p>
|
</p>
|
||||||
</this.Animation>
|
</this.Animation>
|
||||||
|
27
src/components/molecules/LogoUnit.test.jsx
Normal file
27
src/components/molecules/LogoUnit.test.jsx
Normal file
@ -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(<LogoUnit />)
|
||||||
|
|
||||||
|
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(<LogoUnit minimal={true} />)
|
||||||
|
|
||||||
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
|
expect(container.firstChild.className).toMatch(/logounit minimal/)
|
||||||
|
})
|
||||||
|
})
|
@ -1,71 +1,51 @@
|
|||||||
import React, { PureComponent } from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { StaticQuery, graphql } from 'gatsby'
|
|
||||||
import posed from 'react-pose'
|
import posed from 'react-pose'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { moveInTop } from '../atoms/Transitions'
|
import { moveInTop } from '../atoms/Transitions'
|
||||||
import LinkIcon from '../atoms/LinkIcon'
|
import LinkIcon from '../atoms/LinkIcon'
|
||||||
|
import { useMeta } from '../../hooks/use-meta'
|
||||||
import icons from '../atoms/Icons.module.scss'
|
import icons from '../atoms/Icons.module.scss'
|
||||||
import styles from './Networks.module.scss'
|
import styles from './Networks.module.scss'
|
||||||
|
|
||||||
const query = graphql`
|
const Animation = posed.aside(moveInTop)
|
||||||
query {
|
|
||||||
contentYaml {
|
|
||||||
social {
|
|
||||||
Email
|
|
||||||
Blog
|
|
||||||
Twitter
|
|
||||||
GitHub
|
|
||||||
Dribbble
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export default class Networks extends PureComponent {
|
const linkClasses = key =>
|
||||||
static propTypes = {
|
classNames({
|
||||||
minimal: PropTypes.bool,
|
'u-url': key !== 'Email',
|
||||||
hide: PropTypes.bool
|
'u-email': key === 'Email',
|
||||||
}
|
[styles.link]: true
|
||||||
|
|
||||||
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
|
|
||||||
})
|
})
|
||||||
|
|
||||||
render() {
|
const Networks = ({ small, hide }) => {
|
||||||
return (
|
const { social } = useMeta()
|
||||||
<StaticQuery
|
|
||||||
query={query}
|
|
||||||
render={data => {
|
|
||||||
const meta = data.contentYaml
|
|
||||||
|
|
||||||
return (
|
const wrapClasses = classNames([styles.networks], {
|
||||||
!this.props.hide && (
|
[styles.small]: small
|
||||||
<this.Animation className={this.wrapClasses}>
|
})
|
||||||
{Object.keys(meta.social).map((key, i) => (
|
|
||||||
<a
|
return (
|
||||||
className={this.linkClasses(key)}
|
!hide && (
|
||||||
href={meta.social[key]}
|
<Animation className={wrapClasses}>
|
||||||
key={i}
|
{Object.keys(social).map((key, i) => (
|
||||||
>
|
<a
|
||||||
<LinkIcon title={key} className={icons.icon} />
|
className={linkClasses(key)}
|
||||||
<span className={styles.title}>{key}</span>
|
href={social[key]}
|
||||||
</a>
|
key={i}
|
||||||
))}
|
data-testid={`network-${key.toLowerCase()}`}
|
||||||
</this.Animation>
|
>
|
||||||
)
|
<LinkIcon title={key} className={icons.icon} />
|
||||||
)
|
<span className={styles.title}>{key}</span>
|
||||||
}}
|
</a>
|
||||||
/>
|
))}
|
||||||
|
</Animation>
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Networks.propTypes = {
|
||||||
|
small: PropTypes.bool,
|
||||||
|
hide: PropTypes.bool
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Networks
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.minimal {
|
.small {
|
||||||
.link {
|
.link {
|
||||||
padding: $spacer / 4;
|
padding: $spacer / 4;
|
||||||
margin-left: $spacer / 4;
|
margin-left: $spacer / 4;
|
||||||
|
39
src/components/molecules/Networks.test.jsx
Normal file
39
src/components/molecules/Networks.test.jsx
Normal file
@ -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(<Networks />)
|
||||||
|
|
||||||
|
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(<Networks small={true} />)
|
||||||
|
|
||||||
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
|
expect(container.firstChild.className).toMatch(/networks small/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can be hidden', () => {
|
||||||
|
const { container } = render(<Networks hide={true} />)
|
||||||
|
|
||||||
|
expect(container.firstChild).not.toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
@ -1,4 +1,4 @@
|
|||||||
import React, { PureComponent, Fragment } from 'react'
|
import React, { PureComponent } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import Helmet from 'react-helmet'
|
import Helmet from 'react-helmet'
|
||||||
import posed from 'react-pose'
|
import posed from 'react-pose'
|
||||||
@ -44,7 +44,7 @@ export default class ThemeSwitch extends PureComponent {
|
|||||||
return (
|
return (
|
||||||
<Consumer>
|
<Consumer>
|
||||||
{({ dark, toggleDark }) => (
|
{({ dark, toggleDark }) => (
|
||||||
<Fragment>
|
<>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<body className={dark ? 'dark' : null} />
|
<body className={dark ? 'dark' : null} />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
@ -55,7 +55,7 @@ export default class ThemeSwitch extends PureComponent {
|
|||||||
<ThemeToggle dark={dark} />
|
<ThemeToggle dark={dark} />
|
||||||
</label>
|
</label>
|
||||||
</Animation>
|
</Animation>
|
||||||
</Fragment>
|
</>
|
||||||
)}
|
)}
|
||||||
</Consumer>
|
</Consumer>
|
||||||
)
|
)
|
||||||
|
36
src/hooks/use-meta.js
Normal file
36
src/hooks/use-meta.js
Normal file
@ -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
|
||||||
|
}
|
20
src/hooks/use-meta.test.js
Normal file
20
src/hooks/use-meta.test.js
Normal file
@ -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(<div>{social.Twitter}</div>)
|
||||||
|
|
||||||
|
expect(container.textContent).toBe('https://twitter.com/kremalicious')
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user