Skip to content

Commit

Permalink
Merge pull request #69 from esteticalVE/email-validation
Browse files Browse the repository at this point in the history
Added email validation, unit-tests
  • Loading branch information
samajammin authored Mar 8, 2021
2 parents 18c373d + 4d4e61f commit 4af53e0
Show file tree
Hide file tree
Showing 15 changed files with 1,645 additions and 41 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.cache
package.json
package-lock.json
yarn-lock.json
public
1 change: 1 addition & 0 deletions __mocks__/file-mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = "test-file-stub"
28 changes: 28 additions & 0 deletions __mocks__/gatsby.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const React = require("react")
const gatsby = jest.requireActual("gatsby")

module.exports = {
...gatsby,
graphql: jest.fn(),
Link: jest
.fn()
.mockImplementation(
({
activeClassName,
activeStyle,
getProps,
innerRef,
partiallyActive,
ref,
replace,
to,
...rest
}) =>
React.createElement("a", {
...rest,
href: to,
})
),
StaticQuery: jest.fn(),
useStaticQuery: jest.fn(),
}
5 changes: 5 additions & 0 deletions jest-preprocess.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const babelOptions = {
presets: ["babel-preset-gatsby"],
}

module.exports = require("babel-jest").createTransformer(babelOptions)
17 changes: 17 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = {
transform: {
"^.+\\.jsx?$": "<rootDir>/jest-preprocess.js",
},
moduleNameMapper: {
".+\\.(css|styl|less|sass|scss)$": "identity-obj-proxy",
".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
"<rootDir>/__mocks__/file-mock.js",
},
testPathIgnorePatterns: ["node_modules", ".cache", "public"],
transformIgnorePatterns: ["node_modules/(?!(gatsby)/)"],
globals: {
__PATH_PREFIX__: "",
},
testURL: "http://localhost",
setupFiles: ["<rootDir>/loadershim.js"],
}
3 changes: 3 additions & 0 deletions loadershim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
global.___loader = {
enqueue: jest.fn(),
}
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@
"styled-components": "^5.0.0"
},
"devDependencies": {
"prettier": "^1.19.1"
"babel-jest": "^26.6.3",
"babel-preset-gatsby": "^0.9.1",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.6.3",
"prettier": "^1.19.1",
"react-test-renderer": "^17.0.1"
},
"keywords": [
"gatsby",
Expand All @@ -63,7 +68,7 @@
"start": "yarn develop",
"start:static": "gatsby build && gatsby serve",
"serve": "gatsby serve",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
"test": "jest"
},
"repository": {
"type": "git",
Expand Down
32 changes: 24 additions & 8 deletions src/components/NewsletterSignup.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React, { useState } from "react"
import styled from "styled-components"
import { colorOrangeLightest } from "../utils/styles"
import { Input, Button } from "../components/SharedStyledComponents"
import { useToasts } from "react-toast-notifications"
import { FormattedMessage } from "gatsby-plugin-intl"
import { useToasts } from "react-toast-notifications"
import { Input, Button } from "./SharedStyledComponents"
import { colorOrangeLightest } from "../utils/styles"
import { validateEmail } from "../utils/validate-email"
import { ValidateError } from "../utils/validate-error"

const Container = styled.div`
background-color: ${colorOrangeLightest};
Expand Down Expand Up @@ -52,14 +54,15 @@ const SubmitButton = styled(Button)`

const NewsletterSignup = () => {
const [email, setEmail] = useState("")

const [loading, setLoading] = useState(false)
const { addToast } = useToasts()

const handleInputChange = event => {
setEmail(event.target.value)
}

const submitInquiry = () => {
setLoading(true)
fetch("/.netlify/functions/newsletter-signup", {
method: "POST",
headers: {
Expand All @@ -73,23 +76,37 @@ const NewsletterSignup = () => {
appearance: "success",
autoDismiss: true,
})
setLoading(false)
setEmail("")
})
.catch(error => {
console.error(error)
setLoading(false)
addToast("Error submitting, please try again.", {
appearance: "error",
autoDismiss: true,
})
})
.finally(() => setLoading(false))
}

const handleSubmit = event => {
event.preventDefault()
submitInquiry()
try {
validateEmail(email)
submitInquiry()
} catch (error) {
console.error(error)
if (error instanceof ValidateError) {
addToast(`${error.message}`, {
appearance: "error",
autoDismiss: true,
})
}
}
}

const isEmailValid = !!email
const isEmailFieldEmpty = !email

return (
<Container>
Expand All @@ -103,8 +120,7 @@ const NewsletterSignup = () => {
onChange={handleInputChange}
placeholder="Enter your email"
/>

<SubmitButton disabled={!isEmailValid} type="submit">
<SubmitButton disabled={isEmailFieldEmpty || loading} type="submit">
<FormattedMessage id="sign-up" />
</SubmitButton>
</Form>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/projects/circom/en.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ Since its initial release, circom has become a go-to tool for many projects usin

A specification of Circom is being published in Q1 2020 and the new compiler is already in development.

**Follow along:** [Github](https://github.com/iden3/circom), [Blog](https://blog.iden3.io/)
**Follow along:** [Github](https://github.com/iden3/circom), [Blog](https://blog.iden3.io/)
2 changes: 1 addition & 1 deletion src/pages/projects/ethers-js/en.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ Ethers.js v5 continues to progress and will be coming out of beta soon – in th
**Follow along:** [Blog](https://blog.ricmoo.com/), [Github](https://github.com/ethers-io/ethers.js),
Twitter [@ricmoo](https://twitter.com/ricmoo), [@ethersproject](https://twitter.com/ethersproject) (low activity, advisory only)

Ethers.js is a Gitcoin CLR recipient! Contribute at [gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2](https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2)
Ethers.js is a Gitcoin CLR recipient! Contribute at [gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2](https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2)
2 changes: 1 addition & 1 deletion src/pages/projects/uniswap/en.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ In the coming year, the Uniswap team plans on releasing Uniswap V2, a new versio

**Follow along:** [Github](https://github.com/Uniswap), [Twitter](https://twitter.com/UniswapExchange), [Discord](https://discordapp.com/invite/Y7TF6QA), [Reddit](https://www.reddit.com/r/UniSwap/), [Blog](https://medium.com/uniswap)

Uniswap is a Gitcoin CLR recipient! Contribute at [gitcoin.co/grants/48/uniswap](https://gitcoin.co/grants/48/uniswap)
Uniswap is a Gitcoin CLR recipient! Contribute at [gitcoin.co/grants/48/uniswap](https://gitcoin.co/grants/48/uniswap)
12 changes: 12 additions & 0 deletions src/utils/validate-email.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ValidateError } from "./validate-error"
// eslint-disable-next-line
const validEmailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

export const validateEmail = value => {
if (!value && value.trim() === "") {
throw new ValidateError("Email is empty")
}
if (!validEmailReg.test(value)) {
throw new ValidateError("Email is not valid, please try again")
}
}
50 changes: 50 additions & 0 deletions src/utils/validate-email.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { validateEmail } from "./validate-email"
import { ValidateError } from "./validate-error"

describe("utils/validate-email", () => {
const errorTexts = {
empty: "Email is empty",
invalid: "Email is not valid, please try again",
}
it("Should throw error", () => {
expect(() => validateEmail("")).toThrowError(ValidateError)
expect(() => validateEmail("test")).toThrowError(ValidateError)
expect(() => validateEmail("test@test")).toThrowError(ValidateError)
expect(() => validateEmail("test.test.com")).toThrowError(ValidateError)
expect(() => validateEmail(`test"test"test@test.test`)).toThrowError(
ValidateError
)
expect(() => validateEmail("test@test@test@test.test")).toThrowError(
ValidateError
)
expect(() =>
validateEmail(`a\"b(c)d,e:f;g<h>i[j\\k]l@example.com`)
).toThrowError(ValidateError)
expect(() =>
validateEmail(`test\\ test\\"test\\\\test@test.test`)
).toThrowError(ValidateError)
expect(() => validateEmail("test_test@test_test.test.com")).toThrowError(
ValidateError
)
})
it("Should throw error with correct error text", () => {
expect(() => validateEmail("")).toThrowError(errorTexts.empty)
expect(() => validateEmail("test@test")).toThrowError(errorTexts.invalid)
expect(() => validateEmail("test_test@test_test.test.com")).toThrowError(
errorTexts.invalid
)
})
it("Should not throw error with correct email", () => {
expect(() => validateEmail("sbrichards@gmail.com")).not.toThrowError()
expect(() => validateEmail("ve.gr94@gmail.com")).not.toThrowError()
expect(() => validateEmail("test_test@ya.ru")).not.toThrowError()
expect(() => validateEmail("test+test@test.com")).not.toThrowError()
expect(() => validateEmail("a@test.com")).not.toThrowError()
expect(() => validateEmail("test-test@test-test.com")).not.toThrowError()
expect(() => validateEmail("test!test@test.test")).not.toThrowError()
expect(() => validateEmail("test%test.test@test.test")).not.toThrowError()
expect(() =>
validateEmail("test.test-test-test@test.test")
).not.toThrowError()
})
})
7 changes: 7 additions & 0 deletions src/utils/validate-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export class ValidateError extends Error {
constructor(message) {
super(message)
this.name = this.constructor.name
Object.setPrototypeOf(this, ValidateError.prototype)
}
}
Loading

0 comments on commit 4af53e0

Please sign in to comment.