-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(reset-password): Implement reset password using email
- User should be allowed to reset a password - User should see email before reset a password - User should click on link in email and go to reset password [Deliver #187419121]
- Loading branch information
1 parent
577e395
commit c342239
Showing
20 changed files
with
907 additions
and
301 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import "@testing-library/jest-dom"; | ||
import { render, screen } from "@testing-library/react"; | ||
import { Provider } from "react-redux"; | ||
import { BrowserRouter as Router } from "react-router-dom"; | ||
|
||
import store from "../redux/store"; | ||
import GetLinkPage from "../pages/GetLinkPage"; | ||
import { getLink } from "../redux/reducers/getLinkSlice"; | ||
|
||
test("should render registration page correctly", async () => { | ||
render( | ||
<Provider store={store}> | ||
<Router> | ||
<GetLinkPage /> | ||
</Router> | ||
</Provider>, | ||
); | ||
|
||
expect(screen.getByText("eagles", { exact: false })).toBeInTheDocument(); | ||
expect(screen.getByText(/Get a link to reset password/i)).toBeInTheDocument(); | ||
const title = screen.getAllByText("Get a link to reset password"); | ||
const email = screen.getAllByPlaceholderText("Email"); | ||
const description = screen.getAllByText( | ||
"To reset your password provide registered email below. Before proceed make sure you provide valid email.", | ||
); | ||
|
||
expect(title).toBeTruthy(); | ||
expect(email).toBeTruthy(); | ||
expect(description).toBeTruthy(); | ||
}); | ||
|
||
test("should handle initial state", () => { | ||
expect(store.getState().getLink).toEqual({ | ||
isLoading: false, | ||
data: [], | ||
error: null, | ||
}); | ||
}); | ||
|
||
test("should handle getLink.pending", () => { | ||
// @ts-ignore | ||
store.dispatch(getLink.pending()); | ||
expect(store.getState().getLink).toEqual({ | ||
isLoading: true, | ||
data: [], | ||
error: null, | ||
}); | ||
}); | ||
|
||
test("should handle getLink.fulfilled", () => { | ||
const mockData = { message: "Reset link sent successfully" }; | ||
store.dispatch( | ||
getLink.fulfilled(mockData, "", { email: "[email protected]" }), | ||
); | ||
expect(store.getState().getLink).toEqual({ | ||
isLoading: false, | ||
data: mockData, | ||
error: null, | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// @ts-nocheck | ||
import "@testing-library/jest-dom"; | ||
import { render, screen } from "@testing-library/react"; | ||
import { Provider } from "react-redux"; | ||
import { BrowserRouter as Router } from "react-router-dom"; | ||
import { AnyAction } from "@reduxjs/toolkit"; | ||
|
||
import store from "../redux/store"; | ||
import ResetPassword from "../pages/ResetPassword"; | ||
import { resetPassword } from "../redux/reducers/resetPasswordSlice"; | ||
|
||
test("should render reset password page correctly", async () => { | ||
render( | ||
<Provider store={store}> | ||
<Router> | ||
<ResetPassword /> | ||
</Router> | ||
</Provider>, | ||
); | ||
|
||
expect(screen.getByText("eagles", { exact: false })).toBeInTheDocument(); | ||
expect( | ||
screen.getByText("Reset your password", { exact: false }), | ||
).toBeInTheDocument(); | ||
const description = screen.getAllByText( | ||
"Before you write your password consider if your password is strong enough that can not be guessed or cracked by anyone.", | ||
); | ||
const newPassword = screen.getAllByPlaceholderText("New Password"); | ||
const confirmPassword = screen.getAllByPlaceholderText("Confirm password"); | ||
|
||
expect(description).toBeTruthy(); | ||
expect(newPassword).toBeTruthy(); | ||
expect(confirmPassword).toBeTruthy(); | ||
}); | ||
|
||
test("the link is not disabled", () => { | ||
const { getByText } = render( | ||
<Provider store={store}> | ||
<Router> | ||
<ResetPassword /> | ||
</Router> | ||
</Provider>, | ||
); | ||
const linkElement = getByText("Reset"); | ||
expect(linkElement).not.toBeDisabled(); | ||
expect(linkElement).toBeEnabled(); | ||
expect(linkElement).toBeVisible(); | ||
}); | ||
|
||
it("should handle initial state", () => { | ||
expect(store.getState().reset).toEqual({ | ||
isLoading: false, | ||
data: [], | ||
error: null, | ||
}); | ||
}); | ||
|
||
it("should handle resetPassword.pending", () => { | ||
// @ts-ignore | ||
store.dispatch(resetPassword.pending("")); | ||
expect(store.getState().reset).toEqual({ | ||
isLoading: true, | ||
data: [], | ||
error: null, | ||
}); | ||
}); | ||
|
||
it("should handle resetPassword.fulfilled", () => { | ||
const mockData = { message: "Password reset successfully" }; | ||
store.dispatch(resetPassword.fulfilled(mockData, "", {} as AnyAction)); | ||
expect(store.getState().reset).toEqual({ | ||
isLoading: false, | ||
data: mockData, | ||
error: null, | ||
}); | ||
}); | ||
|
||
it("should handle resetPassword.rejected", () => { | ||
store.dispatch(resetPassword.rejected(null, "", {} as AnyAction)); | ||
expect(store.getState().reset).toEqual({ | ||
isLoading: false, | ||
data: [], | ||
error: undefined, | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { FaCircle } from "react-icons/fa"; | ||
|
||
const Logo = () => ( | ||
<div className="text-black font-bold text-[30px] flex items-center gap-1 p-5"> | ||
<h1 className="font-medium text-[36px]"> | ||
<span className="font-[550] text-heading"> eagles</span> | ||
</h1> | ||
<FaCircle className="text-sm text-[#DB4444] mt-3" /> | ||
</div> | ||
); | ||
|
||
export default Logo; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { createSlice } from "@reduxjs/toolkit"; | ||
// @ts-ignore | ||
const createCustomSlice = (name, initialState, extraReducers) => createSlice({ | ||
name, | ||
initialState, | ||
reducers: {}, | ||
extraReducers, | ||
}); | ||
|
||
export default createCustomSlice; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { yupResolver } from "@hookform/resolvers/yup"; | ||
import { SubmitHandler, useForm } from "react-hook-form"; | ||
import { useDispatch, useSelector } from "react-redux"; | ||
import { toast } from "react-toastify"; | ||
import { AxiosError } from "axios"; | ||
|
||
import InputField from "../components/common/auth/InputField"; | ||
import { emailSchema } from "../schemas/PasswordResetSchema"; | ||
import Button from "../components/common/auth/Button"; | ||
import { RegisterError, emailType } from "../../type"; | ||
import { RootState } from "../redux/store"; | ||
import { getLink } from "../redux/reducers/getLinkSlice"; | ||
import Logo from "../components/common/auth/Logo"; | ||
|
||
const GetLinkPage = () => { | ||
const dispatch = useDispatch(); | ||
const loading = useSelector((state: RootState) => state.getLink.isLoading); | ||
const { | ||
register, | ||
reset, | ||
handleSubmit, | ||
formState: { errors }, | ||
} = useForm<emailType>({ | ||
resolver: yupResolver(emailSchema), | ||
}); | ||
|
||
const onSubmit: SubmitHandler<emailType> = async (data: emailType) => { | ||
try { | ||
// @ts-ignore | ||
await dispatch(getLink(data)).unwrap(); | ||
console.log(data); | ||
toast.success("Email sent successfully check your inbox!"); | ||
console.log(data); | ||
reset(); | ||
} catch (err) { | ||
const error = err as AxiosError<RegisterError>; | ||
console.log(error); | ||
toast.error(`${error.message}`); | ||
} | ||
}; | ||
return ( | ||
<div className="w-full h-screen overflow-y-hidden"> | ||
<Logo /> | ||
<div className=" w-[75%] md:w-1/2 flex mx-auto flex-col mt-36"> | ||
<h1 className="text-[#EB5757] text-[15px] sm:text-2xl md:text-[38px] text-center"> | ||
Get a link to reset password | ||
</h1> | ||
<p className="text-[13px] md:text-[16px] text-center pt-6"> | ||
To reset your password provide registered email below. Before proceed | ||
make sure you provide valid email. | ||
</p> | ||
<form | ||
onSubmit={handleSubmit(onSubmit)} | ||
className="w-[100%] md:w-[70%] mx-auto mt-8" | ||
> | ||
<InputField | ||
name="email" | ||
type="email" | ||
placeholder="Email" | ||
register={register} | ||
error={errors.email?.message} | ||
/> | ||
<div className="flex justify-center"> | ||
<Button | ||
text={loading ? "Loading..." : "Send Link"} | ||
backgroundColor="bg-[#EB5757]" | ||
disabled={loading} | ||
data-testid="sent-link-btn" | ||
/> | ||
</div> | ||
</form> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default GetLinkPage; |
Oops, something went wrong.