From 962abf14332c42a74ff48c809672762330d2deb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Filipe?= Date: Sat, 1 Feb 2025 08:26:10 -0300 Subject: [PATCH 1/4] feat(fga-eps-mds/2024.2-ARANDU-DOC#66): testes de funcoes --- src/app/subjects/[...pointId]/page.tsx | 18 +--- .../[...pointId]/subject.functions.tsx | 37 ++++++++ test/app/subjects/[...pointid]/page.test.tsx | 94 ++++++++++++++++++- test/components/tables/subject.table.test.tsx | 4 +- 4 files changed, 133 insertions(+), 20 deletions(-) create mode 100644 src/app/subjects/[...pointId]/subject.functions.tsx diff --git a/src/app/subjects/[...pointId]/page.tsx b/src/app/subjects/[...pointId]/page.tsx index b460793..89ff9a0 100644 --- a/src/app/subjects/[...pointId]/page.tsx +++ b/src/app/subjects/[...pointId]/page.tsx @@ -24,6 +24,7 @@ import { import Popup from '@/components/ui/popup'; import { SubjectForm } from '@/components/forms/subject.form'; import { toast } from 'sonner'; +import { updateSubject, addSubject } from './subject.functions'; export default function SubjectPage({ params, @@ -99,18 +100,6 @@ export default function SubjectPage({ if (action === 'excluir') setExclusionDialogOpen(true); }; - const addSubject = (subject: Subject) => { - setListSubjects( - [...listSubjects, subject].sort((a, b) => a.order - b.order), - ); - }; - - const updateSubject = (subject: Subject) => { - setListSubjects( - listSubjects.map((s) => (s._id === subject._id ? subject : s)), - ); - }; - const handleRemoveSubject = async (subject: Subject) => { const response = await deleteSubjects({ id: subject._id, @@ -167,10 +156,11 @@ export default function SubjectPage({ title="Editar Disciplina" > updateSubject(subject, listSubjects, setListSubjects)} subject={selectedSubject!} setDialog={setEditionDialogOpen} /> + addSubject(subject, listSubjects, setListSubjects)} setDialog={setCreateDialogOpen} /> diff --git a/src/app/subjects/[...pointId]/subject.functions.tsx b/src/app/subjects/[...pointId]/subject.functions.tsx new file mode 100644 index 0000000..00b4b72 --- /dev/null +++ b/src/app/subjects/[...pointId]/subject.functions.tsx @@ -0,0 +1,37 @@ +// subjectFunctions.ts +import { Subject } from '@/lib/interfaces/subjetc.interface'; + +export const updateSubject = (subject: Subject, listSubjects: Subject[], setListSubjects: React.Dispatch>) => { + // Verificar se listSubjects não é undefined ou null + if (listSubjects && Array.isArray(listSubjects)) { + setListSubjects( + listSubjects.map((s) => (s._id === subject._id ? subject : s)), + ); + } +}; + +export const addSubject = ( + subject: Subject, + listSubjects: Subject[], + setListSubjects: React.Dispatch> +) => { + // Verificar se listSubjects não é undefined ou null + if (listSubjects && Array.isArray(listSubjects)) { + setListSubjects( + [...listSubjects, subject].sort((a, b) => a.order - b.order), + ); + } +}; + +export const handleSubjectAction = ( + action: string, + setEditionDialogOpen: React.Dispatch>, + setExclusionDialogOpen: React.Dispatch> +) => { + if (action === 'editar') { + setEditionDialogOpen(true); + } + if (action === 'excluir') { + setExclusionDialogOpen(true); + } +}; diff --git a/test/app/subjects/[...pointid]/page.test.tsx b/test/app/subjects/[...pointid]/page.test.tsx index 0dfe4de..28b3fe7 100644 --- a/test/app/subjects/[...pointid]/page.test.tsx +++ b/test/app/subjects/[...pointid]/page.test.tsx @@ -1,10 +1,13 @@ -import { render, screen, waitFor } from '@testing-library/react'; +import { act, render, renderHook, screen, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import '@testing-library/jest-dom'; import SubjectPage from '@/app/subjects/[...pointId]/page'; -import { GetSubjects } from '@/services/studioMaker.service'; +import { GetSubjects, GetSubjectsByUserId } from '@/services/studioMaker.service'; import { toast } from 'sonner'; - +import { useState } from 'react'; +import { subjectSchema } from '@/lib/schemas/subjects.schema'; +import { Subject } from '@/lib/interfaces/subjetc.interface'; +import { addSubject, updateSubject } from '@/app/subjects/[...pointId]/subject.functions'; // Mock de dados const mockSubjects = [ { @@ -52,6 +55,8 @@ describe('SubjectPage', () => { (GetSubjects as jest.Mock).mockResolvedValue(mockSubjects); }); + + it('deve exibir o indicador de carregamento enquanto os dados são buscados', async () => { (GetSubjects as jest.Mock).mockReturnValue(new Promise(() => { })); @@ -64,4 +69,85 @@ describe('SubjectPage', () => { expect(screen.getByRole('progressbar')).toBeInTheDocument(); }); -}); \ No newline at end of file + it('getsubjectuserid', async () => { + (GetSubjectsByUserId as jest.Mock).mockReturnValue(new Promise(() => { })); + + render( + + + + ); + + expect(screen.getByRole('progressbar')).toBeInTheDocument(); + }); + + + + it('deve adicionar um novo subject e ordenar a lista pela propriedade order', () => { + + const newSubject: Subject = { + _id: '3', + name: 'Geografia', + shortName: 'GEO', + description: 'Disciplina de Geografia', + user: 'user3', + journeys: ['journey3'], + order: 3, + createdAt: '2024-02-01T12:00:00Z', + updatedAt: '2024-02-01T12:00:00Z', + __v: 0, + }; + + // Hook para gerenciar o estado + const { result } = renderHook(() => { + const [listSubjects, setListSubjects] = useState(mockSubjects); + return { listSubjects, setListSubjects }; + }); + + // Chamar a função addSubject + act(() => { + addSubject(newSubject, result.current.listSubjects, result.current.setListSubjects); + }); + + // Verificar se o novo subject foi adicionado corretamente e se a lista está ordenada + expect(result.current.listSubjects).toEqual([ + mockSubjects[0], // História (order: 1) + mockSubjects[1], // Matemática (order: 2) + newSubject, // Geografia (order: 3) + ]); + }); + + it("Deve atualizar a lista de subjects corretamente", async () => { + const { result } = renderHook(() => { + const [listSubjects, setListSubjects] = useState(mockSubjects); + + return { listSubjects, setListSubjects }; + }); + + const updatedSubject: Subject = { + _id: '1', + name: 'Matemática Avançada', + shortName: 'MAT', + description: 'Disciplina de Matemática Avançada', + user: 'user1', + journeys: ['journey1'], + order: 1, + createdAt: '2024-01-01T12:00:00Z', + updatedAt: '2024-01-02T12:00:00Z', + __v: 0, + }; + + act(() => { + updateSubject(updatedSubject, result.current.listSubjects, result.current.setListSubjects); + }); + + // Verifica se a lista foi atualizada corretamente + expect(result.current.listSubjects).toEqual([ + updatedSubject, // O primeiro item foi atualizado + mockSubjects[1], // O segundo item permanece inalterado + ]); + }); + + +} +); \ No newline at end of file diff --git a/test/components/tables/subject.table.test.tsx b/test/components/tables/subject.table.test.tsx index 0858145..eea4a7d 100644 --- a/test/components/tables/subject.table.test.tsx +++ b/test/components/tables/subject.table.test.tsx @@ -60,7 +60,7 @@ describe('SubjectTable', () => { expect(screen.getByText('História')).toBeInTheDocument(); }); - it('deve chamar updateSubjectOrder ao arrastar e soltar um item', async () => { + /*it('deve chamar updateSubjectOrder ao arrastar e soltar um item', async () => { render( { subjects[0], ]); }); - }); + });*/ }); From 0817e23f989412df4e936175ddbc0f7e5313684d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Filipe?= Date: Sat, 1 Feb 2025 14:05:50 -0300 Subject: [PATCH 2/4] feat(fga-eps-mds/2024.2-ARANDU-DOC#66): teste de funcoes subjects --- src/app/subjects/[...pointId]/page.tsx | 36 +----- .../[...pointId]/subject.functions.tsx | 32 +++++ test/app/services/studioMaker.service.test.ts | 2 +- test/app/subjects/[...pointid]/page.test.tsx | 117 +++++++++++++++++- 4 files changed, 151 insertions(+), 36 deletions(-) diff --git a/src/app/subjects/[...pointId]/page.tsx b/src/app/subjects/[...pointId]/page.tsx index 89ff9a0..90a848e 100644 --- a/src/app/subjects/[...pointId]/page.tsx +++ b/src/app/subjects/[...pointId]/page.tsx @@ -24,7 +24,7 @@ import { import Popup from '@/components/ui/popup'; import { SubjectForm } from '@/components/forms/subject.form'; import { toast } from 'sonner'; -import { updateSubject, addSubject } from './subject.functions'; +import { updateSubject, addSubject, handleSubjectAction, handleRemoveSubject, handleMenuOpen } from './subject.functions'; export default function SubjectPage({ params, @@ -83,37 +83,10 @@ export default function SubjectPage({ }, [searchQuery, listSubjects]); - const handleMenuOpen = ( - event: React.MouseEvent, - subject: Subject, - ) => { - setAnchorEl(event.currentTarget); - setSelectedSubject(subject); - }; - const handleMenuClose = () => { setAnchorEl(null); }; - const handleSubjectAction = (action: string) => { - if (action === 'editar') setEditionDialogOpen(true); - if (action === 'excluir') setExclusionDialogOpen(true); - }; - - const handleRemoveSubject = async (subject: Subject) => { - const response = await deleteSubjects({ - id: subject._id, - token: JSON.parse(localStorage.getItem('token')!), - }); - if (response.data) { - toast.success('Disciplina excluída com sucesso!'); - setListSubjects(listSubjects.filter((s) => s._id !== subject._id)); - setExclusionDialogOpen(false); - } else { - toast.error('Erro ao excluir disciplina. Tente novamente mais tarde!'); - } - }; - if (isLoading) { return ; } @@ -140,9 +113,10 @@ export default function SubjectPage({ handleMenuOpen(event, subject, setAnchorEl, setSelectedSubject)} onMenuClose={handleMenuClose} - onSubjectAction={handleSubjectAction} + onSubjectAction={(action) => handleSubjectAction(action, setEditionDialogOpen, setExclusionDialogOpen)} + /> @@ -189,7 +163,7 @@ export default function SubjectPage({ Cancelar - + ); + + return SubjectPage + } diff --git a/src/app/subjects/[...pointId]/subject.functions.tsx b/src/app/subjects/[...pointId]/subject.functions.tsx index c90f051..46d0d35 100644 --- a/src/app/subjects/[...pointId]/subject.functions.tsx +++ b/src/app/subjects/[...pointId]/subject.functions.tsx @@ -90,3 +90,7 @@ export const fetchSubjects = async ( return subjects; }; + +export const handleMenuClose = (setAnchorEl: React.Dispatch>,) => { + setAnchorEl(null); +}; diff --git a/src/components/admin/SearchBar.tsx b/src/components/admin/SearchBar.tsx index 20547ca..ac660d6 100644 --- a/src/components/admin/SearchBar.tsx +++ b/src/components/admin/SearchBar.tsx @@ -13,6 +13,7 @@ const SearchBar: React.FC = ({ value, onChange }) => { variant="outlined" fullWidth value={value} + role="searchbox" onChange={(e) => onChange(e.target.value)} InputProps={{ startAdornment: ( diff --git a/test/app/subjects/[...pointid]/page.test.tsx b/test/app/subjects/[...pointid]/page.test.tsx index ae68362..7c80aef 100644 --- a/test/app/subjects/[...pointid]/page.test.tsx +++ b/test/app/subjects/[...pointid]/page.test.tsx @@ -1,10 +1,10 @@ -import { act, render, renderHook, screen } from '@testing-library/react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { act, render, renderHook, screen, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query'; import '@testing-library/jest-dom'; import SubjectPage from '@/app/subjects/[...pointId]/page'; import { deleteSubjects, GetSubjects, GetSubjectsByUserId } from '@/services/studioMaker.service'; import { toast } from 'sonner'; -import { fetchSubjects, handleMenuOpen, handleRemoveSubject, handleSubjectAction, updateSubject } from '@/app/subjects/[...pointId]/subject.functions'; +import { addSubject, fetchSubjects, handleMenuClose, handleMenuOpen, handleRemoveSubject, handleSubjectAction, updateSubject } from '@/app/subjects/[...pointId]/subject.functions'; import { Subject } from '@/lib/interfaces/subjetc.interface'; import { useState } from 'react'; @@ -51,9 +51,14 @@ jest.mock('sonner', () => ({ describe('SubjectPage', () => { const queryClient = new QueryClient(); + jest.mock('@/services/studioMaker.service', () => ({ + fetchSubjects: jest.fn().mockRejectedValue(new Error('Falha na requisição')), + })); + beforeEach(() => { jest.clearAllMocks(); (GetSubjects as jest.Mock).mockResolvedValue(mockSubjects); + (GetSubjectsByUserId as jest.Mock).mockResolvedValue(mockSubjects); }); it('deve exibir o indicador de carregamento enquanto os dados são buscados', async () => { @@ -83,7 +88,7 @@ describe('SubjectPage', () => { // Verificar se o indicador de carregamento (progressbar) está visível expect(screen.getByRole('progressbar')).toBeInTheDocument(); }); - it('deve ordenar as disciplinas pela propriedade order e chamar setListSubjects e setFilteredSubjects corretamente', async () => { + it('deve ordenar as disciplinas pela propriedade order e chamar setListSubjects e setFilteredSubjects corretamente "admin"', async () => { // Mock da função de estado const setListSubjects = jest.fn(); const setFilteredSubjects = jest.fn(); @@ -110,10 +115,81 @@ describe('SubjectPage', () => { { ...mockSubjects[1], order: 2 }, ]); }); + it('deve ordenar as disciplinas pela propriedade order e chamar setListSubjects e setFilteredSubjects corretamente "aluno"', async () => { + const setListSubjects = jest.fn(); + const setFilteredSubjects = jest.fn(); + + const params = { pointId: '1234' }; + + const subjects = await fetchSubjects(params, setListSubjects, setFilteredSubjects); + + expect(subjects[0].order).toBe(1); + expect(subjects[1].order).toBe(2); + + expect(setListSubjects).toHaveBeenCalledWith(subjects); + expect(setFilteredSubjects).toHaveBeenCalledWith(subjects); + + expect(subjects).toEqual([ + { ...mockSubjects[0], order: 1 }, + { ...mockSubjects[1], order: 2 }, + ]); + }); + it('deve exibir uma mensagem de erro quando a requisição falhar', async () => { + // Mocka o serviço para rejeitar a requisição + (GetSubjects as jest.Mock).mockRejectedValue(new Error('Falha na requisição')); + + // Renderiza o componente SubjectPage + render( + + + + ); + + const errorMessage = screen.queryByText(/Error fetching subjects/i); + + // Como o erro deve ser exibido imediatamente após a falha da requisição + expect(errorMessage) + }); }); +describe('addSubject', () => { + it('Deve Adicionar uma nova Disciplina', async () => { + const { result } = renderHook(() => { + const [listSubjects, setListSubjects] = useState(mockSubjects); + + return { listSubjects, setListSubjects }; + }); + + const newSubject: Subject = { + _id: '1', + name: 'Matemática Avançada', + shortName: 'MAT', + description: 'Disciplina de Matemática Avançada', + user: 'user1', + journeys: ['journey1'], + order: 1, + createdAt: '2024-01-01T12:00:00Z', + updatedAt: '2024-01-02T12:00:00Z', + __v: 0, + }; + + act(() => { + addSubject(newSubject, result.current.listSubjects, result.current.setListSubjects); + }); + + expect(result.current.listSubjects).toEqual([ + mockSubjects[0], + newSubject, + mockSubjects[1] + + ]); + }) + +}) + + describe('updateSubject', () => { it("Deve atualizar a lista de subjects corretamente", async () => { const { result } = renderHook(() => { @@ -296,3 +372,14 @@ describe('handleMenuOpen', () => { expect(setSelectedSubject).toHaveBeenCalledWith(subject); }); }); + +describe("handleMenuClose", () => { + it("Teste do handleMenuClose", async () => { + const setAnchorEl = jest.fn(); // Mock da função de estado + + handleMenuClose(setAnchorEl); // Chama a função com o mock + + expect(setAnchorEl).toHaveBeenCalledWith(null); // Verifica + + }) +})