1
0
mirror of https://github.com/kremalicious/blog.git synced 2024-12-22 17:23:50 +01:00

refactor jest config, add more tests

This commit is contained in:
Matthias Kretschmann 2019-11-24 14:29:25 +01:00
parent 9074735451
commit 61f46d4058
Signed by: m
GPG Key ID: 606EEEF3C479A91F
43 changed files with 834 additions and 288 deletions

View File

@ -2,7 +2,7 @@
<a href="https://kremalicious.com"><img src="src/images/github-header.png" /></a> <a href="https://kremalicious.com"><img src="src/images/github-header.png" /></a>
</p> </p>
<p align="center"> <p align="center">
<strong>🍭 My blog built with <a href="http://gatsbyjs.org">Gatsby</a>. Neat.</strong> <strong>🍭 My blog built with <a href="http://gatsbyjs.org">Gatsby</a> + TypeScript. Neat.</strong>
</p> </p>
<p align="center"> <p align="center">
<a href="https://kremalicious.com">kremalicious.com</a> <a href="https://kremalicious.com">kremalicious.com</a>

View File

@ -3,12 +3,12 @@ module.exports = {
'^.+\\.(tsx?|jsx?)$': 'ts-jest', '^.+\\.(tsx?|jsx?)$': 'ts-jest',
'^.+\\.jsx?$': '<rootDir>/jest/jest-preprocess.js' '^.+\\.jsx?$': '<rootDir>/jest/jest-preprocess.js'
}, },
testRegex: '(/__tests__/.*|\\.(test|spec))\\.(ts|tsx)$', testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.([tj]sx?)$',
moduleNameMapper: { moduleNameMapper: {
'.+\\.(css|styl|less|sass|scss)$': 'identity-obj-proxy', '.+\\.(css|styl|less|sass|scss)$': 'identity-obj-proxy',
'.+\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '.+\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/jest/__mocks__/file-mock.ts', '<rootDir>/jest/__mocks__/file-mock.js',
'\\.svg': '<rootDir>/jest/__mocks__/svgr-mock.ts' '\\.svg': '<rootDir>/jest/__mocks__/svgr-mock.js'
}, },
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
testPathIgnorePatterns: ['node_modules', '.cache', 'public', 'coverage'], testPathIgnorePatterns: ['node_modules', '.cache', 'public', 'coverage'],
@ -16,7 +16,6 @@ module.exports = {
globals: { globals: {
__PATH_PREFIX__: '' __PATH_PREFIX__: ''
}, },
testURL: 'http://localhost',
setupFiles: ['<rootDir>/jest/loadershim.js'], setupFiles: ['<rootDir>/jest/loadershim.js'],
setupFilesAfterEnv: ['<rootDir>/jest/setup-test-env.ts'], setupFilesAfterEnv: ['<rootDir>/jest/setup-test-env.ts'],
collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/@types/**/*'] collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/@types/**/*']

View File

@ -1,20 +1,22 @@
{ {
"edges": [ "avatar": {
{ "edges": [
"node": { {
"childImageSharp": { "node": {
"fixed": { "childImageSharp": {
"aspectRatio": 1, "fixed": {
"width": 80, "aspectRatio": 1,
"height": 80, "width": 80,
"src": "/static/b61a09d5f4cbd9d8b2844091590ddea4/fce1d/avatar.jpg", "height": 80,
"srcSet": "/static/b61a09d5f4cbd9d8b2844091590ddea4/fce1d/avatar.jpg 1x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/c4de8/avatar.jpg 1.5x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/c3234/avatar.jpg 2x", "src": "/static/b61a09d5f4cbd9d8b2844091590ddea4/fce1d/avatar.jpg",
"srcWebp": "/static/b61a09d5f4cbd9d8b2844091590ddea4/ad6b8/avatar.webp", "srcSet": "/static/b61a09d5f4cbd9d8b2844091590ddea4/fce1d/avatar.jpg 1x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/c4de8/avatar.jpg 1.5x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/c3234/avatar.jpg 2x",
"srcSetWebp": "/static/b61a09d5f4cbd9d8b2844091590ddea4/ad6b8/avatar.webp 1x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/5c322/avatar.webp 1.5x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/5bf6b/avatar.webp 2x", "srcWebp": "/static/b61a09d5f4cbd9d8b2844091590ddea4/ad6b8/avatar.webp",
"originalName": "avatar.jpg" "srcSetWebp": "/static/b61a09d5f4cbd9d8b2844091590ddea4/ad6b8/avatar.webp 1x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/5c322/avatar.webp 1.5x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/5bf6b/avatar.webp 2x",
"originalName": "avatar.jpg"
}
} }
} }
} }
} ]
] }
} }

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,39 @@
{
"site": {
"siteMetadata": {
"siteTitle": "kremalicious",
"siteTitleShort": "krlc",
"siteDescription": "Blog of designer & developer Matthias Kretschmann",
"siteUrl": "https://kremalicious.com",
"author": {
"name": "Matthias Kretschmann",
"email": "m@kretschmann.io",
"uri": "https://matthiaskretschmann.com",
"twitter": "https://twitter.com/kremalicious",
"github": "https://github.com/kremalicious",
"facebook": "https://facebook.com/matthiaskretschmann",
"bitcoin": "171qDmKEXm9YBgBLXyGjjPvopP5o9htQ1V",
"ether": "0x339dbC44d39bf1961E385ed0Ae88FC6069b87Ea1"
},
"typekitID": "msu4qap",
"menu": [
{
"title": "Photos",
"link": "/photos"
},
{
"title": "Goodies",
"link": "/tags/goodies"
},
{
"title": "Tags",
"link": "/tags"
}
],
"rss": "/feed.xml",
"jsonfeed": "/feed.json",
"itemsPerPage": 20,
"repoContentPath": "https://github.com/kremalicious/blog/tree/master/content"
}
}
}

View File

@ -0,0 +1,62 @@
{
"photos": {
"edges": [
{
"node": {
"id": "6effe45d-0884-527c-9fba-6f7f567979fd",
"frontmatter": {
"title": "Országház II",
"type": "photo",
"image": {
"childImageSharp": {
"fluid": {
"aspectRatio": 1,
"src": "/static/2dbcf257b4bdf625c24fede935d32425/2423a/2019-11-03-orszaghaz-ii.jpg",
"srcSet": "/static/2dbcf257b4bdf625c24fede935d32425/b7835/2019-11-03-orszaghaz-ii.jpg 100w,\n/static/2dbcf257b4bdf625c24fede935d32425/2de44/2019-11-03-orszaghaz-ii.jpg 200w,\n/static/2dbcf257b4bdf625c24fede935d32425/2423a/2019-11-03-orszaghaz-ii.jpg 400w,\n/static/2dbcf257b4bdf625c24fede935d32425/66039/2019-11-03-orszaghaz-ii.jpg 600w,\n/static/2dbcf257b4bdf625c24fede935d32425/ba820/2019-11-03-orszaghaz-ii.jpg 800w,\n/static/2dbcf257b4bdf625c24fede935d32425/d04d5/2019-11-03-orszaghaz-ii.jpg 3793w",
"srcWebp": "/static/2dbcf257b4bdf625c24fede935d32425/33771/2019-11-03-orszaghaz-ii.webp",
"srcSetWebp": "/static/2dbcf257b4bdf625c24fede935d32425/4f5da/2019-11-03-orszaghaz-ii.webp 100w,\n/static/2dbcf257b4bdf625c24fede935d32425/72345/2019-11-03-orszaghaz-ii.webp 200w,\n/static/2dbcf257b4bdf625c24fede935d32425/33771/2019-11-03-orszaghaz-ii.webp 400w,\n/static/2dbcf257b4bdf625c24fede935d32425/f12d8/2019-11-03-orszaghaz-ii.webp 600w,\n/static/2dbcf257b4bdf625c24fede935d32425/b975c/2019-11-03-orszaghaz-ii.webp 800w,\n/static/2dbcf257b4bdf625c24fede935d32425/f7332/2019-11-03-orszaghaz-ii.webp 3793w",
"sizes": "(max-width: 400px) 100vw, 400px",
"originalImg": "/static/2dbcf257b4bdf625c24fede935d32425/d04d5/2019-11-03-orszaghaz-ii.jpg",
"originalName": "2019-11-03-orszaghaz-ii.jpg",
"presentationWidth": 400,
"presentationHeight": 300
}
}
}
},
"fields": {
"slug": "/orszaghaz-ii/"
}
}
},
{
"node": {
"id": "c80697e5-681d-5fcc-9dab-c3a3821ff0b1",
"frontmatter": {
"title": "Országház I",
"type": "photo",
"image": {
"childImageSharp": {
"fluid": {
"aspectRatio": 1,
"src": "/static/36d87329aeeda296ae923606e5a4a785/2423a/2019-11-02-orszaghaz-i.jpg",
"srcSet": "/static/36d87329aeeda296ae923606e5a4a785/b7835/2019-11-02-orszaghaz-i.jpg 100w,\n/static/36d87329aeeda296ae923606e5a4a785/2de44/2019-11-02-orszaghaz-i.jpg 200w,\n/static/36d87329aeeda296ae923606e5a4a785/2423a/2019-11-02-orszaghaz-i.jpg 400w,\n/static/36d87329aeeda296ae923606e5a4a785/66039/2019-11-02-orszaghaz-i.jpg 600w,\n/static/36d87329aeeda296ae923606e5a4a785/ba820/2019-11-02-orszaghaz-i.jpg 800w,\n/static/36d87329aeeda296ae923606e5a4a785/c9c86/2019-11-02-orszaghaz-i.jpg 3708w",
"srcWebp": "/static/36d87329aeeda296ae923606e5a4a785/33771/2019-11-02-orszaghaz-i.webp",
"srcSetWebp": "/static/36d87329aeeda296ae923606e5a4a785/4f5da/2019-11-02-orszaghaz-i.webp 100w,\n/static/36d87329aeeda296ae923606e5a4a785/72345/2019-11-02-orszaghaz-i.webp 200w,\n/static/36d87329aeeda296ae923606e5a4a785/33771/2019-11-02-orszaghaz-i.webp 400w,\n/static/36d87329aeeda296ae923606e5a4a785/f12d8/2019-11-02-orszaghaz-i.webp 600w,\n/static/36d87329aeeda296ae923606e5a4a785/b975c/2019-11-02-orszaghaz-i.webp 800w,\n/static/36d87329aeeda296ae923606e5a4a785/262c1/2019-11-02-orszaghaz-i.webp 3708w",
"sizes": "(max-width: 400px) 100vw, 400px",
"originalImg": "/static/36d87329aeeda296ae923606e5a4a785/c9c86/2019-11-02-orszaghaz-i.jpg",
"originalName": "2019-11-02-orszaghaz-i.jpg",
"presentationWidth": 400,
"presentationHeight": 297
}
}
}
},
"fields": {
"slug": "/orszaghaz-i/"
}
}
}
]
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
module.exports = 'test-file-stub'

View File

@ -1 +0,0 @@
export default 'test-file-stub'

29
jest/__mocks__/gatsby.js Normal file
View File

@ -0,0 +1,29 @@
/* eslint-disable no-unused-vars */
const React = require('react')
const gatsby = jest.requireActual('gatsby')
module.exports = {
...gatsby,
graphql: jest.fn(),
Link: jest.fn().mockImplementation(
// these props are invalid for an `a` tag
({
activeClassName,
activeStyle,
getProps,
innerRef,
partiallyActive,
ref,
replace,
to,
...rest
}) =>
React.createElement('a', {
...rest,
href: to
})
),
StaticQuery: jest.fn(),
useStaticQuery: jest.fn()
}

View File

@ -1,14 +0,0 @@
import React from 'react'
const gatsby = jest.requireActual('gatsby')
export default {
...gatsby,
graphql: jest.fn(),
Link: jest
.fn()
.mockImplementation(({ to, ...rest }) =>
React.createElement('a', { ...rest, href: to })
),
StaticQuery: jest.fn(),
useStaticQuery: jest.fn()
}

View File

@ -0,0 +1,6 @@
import React from 'react'
export default 'SvgrURL'
const SvgrMock = React.forwardRef((props, ref) => <span ref={ref} {...props} />)
export const ReactComponent = SvgrMock

View File

@ -1,3 +0,0 @@
const content = 'svg'
export const ReactComponent = content
export default content

View File

@ -1 +1,18 @@
import '@testing-library/jest-dom/extend-expect' import '@testing-library/jest-dom/extend-expect'
import * as Gatsby from 'gatsby'
const useStaticQuery = jest.spyOn(Gatsby, 'useStaticQuery')
import meta from '../jest/__fixtures__/meta.json'
import avatar from '../jest/__fixtures__/avatar.json'
import posts from '../jest/__fixtures__/posts.json'
import github from '../jest/__fixtures__/github.json'
beforeAll(() => {
useStaticQuery.mockImplementation(() => ({
...meta,
...avatar,
logo: { edges: [{ node: { relativePath: 'apple-touch-icon.png' } }] },
...posts,
...github
}))
})

View File

@ -10,7 +10,7 @@
"start": "gatsby develop --host 0.0.0.0", "start": "gatsby develop --host 0.0.0.0",
"build": "gatsby build && npm run copy", "build": "gatsby build && npm run copy",
"ssr": "npm run build && serve -s public/", "ssr": "npm run build && serve -s public/",
"test": "npm run lint && jest --coverage", "test": "npm run lint && jest --coverage --silent",
"test:watch": "npm run lint && jest --coverage --watch", "test:watch": "npm run lint && jest --coverage --watch",
"copy": "cp -R content/media/ public", "copy": "cp -R content/media/ public",
"lint": "run-p --continue-on-error lint:js lint:css lint:md", "lint": "run-p --continue-on-error lint:js lint:css lint:md",

View File

@ -4,7 +4,7 @@ export interface ImageProps {
title?: string title?: string
fluid?: FluidObject fluid?: FluidObject
fixed?: FixedObject fixed?: FixedObject
alt: string alt?: string
original?: { src: string } original?: { src: string }
} }

View File

@ -0,0 +1,7 @@
import React from 'react'
import testRender from '../../jest/testRender'
import Layout from './Layout'
describe('Layout', () => {
testRender(<Layout>Hello</Layout>)
})

View File

@ -1,23 +1,17 @@
import React from 'react' import React from 'react'
import testRender from '../../../jest/testRender' import { render } from '@testing-library/react'
import { PureChangelog as Changelog } from './Changelog' import Changelog from './Changelog'
import { GitHubRepo } from '../../@types/GitHub'
const repos: [{ node: GitHubRepo }] = [
{
node: {
name: 'gatsby-plugin-matomo',
url: 'https://hello.com',
owner: { login: 'kremalicious' },
object: {
id: 'hello',
text: 'hello'
}
}
}
]
describe('Changelog', () => { describe('Changelog', () => {
testRender(<Changelog repo="gatsby-plugin-matomo" repos={repos} />) it('renders without crashing', () => {
const { container, rerender } = render(
<Changelog repo="gatsby-plugin-matomo" />
)
expect(container.firstChild).toBeInTheDocument()
// return nothing when no match
rerender(<Changelog repo="nomatch" />)
expect(container.firstChild).not.toBeInTheDocument()
})
}) })

View File

@ -22,7 +22,6 @@ export function PureChangelog({
if (!repoMatch) return null if (!repoMatch) return null
const { object, url, owner } = repoMatch const { object, url, owner } = repoMatch
if (!object) return null
const changelogHtml = const changelogHtml =
object && object &&
@ -53,24 +52,22 @@ export function PureChangelog({
) )
} }
export default function Changelog({ repo }: { repo: string }) { const queryGithub = graphql`
const queryGithub = graphql` query GitHubReposInfo {
query GitHubReposInfo { github {
github { viewer {
viewer { repositories(first: 100, privacy: PUBLIC, isFork: false) {
repositories(first: 100, privacy: PUBLIC, isFork: false) { edges {
edges { node {
node { name
name url
url owner {
owner { login
login }
} object(expression: "master:CHANGELOG.md") {
object(expression: "master:CHANGELOG.md") { id
id ... on GitHub_Blob {
... on GitHub_Blob { text
text
}
} }
} }
} }
@ -78,7 +75,10 @@ export default function Changelog({ repo }: { repo: string }) {
} }
} }
} }
` }
`
export default function Changelog({ repo }: { repo: string }) {
const data: GitHub = useStaticQuery(queryGithub) const data: GitHub = useStaticQuery(queryGithub)
const repos: [{ node: GitHubRepo }] = data.github.viewer.repositories.edges const repos: [{ node: GitHubRepo }] = data.github.viewer.repositories.edges
return <PureChangelog repo={repo} repos={repos} /> return <PureChangelog repo={repo} repos={repos} />

View File

@ -1,9 +0,0 @@
import React from 'react'
// import { render } from '@testing-library/react'
import testRender from '../../../jest/testRender'
import Container from './Container'
describe('Container', () => {
testRender(<Container>Hello</Container>)
})

View File

@ -14,7 +14,7 @@ export default function Copy({ text }: { text: string }) {
<Clipboard <Clipboard
data-clipboard-text={text} data-clipboard-text={text}
button-title="Copy to clipboard" button-title="Copy to clipboard"
onSuccess={e => onCopySuccess(e)} onSuccess={(e: ClipboardJS.Event) => onCopySuccess(e)}
className={styles.button} className={styles.button}
> >
<Icon name="Copy" /> <Icon name="Copy" />

View File

@ -1,9 +0,0 @@
import React from 'react'
// import { render } from '@testing-library/react'
import testRender from '../../../jest/testRender'
import Hamburger from './Hamburger'
describe('Hamburger', () => {
testRender(<Hamburger onClick={() => null} />)
})

View File

@ -1,16 +0,0 @@
import React, { Suspense } from 'react'
import { render, waitForElement } from '@testing-library/react'
import Time from './Time'
describe('Time', () => {
test('renders lazy', async () => {
const { getByText } = render(
<Suspense fallback="test loading">
<Time date="2017/12/23" />
</Suspense>
)
const lazyElement = await waitForElement(() => getByText(/years ago/i))
expect(lazyElement).toBeInTheDocument()
})
})

View File

@ -4,11 +4,23 @@ import { Image } from '../atoms/Image'
import styles from './Featured.module.scss' import styles from './Featured.module.scss'
import { Post } from '../../@types/Post' import { Post } from '../../@types/Post'
function FeaturedPure({ const query = graphql`
data query {
}: { allMarkdownRemark(
data: { allMarkdownRemark: { edges: [{ node: Post }] } } filter: { frontmatter: { featured: { eq: true } } }
}) { sort: { fields: [fields___date], order: DESC }
) {
edges {
node {
...PostTeaser
}
}
}
}
`
export default function Featured() {
const data = useStaticQuery(query)
return ( return (
<div className={styles.featured}> <div className={styles.featured}>
{data.allMarkdownRemark.edges.map(({ node }: { node: Post }) => { {data.allMarkdownRemark.edges.map(({ node }: { node: Post }) => {
@ -27,34 +39,3 @@ function FeaturedPure({
</div> </div>
) )
} }
const query = graphql`
query {
allMarkdownRemark(
filter: { frontmatter: { featured: { eq: true } } }
sort: { fields: [fields___date], order: DESC }
) {
edges {
node {
id
frontmatter {
title
image {
childImageSharp {
...ImageFluidThumb
}
}
}
fields {
slug
}
}
}
}
}
`
export default function Featured() {
const data = useStaticQuery(query)
return <FeaturedPure data={data} />
}

View File

@ -1,9 +1,32 @@
import React from 'react' import React from 'react'
import { Link } from 'gatsby' import { Link, graphql } from 'gatsby'
import { Image } from '../../components/atoms/Image' import { Image } from '../atoms/Image'
import styles from './PostTeaser.module.scss' import styles from './PostTeaser.module.scss'
import { Post } from '../../@types/Post' import { Post } from '../../@types/Post'
export const postTeaserQuery = graphql`
fragment PostTeaser on MarkdownRemark {
id
fileAbsolutePath
frontmatter {
title
type
linkurl
tags
featured
image {
childImageSharp {
...ImageFluidThumb
}
}
}
fields {
slug
date(formatString: "MMMM DD, YYYY")
}
}
`
export default function PostTeaser({ export default function PostTeaser({
post, post,
toggleSearch toggleSearch

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { graphql, useStaticQuery } from 'gatsby' import { graphql, useStaticQuery } from 'gatsby'
import PostTeaser from '../../templates/Post/PostTeaser' import PostTeaser from './PostTeaser'
import styles from './RelatedPosts.module.scss' import styles from './RelatedPosts.module.scss'
import { Post, Frontmatter } from '../../@types/Post' import { Post, Frontmatter } from '../../@types/Post'
@ -9,23 +9,7 @@ const query = graphql`
allMarkdownRemark(sort: { order: DESC, fields: [fields___date] }) { allMarkdownRemark(sort: { order: DESC, fields: [fields___date] }) {
edges { edges {
node { node {
id ...PostTeaser
fileAbsolutePath
frontmatter {
title
type
linkurl
tags
image {
childImageSharp {
...ImageFluidThumb
}
}
}
fields {
slug
date(formatString: "MMMM DD, YYYY")
}
} }
} }
} }

View File

@ -2,7 +2,7 @@ import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { graphql, useStaticQuery } from 'gatsby' import { graphql, useStaticQuery } from 'gatsby'
import Container from '../../atoms/Container' import Container from '../../atoms/Container'
import PostTeaser from '../../../templates/Post/PostTeaser' import PostTeaser from '../PostTeaser'
import SearchResultsEmpty from './SearchResultsEmpty' import SearchResultsEmpty from './SearchResultsEmpty'
import styles from './SearchResults.module.scss' import styles from './SearchResults.module.scss'
import { Post } from '../../../@types/Post' import { Post } from '../../../@types/Post'
@ -16,18 +16,7 @@ const query = graphql`
allMarkdownRemark { allMarkdownRemark {
edges { edges {
node { node {
id ...PostTeaser
frontmatter {
title
image {
childImageSharp {
...ImageFluidThumb
}
}
}
fields {
slug
}
} }
} }
} }

View File

@ -29,23 +29,26 @@ const ThemeToggleInput = ({
/> />
) )
const HeadMarkup = ({ themeColor }: { themeColor: string }) => (
<Helmet>
<meta name="theme-color" content={themeColor} />
<meta
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
</Helmet>
)
export default function ThemeSwitch() { export default function ThemeSwitch() {
const darkMode = useDarkMode(false, { const darkMode = useDarkMode(false, {
classNameDark: 'dark', classNameDark: 'dark',
classNameLight: 'light' classNameLight: 'light'
}) })
const themeColor = darkMode.value ? '#1d2224' : '#e7eef4' const themeColor = darkMode.value ? '#1d2224' : '#e7eef4'
return ( return (
<> <>
<Helmet> <HeadMarkup themeColor={themeColor} />
<meta name="theme-color" content={themeColor} />
<meta
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
</Helmet>
<aside className={styles.themeSwitch}> <aside className={styles.themeSwitch}>
<label <label
htmlFor="toggle" htmlFor="toggle"

View File

@ -1,28 +0,0 @@
import React from 'react'
import { render } from '@testing-library/react'
import { VcardPure as Vcard } from './Vcard'
import avatar from '../../../jest/__fixtures__/avatar.json'
const links = [
'twitter.com',
'github.com',
'facebook.com',
'feed.xml',
'feed.json',
'whatever'
]
describe('Vcard', () => {
it('renders without crashing', () => {
const { container } = render(
<Vcard
avatar={avatar.edges[0].node.childImageSharp.fixed}
name="Hello You"
uri="https://demo.com"
links={links}
/>
)
expect(container.firstChild).toBeInTheDocument()
})
})

View File

@ -1,21 +1,33 @@
import React from 'react' import React from 'react'
import { graphql, useStaticQuery } from 'gatsby' import { graphql, useStaticQuery } from 'gatsby'
import Img, { FixedObject } from 'gatsby-image' import Img from 'gatsby-image'
import IconLinks from './Networks' import IconLinks from './Networks'
import styles from './Vcard.module.scss' import styles from './Vcard.module.scss'
import { useSiteMetadata } from '../../hooks/use-site-metadata' import { useSiteMetadata } from '../../hooks/use-site-metadata'
export function VcardPure({ const query = graphql`
avatar, query {
uri, avatar: allFile(filter: { name: { eq: "avatar" } }) {
name, edges {
links node {
}: { childImageSharp {
avatar: FixedObject fixed(width: 80, height: 80, quality: 90) {
uri: string ...GatsbyImageSharpFixed_withWebp_noBase64
name: string }
links: string[] }
}) { }
}
}
}
`
export default function Vcard() {
const data = useStaticQuery(query)
const { author, rss, jsonfeed } = useSiteMetadata()
const { twitter, github, name, uri } = author
const avatar = data.avatar.edges[0].node.childImageSharp.fixed
const links = [twitter, github, rss, jsonfeed]
return ( return (
<div className={styles.vcard}> <div className={styles.vcard}>
<Img className={styles.avatar} fixed={avatar} alt="avatar" /> <Img className={styles.avatar} fixed={avatar} alt="avatar" />
@ -30,29 +42,3 @@ export function VcardPure({
</div> </div>
) )
} }
export default function Vcard() {
const query = graphql`
query {
avatar: allFile(filter: { name: { eq: "avatar" } }) {
edges {
node {
childImageSharp {
fixed(width: 80, height: 80, quality: 90) {
...GatsbyImageSharpFixed_withWebp_noBase64
}
}
}
}
}
}
`
const data = useStaticQuery(query)
const { author, rss, jsonfeed } = useSiteMetadata()
const { twitter, github, name, uri } = author
const avatar = data.avatar.edges[0].node.childImageSharp.fixed
const links = [twitter, github, rss, jsonfeed]
return <VcardPure avatar={avatar} links={links} uri={uri} name={name} />
}

View File

@ -0,0 +1,7 @@
import React from 'react'
import testRender from '../../../jest/testRender'
import Footer from './Footer'
describe('Footer', () => {
testRender(<Footer />)
})

View File

@ -0,0 +1,7 @@
import React from 'react'
import testRender from '../../../jest/testRender'
import Header from './Header'
describe('Header', () => {
testRender(<Header />)
})

View File

@ -1,39 +1,39 @@
import { useStaticQuery, graphql } from 'gatsby' import { useStaticQuery, graphql } from 'gatsby'
import { Site } from '../@types/Site' import { Site } from '../@types/Site'
export function useSiteMetadata(): Site { const query = graphql`
const query = graphql` query {
query { site {
site { siteMetadata {
siteMetadata { siteTitle
siteTitle siteTitleShort
siteTitleShort siteDescription
siteDescription siteUrl
siteUrl author {
author { name
name email
email uri
uri twitter
twitter github
github facebook
facebook bitcoin
bitcoin ether
ether
}
typekitID
menu {
title
link
}
rss
jsonfeed
itemsPerPage
repoContentPath
} }
typekitID
menu {
title
link
}
rss
jsonfeed
itemsPerPage
repoContentPath
} }
} }
` }
`
export function useSiteMetadata(): Site {
const { site } = useStaticQuery(query) const { site } = useStaticQuery(query)
return site.siteMetadata return site.siteMetadata
} }

View File

@ -0,0 +1,13 @@
import React from 'react'
import { render } from '@testing-library/react'
import { createHistory, createMemorySource } from '@reach/router'
import NotFound from '../404'
describe('/404', () => {
const history = createHistory(createMemorySource('/404'))
it('renders without crashing', () => {
const { container } = render(<NotFound location={history.location} />)
expect(container.firstChild).toBeInTheDocument()
})
})

View File

@ -0,0 +1,17 @@
import React from 'react'
import { render } from '@testing-library/react'
import { createHistory, createMemorySource } from '@reach/router'
import Photos from '../photos'
import data from '../../../jest/__fixtures__/photos.json'
describe('/photos', () => {
const history = createHistory(createMemorySource('/photos'))
it('renders without crashing', () => {
const { container } = render(
<Photos data={data} location={history.location} />
)
expect(container.firstChild).toBeInTheDocument()
})
})

View File

@ -0,0 +1,24 @@
import React from 'react'
import { render } from '@testing-library/react'
import { createHistory, createMemorySource } from '@reach/router'
import Tags from '../tags'
describe('/tags', () => {
const history = createHistory(createMemorySource('/tags'))
const data = {
allMarkdownRemark: {
group: [
{ fieldValue: 'android', totalCount: 2 },
{ fieldValue: 'aperture', totalCount: 18 }
]
}
}
it('renders without crashing', () => {
const { container } = render(
<Tags data={data} location={history.location} />
)
expect(container.firstChild).toBeInTheDocument()
})
})

View File

@ -0,0 +1,13 @@
import React from 'react'
import { render, waitForElement } from '@testing-library/react'
import Thanks from '../thanks'
describe('/thanks', () => {
it('renders without crashing', async () => {
const { container } = render(<Thanks />)
const lazyElement = await waitForElement(() =>
container.querySelector('button')
)
expect(lazyElement).toBeInTheDocument()
})
})

View File

@ -32,7 +32,7 @@ export default function Photos({
data, data,
location location
}: { }: {
data: { photos: { edges: [{ node: Post }] } } data: any
location: Location location: Location
}) { }) {
return ( return (
@ -42,7 +42,7 @@ export default function Photos({
location={location} location={location}
section={styles.photos} section={styles.photos}
> >
{data.photos.edges.map(({ node }) => ( {data.photos.edges.map(({ node }: { node: Post }) => (
<PhotoThumb key={node.id} photo={node} /> <PhotoThumb key={node.id} photo={node} />
))} ))}
</Page> </Page>

View File

@ -0,0 +1,17 @@
import React from 'react'
import { render } from '@testing-library/react'
import Post from '.'
import data from '../../../jest/__fixtures__/post.json'
describe('Post', () => {
const pageContext = {
next: { title: 'hello', slug: '/hello' },
prev: { title: 'hello2', slug: '/hello2' }
}
it('renders without crashing', () => {
const { container } = render(<Post data={data} pageContext={pageContext} />)
expect(container.firstChild).toBeInTheDocument()
})
})

View File

@ -0,0 +1,28 @@
import React from 'react'
import { render } from '@testing-library/react'
import { createHistory, createMemorySource } from '@reach/router'
import Posts from './Posts'
import data from '../../jest/__fixtures__/posts.json'
describe('Post', () => {
const history = createHistory(createMemorySource('/photos'))
const pageContext = {
tag: 'hello',
slug: '/hello',
currentPageNumber: 2,
numPages: 20
}
it('renders without crashing', () => {
const { container } = render(
<Posts
data={data}
pageContext={pageContext}
location={history.location}
/>
)
expect(container.firstChild).toBeInTheDocument()
})
})

View File

@ -17,7 +17,7 @@ export default function Posts({
location, location,
pageContext pageContext
}: { }: {
data: { allMarkdownRemark: { edges: [{ node: Post }] } } data: any
location: Location location: Location
pageContext: { pageContext: {
tag: string tag: string