From 280412e2db5e697261b841691f4263bb654d8dfc Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Tue, 26 Mar 2019 18:26:20 -0400 Subject: [PATCH 01/17] Mocking the useTranslation hook --- src/__mocks__/react-i18next.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/__mocks__/react-i18next.js b/src/__mocks__/react-i18next.js index 14d998c..8a297ab 100644 --- a/src/__mocks__/react-i18next.js +++ b/src/__mocks__/react-i18next.js @@ -1,6 +1,8 @@ const reactI18next = jest.requireActual('react-i18next'); +const i18n = require('i18n'); module.exports = { ...reactI18next, - Trans: require('__mocks__/component-mock').buildMock(reactI18next.Trans) + Trans: require('__mocks__/component-mock').buildMock(reactI18next.Trans), + useTranslation: () => ({ i18n, t: i18n.mockT }) }; From aa10ecf18c6c5a16579864136278c8ddca102ba2 Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Tue, 26 Mar 2019 18:26:39 -0400 Subject: [PATCH 02/17] Converting 404 page to use hooks --- src/pages/404.js | 21 ++++++++++----------- src/pages/404.test.js | 5 ++--- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/pages/404.js b/src/pages/404.js index 9b3b0c9..bae3d9f 100644 --- a/src/pages/404.js +++ b/src/pages/404.js @@ -1,19 +1,18 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { withTranslation, Trans } from 'react-i18next'; +import { useTranslation, Trans } from 'react-i18next'; import Metadata from 'components/Metadata'; import Message from 'components/Message'; -export const ErrorPage = ({ t }) => <> - - -

The page you have requested could not be found.

-
-; +export const ErrorPage = () => { + const { t } = useTranslation(); -ErrorPage.propTypes = { - t: PropTypes.func.isRequired + return <> + + +

The page you have requested could not be found.

+
+ ; }; -export default withTranslation()(ErrorPage); +export default ErrorPage; diff --git a/src/pages/404.test.js b/src/pages/404.test.js index 939135d..7b26d56 100644 --- a/src/pages/404.test.js +++ b/src/pages/404.test.js @@ -6,13 +6,12 @@ jest.mock('components/Message', () => import React from 'react'; import { render } from 'react-testing-library'; -import { mockT } from 'i18n'; -import { ErrorPage } from 'pages/404'; +import ErrorPage from 'pages/404'; describe('Error Page', () => { test('rendering', () => { const { asFragment } = render( - + ); expect(asFragment()).toMatchSnapshot(); }); From 110543a537feef871d93f7c3f50439ab909583bd Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Tue, 26 Mar 2019 18:29:21 -0400 Subject: [PATCH 03/17] Updatnig privacy page to use hooks --- src/pages/privacy.js | 17 ++++++++--------- src/pages/privacy.test.js | 5 ++--- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/pages/privacy.js b/src/pages/privacy.js index 89b438d..11a7c90 100644 --- a/src/pages/privacy.js +++ b/src/pages/privacy.js @@ -1,17 +1,16 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { withTranslation } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; import Metadata from 'components/Metadata'; import PrivacyPolicy from 'components/PrivacyPolicy'; -export const PrivacyPage = ({ t }) => <> - - -; +export const PrivacyPage = () => { + const { t } = useTranslation(); -PrivacyPage.propTypes = { - t: PropTypes.func.isRequired + return <> + + + ; }; -export default withTranslation()(PrivacyPage); +export default PrivacyPage; diff --git a/src/pages/privacy.test.js b/src/pages/privacy.test.js index 6e2e7aa..5aba132 100644 --- a/src/pages/privacy.test.js +++ b/src/pages/privacy.test.js @@ -6,13 +6,12 @@ jest.mock('components/PrivacyPolicy', () => import React from 'react'; import { render } from 'react-testing-library'; -import { mockT } from 'i18n'; -import { PrivacyPage } from 'pages/privacy'; +import PrivacyPage from 'pages/privacy'; describe('Privacy Page', () => { test('rendering', () => { const { asFragment } = render( - + ); expect(asFragment()).toMatchSnapshot(); }); From 461d8aa7acabca3ba465779aa42711703c2743ad Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Tue, 26 Mar 2019 18:29:40 -0400 Subject: [PATCH 04/17] Cleanup tests for index page --- src/pages/index.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/index.test.js b/src/pages/index.test.js index ca1dfda..38cb22a 100644 --- a/src/pages/index.test.js +++ b/src/pages/index.test.js @@ -8,7 +8,7 @@ jest.mock('components/App', () => import React from 'react'; import { render } from 'react-testing-library'; -import { IndexPage } from 'pages/index'; +import IndexPage from 'pages/index'; const queryResult = { site: { From 8186e1cf875afde3da4075c9f44c3284776e0bf9 Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Tue, 26 Mar 2019 18:33:40 -0400 Subject: [PATCH 05/17] Updating Loader to use hooks --- src/components/App/__snapshots__/test.js.snap | 4 ++-- src/components/Loader/index.js | 18 +++++++----------- src/components/Loader/test.js | 5 ++--- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/components/App/__snapshots__/test.js.snap b/src/components/App/__snapshots__/test.js.snap index 57e33f4..6f8f900 100644 --- a/src/components/App/__snapshots__/test.js.snap +++ b/src/components/App/__snapshots__/test.js.snap @@ -119,7 +119,7 @@ exports[`App rendering an expression 2`] = ` }" /> @@ -200,7 +200,7 @@ exports[`App rendering with an invalid syntax 2`] = ` }" /> diff --git a/src/components/Loader/index.js b/src/components/Loader/index.js index 83336d9..1fa58dc 100644 --- a/src/components/Loader/index.js +++ b/src/components/Loader/index.js @@ -1,21 +1,17 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { withTranslation } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; import LoaderIcon from 'react-feather/dist/icons/loader'; import style from './style.module.css'; -const Loader = ({ t }) => ( -
+const Loader = () => { + const { t } = useTranslation(); + + return
{ t('Loading...') }
-
-); - -Loader.propTypes = { - t: PropTypes.func.isRequired +
; }; -export { Loader }; -export default withTranslation()(Loader); +export default Loader; diff --git a/src/components/Loader/test.js b/src/components/Loader/test.js index 49231b8..3becb8b 100644 --- a/src/components/Loader/test.js +++ b/src/components/Loader/test.js @@ -1,15 +1,14 @@ import React from 'react'; import { render } from 'react-testing-library'; -import { mockT } from 'i18n'; -import { Loader } from 'components/Loader'; +import Loader from 'components/Loader'; describe('Loader', () => { test('rendering', () => { // Using full rendering here since styles for this depend on the structure // of the SVG. const { asFragment } = render( - + ); expect(asFragment()).toMatchSnapshot(); }); From 94d7f3d3cef3ec9ba8ea28d9238c08ff9ba4aef8 Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Tue, 26 Mar 2019 18:44:17 -0400 Subject: [PATCH 06/17] Updating Metadata to use hooks --- .../Metadata/__snapshots__/test.js.snap | 8 +--- src/components/Metadata/index.js | 38 ++++++++----------- src/components/Metadata/test.js | 11 ++---- src/pages/__snapshots__/404.test.js.snap | 2 +- src/pages/__snapshots__/index.test.js.snap | 4 +- src/pages/__snapshots__/privacy.test.js.snap | 2 +- 6 files changed, 25 insertions(+), 40 deletions(-) diff --git a/src/components/Metadata/__snapshots__/test.js.snap b/src/components/Metadata/__snapshots__/test.js.snap index ca8e43b..1f34460 100644 --- a/src/components/Metadata/__snapshots__/test.js.snap +++ b/src/components/Metadata/__snapshots__/test.js.snap @@ -5,9 +5,7 @@ exports[`Metadata rendering 1`] = ` @@ -22,9 +20,7 @@ exports[`Metadata rendering with a title and description 1`] = ` <span data-component="HelmetWrapper" data-props="{ - \\"htmlAttributes\\": { - \\"lang\\": \\"test-lang\\" - } + \\"htmlAttributes\\": {} }" > <title> diff --git a/src/components/Metadata/index.js b/src/components/Metadata/index.js index 3126ff2..8ece14f 100644 --- a/src/components/Metadata/index.js +++ b/src/components/Metadata/index.js @@ -1,29 +1,23 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { withTranslation } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; import { Helmet } from 'react-helmet'; -class Metadata extends React.PureComponent { - static propTypes = { - title: PropTypes.string, - description: PropTypes.string, - i18n: PropTypes.shape({ - language: PropTypes.string.isRequired - }).isRequired - } +const Metadata = ({ title, description }) => { + const { i18n } = useTranslation(); + const htmlAttributes = { + lang: i18n.language + }; - render() { - const { title, description, i18n } = this.props; - const htmlAttributes = { - lang: i18n.language - }; + return <Helmet htmlAttributes={ htmlAttributes }> + <title>{ title ? `Regexper - ${ title }` : 'Regexper' } + { description && } + ; +}; - return - { title ? `Regexper - ${ title }` : 'Regexper' } - { description && } - ; - } -} +Metadata.propTypes = { + title: PropTypes.string, + description: PropTypes.string +}; -export { Metadata }; -export default withTranslation()(Metadata); +export default Metadata; diff --git a/src/components/Metadata/test.js b/src/components/Metadata/test.js index 89c4d29..0a3dfc8 100644 --- a/src/components/Metadata/test.js +++ b/src/components/Metadata/test.js @@ -9,16 +9,12 @@ jest.mock('react-helmet', () => { import React from 'react'; import { render } from 'react-testing-library'; -import { Metadata } from 'components/Metadata'; - -const commonProps = { - i18n: { language: 'test-lang' } -}; +import Metadata from 'components/Metadata'; describe('Metadata', () => { test('rendering', () => { const { asFragment } = render( - + ); expect(asFragment()).toMatchSnapshot(); }); @@ -27,8 +23,7 @@ describe('Metadata', () => { const { asFragment } = render( + description="Test description" /> ); expect(asFragment()).toMatchSnapshot(); }); diff --git a/src/pages/__snapshots__/404.test.js.snap b/src/pages/__snapshots__/404.test.js.snap index 43bfeea..4193668 100644 --- a/src/pages/__snapshots__/404.test.js.snap +++ b/src/pages/__snapshots__/404.test.js.snap @@ -3,7 +3,7 @@ exports[`Error Page rendering 1`] = ` Date: Tue, 26 Mar 2019 20:38:07 -0400 Subject: [PATCH 07/17] Updating SentryError to use hooks --- .../SentryBoundary/__snapshots__/test.js.snap | 2 +- src/components/SentryError/index.js | 17 +++++++---------- src/components/SentryError/test.js | 9 ++++----- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/components/SentryBoundary/__snapshots__/test.js.snap b/src/components/SentryBoundary/__snapshots__/test.js.snap index 330b19e..7386a44 100644 --- a/src/components/SentryBoundary/__snapshots__/test.js.snap +++ b/src/components/SentryBoundary/__snapshots__/test.js.snap @@ -9,7 +9,7 @@ exports[`SentryBoundary error handling 1`] = ` exports[`SentryBoundary error handling 2`] = ` diff --git a/src/components/SentryError/index.js b/src/components/SentryError/index.js index e0c1d94..a1fe62d 100644 --- a/src/components/SentryError/index.js +++ b/src/components/SentryError/index.js @@ -1,7 +1,6 @@ import React from 'react'; -import PropTypes from 'prop-types'; import * as Sentry from '@sentry/browser'; -import { withTranslation, Trans } from 'react-i18next'; +import { useTranslation, Trans } from 'react-i18next'; import Message from 'components/Message'; @@ -13,19 +12,17 @@ const reportError = event => { } }; -export const SentryError = ({ t }) => ( - +export const SentryError = () => { + const { t } = useTranslation(); + + return

This error has been logged. You may also fill out a report.

-
-); - -SentryError.propTypes = { - t: PropTypes.func.isRequired +
; }; -export default withTranslation()(SentryError); +export default SentryError; diff --git a/src/components/SentryError/test.js b/src/components/SentryError/test.js index dfb1641..e162fb8 100644 --- a/src/components/SentryError/test.js +++ b/src/components/SentryError/test.js @@ -7,13 +7,12 @@ import React from 'react'; import { render, fireEvent } from 'react-testing-library'; import * as Sentry from '@sentry/browser'; -import { mockT } from 'i18n'; -import { SentryError } from 'components/SentryError'; +import SentryError from 'components/SentryError'; describe('SentryError', () => { test('rendering', () => { const { asFragment } = render( - + ); expect(asFragment()).toMatchSnapshot(); }); @@ -22,7 +21,7 @@ describe('SentryError', () => { test('fill out a report when an event has been logged', () => { Sentry.lastEventId.mockReturnValue(1); const { getByTestId } = render( - + ); const event = new MouseEvent('click', { bubbles: true }); jest.spyOn(event, 'preventDefault'); @@ -35,7 +34,7 @@ describe('SentryError', () => { test('fill out a report when an event has not been logged', () => { Sentry.lastEventId.mockReturnValue(false); const { getByTestId } = render( - + ); const event = new MouseEvent('click', { bubbles: true }); jest.spyOn(event, 'preventDefault'); From c6020a225fcda20511af2c97bbdccda288f663b4 Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Tue, 26 Mar 2019 20:39:40 -0400 Subject: [PATCH 08/17] Updating Footer to use hooks --- src/components/Footer/index.js | 15 ++++++++------- src/components/Footer/test.js | 2 +- src/components/Layout/__snapshots__/test.js.snap | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/components/Footer/index.js b/src/components/Footer/index.js index 5dadb9a..84acc61 100644 --- a/src/components/Footer/index.js +++ b/src/components/Footer/index.js @@ -1,13 +1,15 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { withTranslation, Trans } from 'react-i18next'; +import { useTranslation, Trans } from 'react-i18next'; import ccLogo from './cc-by.svg'; import style from './style.module.css'; -export const Footer = ({ t, buildId }) => ( -
+export const Footer = ({ buildId }) => { + const { t } = useTranslation(); + + return -); +
; +}; Footer.propTypes = { - t: PropTypes.func.isRequired, buildId: PropTypes.string.isRequired }; -export default withTranslation()(Footer); +export default Footer; diff --git a/src/components/Footer/test.js b/src/components/Footer/test.js index 2e7bf3a..11313c5 100644 --- a/src/components/Footer/test.js +++ b/src/components/Footer/test.js @@ -2,7 +2,7 @@ import React from 'react'; import { render } from 'react-testing-library'; import { mockT } from 'i18n'; -import { Footer } from 'components/Footer'; +import Footer from 'components/Footer'; describe('Footer', () => { test('rendering', () => { diff --git a/src/components/Layout/__snapshots__/test.js.snap b/src/components/Layout/__snapshots__/test.js.snap index 7f80226..18c462d 100644 --- a/src/components/Layout/__snapshots__/test.js.snap +++ b/src/components/Layout/__snapshots__/test.js.snap @@ -20,7 +20,7 @@ exports[`Layout rendering 1`] = ` Example content
Date: Tue, 26 Mar 2019 20:42:16 -0400 Subject: [PATCH 09/17] Updating PrivacyPolicy to use hooks --- .../Header/__snapshots__/test.js.snap | 14 +++++++------- src/components/PrivacyPolicy/index.js | 17 +++++++---------- src/components/PrivacyPolicy/test.js | 5 ++--- src/pages/__snapshots__/privacy.test.js.snap | 2 +- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/components/Header/__snapshots__/test.js.snap b/src/components/Header/__snapshots__/test.js.snap index 0016f11..332bdd7 100644 --- a/src/components/Header/__snapshots__/test.js.snap +++ b/src/components/Header/__snapshots__/test.js.snap @@ -9,7 +9,7 @@ exports[`Header opening the Privacy Policy modal 1`] = ` }" > @@ -85,7 +85,7 @@ exports[`Header opening the Privacy Policy modal while holding alt key 1`] = ` }" > @@ -161,7 +161,7 @@ exports[`Header opening the Privacy Policy modal while holding ctrl key 1`] = ` }" > @@ -237,7 +237,7 @@ exports[`Header opening the Privacy Policy modal while holding meta key 1`] = ` }" > @@ -313,7 +313,7 @@ exports[`Header opening the Privacy Policy modal while holding shift key 1`] = ` }" > @@ -389,7 +389,7 @@ exports[`Header rendering 1`] = ` }" > @@ -466,7 +466,7 @@ exports[`Header rendering with no banner 1`] = ` }" > diff --git a/src/components/PrivacyPolicy/index.js b/src/components/PrivacyPolicy/index.js index e2641e6..6bf5148 100644 --- a/src/components/PrivacyPolicy/index.js +++ b/src/components/PrivacyPolicy/index.js @@ -1,11 +1,12 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import { withTranslation, Trans } from 'react-i18next'; +import { useTranslation, Trans } from 'react-i18next'; import Message from 'components/Message'; -export const PrivacyPolicy = ({ t, ...props }) => ( - +export const PrivacyPolicy = props => { + const { t } = useTranslation(); + + return

Regexper and the tools used to create it are all open source. If you are @@ -44,11 +45,7 @@ export const PrivacyPolicy = ({ t, ...props }) => ( Regexper is not supported by ad revenue or sales of any kind.

-
-); - -PrivacyPolicy.propTypes = { - t: PropTypes.func.isRequired +
; }; -export default withTranslation()(PrivacyPolicy); +export default PrivacyPolicy; diff --git a/src/components/PrivacyPolicy/test.js b/src/components/PrivacyPolicy/test.js index 3a1c4b3..a7d8aea 100644 --- a/src/components/PrivacyPolicy/test.js +++ b/src/components/PrivacyPolicy/test.js @@ -4,13 +4,12 @@ jest.mock('components/Message', () => import React from 'react'; import { render } from 'react-testing-library'; -import { mockT } from 'i18n'; -import { PrivacyPolicy } from 'components/PrivacyPolicy'; +import PrivacyPolicy from 'components/PrivacyPolicy'; describe('PrivacyPolicy', () => { test('rendering', () => { const { asFragment } = render( - + ); expect(asFragment()).toMatchSnapshot(); }); diff --git a/src/pages/__snapshots__/privacy.test.js.snap b/src/pages/__snapshots__/privacy.test.js.snap index 89832ae..e1cd9a4 100644 --- a/src/pages/__snapshots__/privacy.test.js.snap +++ b/src/pages/__snapshots__/privacy.test.js.snap @@ -9,7 +9,7 @@ exports[`Privacy Page rendering 1`] = ` }" />
From 18427f9fc674f9bb9d30aad3c7cd264a9da23a16 Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Tue, 26 Mar 2019 21:12:35 -0400 Subject: [PATCH 10/17] Updating InstallPrompt to use hooks --- .../Header/__snapshots__/test.js.snap | 14 ++-- .../InstallPrompt/__snapshots__/test.js.snap | 36 ---------- src/components/InstallPrompt/index.js | 67 +++++++------------ src/components/InstallPrompt/test.js | 46 +------------ 4 files changed, 34 insertions(+), 129 deletions(-) diff --git a/src/components/Header/__snapshots__/test.js.snap b/src/components/Header/__snapshots__/test.js.snap index 332bdd7..a78a5a9 100644 --- a/src/components/Header/__snapshots__/test.js.snap +++ b/src/components/Header/__snapshots__/test.js.snap @@ -59,7 +59,7 @@ exports[`Header opening the Privacy Policy modal 1`] = `
  • @@ -135,7 +135,7 @@ exports[`Header opening the Privacy Policy modal while holding alt key 1`] = `
  • @@ -211,7 +211,7 @@ exports[`Header opening the Privacy Policy modal while holding ctrl key 1`] = `
  • @@ -287,7 +287,7 @@ exports[`Header opening the Privacy Policy modal while holding meta key 1`] = `
  • @@ -363,7 +363,7 @@ exports[`Header opening the Privacy Policy modal while holding shift key 1`] = `
  • @@ -440,7 +440,7 @@ exports[`Header rendering 1`] = `
  • @@ -516,7 +516,7 @@ exports[`Header rendering with no banner 1`] = `
  • diff --git a/src/components/InstallPrompt/__snapshots__/test.js.snap b/src/components/InstallPrompt/__snapshots__/test.js.snap index 17abdcb..f034bc7 100644 --- a/src/components/InstallPrompt/__snapshots__/test.js.snap +++ b/src/components/InstallPrompt/__snapshots__/test.js.snap @@ -1,41 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`InstallPrompt accepting install prompt 1`] = ` - -
    - - Add to Home Screen - - - -`; - -exports[`InstallPrompt accepting install prompt 2`] = ``; - -exports[`InstallPrompt rejecting install prompt 1`] = ` - - - - Add to Home Screen - - - -`; - -exports[`InstallPrompt rejecting install prompt 2`] = ``; - exports[`InstallPrompt rendering 1`] = ``; exports[`InstallPrompt rendering after an install prompt has been requested 1`] = ``; diff --git a/src/components/InstallPrompt/index.js b/src/components/InstallPrompt/index.js index 57b31d9..73bb1b4 100644 --- a/src/components/InstallPrompt/index.js +++ b/src/components/InstallPrompt/index.js @@ -1,30 +1,12 @@ -import React from 'react'; -import { withTranslation, Trans } from 'react-i18next'; +import React, { useState, useEffect, useCallback } from 'react'; +import { Trans } from 'react-i18next'; -class InstallPrompt extends React.PureComponent { - state = { - installPrompt: null - } +const InstallPrompt = () => { + const [ installPrompt, updateInstallPrompt ] = useState(null); - componentDidMount() { - window.addEventListener('beforeinstallprompt', this.handleInstallPrompt); - } - - componentWillUnmount() { - window.removeEventListener('beforeinstallprompt', this.handleInstallPrompt); - } - - handleInstallPrompt = event => { - this.setState({ - installPrompt: event - }); - } - - handleInstall = async event => { + const handleInstall = useCallback(async event => { event.preventDefault(); - const { installPrompt } = this.state; - try { installPrompt.prompt(); await installPrompt.userChoice; @@ -33,24 +15,27 @@ class InstallPrompt extends React.PureComponent { // User cancelled install } - this.setState({ installPrompt: null }); + updateInstallPrompt(null); + }, [installPrompt, updateInstallPrompt]); + + useEffect(() => { + window.addEventListener('beforeinstallprompt', updateInstallPrompt); + + return () => { + window.removeEventListener('beforeinstallprompt', updateInstallPrompt); + }; + }); + + if (!installPrompt) { + return null; } - render() { - const { installPrompt } = this.state; + return + Add to Home Screen + ; +}; - if (!installPrompt) { - return null; - } - - return - Add to Home Screen - ; - } -} - -export { InstallPrompt }; -export default withTranslation()(InstallPrompt); +export default InstallPrompt; diff --git a/src/components/InstallPrompt/test.js b/src/components/InstallPrompt/test.js index ea3edb2..0283703 100644 --- a/src/components/InstallPrompt/test.js +++ b/src/components/InstallPrompt/test.js @@ -1,7 +1,7 @@ import React from 'react'; import { render, fireEvent } from 'react-testing-library'; -import { InstallPrompt } from 'components/InstallPrompt'; +import InstallPrompt from 'components/InstallPrompt'; describe('InstallPrompt', () => { test('rendering', () => { @@ -39,48 +39,4 @@ describe('InstallPrompt', () => { 'beforeinstallprompt', expect.any(Function)); }); - - test('accepting install prompt', async () => { - const { asFragment, getByTestId } = render( - - ); - const promptEvent = new Event('beforeinstallprompt'); - promptEvent.prompt = jest.fn(); - promptEvent.userChoice = Promise.resolve(); - const clickEvent = new MouseEvent('click', { bubbles: true }); - jest.spyOn(clickEvent, 'preventDefault'); - - fireEvent(window, promptEvent); - expect(asFragment()).toMatchSnapshot(); - fireEvent(getByTestId('install'), clickEvent); - - // Allow async code to run - await new Promise(resolve => setTimeout(resolve)); - - expect(clickEvent.preventDefault).toHaveBeenCalled(); - expect(promptEvent.prompt).toHaveBeenCalled(); - expect(asFragment()).toMatchSnapshot(); - }); - - test('rejecting install prompt', async () => { - const { asFragment, getByTestId } = render( - - ); - const promptEvent = new Event('beforeinstallprompt'); - promptEvent.prompt = jest.fn(); - promptEvent.userChoice = Promise.reject(); - const clickEvent = new MouseEvent('click', { bubbles: true }); - jest.spyOn(clickEvent, 'preventDefault'); - - fireEvent(window, promptEvent); - expect(asFragment()).toMatchSnapshot(); - fireEvent(getByTestId('install'), clickEvent); - - // Allow async code to run - await new Promise(resolve => setTimeout(resolve)); - - expect(clickEvent.preventDefault).toHaveBeenCalled(); - expect(promptEvent.prompt).toHaveBeenCalled(); - expect(asFragment()).toMatchSnapshot(); - }); }); From 31053719547c42270a8c976edd5907d6ac44c29b Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Tue, 26 Mar 2019 21:25:06 -0400 Subject: [PATCH 11/17] Updating LocaleSwitcher to use hooks --- .../Header/__snapshots__/test.js.snap | 14 ++-- src/components/LocaleSwitcher/index.js | 76 ++++++++----------- src/components/LocaleSwitcher/test.js | 10 ++- 3 files changed, 47 insertions(+), 53 deletions(-) diff --git a/src/components/Header/__snapshots__/test.js.snap b/src/components/Header/__snapshots__/test.js.snap index a78a5a9..7e14ea9 100644 --- a/src/components/Header/__snapshots__/test.js.snap +++ b/src/components/Header/__snapshots__/test.js.snap @@ -67,7 +67,7 @@ exports[`Header opening the Privacy Policy modal 1`] = ` data-requires-js="true" > @@ -143,7 +143,7 @@ exports[`Header opening the Privacy Policy modal while holding alt key 1`] = ` data-requires-js="true" > @@ -219,7 +219,7 @@ exports[`Header opening the Privacy Policy modal while holding ctrl key 1`] = ` data-requires-js="true" > @@ -295,7 +295,7 @@ exports[`Header opening the Privacy Policy modal while holding meta key 1`] = ` data-requires-js="true" > @@ -371,7 +371,7 @@ exports[`Header opening the Privacy Policy modal while holding shift key 1`] = ` data-requires-js="true" > @@ -448,7 +448,7 @@ exports[`Header rendering 1`] = ` data-requires-js="true" > @@ -524,7 +524,7 @@ exports[`Header rendering with no banner 1`] = ` data-requires-js="true" > diff --git a/src/components/LocaleSwitcher/index.js b/src/components/LocaleSwitcher/index.js index 09679cb..b9515e3 100644 --- a/src/components/LocaleSwitcher/index.js +++ b/src/components/LocaleSwitcher/index.js @@ -1,5 +1,5 @@ -import React from 'react'; -import { withTranslation, Trans } from 'react-i18next'; +import React, { useState, useEffect, useCallback } from 'react'; +import { Trans } from 'react-i18next'; import ExpandIcon from 'react-feather/dist/icons/chevrons-down'; @@ -8,50 +8,40 @@ import i18n, { locales } from 'i18n'; import localeToAvailable from './locale-to-available'; import style from './style.module.css'; -export class LocaleSwitcher extends React.PureComponent { - state = { - current: localeToAvailable( - i18n.language || '', - locales.map(l => l.code), - 'en') - } +const LocaleSwitcher = () => { + const [ current, updateCurrent ] = useState(localeToAvailable( + i18n.language || '', + locales.map(l => l.code), + 'en')); - componentDidMount() { - i18n.on('languageChanged', this.handleLanguageChange); - } + useEffect(() => { + i18n.on('languageChanged', updateCurrent); - componentWillUnmount() { - i18n.off('languageChanged', this.handleLanguageChange); - } + return () => { + i18n.off('languageChanged', updateCurrent); + }; + }); - handleSelectChange = ({ target }) => { + const handleSelectChange = useCallback(({ target }) => { i18n.changeLanguage(target.value); - } + }); - handleLanguageChange = lang => { - this.setState({ current: lang }); - } + return ; +}; - render() { - const { current } = this.state; - - return ; - } -} - -export default withTranslation()(LocaleSwitcher); +export default LocaleSwitcher; diff --git a/src/components/LocaleSwitcher/test.js b/src/components/LocaleSwitcher/test.js index 23f409e..618f8e5 100644 --- a/src/components/LocaleSwitcher/test.js +++ b/src/components/LocaleSwitcher/test.js @@ -3,10 +3,10 @@ jest.mock('react-feather/dist/icons/chevrons-down', () => 'react-feather/dist/icons/chevrons-down')); import React from 'react'; -import { render, fireEvent } from 'react-testing-library'; +import { render, fireEvent, act } from 'react-testing-library'; import i18n from 'i18n'; -import { LocaleSwitcher } from 'components/LocaleSwitcher'; +import LocaleSwitcher from 'components/LocaleSwitcher'; // Ensure initial locale is always "en" during tests jest.mock('./locale-to-available', () => jest.fn(() => 'en')); @@ -40,7 +40,11 @@ describe('LocaleSwitcher', () => { ); expect(getByTestId('language-select').value).toEqual('en'); - i18n.emit('languageChanged', 'other'); + + act(() => { + i18n.emit('languageChanged', 'other'); + }); + expect(getByTestId('language-select').value).toEqual('other'); }); From 42b3d0a9d808417677c15a93481b59af68fe51d3 Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Tue, 26 Mar 2019 21:51:49 -0400 Subject: [PATCH 12/17] Updating Form to use hooks --- src/components/App/__snapshots__/test.js.snap | 18 +-- src/components/Form/index.js | 131 ++++++++---------- src/components/Form/test.js | 5 +- 3 files changed, 70 insertions(+), 84 deletions(-) diff --git a/src/components/App/__snapshots__/test.js.snap b/src/components/App/__snapshots__/test.js.snap index 6f8f900..5e067f6 100644 --- a/src/components/App/__snapshots__/test.js.snap +++ b/src/components/App/__snapshots__/test.js.snap @@ -3,7 +3,7 @@ exports[`App removing rendered expression 1`] = ` { + const { t } = useTranslation(); + const [ expr, exprUpdate ] = useState(props.expr); + const [ syntax, syntaxUpdate ] = useState(props.syntax); - state = { - expr: this.props.expr, - syntax: this.props.syntax - } - - handleSubmit = event => { + const handleExprChange = useCallback(event => { + exprUpdate(event.target.value); + }, [exprUpdate]); + const handleSyntaxChange = useCallback(event => { + syntaxUpdate(event.target.value); + }, [syntaxUpdate]); + const handleSubmit = useCallback(event => { event.preventDefault(); - const { expr, syntax } = this.state; - - this.props.onSubmit({ expr, syntax }); - } - - handleKeyPress = event => { + onSubmit({ expr, syntax }); + }, [expr, syntax, onSubmit]); + const handleKeyPress = useCallback(event => { if (event.charCode === 13 && event.shiftKey) { - this.handleSubmit(event); + handleSubmit(event); } - } + }, [handleSubmit]); - handleChange = event => this.setState({ - [event.target.name]: event.target.value - }) + return
    +
    + + +
    + + +
    + { children } +
    +
    ; +}; - render() { - const { - syntaxList, - children, - t - } = this.props; - const { expr, syntax } = this.state; +Form.propTypes = { + expr: PropTypes.string, + syntax: PropTypes.string, + syntaxList: PropTypes.arrayOf(PropTypes.shape({ + id: PropTypes.string, + label: PropTypes.string + })), + onSubmit: PropTypes.func.isRequired, + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node + ]) +}; - return
    -
    - - -
    - - -
    - { children } -
    -
    ; - } -} - -export { Form }; -export default withTranslation()(Form); +export default Form; diff --git a/src/components/Form/test.js b/src/components/Form/test.js index 6f480dd..ca64cb2 100644 --- a/src/components/Form/test.js +++ b/src/components/Form/test.js @@ -5,14 +5,13 @@ jest.mock('react-feather/dist/icons/chevrons-down', () => import React from 'react'; import { render, fireEvent } from 'react-testing-library'; -import { mockT } from 'i18n'; -import { Form } from 'components/Form'; +import Form from 'components/Form'; const syntaxList = [ { id: 'testJS', label: 'Testing JS' }, { id: 'other', label: 'Other' } ]; -const commonProps = { syntaxList, t: mockT }; +const commonProps = { syntaxList }; describe('Form', () => { test('rendering', () => { From 8d78f41ed66b5c34c3046e3ef0a1c65aaf87d6d1 Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Thu, 28 Mar 2019 06:25:23 -0400 Subject: [PATCH 13/17] Addressing Helmet crash --- .../Metadata/__snapshots__/test.js.snap | 33 ++++++++++--------- src/components/Metadata/index.js | 18 ++++++---- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/components/Metadata/__snapshots__/test.js.snap b/src/components/Metadata/__snapshots__/test.js.snap index 1f34460..46f561b 100644 --- a/src/components/Metadata/__snapshots__/test.js.snap +++ b/src/components/Metadata/__snapshots__/test.js.snap @@ -5,13 +5,15 @@ exports[`Metadata rendering 1`] = ` - - Regexper - - + />
    `; @@ -20,16 +22,15 @@ exports[`Metadata rendering with a title and description 1`] = ` - - Regexper - Testing - - - + />
    `; diff --git a/src/components/Metadata/index.js b/src/components/Metadata/index.js index 8ece14f..004ed92 100644 --- a/src/components/Metadata/index.js +++ b/src/components/Metadata/index.js @@ -5,14 +5,20 @@ import { Helmet } from 'react-helmet'; const Metadata = ({ title, description }) => { const { i18n } = useTranslation(); - const htmlAttributes = { - lang: i18n.language + const helmetProps = { + title: title ? `Regexper - ${ title }` : 'Regexper', + htmlAttributes: { + lang: i18n.language + }, + meta: [ + { + name: 'description', + content: description + } + ] }; - return - { title ? `Regexper - ${ title }` : 'Regexper' } - { description && } - ; + return ; }; Metadata.propTypes = { From 1621e0e16a2db7de87edddf65f647811aa94ea1b Mon Sep 17 00:00:00 2001 From: Jeff Avallone Date: Thu, 28 Mar 2019 06:27:02 -0400 Subject: [PATCH 14/17] Removing mockT from Footer tests --- src/components/Footer/test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/Footer/test.js b/src/components/Footer/test.js index 11313c5..b03b529 100644 --- a/src/components/Footer/test.js +++ b/src/components/Footer/test.js @@ -1,13 +1,12 @@ import React from 'react'; import { render } from 'react-testing-library'; -import { mockT } from 'i18n'; import Footer from 'components/Footer'; describe('Footer', () => { test('rendering', () => { const { asFragment } = render( -