From 98d707607d349923f892ab6e1c6b0cfab4b256e7 Mon Sep 17 00:00:00 2001 From: Paola Date: Sat, 29 Apr 2023 17:19:35 +0200 Subject: [PATCH 1/5] test-1 for createPost --- client/src/components/CreateProject.test.tsx | 59 ++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 client/src/components/CreateProject.test.tsx diff --git a/client/src/components/CreateProject.test.tsx b/client/src/components/CreateProject.test.tsx new file mode 100644 index 00000000..ec3b3134 --- /dev/null +++ b/client/src/components/CreateProject.test.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import { render, fireEvent, screen } from '@testing-library/react'; +import CreateProject from './CreateProject'; + +describe('CreateProject', () => { + it('submits the form', async () => { + const mockNavigate = jest.fn(); + const mockCreateProject = jest.fn().mockResolvedValueOnce({ status: 200 }); + const onClose = jest.fn(); + + const { getByLabelText, getByText } = render( + , + { + // Mocking the useNavigate hook + wrapper: ({ children }) => ( +
{children}
+ ), + } + ); + + const titleInput = getByLabelText('Title:'); + fireEvent.change(titleInput, { target: { value: 'Test Project' } }); + + const descriptionInput = screen.getByRole('textbox', { name: 'Rich Text Editor, snow' }); + fireEvent.change(descriptionInput, { target: { value: 'Test description' } }); + + const imageInput = getByLabelText('Image:'); + Object.defineProperty(imageInput, 'files', { + value: [ + new File(['test'], 'test.png', { type: 'image/png' }), + ], + }); + fireEvent.change(imageInput); + + const tagsInput = getByLabelText('Tags:'); + fireEvent.change(tagsInput, { target: { value: 'test, project' } }); + + const submitButton = getByText('Create new project'); + fireEvent.click(submitButton); + + await screen.findByText('Your new project'); + + expect(mockCreateProject).toHaveBeenCalledWith({ + title: 'Test Project', + description: 'Test description', + tags: 'test, project', + quillValue: 'Test description', + image: '', + createdBy: null, + updates: [], + chat: [], + author: '', + date: '', + }); + + expect(mockNavigate).toHaveBeenCalledWith('/posts/null'); + expect(onClose).toHaveBeenCalled(); + }); +}); From 84f6fb4b49846d659c5f249d6db36773ecae5269 Mon Sep 17 00:00:00 2001 From: Paola Date: Mon, 1 May 2023 14:36:27 +0200 Subject: [PATCH 2/5] Advance on tests --- client/src/components/CreateProject.test.tsx | 1 + client/src/components/Login.tsx | 87 ++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 client/src/components/Login.tsx diff --git a/client/src/components/CreateProject.test.tsx b/client/src/components/CreateProject.test.tsx index ec3b3134..a743dd96 100644 --- a/client/src/components/CreateProject.test.tsx +++ b/client/src/components/CreateProject.test.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { render, fireEvent, screen } from '@testing-library/react'; import CreateProject from './CreateProject'; +import ReactQuill from 'react-quill'; describe('CreateProject', () => { it('submits the form', async () => { diff --git a/client/src/components/Login.tsx b/client/src/components/Login.tsx new file mode 100644 index 00000000..72d0e16c --- /dev/null +++ b/client/src/components/Login.tsx @@ -0,0 +1,87 @@ +import React from 'react'; +import { useContext, useState } from 'react'; +import { useNavigate, Link } from 'react-router-dom'; +import UserContext from '../context/UserContext'; +import '../styles/login.css'; +import http from '../services/api.service'; +import { useForm, SubmitHandler } from 'react-hook-form'; + +interface ICredentials { + email: string; + password: string; +} + +const initialCredentials: ICredentials = { + email: '', + password: '', +}; + +interface IFormInput { + email: string; + password: string; +} + +function Login() { + const { user, setUser } = useContext(UserContext); + const [credentials, setCredentials] = useState(initialCredentials); + const navigate = useNavigate(); + const { + register, + handleSubmit, + formState: { errors }, + } = useForm(); + + const onSubmit: SubmitHandler = async (data) => { + const response = await http.login(credentials); + if (response!.status === 401) { + alert('Wrong email or password'); + return; + } else { + setUser(response!.data); + navigate('/home'); + } + }; + + return ( +
+
+

Login

+
+ + + {errors.email && {errors.email.message}} + + + {errors.password && ( + {errors.password.message} + )} + +
+ Dont have an account? + Sign Up +
+
+ ); +} + +export default Login; From 037206d9a3922477d02a5c2e532a3e63a9ddc626 Mon Sep 17 00:00:00 2001 From: Paola Date: Mon, 1 May 2023 16:32:02 +0200 Subject: [PATCH 3/5] Test render of all elements --- client/assets/css/__mocks__/styleMock.js | 1 + client/package.json | 5 +- client/src/components/CreateProject.test.tsx | 148 ++++++++++++++----- client/src/components/CreateProject.tsx | 2 + 4 files changed, 121 insertions(+), 35 deletions(-) create mode 100644 client/assets/css/__mocks__/styleMock.js diff --git a/client/assets/css/__mocks__/styleMock.js b/client/assets/css/__mocks__/styleMock.js new file mode 100644 index 00000000..a0995453 --- /dev/null +++ b/client/assets/css/__mocks__/styleMock.js @@ -0,0 +1 @@ +module.exports = {}; \ No newline at end of file diff --git a/client/package.json b/client/package.json index 004be04b..310b0a2d 100644 --- a/client/package.json +++ b/client/package.json @@ -75,6 +75,9 @@ "jest": { "transformIgnorePatterns": [ "/node_modules/(?!(axios)/)" - ] + ], + "moduleNameMapper": { + "\\.(css|less)$": "/assets/css/__mocks__/styleMock.js" + } } } diff --git a/client/src/components/CreateProject.test.tsx b/client/src/components/CreateProject.test.tsx index a743dd96..2e69d684 100644 --- a/client/src/components/CreateProject.test.tsx +++ b/client/src/components/CreateProject.test.tsx @@ -1,51 +1,75 @@ import React from 'react'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, fireEvent, screen, getByLabelText } from '../utils/test-utils'; import CreateProject from './CreateProject'; -import ReactQuill from 'react-quill'; +import { BrowserRouter } from 'react-router-dom'; describe('CreateProject', () => { - it('submits the form', async () => { + const onClose = jest.fn(); + beforeEach(() => { + render( + + + + ); + }); + + it('renders submit form', () => { + const titleInput = screen.getByLabelText('Title:'); + const descriptionInput = screen.getByText('Description:'); + const imgInput = screen.getByLabelText('Image:'); + const tagsInput = screen.getByLabelText('Tags:'); + const submitBtn = screen.getByRole('submit-button'); + const closeBtn = screen.getByRole('close-button'); + expect(titleInput).toBeInTheDocument(); + expect(descriptionInput).toBeInTheDocument(); + expect(imgInput).toBeInTheDocument(); + expect(tagsInput).toBeInTheDocument(); + expect(submitBtn).toBeInTheDocument(); + expect(closeBtn).toBeInTheDocument(); + }) + + it('sumbits the form successfully', async () => { const mockNavigate = jest.fn(); const mockCreateProject = jest.fn().mockResolvedValueOnce({ status: 200 }); - const onClose = jest.fn(); - - const { getByLabelText, getByText } = render( - , - { - // Mocking the useNavigate hook - wrapper: ({ children }) => ( -
{children}
- ), - } - ); + const mockProject = { + id: '2', + title: '', + description: '', + tags: [], + quillValue: '', + image: '', + createdBy: null, + updates: [], + chat: [], + author: '', + date: '', + } - const titleInput = getByLabelText('Title:'); + const titleInput = screen.getByLabelText('Title:'); fireEvent.change(titleInput, { target: { value: 'Test Project' } }); - const descriptionInput = screen.getByRole('textbox', { name: 'Rich Text Editor, snow' }); - fireEvent.change(descriptionInput, { target: { value: 'Test description' } }); - - const imageInput = getByLabelText('Image:'); - Object.defineProperty(imageInput, 'files', { - value: [ - new File(['test'], 'test.png', { type: 'image/png' }), - ], - }); - fireEvent.change(imageInput); + // const imageInput = screen.getByLabelText('Image:'); + // Object.defineProperty(imageInput, 'files', { + // value: [ + // new File(['test'], 'test.png', { type: 'image/png' }), + // ], + // }); + // fireEvent.change(imageInput); - const tagsInput = getByLabelText('Tags:'); - fireEvent.change(tagsInput, { target: { value: 'test, project' } }); + // const tagsInput = screen.getByLabelText('Tags:'); + // fireEvent.change(tagsInput, { target: { value: 'test, project' } }); - const submitButton = getByText('Create new project'); + const submitButton = screen.getByText('Create new project'); fireEvent.click(submitButton); await screen.findByText('Your new project'); expect(mockCreateProject).toHaveBeenCalledWith({ + id: '2', title: 'Test Project', - description: 'Test description', - tags: 'test, project', - quillValue: 'Test description', + description: '', + tags: [], + quillValue: '', image: '', createdBy: null, updates: [], @@ -54,7 +78,63 @@ describe('CreateProject', () => { date: '', }); - expect(mockNavigate).toHaveBeenCalledWith('/posts/null'); + expect(mockNavigate).toHaveBeenCalledWith('/posts/2'); expect(onClose).toHaveBeenCalled(); - }); -}); + }) +}) + +// describe('CreateProject', () => { +// it('submits the form', async () => { +// const mockNavigate = jest.fn(); +// const mockCreateProject = jest.fn().mockResolvedValueOnce({ status: 200 }); +// const onClose = jest.fn(); + +// const { getByLabelText, getByText } = render( +// , +// { +// // Mocking the useNavigate hook +// wrapper: ({ children }) => ( +//
{children}
+// ), +// } +// ); + +// const titleInput = getByLabelText('Title:'); +// fireEvent.change(titleInput, { target: { value: 'Test Project' } }); + +// const descriptionInput = screen.getByRole('textbox', { name: 'Rich Text Editor, snow' }); +// fireEvent.change(descriptionInput, { target: { value: 'Test description' } }); + +// const imageInput = getByLabelText('Image:'); +// Object.defineProperty(imageInput, 'files', { +// value: [ +// new File(['test'], 'test.png', { type: 'image/png' }), +// ], +// }); +// fireEvent.change(imageInput); + +// const tagsInput = getByLabelText('Tags:'); +// fireEvent.change(tagsInput, { target: { value: 'test, project' } }); + +// const submitButton = getByText('Create new project'); +// fireEvent.click(submitButton); + +// await screen.findByText('Your new project'); + +// expect(mockCreateProject).toHaveBeenCalledWith({ +// title: 'Test Project', +// description: 'Test description', +// tags: 'test, project', +// quillValue: '', +// image: '', +// createdBy: null, +// updates: [], +// chat: [], +// author: '', +// date: '', +// }); + +// expect(mockNavigate).toHaveBeenCalledWith('/posts/null'); +// expect(onClose).toHaveBeenCalled(); +// }); +// }); diff --git a/client/src/components/CreateProject.tsx b/client/src/components/CreateProject.tsx index eb92dbba..4a58eebd 100644 --- a/client/src/components/CreateProject.tsx +++ b/client/src/components/CreateProject.tsx @@ -94,6 +94,7 @@ const CreateProject: React.FC = ({ open, onClose }) => { @@ -148,6 +149,7 @@ const CreateProject: React.FC = ({ open, onClose }) => { From 1af18dd60a7d0175ee4c403268e217236927a7f2 Mon Sep 17 00:00:00 2001 From: Paola Date: Mon, 1 May 2023 19:32:45 +0200 Subject: [PATCH 4/5] Basic tests completed --- client/src/components/CreateProject.test.tsx | 148 +++++-------------- client/src/components/CreateProject.tsx | 9 +- client/src/types/project.type.tsx | 2 +- 3 files changed, 50 insertions(+), 109 deletions(-) diff --git a/client/src/components/CreateProject.test.tsx b/client/src/components/CreateProject.test.tsx index 2e69d684..1e50e4db 100644 --- a/client/src/components/CreateProject.test.tsx +++ b/client/src/components/CreateProject.test.tsx @@ -3,17 +3,15 @@ import { render, fireEvent, screen, getByLabelText } from '../utils/test-utils'; import CreateProject from './CreateProject'; import { BrowserRouter } from 'react-router-dom'; -describe('CreateProject', () => { +describe('CreateProject rendering tests', () => { const onClose = jest.fn(); - beforeEach(() => { + + it('renders the submit form', () => { render( ); - }); - - it('renders submit form', () => { const titleInput = screen.getByLabelText('Title:'); const descriptionInput = screen.getByText('Description:'); const imgInput = screen.getByLabelText('Image:'); @@ -28,113 +26,49 @@ describe('CreateProject', () => { expect(closeBtn).toBeInTheDocument(); }) - it('sumbits the form successfully', async () => { - const mockNavigate = jest.fn(); - const mockCreateProject = jest.fn().mockResolvedValueOnce({ status: 200 }); - const mockProject = { - id: '2', - title: '', - description: '', - tags: [], - quillValue: '', - image: '', - createdBy: null, - updates: [], - chat: [], - author: '', - date: '', - } - - const titleInput = screen.getByLabelText('Title:'); - fireEvent.change(titleInput, { target: { value: 'Test Project' } }); - - // const imageInput = screen.getByLabelText('Image:'); - // Object.defineProperty(imageInput, 'files', { - // value: [ - // new File(['test'], 'test.png', { type: 'image/png' }), - // ], - // }); - // fireEvent.change(imageInput); - - // const tagsInput = screen.getByLabelText('Tags:'); - // fireEvent.change(tagsInput, { target: { value: 'test, project' } }); - - const submitButton = screen.getByText('Create new project'); - fireEvent.click(submitButton); - - await screen.findByText('Your new project'); - - expect(mockCreateProject).toHaveBeenCalledWith({ - id: '2', - title: 'Test Project', - description: '', - tags: [], - quillValue: '', - image: '', - createdBy: null, - updates: [], - chat: [], - author: '', - date: '', - }); - - expect(mockNavigate).toHaveBeenCalledWith('/posts/2'); + it('executes onClose() when closeBtn is clicked', () => { + render( + + + + ); + const closeBtn = screen.getByRole('close-button'); + fireEvent.click(closeBtn) expect(onClose).toHaveBeenCalled(); }) -}) - -// describe('CreateProject', () => { -// it('submits the form', async () => { -// const mockNavigate = jest.fn(); -// const mockCreateProject = jest.fn().mockResolvedValueOnce({ status: 200 }); -// const onClose = jest.fn(); - -// const { getByLabelText, getByText } = render( -// , -// { -// // Mocking the useNavigate hook -// wrapper: ({ children }) => ( -//
{children}
-// ), -// } -// ); - -// const titleInput = getByLabelText('Title:'); -// fireEvent.change(titleInput, { target: { value: 'Test Project' } }); -// const descriptionInput = screen.getByRole('textbox', { name: 'Rich Text Editor, snow' }); -// fireEvent.change(descriptionInput, { target: { value: 'Test description' } }); - -// const imageInput = getByLabelText('Image:'); -// Object.defineProperty(imageInput, 'files', { -// value: [ -// new File(['test'], 'test.png', { type: 'image/png' }), -// ], -// }); -// fireEvent.change(imageInput); + it('Does not render the component if open is false', () => { + render( + + + + ); + expect(document.querySelector('.overlay')).not.toBeInTheDocument(); + }) -// const tagsInput = getByLabelText('Tags:'); -// fireEvent.change(tagsInput, { target: { value: 'test, project' } }); -// const submitButton = getByText('Create new project'); -// fireEvent.click(submitButton); + it('Requires title and img inputs to be filled in order to submit the form', () => { + render( + + + + ); + const titleInput = screen.getByLabelText('Title:'); + const imgInput = screen.getByLabelText('Image:'); + const submitButton = screen.getByRole('submit-button'); + expect(submitButton).toBeDisabled(); -// await screen.findByText('Your new project'); + fireEvent.change(titleInput, { target: { value: 'Not empty' } }); + expect(submitButton).toBeDisabled(); -// expect(mockCreateProject).toHaveBeenCalledWith({ -// title: 'Test Project', -// description: 'Test description', -// tags: 'test, project', -// quillValue: '', -// image: '', -// createdBy: null, -// updates: [], -// chat: [], -// author: '', -// date: '', -// }); + render( + + + + ); + fireEvent.change(imgInput, { target: { files: ['file'] } }); + fireEvent.change(titleInput, { target: { value: 'Not empty' } }); + expect(submitButton).not.toBeDisabled(); + }) +}) -// expect(mockNavigate).toHaveBeenCalledWith('/posts/null'); -// expect(onClose).toHaveBeenCalled(); -// }); -// }); diff --git a/client/src/components/CreateProject.tsx b/client/src/components/CreateProject.tsx index f8689ca9..cdd64231 100644 --- a/client/src/components/CreateProject.tsx +++ b/client/src/components/CreateProject.tsx @@ -3,7 +3,6 @@ import '../styles/createProject.css'; import UserContext from '../context/UserContext'; import { UserContextType } from '../types/user.type'; import Axios from 'axios'; -import { AxiosResponse } from 'axios'; import { useNavigate } from 'react-router-dom'; import ReactQuill from 'react-quill'; import 'react-quill/dist/quill.snow.css'; @@ -36,6 +35,7 @@ const CreateProject: React.FC = ({ open, onClose }) => { const { user } = useContext(UserContext); const [projectInfo, setProjectInfo] = useState(initialState); const [quillValue, setQuillValue] = useState(''); + const [submitDisabled, setSubmitDisabled] = useState(true); function handleChange(e: React.ChangeEvent) { const { name, value } = e.target; @@ -43,10 +43,14 @@ const CreateProject: React.FC = ({ open, onClose }) => { ...prev, [name]: value, })); + projectInfo.image ? setSubmitDisabled(false) : setSubmitDisabled(true); + } function handleFileInputChange(e: React.ChangeEvent) { if (e.target.files) setSelectedFile(e.target.files[0]); + projectInfo.title ? setSubmitDisabled(false) : setSubmitDisabled(true); + } async function handleSubmit(e: React.FormEvent) { @@ -86,6 +90,7 @@ const CreateProject: React.FC = ({ open, onClose }) => { } else { navigate(`/posts/${project.id}`); onClose(); + setSubmitDisabled(true); } } @@ -104,6 +109,7 @@ const CreateProject: React.FC = ({ open, onClose }) => {
= ({ open, onClose }) => {