From de0bf69d7a1c0879305f6865ec19b7c6f380972f Mon Sep 17 00:00:00 2001 From: Hailey Date: Thu, 19 Sep 2024 12:08:28 -0700 Subject: [PATCH] add tests --- __tests__/lib/string.test.ts | 82 +++++++++++++++++++++++++++ src/lib/strings/email-typo.ts | 9 +++ src/screens/Signup/StepInfo/index.tsx | 13 +++-- 3 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 src/lib/strings/email-typo.ts diff --git a/__tests__/lib/string.test.ts b/__tests__/lib/string.test.ts index f226de992b..4ee575b4b5 100644 --- a/__tests__/lib/string.test.ts +++ b/__tests__/lib/string.test.ts @@ -1,5 +1,7 @@ import {RichText} from '@atproto/api' +import tldts from 'tldts' +import {emailTypoCheck} from 'lib/strings/email-typo' import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player' import { createStarterPackGooglePlayUri, @@ -985,3 +987,83 @@ describe('createStarterPackGooglePlayUri', () => { expect(createStarterPackGooglePlayUri(undefined, 'rkey')).toEqual(null) }) }) + +describe('emailTypoChecker', () => { + const invalidCases = [ + 'gnail.com', + 'gnail.co', + 'gmaill.com', + 'gmaill.co', + 'gmai.com', + 'gmai.co', + 'gmal.com', + 'gmal.co', + 'gmail.co', + 'iclod.com', + 'iclod.co', + 'outllok.com', + 'outllok.co', + 'outlook.co', + 'yaoo.com', + 'yaoo.co', + 'yaho.com', + 'yaho.co', + 'yahooo.com', + 'yahooo.co', + 'yahoo.co', + 'hithere.jul', + 'agpowj.notshop', + 'thisisnot.avalid.tld.nope', + // old tld for czechoslovakia + 'czechoslovakia.cs', + // tlds that cbs was registering in 2024 but cancelled + 'liveon.cbs', + 'its.showtime', + ] + const validCases = [ + 'gmail.com', + 'outlook.com', + 'yahoo.com', + 'icloud.com', + 'firefox.com', + 'firefox.co', + 'hello.world.com', + 'buy.me.a.coffee.shop', + 'mayotte.yt', + 'aland.ax', + 'bouvet.bv', + 'uk.gb', + 'chad.td', + 'somalia.so', + 'plane.aero', + 'cute.cat', + 'together.coop', + 'findme.jobs', + 'nightatthe.museum', + 'industrial.mil', + 'czechrepublic.cz', + 'lovakia.sk', + // new gtlds in 2024 + 'whatsinyour.locker', + 'letsmakea.deal', + 'skeet.now', + 'everyone.みんな', + 'bourgeois.lifestyle', + 'california.living', + 'skeet.ing', + 'listeningto.music', + 'createa.meme', + ] + + for (const domain of invalidCases) { + it(`returns true when calling emailTypoCheck for abcde@${domain}`, () => { + expect(emailTypoCheck(`abcde@${domain}`, tldts)).toEqual(true) + }) + } + + for (const domain of validCases) { + it(`returns false when calling emailTypoCheck for abcde@${domain}`, () => { + expect(emailTypoCheck(`abcde@${domain}`, tldts)).toEqual(false) + }) + } +}) diff --git a/src/lib/strings/email-typo.ts b/src/lib/strings/email-typo.ts new file mode 100644 index 0000000000..2daf9b9637 --- /dev/null +++ b/src/lib/strings/email-typo.ts @@ -0,0 +1,9 @@ +import type tldts from 'tldts' + +const COMMON_ERROR_PATTERN = + /\b([a-zA-Z0-9._%+-]+)@(gnail\.(co|com)|gmaill\.(co|com)|gmai\.(co|com)|gmail\.co|gmal\.(co|com)|iclod\.(co|com)|icloud\.co|outllok\.(co|com)|outlok\.(co|com)|outlook\.co|yaoo\.(co|com)|yaho\.(co|com)|yahoo\.co|yahooo\.(co|com))\b/ + +export function emailTypoCheck(email: string, dynamicTldts: typeof tldts) { + const isIcann = dynamicTldts.parse(email).isIcann + return !isIcann || COMMON_ERROR_PATTERN.test(email) +} diff --git a/src/screens/Signup/StepInfo/index.tsx b/src/screens/Signup/StepInfo/index.tsx index 983bcecbc6..758f37fadc 100644 --- a/src/screens/Signup/StepInfo/index.tsx +++ b/src/screens/Signup/StepInfo/index.tsx @@ -7,6 +7,7 @@ import type tldts from 'tldts' import {logEvent} from '#/lib/statsig/statsig' import {logger} from '#/logger' +import {emailTypoCheck} from 'lib/strings/email-typo' import {ScreenTransition} from '#/screens/Login/ScreenTransition' import {is13, is18, useSignupContext} from '#/screens/Signup/state' import {Policies} from '#/screens/Signup/StepInfo/Policies' @@ -31,9 +32,6 @@ function sanitizeDate(date: Date): Date { return date } -const COMMON_ERROR_PATTERN = - /\b([a-zA-Z0-9._%+-]+)@(gnail\.com|gmaill\.com|gmai\.com|gmail\.co|gmal\.com|iclod\.com|icloud\.co|outllok\.com|outlok\.com|outlook\.co|yaoo\.com|yaho\.com|yahoo\.co|yahooo\.com)\b/ - export function StepInfo({ onPressBack, isServerError, @@ -50,6 +48,7 @@ export function StepInfo({ const inviteCodeValueRef = useRef(state.inviteCode) const emailValueRef = useRef(state.email) + const prevEmailValueRef = useRef(state.email) const passwordValueRef = useRef(state.password) const [hasWarnedEmail, setHasWarnedEmail] = React.useState(false) @@ -67,11 +66,12 @@ export function StepInfo({ const onNextPress = () => { const inviteCode = inviteCodeValueRef.current const email = emailValueRef.current + const emailChanged = prevEmailValueRef.current !== email const password = passwordValueRef.current - if (!hasWarnedEmail && tldtsRef.current) { - const isIcann = tldtsRef.current.parse(email).isIcann - if (!isIcann || COMMON_ERROR_PATTERN.test(email)) { + if (emailChanged && tldtsRef.current) { + if (emailTypoCheck(email, tldtsRef.current)) { + prevEmailValueRef.current = email setHasWarnedEmail(true) return dispatch({ type: 'setError', @@ -83,6 +83,7 @@ export function StepInfo({ } else if (hasWarnedEmail) { setHasWarnedEmail(false) } + prevEmailValueRef.current = email if (!is13(state.dateOfBirth)) { return