From 0e78f34d155ca26b0ebbdb03df20fd61f7eb6a43 Mon Sep 17 00:00:00 2001
From: Matthias Kretschmann
Date: Tue, 16 Apr 2019 03:59:21 +0200
Subject: [PATCH] add more tests
---
jest/__fixtures__/meta.json | 3 +
package.json | 1 +
src/components/Layout.jsx | 73 ++++++++++---------
src/components/atoms/Vcard.jsx | 14 ++--
src/components/atoms/Vcard.test.jsx | 37 ++++++++++
src/components/molecules/ThemeSwitch.jsx | 5 +-
src/components/molecules/ThemeSwitch.test.jsx | 17 +++++
src/components/organisms/Footer.jsx | 23 ++++--
src/store/provider.jsx | 34 ++++-----
9 files changed, 139 insertions(+), 68 deletions(-)
create mode 100644 src/components/atoms/Vcard.test.jsx
create mode 100644 src/components/molecules/ThemeSwitch.test.jsx
diff --git a/jest/__fixtures__/meta.json b/jest/__fixtures__/meta.json
index 1ad3618..c4704af 100644
--- a/jest/__fixtures__/meta.json
+++ b/jest/__fixtures__/meta.json
@@ -9,6 +9,9 @@
"childImageSharp": {
"fluid": {
"src": "/static/b45f45aa8d98d4e4019a242d38f2f248/bc3a8/avatar.jpg"
+ },
+ "resize": {
+ "src": "/static/b45f45aa8d98d4e4019a242d38f2f248/bc3a8/avatar.jpg"
}
}
},
diff --git a/package.json b/package.json
index 4700725..44e8ef0 100644
--- a/package.json
+++ b/package.json
@@ -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"
},
diff --git a/src/components/Layout.jsx b/src/components/Layout.jsx
index 999de04..837bd65 100644
--- a/src/components/Layout.jsx
+++ b/src/components/Layout.jsx
@@ -25,59 +25,62 @@ const query = graphql`
}
`
-const LayoutMarkup = ({ children, isHomepage, allowedHosts, location }) => (
- <>
-
-
+const LayoutMarkup = ({ children, data, location }) => {
+ const { allowedHosts } = data.contentYaml
+ const isHomepage = location.pathname === '/'
-
-
-
- {children}
-
-
+ return (
+ <>
+
+
-
- >
-)
+
+
+
+ {children}
+
+
+
+
+ >
+ )
+}
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 (
{
- const { allowedHosts } = data.contentYaml
-
- return (
-
- {children}
-
- )
- }}
+ render={data => (
+
+ {children}
+
+ )}
/>
)
}
diff --git a/src/components/atoms/Vcard.jsx b/src/components/atoms/Vcard.jsx
index ecb57df..6ea6626 100644
--- a/src/components/atoms/Vcard.jsx
+++ b/src/components/atoms/Vcard.jsx
@@ -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=='
diff --git a/src/components/atoms/Vcard.test.jsx b/src/components/atoms/Vcard.test.jsx
new file mode 100644
index 0000000..45b42a7
--- /dev/null
+++ b/src/components/atoms/Vcard.test.jsx
@@ -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()
+
+ 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')
+ })
+})
diff --git a/src/components/molecules/ThemeSwitch.jsx b/src/components/molecules/ThemeSwitch.jsx
index 8437f5e..1c689ed 100644
--- a/src/components/molecules/ThemeSwitch.jsx
+++ b/src/components/molecules/ThemeSwitch.jsx
@@ -48,7 +48,10 @@ export default class ThemeSwitch extends PureComponent {
-
+
)
+}
+
+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 (
-
- )
+ return
}}
/>
)
diff --git a/src/store/provider.jsx b/src/store/provider.jsx
index bae29b5..4f5fdfa 100644
--- a/src/store/provider.jsx
+++ b/src/store/provider.jsx
@@ -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() {