mirror of
https://github.com/kremalicious/portfolio.git
synced 2024-12-31 17:17:38 +01:00
add more tests
This commit is contained in:
parent
05aa2ffa84
commit
0e78f34d15
@ -9,6 +9,9 @@
|
||||
"childImageSharp": {
|
||||
"fluid": {
|
||||
"src": "/static/b45f45aa8d98d4e4019a242d38f2f248/bc3a8/avatar.jpg"
|
||||
},
|
||||
"resize": {
|
||||
"src": "/static/b45f45aa8d98d4e4019a242d38f2f248/bc3a8/avatar.jpg"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -18,6 +18,7 @@
|
||||
"format": "prettier --write 'src/**/*.{js,jsx}'",
|
||||
"format:css": "prettier-stylelint --write --quiet 'src/**/*.{css,scss}'",
|
||||
"test": "npm run lint && jest --coverage",
|
||||
"test:watch": "npm run lint && jest --coverage --watch",
|
||||
"deploy": "./scripts/deploy.sh",
|
||||
"new": "babel-node ./scripts/new.js"
|
||||
},
|
||||
|
@ -25,59 +25,62 @@ const query = graphql`
|
||||
}
|
||||
`
|
||||
|
||||
const LayoutMarkup = ({ children, isHomepage, allowedHosts, location }) => (
|
||||
<>
|
||||
<Typekit />
|
||||
<HostnameCheck allowedHosts={allowedHosts} />
|
||||
const LayoutMarkup = ({ children, data, location }) => {
|
||||
const { allowedHosts } = data.contentYaml
|
||||
const isHomepage = location.pathname === '/'
|
||||
|
||||
<PoseGroup animateOnMount={true}>
|
||||
<RoutesContainer
|
||||
key={location.pathname}
|
||||
delay={timeout}
|
||||
delayChildren={timeout}
|
||||
>
|
||||
<Header minimal={!isHomepage} />
|
||||
<main className={styles.screen}>{children}</main>
|
||||
</RoutesContainer>
|
||||
</PoseGroup>
|
||||
return (
|
||||
<>
|
||||
<Typekit />
|
||||
<HostnameCheck allowedHosts={allowedHosts} />
|
||||
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
<PoseGroup animateOnMount={true}>
|
||||
<RoutesContainer
|
||||
key={location.pathname}
|
||||
delay={timeout}
|
||||
delayChildren={timeout}
|
||||
>
|
||||
<Header minimal={!isHomepage} />
|
||||
<main className={styles.screen}>{children}</main>
|
||||
</RoutesContainer>
|
||||
</PoseGroup>
|
||||
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
LayoutMarkup.propTypes = {
|
||||
children: PropTypes.any.isRequired,
|
||||
isHomepage: PropTypes.bool.isRequired,
|
||||
allowedHosts: PropTypes.array.isRequired,
|
||||
location: PropTypes.object.isRequired
|
||||
data: PropTypes.shape({
|
||||
contentYaml: PropTypes.shape({
|
||||
allowedHosts: PropTypes.array.isRequired
|
||||
}).isRequired
|
||||
}).isRequired,
|
||||
location: PropTypes.shape({
|
||||
pathname: PropTypes.string.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
export default class Layout extends PureComponent {
|
||||
static propTypes = {
|
||||
children: PropTypes.any.isRequired,
|
||||
location: PropTypes.object.isRequired
|
||||
location: PropTypes.shape({
|
||||
pathname: PropTypes.string.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, location } = this.props
|
||||
const isHomepage = location.pathname === '/'
|
||||
|
||||
return (
|
||||
<StaticQuery
|
||||
query={query}
|
||||
render={data => {
|
||||
const { allowedHosts } = data.contentYaml
|
||||
|
||||
return (
|
||||
<LayoutMarkup
|
||||
isHomepage={isHomepage}
|
||||
allowedHosts={allowedHosts}
|
||||
location={location}
|
||||
>
|
||||
{children}
|
||||
</LayoutMarkup>
|
||||
)
|
||||
}}
|
||||
render={data => (
|
||||
<LayoutMarkup data={data} location={location}>
|
||||
{children}
|
||||
</LayoutMarkup>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ const query = graphql`
|
||||
email
|
||||
avatar {
|
||||
childImageSharp {
|
||||
original: resize {
|
||||
resize {
|
||||
src
|
||||
}
|
||||
}
|
||||
@ -62,15 +62,16 @@ export default class Vcard extends PureComponent {
|
||||
|
||||
// Construct the download from a blob of the just constructed vCard,
|
||||
// and save it to user's file system
|
||||
const downloadVcard = (vcard, meta) => {
|
||||
const name = meta.addressbook.split('/').join('')
|
||||
export const downloadVcard = (vcard, meta) => {
|
||||
const { addressbook } = meta
|
||||
const name = addressbook.split('/').join('')
|
||||
const blob = new Blob([vcard], { type: 'text/x-vcard' })
|
||||
saveAs(blob, name)
|
||||
}
|
||||
|
||||
const constructVcard = meta => {
|
||||
export const constructVcard = meta => {
|
||||
const contact = new vCard()
|
||||
const photoSrc = meta.avatar.childImageSharp.original.src
|
||||
const photoSrc = meta.avatar.childImageSharp.resize.src
|
||||
|
||||
// first, convert the avatar to base64, then construct all vCard elements
|
||||
toDataURL(
|
||||
@ -99,7 +100,7 @@ const constructVcard = meta => {
|
||||
|
||||
// Helper function to create base64 string from avatar image
|
||||
// without the need to read image file from file system
|
||||
const toDataURL = (src, callback, outputFormat) => {
|
||||
export const toDataURL = (src, callback, outputFormat) => {
|
||||
const img = new Image()
|
||||
img.crossOrigin = 'Anonymous'
|
||||
|
||||
@ -118,6 +119,7 @@ const toDataURL = (src, callback, outputFormat) => {
|
||||
}
|
||||
|
||||
img.src = src
|
||||
|
||||
if (img.complete || img.complete === undefined) {
|
||||
img.src =
|
||||
'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=='
|
||||
|
37
src/components/atoms/Vcard.test.jsx
Normal file
37
src/components/atoms/Vcard.test.jsx
Normal file
@ -0,0 +1,37 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import { StaticQuery } from 'gatsby'
|
||||
import vCard from 'vcf'
|
||||
import Vcard, { constructVcard, downloadVcard, toDataURL } from './Vcard'
|
||||
import data from '../../../jest/__fixtures__/meta.json'
|
||||
|
||||
describe('Vcard', () => {
|
||||
beforeEach(() => {
|
||||
StaticQuery.mockImplementationOnce(({ render }) => render({ ...data }))
|
||||
})
|
||||
|
||||
it('renders correctly', () => {
|
||||
const { container } = render(<Vcard />)
|
||||
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('vCard can be constructed', async () => {
|
||||
await constructVcard(data.contentYaml)
|
||||
})
|
||||
|
||||
it('vCard can be downloaded', async () => {
|
||||
const contact = new vCard()
|
||||
const vcard = contact.toString('3.0')
|
||||
|
||||
global.URL.createObjectURL = jest.fn(() => 'details')
|
||||
await downloadVcard(vcard, data.contentYaml)
|
||||
expect(global.URL.createObjectURL).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('Base64 from image can be constructed', () => {
|
||||
const photoSrc = data.contentYaml.avatar.childImageSharp.resize.src
|
||||
|
||||
toDataURL(photoSrc, () => null, 'image/jpeg')
|
||||
})
|
||||
})
|
@ -48,7 +48,10 @@ export default class ThemeSwitch extends PureComponent {
|
||||
<Helmet>
|
||||
<body className={dark ? 'dark' : null} />
|
||||
</Helmet>
|
||||
<Animation className={styles.themeSwitch}>
|
||||
<Animation
|
||||
className={styles.themeSwitch}
|
||||
data-testid={'theme-switch'}
|
||||
>
|
||||
<label className={styles.checkbox}>
|
||||
<span className={styles.label}>Toggle Night Mode</span>
|
||||
<ThemeToggleInput dark={dark} toggleDark={toggleDark} />
|
||||
|
17
src/components/molecules/ThemeSwitch.test.jsx
Normal file
17
src/components/molecules/ThemeSwitch.test.jsx
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import AppProvider from '../../store/provider'
|
||||
import ThemeSwitch from './ThemeSwitch'
|
||||
|
||||
describe('ThemeSwitch', () => {
|
||||
it('renders correctly', () => {
|
||||
const { getByTestId } = render(
|
||||
<AppProvider>
|
||||
<ThemeSwitch />
|
||||
</AppProvider>
|
||||
)
|
||||
|
||||
expect(getByTestId('theme-switch')).toBeInTheDocument()
|
||||
expect(getByTestId('theme-switch').nodeName).toBe('ASIDE')
|
||||
})
|
||||
})
|
@ -1,4 +1,5 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Link, StaticQuery, graphql } from 'gatsby'
|
||||
import classNames from 'classnames'
|
||||
import Vcard from '../atoms/Vcard'
|
||||
@ -24,12 +25,10 @@ const query = graphql`
|
||||
}
|
||||
`
|
||||
|
||||
let classes = classNames('h-card', [styles.footer])
|
||||
export const FooterMarkup = ({ pkg, meta, year }) => {
|
||||
const classes = classNames('h-card', [styles.footer])
|
||||
|
||||
export default class Footer extends PureComponent {
|
||||
state = { year: new Date().getFullYear() }
|
||||
|
||||
FooterMarkup = ({ meta, pkg, year }) => (
|
||||
return (
|
||||
<footer className={classes}>
|
||||
<Link to={'/'}>
|
||||
<LogoUnit minimal />
|
||||
@ -55,6 +54,16 @@ export default class Footer extends PureComponent {
|
||||
</p>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
||||
FooterMarkup.propTypes = {
|
||||
pkg: PropTypes.object.isRequired,
|
||||
meta: PropTypes.object.isRequired,
|
||||
year: PropTypes.number.isRequired
|
||||
}
|
||||
|
||||
export default class Footer extends PureComponent {
|
||||
state = { year: new Date().getFullYear() }
|
||||
|
||||
render() {
|
||||
return (
|
||||
@ -64,9 +73,7 @@ export default class Footer extends PureComponent {
|
||||
const pkg = data.portfolioJson
|
||||
const meta = data.contentYaml
|
||||
|
||||
return (
|
||||
<this.FooterMarkup year={this.state.year} pkg={pkg} meta={meta} />
|
||||
)
|
||||
return <FooterMarkup year={this.state.year} pkg={pkg} meta={meta} />
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
@ -23,28 +23,26 @@ export default class AppProvider extends PureComponent {
|
||||
getCountry = async () => {
|
||||
let trace = []
|
||||
|
||||
await fetch('/cdn-cgi/trace?no-cache=1')
|
||||
.then(data => {
|
||||
let lines
|
||||
try {
|
||||
const data = await fetch('/cdn-cgi/trace?no-cache=1')
|
||||
const text = await data.text()
|
||||
const lines = text.split('\n')
|
||||
|
||||
data.text().then(text => {
|
||||
lines = text.split('\n')
|
||||
let keyValue
|
||||
|
||||
let keyValue
|
||||
lines.forEach(line => {
|
||||
keyValue = line.split('=')
|
||||
trace[keyValue[0]] = decodeURIComponent(keyValue[1] || '')
|
||||
|
||||
lines.forEach(line => {
|
||||
keyValue = line.split('=')
|
||||
trace[keyValue[0]] = decodeURIComponent(keyValue[1] || '')
|
||||
|
||||
if (keyValue[0] === 'loc' && trace['loc'] !== 'XX') {
|
||||
this.setState({ location: trace['loc'] })
|
||||
} else {
|
||||
return
|
||||
}
|
||||
})
|
||||
})
|
||||
if (keyValue[0] === 'loc' && trace['loc'] !== 'XX') {
|
||||
this.setState({ location: trace['loc'] })
|
||||
} else {
|
||||
return
|
||||
}
|
||||
})
|
||||
.catch(() => null) // fail silently
|
||||
} catch (error) {
|
||||
return null // fail silently
|
||||
}
|
||||
}
|
||||
|
||||
setDark() {
|
||||
|
Loading…
Reference in New Issue
Block a user