@@ -6,7 +6,6 @@ import * as ProjectAPI from '../../API/Project';
66import * as CommentAPI from '../../API/Comment' ;
77import * as UserAPI from '../../API/User' ;
88
9- // --- Mocks ---
109const navigateMock = vi . fn ( ) ;
1110const logoutMock = vi . fn ( ) ;
1211
@@ -22,127 +21,92 @@ vi.mock('../../API/AuthContext', () => ({
2221 } )
2322} ) ) ;
2423
25- // Mocks das APIs
2624vi . mock ( '../../API/Project' , ( ) => ( { GetUserProjects : vi . fn ( ) } ) ) ;
2725vi . mock ( '../../API/Comment' , ( ) => ( { GetUserComments : vi . fn ( ) , DeleteComment : vi . fn ( ) } ) ) ;
2826vi . mock ( '../../API/User' , ( ) => ( { DeleteProfile : vi . fn ( ) } ) ) ;
29-
30- // Mocks Visuais
3127vi . mock ( '../../components/layout/Sidebar' , ( ) => ( { default : ( ) => < div /> } ) ) ;
32- // Mocks Visuais
33- interface MockPostcardProps {
34- post : { title : string } ;
35- deleteLabel ?: string ;
36- onDelete ?: ( ) => void ;
37- }
3828vi . mock ( '../../components/domain/Postcard' , ( ) => ( {
39- default : ( { post, deleteLabel, onDelete } : MockPostcardProps ) => (
29+ default : ( { post, deleteLabel, onDelete } : any ) => (
4030 < div data-testid = "postcard" >
4131 < span > { post . title } </ span >
4232 { deleteLabel && < button onClick = { onDelete } data-testid = "mock-delete-btn" > Deletar { deleteLabel } </ button > }
4333 </ div >
4434 )
4535} ) ) ;
46- vi . mock ( '../../components/common/Toast' , ( ) => ( { default : ( { message } : { message : string } ) => < div data-testid = "toast" > { message } </ div > } ) ) ;
47-
48- // Mock Modal
49- interface ModalProps {
50- isOpen : boolean ;
51- children : React . ReactNode ;
52- title : string ;
53- }
36+ vi . mock ( '../../components/common/Toast' , ( ) => ( { default : ( { message } : any ) => < div data-testid = "toast" > { message } </ div > } ) ) ;
5437vi . mock ( '../../components/common/Modal' , ( ) => ( {
55- default : ( { isOpen, children, title } : ModalProps ) => isOpen ? (
56- < div data-testid = "modal" >
57- < h2 > { title } </ h2 >
58- { children }
59- </ div >
60- ) : null
38+ default : ( { isOpen, children, title } : any ) => isOpen ? < div data-testid = "modal" > < h2 > { title } </ h2 > { children } </ div > : null
6139} ) ) ;
6240vi . mock ( '../../components/common/Modal/styles' , ( ) => ( {
63- ModalActions : ( { children } : { children : React . ReactNode } ) => < div > { children } </ div > ,
64- ChoiceButton : ( { children, onClick } : { children : React . ReactNode ; onClick : ( ) => void } ) => < button onClick = { onClick } > { children } </ button > ,
41+ ModalActions : ( { children } : any ) => < div > { children } </ div > ,
42+ ChoiceButton : ( { children, onClick } : any ) => < button onClick = { onClick } > { children } </ button > ,
6543} ) ) ;
66-
67- // Mock Dropdown
68- interface StyleProps {
69- children ?: React . ReactNode ;
70- onClick ?: React . MouseEventHandler ;
71- }
7244vi . mock ( '../../components/common/Dropdown/styles' , ( ) => ( {
73- DropdownMenu : ( { children } : StyleProps ) => < div data-testid = "dropdown" > { children } </ div > ,
74- MenuItem : ( { children, onClick } : StyleProps ) => < button onClick = { onClick } > { children } </ button > ,
75- DangerMenuItem : ( { children, onClick } : StyleProps ) => < button onClick = { onClick } > { children } </ button > ,
45+ DropdownMenu : ( { children } : any ) => < div data-testid = "dropdown" > { children } </ div > ,
46+ MenuItem : ( { children, onClick } : any ) => < button onClick = { onClick } > { children } </ button > ,
47+ DangerMenuItem : ( { children, onClick } : any ) => < button onClick = { onClick } > { children } </ button > ,
7648 Separator : ( ) => < hr />
7749} ) ) ;
7850
51+
7952describe ( 'Página Profile' , ( ) => {
8053 beforeEach ( ( ) => {
8154 vi . clearAllMocks ( ) ;
82- // Default mocks
8355 vi . spyOn ( ProjectAPI , 'GetUserProjects' ) . mockResolvedValue ( [ ] ) ;
8456 vi . spyOn ( CommentAPI , 'GetUserComments' ) . mockResolvedValue ( [ ] ) ;
8557 } ) ;
8658
8759 it ( 'deve lidar com lista vazia de projetos' , async ( ) => {
8860 render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
89- await waitFor ( ( ) => {
90- expect ( screen . getByText ( 'Nenhum projeto encontrado.' ) ) . toBeInTheDocument ( ) ;
91- } ) ;
61+ await waitFor ( ( ) => expect ( screen . getByText ( 'Nenhum projeto encontrado.' ) ) . toBeInTheDocument ( ) ) ;
9262 } ) ;
9363
9464 it ( 'deve lidar com erro na API ao carregar dados' , async ( ) => {
95- const consoleSpy = vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } ) ; // Silencia console.error
65+ const consoleSpy = vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } ) ;
9666 vi . spyOn ( ProjectAPI , 'GetUserProjects' ) . mockRejectedValue ( new Error ( 'Erro API' ) ) ;
97-
9867 render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
99-
100- await waitFor ( ( ) => {
101- expect ( consoleSpy ) . toHaveBeenCalledWith ( "Falha ao buscar dados do perfil:" , expect . any ( Error ) ) ;
102- } ) ;
68+ await waitFor ( ( ) => expect ( consoleSpy ) . toHaveBeenCalledWith ( "Falha ao buscar dados do perfil:" , expect . any ( Error ) ) ) ;
10369 consoleSpy . mockRestore ( ) ;
10470 } ) ;
10571
10672 it ( 'deve deletar um comentário da lista visualmente' , async ( ) => {
107- // Setup: 1 comentário na lista
108- vi . spyOn ( CommentAPI , 'GetUserComments' ) . mockResolvedValue ( [
109- { commentID : 'c1' , content : 'Comentário Teste' , projectTitle : 'Proj' }
110- ] as unknown as CommentAPI . CommentProps [ ] ) ;
111- vi . spyOn ( CommentAPI , 'DeleteComment' ) . mockResolvedValue ( { } as unknown as void ) ;
73+ vi . spyOn ( CommentAPI , 'GetUserComments' ) . mockResolvedValue ( [ { commentID : 'c1' , content : 'Teste' , projectTitle : 'Proj' } ] as any ) ;
74+ vi . spyOn ( CommentAPI , 'DeleteComment' ) . mockResolvedValue ( { } as any ) ;
11275
11376 render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
11477
115- // Muda para aba de comentários
116- fireEvent . click ( screen . getByTitle ( 'Ver comentários' ) ) ;
78+ const commentsBtn = await screen . findByTitle ( 'Ver comentários' ) ;
79+ fireEvent . click ( commentsBtn ) ;
11780
118- // Aguarda renderizar
11981 await waitFor ( ( ) => expect ( screen . getByText ( 'Comentou em: Proj' ) ) . toBeInTheDocument ( ) ) ;
12082
121- // Clica no botão de deletar (simulado no mock do Postcard)
12283 const deleteBtn = screen . getByTestId ( 'mock-delete-btn' ) ;
12384 fireEvent . click ( deleteBtn ) ;
12485
125- // Verifica se a API foi chamada e o item sumiu
126- await waitFor ( ( ) => {
127- expect ( CommentAPI . DeleteComment ) . toHaveBeenCalledWith ( 'c1' ) ;
128- } ) ;
86+ await waitFor ( ( ) => expect ( CommentAPI . DeleteComment ) . toHaveBeenCalledWith ( 'c1' ) ) ;
12987 } ) ;
13088
89+
13190 it ( 'deve abrir menu, clicar em editar perfil e navegar' , async ( ) => {
13291 render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
133- fireEvent . click ( screen . getByTitle ( 'Configurações' ) ) ;
134- fireEvent . click ( screen . getByText ( 'Editar Perfil' ) ) ;
92+
93+ const settingsBtn = await screen . findByTitle ( 'Configurações' ) ;
94+ fireEvent . click ( settingsBtn ) ;
95+
96+ const editBtn = await screen . findByText ( 'Editar Perfil' ) ;
97+ fireEvent . click ( editBtn ) ;
98+
13599 expect ( navigateMock ) . toHaveBeenCalledWith ( '/editProfile' ) ;
136100 } ) ;
137101
138102 it ( 'deve fechar o menu ao clicar fora dele' , async ( ) => {
139103 render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
140104
141- // Abre o menu
142- fireEvent . click ( screen . getByTitle ( 'Configurações' ) ) ;
143- expect ( screen . getByTestId ( 'dropdown' ) ) . toBeInTheDocument ( ) ;
105+ const settingsBtn = await screen . findByTitle ( 'Configurações' ) ;
106+ fireEvent . click ( settingsBtn ) ;
107+
108+ await screen . findByTestId ( 'dropdown' ) ;
144109
145- // Clica no body (fora do menu)
146110 fireEvent . mouseDown ( document . body ) ;
147111
148112 await waitFor ( ( ) => {
@@ -153,15 +117,16 @@ describe('Página Profile', () => {
153117 it ( 'deve cancelar a exclusão do perfil no modal' , async ( ) => {
154118 render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
155119
156- // Abre modal
157- fireEvent . click ( screen . getByTitle ( 'Configurações' ) ) ;
158- fireEvent . click ( screen . getByText ( 'Excluir Perfil' ) ) ;
120+ const settingsBtn = await screen . findByTitle ( 'Configurações' ) ;
121+ fireEvent . click ( settingsBtn ) ;
122+
123+ const deleteOption = await screen . findByText ( 'Excluir Perfil' ) ;
124+ fireEvent . click ( deleteOption ) ;
159125
160- // Clica em Cancelar
161- const cancelBtn = screen . getByText ( 'Cancelar' ) ;
126+ const cancelBtn = await screen . findByText ( 'Cancelar' ) ;
162127 fireEvent . click ( cancelBtn ) ;
163128
164- expect ( screen . queryByTestId ( 'modal' ) ) . not . toBeInTheDocument ( ) ;
129+ await waitFor ( ( ) => expect ( screen . queryByTestId ( 'modal' ) ) . not . toBeInTheDocument ( ) ) ;
165130 expect ( UserAPI . DeleteProfile ) . not . toHaveBeenCalled ( ) ;
166131 } ) ;
167132
@@ -170,15 +135,17 @@ describe('Página Profile', () => {
170135
171136 render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
172137
173- // Fluxo de exclusão
174- fireEvent . click ( screen . getByTitle ( 'Configurações' ) ) ;
175- fireEvent . click ( screen . getByText ( 'Excluir Perfil' ) ) ;
176- fireEvent . click ( screen . getByRole ( 'button' , { name : 'Excluir Conta' } ) ) ;
138+ const settingsBtn = await screen . findByTitle ( 'Configurações' ) ;
139+ fireEvent . click ( settingsBtn ) ;
140+
141+ const deleteOption = await screen . findByText ( 'Excluir Perfil' ) ;
142+ fireEvent . click ( deleteOption ) ;
143+
144+ const confirmBtn = await screen . findByRole ( 'button' , { name : 'Excluir Conta' } ) ;
145+ fireEvent . click ( confirmBtn ) ;
177146
178147 await waitFor ( ( ) => {
179148 expect ( screen . getByTestId ( 'toast' ) ) . toHaveTextContent ( 'Conta já encerrada' ) ;
180- // Verifica se forçou logout mesmo com erro
181- expect ( logoutMock ) . not . toHaveBeenCalled ( ) ; // Só chama no timeout, difícil testar sem fake timers, mas verificamos o toast
182149 } ) ;
183150 } ) ;
184151
@@ -187,88 +154,63 @@ describe('Página Profile', () => {
187154
188155 render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
189156
190- fireEvent . click ( screen . getByTitle ( 'Configurações' ) ) ;
191- fireEvent . click ( screen . getByText ( 'Excluir Perfil' ) ) ;
192- fireEvent . click ( screen . getByRole ( 'button' , { name : 'Excluir Conta' } ) ) ;
157+ const settingsBtn = await screen . findByTitle ( 'Configurações' ) ;
158+ fireEvent . click ( settingsBtn ) ;
159+
160+ const deleteOption = await screen . findByText ( 'Excluir Perfil' ) ;
161+ fireEvent . click ( deleteOption ) ;
162+
163+ const confirmBtn = await screen . findByRole ( 'button' , { name : 'Excluir Conta' } ) ;
164+ fireEvent . click ( confirmBtn ) ;
193165
194166 await waitFor ( ( ) => {
195167 expect ( screen . getByTestId ( 'toast' ) ) . toHaveTextContent ( 'Erro genérico' ) ;
196168 } ) ;
197169 } ) ;
198170
199171 it ( 'deve carregar dados do perfil e mostrar posts por padrão' , async ( ) => {
200- vi . spyOn ( ProjectAPI , 'GetUserProjects' ) . mockResolvedValue ( [ { id : '1' , title : 'Meu Projeto' } ] as unknown as ProjectAPI . ProjectProps [ ] ) ;
201-
202- render (
203- < BrowserRouter >
204- < Profile />
205- </ BrowserRouter >
206- ) ;
207-
208- expect ( screen . getByText ( 'tester' ) ) . toBeInTheDocument ( ) ; // Username
209-
210- await waitFor ( ( ) => {
211- expect ( screen . getByText ( 'Meu Projeto' ) ) . toBeInTheDocument ( ) ;
212- } ) ;
172+ vi . spyOn ( ProjectAPI , 'GetUserProjects' ) . mockResolvedValue ( [ { id : '1' , title : 'Meu Projeto' } ] as any ) ;
173+ render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
174+ await waitFor ( ( ) => expect ( screen . getByText ( 'tester' ) ) . toBeInTheDocument ( ) ) ;
175+ await waitFor ( ( ) => expect ( screen . getByText ( 'Meu Projeto' ) ) . toBeInTheDocument ( ) ) ;
213176 } ) ;
214177
215178 it ( 'deve alternar para a aba de comentários' , async ( ) => {
216- vi . spyOn ( CommentAPI , 'GetUserComments' ) . mockResolvedValue ( [
217- { commentID : 'c1' , content : 'Bom post' , projectTitle : 'Projeto X' }
218- ] as unknown as CommentAPI . CommentProps [ ] ) ;
219-
220- render (
221- < BrowserRouter >
222- < Profile />
223- </ BrowserRouter >
224- ) ;
225-
226- // Clica no ícone de comentários
227- const commentsBtn = screen . getByTitle ( 'Ver comentários' ) ;
179+ vi . spyOn ( CommentAPI , 'GetUserComments' ) . mockResolvedValue ( [ { commentID : 'c1' , content : 'Bom post' , projectTitle : 'Proj' } ] as any ) ;
180+ render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
181+
182+ const commentsBtn = await screen . findByTitle ( 'Ver comentários' ) ;
228183 fireEvent . click ( commentsBtn ) ;
229184
230- await waitFor ( ( ) => {
231- expect ( screen . getByText ( 'Comentou em: Projeto X' ) ) . toBeInTheDocument ( ) ;
232- } ) ;
185+ await waitFor ( ( ) => expect ( screen . getByText ( 'Comentou em: Proj' ) ) . toBeInTheDocument ( ) ) ;
233186 } ) ;
234187
235188 it ( 'deve abrir menu e fazer logout' , async ( ) => {
236- render (
237- < BrowserRouter >
238- < Profile />
239- </ BrowserRouter >
240- ) ;
189+ render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
241190
242- const settingsBtn = screen . getByTitle ( 'Configurações' ) ;
191+ const settingsBtn = await screen . findByTitle ( 'Configurações' ) ;
243192 fireEvent . click ( settingsBtn ) ;
244193
245- const logoutBtn = screen . getByText ( 'Sair' ) ;
194+ const logoutBtn = await screen . findByText ( 'Sair' ) ;
246195 fireEvent . click ( logoutBtn ) ;
247196
248197 expect ( logoutMock ) . toHaveBeenCalled ( ) ;
249198 expect ( navigateMock ) . toHaveBeenCalledWith ( '/login' ) ;
250199 } ) ;
251200
252201 it ( 'deve excluir a conta com sucesso' , async ( ) => {
253- vi . spyOn ( UserAPI , 'DeleteProfile' ) . mockResolvedValue ( { } as unknown as void ) ;
202+ vi . spyOn ( UserAPI , 'DeleteProfile' ) . mockResolvedValue ( { } as any ) ;
254203
255- render (
256- < BrowserRouter >
257- < Profile />
258- </ BrowserRouter >
259- ) ;
204+ render ( < BrowserRouter > < Profile /> </ BrowserRouter > ) ;
260205
261- // Abre menu
262- fireEvent . click ( screen . getByTitle ( 'Configurações' ) ) ;
206+ const settingsBtn = await screen . findByTitle ( 'Configurações' ) ;
207+ fireEvent . click ( settingsBtn ) ;
263208
264- // Clica em Excluir Perfil
265- fireEvent . click ( screen . getByText ( 'Excluir Perfil' ) ) ;
266-
267- // Modal aparece
268- expect ( screen . getByTestId ( 'modal' ) ) . toBeInTheDocument ( ) ;
209+ const deleteOption = await screen . findByText ( 'Excluir Perfil' ) ;
210+ fireEvent . click ( deleteOption ) ;
269211
270- // Confirma exclusão
271- fireEvent . click ( screen . getByRole ( 'button' , { name : 'Excluir Conta' } ) ) ;
212+ const confirmBtn = await screen . findByRole ( 'button' , { name : 'Excluir Conta' } ) ;
213+ fireEvent . click ( confirmBtn ) ;
272214
273215 await waitFor ( ( ) => {
274216 expect ( UserAPI . DeleteProfile ) . toHaveBeenCalled ( ) ;
0 commit comments