diff --git a/jest.setup.js b/jest.setup.js
index 4298493..7d55f67 100644
--- a/jest.setup.js
+++ b/jest.setup.js
@@ -1,5 +1,6 @@
import '@testing-library/jest-dom'
import {server} from "./mocks/server";
+import mockRouter from 'next-router-mock'
require('dotenv').config({path: './.env.local'});
@@ -10,6 +11,8 @@ beforeAll(() => {
})
beforeEach(() => {
localStorage.clear();
+ mockRouter.query = {}
+
})
afterEach(() => {
diff --git a/src/components/login-expert/LoginExpertComponent.jsx b/src/components/login-expert/LoginExpertComponent.jsx
new file mode 100644
index 0000000..9be301b
--- /dev/null
+++ b/src/components/login-expert/LoginExpertComponent.jsx
@@ -0,0 +1,123 @@
+import {Box, Button, Container, Paper, Stack, TextField, Typography} from "@mui/material";
+import {Field, Formik} from "formik";
+import SvgLogin from "@/core/components/svgs/SvgLogin";
+import StyledForm from "@/core/components/StyledForm";
+import PasswordField from "@/core/components/PasswordField";
+import LoginIcon from "@mui/icons-material/Login";
+import {GET_USER_TOKEN} from "@/core/data/apiRoutes";
+import * as Yup from "yup";
+import useRequest from "@/lib/app/hooks/useRequest";
+import useUser from "@/lib/app/hooks/useUser";
+import {useTranslations} from "next-intl";
+
+const LoginExpertComponent = () =>{
+ const t = useTranslations();
+ const requestServer = useRequest()
+ const {setToken} = useUser(); // pass token to set token
+ const handleSubmit = (values, props) => {
+ requestServer(GET_USER_TOKEN, 'post', {
+ data: {
+ username: values.username,
+ password: values.password,
+ },
+ success: {
+ notification: {show: false}
+ }
+ }).then((response) => {
+ setToken(response.data.token)
+ }).catch(() => {
+ props.setSubmitting(false)
+ })
+ };
+ const initialValues = {
+ username: "",
+ password: "",
+ };
+ const validationSchema = Yup.object().shape({
+ username: Yup.string().required(t("LoginPage.username_error_message_required")),
+ password: Yup.string().required(t("LoginPage.password_error_message_required")),
+ });
+
+ return(
+
+
+
+ {(props) => (
+
+
+
+
+
+ {t("login_expert")}
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+ )
+}
+export default LoginExpertComponent
\ No newline at end of file
diff --git a/src/components/login-expert/LoginLinkRouting.jsx b/src/components/login-expert/LoginLinkRouting.jsx
new file mode 100644
index 0000000..1930b3c
--- /dev/null
+++ b/src/components/login-expert/LoginLinkRouting.jsx
@@ -0,0 +1,28 @@
+import LinkRouting from "@/core/components/LinkRouting";
+import {Stack} from "@mui/material";
+import {useRouter} from "next/router";
+import {useTranslations} from "next-intl";
+
+const LoginLinkRouting = () => {
+ const t = useTranslations();
+ const router = useRouter()
+ const backUrlDecodedPath = router.query?.back_url
+
+ return (
+
+
+ {t("LoginPage.link_routing_back_to")}{" "}
+ {backUrlDecodedPath
+ ? t("LoginPage.link_routing_previuos_page")
+ : t("LoginPage.link_routing_main_page")}
+
+
+ )
+}
+export default LoginLinkRouting
\ No newline at end of file
diff --git a/src/components/login-expert/__test__/LoginExpertComponent.test.js b/src/components/login-expert/__test__/LoginExpertComponent.test.js
new file mode 100644
index 0000000..d76e49d
--- /dev/null
+++ b/src/components/login-expert/__test__/LoginExpertComponent.test.js
@@ -0,0 +1,153 @@
+import {act, findByText, fireEvent, getByText, render, screen, waitFor} from '@testing-library/react';
+import MockAppWithProviders from '../../../../mocks/AppWithProvider';
+import mockRouter from 'next-router-mock'
+import LoginExpertComponent from "@/components/login-expert/LoginExpertComponent";
+import LoginLinkRouting from "@/components/login-expert/LoginLinkRouting";
+
+describe('Login expert component from login page', () => {
+
+ describe('Rendering', () => {
+ it('LoginExpertComponent should see login expert text on the page',() => {
+ render(
+
+
+
+ );
+ const loginExpertElement = screen.getByRole('heading', { level: 4 });
+ expect(loginExpertElement).toHaveTextContent('ورود کارشناس');
+ });
+
+ it('LoginExpertComponent from LoginComponent Button should render login text', () => {
+ render(
+
+
+
+ );
+ const button = screen.getByText("ورود");
+ // Assertions for button props
+ expect(button).toHaveAttribute('type', 'submit');
+ expect(button).toHaveTextContent('ورود');
+ });
+
+ it("Show error when username is empty", async ()=>{
+ render(
+
+
+
+ );
+
+ const usernameInput = screen.getByLabelText("نام کاربری")
+
+ expect(screen.queryByText("وارد کردن نام کاربری الزامیست")).not.toBeInTheDocument()
+
+ fireEvent.blur(usernameInput);
+
+ await waitFor(()=>{
+ expect(screen.queryByText("وارد کردن نام کاربری الزامیست")).toBeInTheDocument()
+ })
+
+ fireEvent.change(usernameInput, {target : {value : "testuser"}})
+
+ await waitFor(()=>{
+ expect(screen.queryByText("وارد کردن نام کاربری الزامیست")).not.toBeInTheDocument()
+ })
+ })
+ it("Show error when password is empty", async ()=>{
+ render(
+
+
+
+ );
+
+ const passwordInput = screen.getByLabelText("رمز عبور")
+
+ expect(screen.queryByText("وارد کردن رمز عبور الزامیست")).not.toBeInTheDocument()
+
+ fireEvent.blur(passwordInput);
+
+ await waitFor(()=>{
+ expect(screen.queryByText("وارد کردن رمز عبور الزامیست")).toBeInTheDocument()
+ })
+
+ fireEvent.change(passwordInput, {target : {value : "testuser"}})
+
+ await waitFor(()=>{
+ expect(screen.queryByText("وارد کردن رمز عبور الزامیست")).not.toBeInTheDocument()
+ })
+ })
+ });
+
+ describe("Behavior", ()=>{
+ it('Should fill the username field', async () => {
+ render(
+
+
+
+ );
+ // Get username and password input elements by their name attributes
+ const usernameInput = screen.getByLabelText('نام کاربری');
+
+ fireEvent.change(usernameInput, {target: {value: 'testuser'}});
+ await act(async ()=>{
+ // Simulate user input
+ expect(usernameInput).toHaveValue('testuser');
+ })
+ });
+
+ it('Should fill the password fields', async () => {
+ render(
+
+
+
+ );
+ // Get username and password input elements by their name attributes
+ const passwordInput = screen.getByLabelText('رمز عبور');
+ fireEvent.change(passwordInput, {target: {value: 'password123'}});
+
+ await act(async ()=>{
+ // Simulate user input
+ expect(passwordInput).toHaveValue('password123');
+ })
+ });
+
+ // this test is for when back url does not exist to run this test you should comment if in mock func
+ it('Should get main page when back url dos not exist', async () => {
+ render(
+
+
+
+ )
+ const linkElement = await screen.findByTestId("link_routing")
+ expect(linkElement).toHaveTextContent("بازگشت به صفحه اصلی")
+ });
+
+ })
+ describe("validation", ()=>{
+ it("Disabled submit button until fields completed", async ()=> {
+ render(
+
+
+
+ )
+ const usernameInput = screen.getByLabelText('نام کاربری');
+ const passwordInput = screen.getByLabelText('رمز عبور');
+ const submitButton = screen.getByText('ورود');
+
+ expect(submitButton).toBeDisabled();
+
+ fireEvent.change(usernameInput, {target: {value: 'testuser'}});
+
+ await waitFor(async () => {
+ // Now, the submit button should be enabled because both fields are completed
+ expect(submitButton).toBeDisabled();
+ });
+
+ fireEvent.change(passwordInput, {target: {value: 'password123'}});
+
+ await waitFor(async () => {
+ // Now, the submit button should be enabled because both fields are completed
+ expect(submitButton).toBeEnabled();
+ });
+ })
+ })
+});
\ No newline at end of file
diff --git a/src/components/login-expert/__test__/LoginLinkRouting.test.js b/src/components/login-expert/__test__/LoginLinkRouting.test.js
new file mode 100644
index 0000000..a63d314
--- /dev/null
+++ b/src/components/login-expert/__test__/LoginLinkRouting.test.js
@@ -0,0 +1,18 @@
+import {render, screen} from "@testing-library/react";
+import MockAppWithProviders from "../../../../mocks/AppWithProvider";
+import LoginLinkRouting from "@/components/login-expert/LoginLinkRouting";
+
+describe("Login expert component from login page",()=>{
+
+ describe('Rendering', () => {
+ it('LoginLinkRouting from LoginComponent Should get main page when back url dos not exist', async () => {
+ render(
+
+
+
+ )
+ const linkElement = await screen.findByTestId("link_routing")
+ expect(linkElement).toHaveTextContent("بازگشت به صفحه اصلی")
+ });
+ })
+})
diff --git a/src/components/login-expert/index.jsx b/src/components/login-expert/index.jsx
index 45d897b..dc36d9a 100644
--- a/src/components/login-expert/index.jsx
+++ b/src/components/login-expert/index.jsx
@@ -1,151 +1,16 @@
-import LinkRouting from "@/core/components/LinkRouting";
-import PasswordField from "@/core/components/PasswordField";
-import StyledForm from "@/core/components/StyledForm";
-import {GET_USER_TOKEN} from "@/core/data/apiRoutes";
import CenterLayout from "@/layouts/CenterLayout";
import FullPageLayout from "@/layouts/FullPageLayout";
-import useUser from "@/lib/app/hooks/useUser";
-import LoginIcon from "@mui/icons-material/Login";
-import {Box, Button, Container, Paper, Stack, TextField, Typography,} from "@mui/material";
-import {Field, Formik} from "formik";
-import {useTranslations} from "next-intl";
-import {useSearchParams} from "next/navigation";
-import * as Yup from "yup";
-import useDirection from "@/lib/app/hooks/useDirection";
-import SvgLogin from "@/core/components/svgs/SvgLogin";
-import useRequest from "@/lib/app/hooks/useRequest";
+import LoginLinkRouting from "@/components/login-expert/LoginLinkRouting";
+import LoginExpertComponent from "@/components/login-expert/LoginExpertComponent";
const LoginComponent = () => {
- const t = useTranslations();
- const {directionApp} = useDirection(); // should delete because we don't have direction anymore
- const {setToken} = useUser(); // pass token to set token
- const requestServer = useRequest()
-
- // getting url query
- const searchParams = useSearchParams();
- const backUrlDecodedPath = searchParams.get("back_url");
-
- //formik properties
- const handleSubmit = (values, props) => {
- requestServer(GET_USER_TOKEN, 'post', {
- data: {
- username: values.username,
- password: values.password,
- },
- success: {
- notification: {show: false}
- }
- }).then((response) => {
- setToken(response.data.token)
- }).catch(() => {
- props.setSubmitting(false)
- })
- };
- const initialValues = {
- username: "",
- password: "",
- };
- const validationSchema = Yup.object().shape({
- username: Yup.string().required(t("LoginPage.username_error_message_required")),
- password: Yup.string().required(t("LoginPage.password_error_message_required")),
- });
return (
-
-
-
- {(props) => (
-
-
-
-
-
- {t("login_expert")}
-
-
-
-
-
-
-
-
-
-
-
- )}
-
-
-
+
-
-
- {t("LoginPage.link_routing_back_to")}{"Witel"}
- {backUrlDecodedPath
- ? t("LoginPage.link_routing_previuos_page")
- : t("LoginPage.link_routing_main_page")}
-
-
+
);
};
diff --git a/src/core/components/PasswordField/__test__/index.test.js b/src/core/components/PasswordField/__test__/index.test.js
new file mode 100644
index 0000000..479f91f
--- /dev/null
+++ b/src/core/components/PasswordField/__test__/index.test.js
@@ -0,0 +1,31 @@
+import {fireEvent, getByRole, render, screen} from "@testing-library/react";
+import PasswordField from "@/core/components/PasswordField";
+import {Formik} from "formik";
+
+describe('Password Field component in core folder', () => {
+ describe('Rendering', () => {
+ it('Show password when visibility icon clicked',() => {
+ render (
+ {}}>
+ {(props)=>(
+
+ )}
+
+ )
+
+ const iconElement = screen.getByLabelText("رمز عبور")
+ const iconButton = screen.getByRole("button")
+
+
+ expect(iconElement).toHaveAttribute('type', 'password');
+
+ fireEvent.click(iconButton);
+
+ expect(iconElement).toHaveAttribute("type", "text");
+
+ fireEvent.click(iconButton);
+
+ expect(iconElement).toHaveAttribute('type', 'password');
+ })
+ })
+})
\ No newline at end of file
diff --git a/src/core/components/PasswordField.jsx b/src/core/components/PasswordField/index.jsx
similarity index 100%
rename from src/core/components/PasswordField.jsx
rename to src/core/components/PasswordField/index.jsx