diff --git a/app/soapbox/features/verification/__tests__/index.test.tsx b/app/soapbox/features/verification/__tests__/index.test.tsx
new file mode 100644
index 000000000..b4c28509e
--- /dev/null
+++ b/app/soapbox/features/verification/__tests__/index.test.tsx
@@ -0,0 +1,100 @@
+import { Map as ImmutableMap } from 'immutable';
+import React from 'react';
+import { Route, Switch } from 'react-router-dom';
+
+import { __stub } from '../../../__mocks__/api';
+import { render, screen } from '../../../jest/test-helpers';
+import Verification from '../index';
+
+const TestableComponent = () => (
+
+
+ Homepage
+
+);
+
+const renderComponent = (store) => render(
+ ,
+ {},
+ store,
+ { initialEntries: ['/auth/verify'] },
+);
+
+describe('', () => {
+ let store;
+
+ beforeEach(() => {
+ store = {
+ verification: ImmutableMap({
+ instance: {
+ isReady: true,
+ registrations: true,
+ },
+ isComplete: false,
+ }),
+ };
+
+ __stub(mock => {
+ mock.onGet('/api/v1/pepe/instance')
+ .reply(200, {
+ age_minimum: 18,
+ approval_required: true,
+ challenges: ['age', 'email', 'sms'],
+ });
+
+ mock.onPost('/api/v1/pepe/registrations')
+ .reply(200, {
+ access_token: 'N-dZmNqNSmTutJLsGjZ5AnJL4sLw_y-N3pn2acSqJY8',
+ });
+ });
+ });
+
+ describe('When registration is closed', () => {
+ it('successfully redirects to the homepage', () => {
+ const verification = store.verification.setIn(['instance', 'registrations'], false);
+ store.verification = verification;
+
+ renderComponent(store);
+ expect(screen.getByTestId('home')).toHaveTextContent('Homepage');
+ });
+ });
+
+ describe('When verification is complete', () => {
+ it('successfully renders the Registration component', () => {
+ const verification = store.verification.set('isComplete', true);
+ store.verification = verification;
+
+ renderComponent(store);
+ expect(screen.getByRole('heading')).toHaveTextContent('Register your account');
+ });
+ });
+
+ describe('Switching verification steps', () => {
+ it('successfully renders the Birthday step', () => {
+ const verification = store.verification.set('currentChallenge', 'age');
+ store.verification = verification;
+
+ renderComponent(store);
+
+ expect(screen.getByRole('heading')).toHaveTextContent('Enter your birth date');
+ });
+
+ it('successfully renders the Email step', () => {
+ const verification = store.verification.set('currentChallenge', 'email');
+ store.verification = verification;
+
+ renderComponent(store);
+
+ expect(screen.getByRole('heading')).toHaveTextContent('Enter your email address');
+ });
+
+ it('successfully renders the SMS step', () => {
+ const verification = store.verification.set('currentChallenge', 'sms');
+ store.verification = verification;
+
+ renderComponent(store);
+
+ expect(screen.getByRole('heading')).toHaveTextContent('Enter your phone number');
+ });
+ });
+});
diff --git a/app/soapbox/features/verification/index.js b/app/soapbox/features/verification/index.js
deleted file mode 100644
index 63ad1b07c..000000000
--- a/app/soapbox/features/verification/index.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import * as React from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import { Redirect } from 'react-router-dom';
-
-import { fetchVerificationConfig } from 'soapbox/actions/verification';
-
-import Registration from './registration';
-import AgeVerification from './steps/age_verification';
-import EmailVerification from './steps/email_verification';
-import SmsVerification from './steps/sms_verification';
-
-const verificationSteps = {
- email: EmailVerification,
- sms: SmsVerification,
- age: AgeVerification,
-};
-
-const Verification = () => {
- const dispatch = useDispatch();
-
- const isInstanceReady = useSelector((state) => state.getIn(['verification', 'instance', 'isReady'], false) === true);
- const isRegistrationOpen = useSelector(state => state.getIn(['verification', 'instance', 'registrations'], false) === true);
- const currentChallenge = useSelector((state) => state.getIn(['verification', 'currentChallenge']));
- const isVerificationComplete = useSelector((state) => state.getIn(['verification', 'isComplete']));
- const StepToRender = verificationSteps[currentChallenge];
-
- React.useEffect(() => {
- dispatch(fetchVerificationConfig());
- }, []);
-
- if (isInstanceReady && !isRegistrationOpen) {
- return ;
- }
-
- if (isVerificationComplete) {
- return (
-
- );
- }
-
- if (!currentChallenge) {
- return null;
- }
-
- return (
-
- );
-};
-
-export default Verification;
diff --git a/app/soapbox/features/verification/index.tsx b/app/soapbox/features/verification/index.tsx
new file mode 100644
index 000000000..db2dcaaf6
--- /dev/null
+++ b/app/soapbox/features/verification/index.tsx
@@ -0,0 +1,58 @@
+import * as React from 'react';
+import { useDispatch } from 'react-redux';
+import { Redirect } from 'react-router-dom';
+
+import { fetchVerificationConfig } from 'soapbox/actions/verification';
+import { useAppSelector } from 'soapbox/hooks';
+
+import Registration from './registration';
+import AgeVerification from './steps/age-verification';
+import EmailVerification from './steps/email-verification';
+import SmsVerification from './steps/sms-verification';
+
+// eslint-disable-next-line no-unused-vars
+enum ChallengeTypes {
+ EMAIL = 'email', // eslint-disable-line no-unused-vars
+ SMS = 'sms', // eslint-disable-line no-unused-vars
+ AGE = 'age', // eslint-disable-line no-unused-vars
+}
+
+const verificationSteps = {
+ email: EmailVerification,
+ sms: SmsVerification,
+ age: AgeVerification,
+};
+
+const Verification = () => {
+ const dispatch = useDispatch();
+
+ const isInstanceReady = useAppSelector((state) => state.verification.getIn(['instance', 'isReady'], false) === true);
+ const isRegistrationOpen = useAppSelector(state => state.verification.getIn(['instance', 'registrations'], false) === true);
+ const currentChallenge = useAppSelector((state) => state.verification.getIn(['currentChallenge']) as ChallengeTypes);
+ const isVerificationComplete = useAppSelector((state) => state.verification.get('isComplete'));
+ const StepToRender = verificationSteps[currentChallenge];
+
+ React.useEffect(() => {
+ dispatch(fetchVerificationConfig());
+ }, []);
+
+ if (isInstanceReady && !isRegistrationOpen) {
+ return ;
+ }
+
+ if (isVerificationComplete) {
+ return (
+
+ );
+ }
+
+ if (!currentChallenge) {
+ return null;
+ }
+
+ return (
+
+ );
+};
+
+export default Verification;
diff --git a/app/soapbox/features/verification/registration.js b/app/soapbox/features/verification/registration.js
index fb874b597..b00be7ad0 100644
--- a/app/soapbox/features/verification/registration.js
+++ b/app/soapbox/features/verification/registration.js
@@ -20,7 +20,7 @@ const Registration = () => {
const dispatch = useDispatch();
const intl = useIntl();
- const isLoading = useSelector((state) => state.getIn(['verification', 'isLoading']));
+ const isLoading = useSelector((state) => state.verification.get('isLoading'));
const siteTitle = useSelector((state) => state.instance.title);
const [state, setState] = React.useState(initialState);
@@ -89,7 +89,7 @@ const Registration = () => {
-
-
-