From f5f6c0b5fdc6907859757b9025738c277f175c18 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Tue, 16 Apr 2019 21:21:01 +0200 Subject: [PATCH] refactorings --- gatsby-browser.js | 2 +- gatsby-ssr.js | 2 +- jest/setup-test-env.js | 2 + package.json | 1 + src/components/atoms/Vcard.jsx | 90 ++++++------- src/components/atoms/Vcard.test.jsx | 31 +++-- .../molecules/Availability.test.jsx | 4 +- src/components/molecules/Networks.test.jsx | 4 +- src/components/molecules/ThemeSwitch.test.jsx | 2 +- src/components/organisms/Footer.jsx | 5 +- src/components/organisms/Footer.test.jsx | 22 ++++ src/components/organisms/Header.test.jsx | 22 ++++ src/hooks/use-meta.test.js | 4 +- src/store/Provider.jsx | 73 +++++++++++ src/store/Provider.test.jsx | 11 ++ src/store/provider.jsx | 120 ------------------ src/{store => utils}/countrycode-latlong.json | 0 src/utils/getCountry.js | 28 ++++ src/utils/getCountry.test.js | 27 ++++ src/utils/getLocationTimes.js | 25 ++++ src/utils/getLocationTimes.test.js | 9 ++ 21 files changed, 289 insertions(+), 195 deletions(-) create mode 100644 src/components/organisms/Footer.test.jsx create mode 100644 src/components/organisms/Header.test.jsx create mode 100644 src/store/Provider.jsx create mode 100644 src/store/Provider.test.jsx delete mode 100644 src/store/provider.jsx rename src/{store => utils}/countrycode-latlong.json (100%) create mode 100644 src/utils/getCountry.js create mode 100644 src/utils/getCountry.test.js create mode 100644 src/utils/getLocationTimes.js create mode 100644 src/utils/getLocationTimes.test.js diff --git a/gatsby-browser.js b/gatsby-browser.js index 487a949..ad5009f 100644 --- a/gatsby-browser.js +++ b/gatsby-browser.js @@ -1,6 +1,6 @@ import './src/styles/global.scss' import React from 'react' -import AppProvider from './src/store/provider' +import AppProvider from './src/store/Provider' import wrapPageElementWithTransition from './src/helpers/wrapPageElement' // IntersectionObserver polyfill for gatsby-image (Safari, IE) diff --git a/gatsby-ssr.js b/gatsby-ssr.js index 1f8c9ea..3c4acbe 100644 --- a/gatsby-ssr.js +++ b/gatsby-ssr.js @@ -1,6 +1,6 @@ import React from 'react' import { renderToString } from 'react-dom/server' -import AppProvider from './src/store/provider' +import AppProvider from './src/store/Provider' import wrapPageElementWithTransition from './src/helpers/wrapPageElement' export const replaceRenderer = ({ bodyComponent, replaceBodyHTMLString }) => { diff --git a/jest/setup-test-env.js b/jest/setup-test-env.js index 99c14cd..395c3d5 100644 --- a/jest/setup-test-env.js +++ b/jest/setup-test-env.js @@ -2,3 +2,5 @@ import 'jest-dom/extend-expect' // this is basically: afterEach(cleanup) import 'react-testing-library/cleanup-after-each' + +import 'jest-canvas-mock' diff --git a/package.json b/package.json index 44e8ef0..ce78ab2 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "eslint-plugin-react": "^7.12.4", "identity-obj-proxy": "^3.0.0", "jest": "^24.7.1", + "jest-canvas-mock": "^2.0.0-beta.1", "jest-dom": "^3.1.3", "ora": "^3.4.0", "prepend": "^1.0.2", diff --git a/src/components/atoms/Vcard.jsx b/src/components/atoms/Vcard.jsx index 6ea6626..e6b25a8 100644 --- a/src/components/atoms/Vcard.jsx +++ b/src/components/atoms/Vcard.jsx @@ -41,7 +41,7 @@ export default class Vcard extends PureComponent { const handleAddressbookClick = e => { e.preventDefault() - constructVcard(meta) + init(meta) } return ( @@ -60,6 +60,16 @@ export default class Vcard extends PureComponent { } } +export const init = async meta => { + const photoSrc = meta.avatar.childImageSharp.resize.src + + // first, convert the avatar to base64, then construct all vCard elements + const dataUrl = await toDataURL(photoSrc, 'image/jpeg') + const vcard = await constructVcard(dataUrl, meta) + + downloadVcard(vcard, meta) +} + // Construct the download from a blob of the just constructed vCard, // and save it to user's file system export const downloadVcard = (vcard, meta) => { @@ -69,60 +79,54 @@ export const downloadVcard = (vcard, meta) => { saveAs(blob, name) } -export const constructVcard = meta => { +export const constructVcard = async (dataUrl, meta) => { const contact = new vCard() - const photoSrc = meta.avatar.childImageSharp.resize.src - // first, convert the avatar to base64, then construct all vCard elements - toDataURL( - photoSrc, - dataUrl => { - // stripping this data out of base64 string is required - // for vcard to actually display the image for whatever reason - const dataUrlCleaned = dataUrl.split('data:image/jpeg;base64,').join('') - contact.set('photo', dataUrlCleaned, { encoding: 'b', type: 'JPEG' }) - contact.set('fn', meta.title) - contact.set('title', meta.tagline) - contact.set('email', meta.email) - contact.set('url', meta.url, { type: 'Portfolio' }) - contact.add('url', meta.social.Blog, { type: 'Blog' }) - contact.set('nickname', 'kremalicious') - contact.add('x-socialprofile', meta.social.Twitter, { type: 'twitter' }) - contact.add('x-socialprofile', meta.social.GitHub, { type: 'GitHub' }) + // stripping this data out of base64 string is required + // for vcard to actually display the image for whatever reason + // const dataUrlCleaned = dataUrl.split('data:image/jpeg;base64,').join('') + // contact.set('photo', dataUrlCleaned, { encoding: 'b', type: 'JPEG' }) + contact.set('fn', meta.title) + contact.set('title', meta.tagline) + contact.set('email', meta.email) + contact.set('url', meta.url, { type: 'Portfolio' }) + contact.add('url', meta.social.Blog, { type: 'Blog' }) + contact.set('nickname', 'kremalicious') + contact.add('x-socialprofile', meta.social.Twitter, { type: 'twitter' }) + contact.add('x-socialprofile', meta.social.GitHub, { type: 'GitHub' }) - const vcard = contact.toString('3.0') + const vcard = contact.toString('3.0') - downloadVcard(vcard, meta) - }, - 'image/jpeg' - ) + return vcard } // Helper function to create base64 string from avatar image // without the need to read image file from file system -export const toDataURL = (src, callback, outputFormat) => { +export const toDataURL = async (photoSrc, outputFormat) => { const img = new Image() img.crossOrigin = 'Anonymous' + img.src = photoSrc - img.onload = function() { - // yeah, we're gonna create a fake canvas to render the image - // and then create a base64 string from the rendered result - const canvas = document.createElement('canvas') - const ctx = canvas.getContext('2d') - let dataURL + img.onload = () => {} - canvas.height = this.naturalHeight - canvas.width = this.naturalWidth - ctx.drawImage(this, 0, 0) - dataURL = canvas.toDataURL(outputFormat) - callback(dataURL) - } + // yeah, we're gonna create a fake canvas to render the image + // and then create a base64 string from the rendered result + const canvas = document.createElement('canvas') + const ctx = canvas.getContext('2d') + let dataURL - img.src = src + canvas.height = img.naturalHeight + canvas.width = img.naturalWidth + ctx.drawImage(img, 0, 0) + dataURL = canvas.toDataURL(outputFormat) - if (img.complete || img.complete === undefined) { - img.src = - 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==' - img.src = src - } + // img.src = photoSrc + + // if (img.complete || img.complete === undefined) { + // img.src = + // 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==' + // img.src = photoSrc + // } + + return dataURL } diff --git a/src/components/atoms/Vcard.test.jsx b/src/components/atoms/Vcard.test.jsx index 45b42a7..d346120 100644 --- a/src/components/atoms/Vcard.test.jsx +++ b/src/components/atoms/Vcard.test.jsx @@ -1,37 +1,36 @@ 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 Vcard, { constructVcard, toDataURL, init } from './Vcard' import data from '../../../jest/__fixtures__/meta.json' describe('Vcard', () => { beforeEach(() => { StaticQuery.mockImplementationOnce(({ render }) => render({ ...data })) + + global.URL.createObjectURL = jest.fn() }) 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) + it('combined vCard download process finishes', async () => { + await init(data.contentYaml) expect(global.URL.createObjectURL).toHaveBeenCalledTimes(1) }) - it('Base64 from image can be constructed', () => { - const photoSrc = data.contentYaml.avatar.childImageSharp.resize.src + it('vCard can be constructed', async () => { + const vcard = await constructVcard( + 'data:image/jpeg;base64,00', + data.contentYaml + ) + expect(vcard).toBeDefined() + }) - toDataURL(photoSrc, () => null, 'image/jpeg') + it('Base64 from image can be constructed', async () => { + const dataUrl = await toDataURL('hello', 'image/jpeg') + expect(dataUrl).toBeDefined() }) }) diff --git a/src/components/molecules/Availability.test.jsx b/src/components/molecules/Availability.test.jsx index b552111..d656d2a 100644 --- a/src/components/molecules/Availability.test.jsx +++ b/src/components/molecules/Availability.test.jsx @@ -6,9 +6,7 @@ import data from '../../../jest/__fixtures__/meta.json' describe('Availability', () => { it('renders correctly from data file values', () => { - useStaticQuery.mockImplementation(() => { - return { ...data } - }) + useStaticQuery.mockImplementation(() => ({ ...data })) const { container } = render() expect(container.firstChild).toBeInTheDocument() }) diff --git a/src/components/molecules/Networks.test.jsx b/src/components/molecules/Networks.test.jsx index 9ef5674..921e86f 100644 --- a/src/components/molecules/Networks.test.jsx +++ b/src/components/molecules/Networks.test.jsx @@ -5,9 +5,7 @@ import Networks from './Networks' import data from '../../../jest/__fixtures__/meta.json' beforeEach(() => { - useStaticQuery.mockImplementationOnce(() => { - return { ...data } - }) + useStaticQuery.mockImplementationOnce(() => ({ ...data })) }) describe('Networks', () => { diff --git a/src/components/molecules/ThemeSwitch.test.jsx b/src/components/molecules/ThemeSwitch.test.jsx index 4ddb029..08828e1 100644 --- a/src/components/molecules/ThemeSwitch.test.jsx +++ b/src/components/molecules/ThemeSwitch.test.jsx @@ -1,6 +1,6 @@ import React from 'react' import { render } from 'react-testing-library' -import AppProvider from '../../store/provider' +import AppProvider from '../../store/Provider' import ThemeSwitch from './ThemeSwitch' describe('ThemeSwitch', () => { diff --git a/src/components/organisms/Footer.jsx b/src/components/organisms/Footer.jsx index 8ec65f8..cd100b0 100644 --- a/src/components/organisms/Footer.jsx +++ b/src/components/organisms/Footer.jsx @@ -11,9 +11,6 @@ const query = graphql` query { # the package.json file portfolioJson { - name - homepage - repository bugs } @@ -25,7 +22,7 @@ const query = graphql` } ` -export const FooterMarkup = ({ pkg, meta, year }) => { +const FooterMarkup = ({ pkg, meta, year }) => { const classes = classNames('h-card', [styles.footer]) return ( diff --git a/src/components/organisms/Footer.test.jsx b/src/components/organisms/Footer.test.jsx new file mode 100644 index 0000000..2127680 --- /dev/null +++ b/src/components/organisms/Footer.test.jsx @@ -0,0 +1,22 @@ +import React from 'react' +import { render } from 'react-testing-library' +import { StaticQuery, useStaticQuery } from 'gatsby' +import Footer from './Footer' +import data from '../../../jest/__fixtures__/meta.json' + +describe('Header', () => { + beforeEach(() => { + StaticQuery.mockImplementation(({ render }) => + render({ + ...data, + portfolioJson: { bugs: '' } + }) + ) + useStaticQuery.mockImplementation(() => ({ ...data })) + }) + + it('renders correctly', () => { + const { container } = render(