Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hechos test de Groups, UserGroups y GroupDetails #116

Merged
merged 20 commits into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion users/userservice/user-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ app.post('/group/add', async (req, res) => {
}

const newGroup = new Group({ name: name,
members: [username] });
members: [username],
createdAt:Date.now() });
await newGroup.save();

res.json({ message: 'Group created successfully' });
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@
"errorPrefix": "Error: ",
"joinable": "Groups you can join",
"join": "Join group",
"noGroups": "There are no groups available to join."
"nogroups": "There are no groups available to join."
},
"groupsTable": {
"groupName": "Group name",
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@
"errorPrefix": "Error: ",
"joinable": "Grupos a los que puedes unirte",
"join": "Unirse al grupo",
"noGroups": "No hay grupos disponibles para unirse."
"nogroups": "No hay grupos a los que puedas unirte."
},
"groupsTable": {
"groupName": "Nombre del grupo",
Expand Down
83 changes: 56 additions & 27 deletions webapp/src/pages/Social/GroupDetails.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import axios from 'axios';
import { Container, Box, Text, Heading, Table, Thead, Tbody, Tr, Th, Td, Avatar, Link } from '@chakra-ui/react';
import Nav from "../../components/Nav/Nav.js";
import Footer from "../../components/Footer/Footer.js";
Expand All @@ -9,39 +8,71 @@ import { useTranslation } from "react-i18next";
const GroupDetails = () => {
const { t } = useTranslation();
const [group, setGroup] = useState(null);
const [error, setError] = useState(null);
const { groupName } = useParams();
const apiEndpoint = process.env.REACT_APP_API_ENDPOINT || 'http://localhost:8000';
const navigate = useNavigate();

useEffect(() => {
const fetchGroupDetails = async () => {
try {
const response = await axios.get(`${apiEndpoint}/group/${encodeURIComponent(groupName)}`);
setGroup(response.data.group);
} catch (error) {
console.error('Error fetching group details:', error);
}
};

fetchGroupDetails();
}, [groupName]);
}, []);

const fetchGroupDetails = async () => {
try {
const response = await fetch(`${apiEndpoint}/group/${encodeURIComponent(groupName)}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
setGroup(data.group);
setError(null);
} catch (error) {
setError(error);
console.error("Error al obtener los detalles del grupo:", error);
}
};


const redirectToProfile = (username) => {
navigate(`/perfil?user=${username}`);
};

if (error) {
return (
<>
<Nav />
<Box>
<Heading as="h2">Error: {error.message}</Heading>
</Box>
<Footer />
</>
);
}

if (!group) {
return (
<>
<Nav />
<Box>
<Heading as="h2">Cargando...</Heading>
</Box>
<Footer />
</>
);
}

return (
<>
<Nav/>
<Container maxW="md" mt="5">
<Heading as="h1" mb="5">{t('pages.groupdetails.details')} {groupName}</Heading>
{group ? (
group && (
<>
<Nav/>
<Container maxW="md" mt="5">
<Heading as="h1" mb="5">{t('pages.groupdetails.details')} {group.name}</Heading>
<Box>
<Text fontSize="lg" fontWeight="bold" mb="4">
{t('pages.groupdetails.createdBy')} {group.members.length > 0 ? group.members[0] : ''}
{t('pages.groupdetails.when')} {new Date(group.createdAt).toLocaleDateString()}
{t('pages.groupdetails.createdBy')} {group.members.length > 0 ? group.members[0] : ''}
{t('pages.groupdetails.when')} {new Date(group.createdAt).toLocaleDateString()}
</Text>

<Text fontSize="lg" fontWeight="bold" mb="2">{t('pages.groupdetails.participants')} ({group.members.length}) :</Text>
<Table variant="striped">
<Thead>
Expand All @@ -55,23 +86,21 @@ const GroupDetails = () => {
{group.members.map((member, index) => (
<Tr key={index}>
<Td>
<Avatar size="sm" name={member} />
<Avatar size="sm" name={member} data-testid={`user-avatar-${member}`}/>
</Td>
<Td>{member}</Td>
<Td>
<Link color="blue.500" onClick={() => redirectToProfile(member)}>{t('pages.groupdetails.viewProfile')}</Link>
<Link data-testid={`view-profile-button-${member}`} color="blue.500" onClick={() => redirectToProfile(member)}>{t('pages.groupdetails.viewProfile')}</Link>
</Td>
</Tr>
))}
</Tbody>
</Table>
</Box>
) : (
<Text>{t('pages.groupdetails.loading')}</Text>
)}
</Container>
<Footer/>
</>
</Container>
<Footer/>
</>
)
);
};

Expand Down
110 changes: 110 additions & 0 deletions webapp/src/pages/Social/GroupDetails.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React from 'react';
import { render, screen, waitFor, fireEvent } from "@testing-library/react";
import { MemoryRouter } from 'react-router-dom';
import GroupDetails from './GroupDetails';
import { I18nextProvider } from "react-i18next";
import i18n from "../../i18n.js";

const renderComponentWithRouter = async () => {
render(
<I18nextProvider i18n={i18n}>
<MemoryRouter >
<GroupDetails />
</MemoryRouter>
</I18nextProvider>
);
localStorage.setItem("username", "user1");
};

let originalFetch;

beforeEach(() => {
originalFetch = global.fetch;
global.fetch = jest.fn();
});

afterEach(() => {
global.fetch = originalFetch;
jest.restoreAllMocks();
});

const groupData = {
name: 'exampleGroup',
members: ['user1', 'user2'],
createdAt: '2024-04-11T12:00:00Z',
};

const mockNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => mockNavigate,
}));

describe('GroupDetails', () => {
beforeEach(() => {
localStorage.clear();
});

afterEach(() => {
global.fetch.mockRestore();
});


it('renders loading text when group data is not yet fetched', () => {
jest.spyOn(global, "fetch").mockResolvedValue({
json: jest.fn().mockResolvedValueOnce(groupData),
});
renderComponentWithRouter();
expect(screen.getByText('Cargando...')).toBeInTheDocument();
});

it('renders group details when data is fetched', async () => {

jest.spyOn(global, "fetch").mockResolvedValue({
ok: true,
json: jest.fn().mockResolvedValueOnce(groupData),
});

renderComponentWithRouter();

await waitFor(() => {
expect(screen.getByText('Detalles del grupo exampleGroup')).toBeInTheDocument();
expect(screen.getByText('Avatar')).toBeInTheDocument();
expect(screen.getByText('Nombre')).toBeInTheDocument();
const viewProfile = screen.getAllByText('Ver perfil');
expect(viewProfile).toHaveLength(3);
expect(screen.getByTestId('user-avatar-user1')).toBeInTheDocument();
expect(screen.getByTestId('user-avatar-user2')).toBeInTheDocument();
expect(screen.getByText('user1')).toBeInTheDocument();
expect(screen.getByText('user2')).toBeInTheDocument();
});
});

it('redirects to user profile when view profile link is clicked', async () => {

jest.spyOn(global, "fetch").mockResolvedValue({
ok: true,
json: jest.fn().mockResolvedValueOnce(groupData),
});

renderComponentWithRouter();

await waitFor(() => {
expect(screen.getByText('Detalles del grupo exampleGroup')).toBeInTheDocument();
expect(screen.getByText('Avatar')).toBeInTheDocument();
expect(screen.getByText('Nombre')).toBeInTheDocument();
const viewProfile = screen.getAllByText('Ver perfil');
expect(viewProfile).toHaveLength(3);
expect(screen.getByTestId('user-avatar-user1')).toBeInTheDocument();
expect(screen.getByTestId('user-avatar-user2')).toBeInTheDocument();
expect(screen.getByText('user1')).toBeInTheDocument();
expect(screen.getByText('user2')).toBeInTheDocument();
});

const viewProfileButtons = screen.getByTestId('view-profile-button-user1');

fireEvent.click(viewProfileButtons);
expect(mockNavigate).toHaveBeenCalledWith('/perfil?user=user1');
});
});

58 changes: 42 additions & 16 deletions webapp/src/pages/Social/Groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,42 @@ const Groups = () => {
}, []);

const fetchData = async () => {
try {
const response = await axios.get(`${apiEndpoint}/group/list`);
const userGroups = response.data.groups.filter(group => !group.members.includes(username));
setGroups(userGroups);
} catch (error) {
console.error('Error fetching data:', error);
}
fetch(`${apiEndpoint}/group/list`)
.then(response => response.json())
.then(data => {
const userGroups = data.groups.filter(group => !group.members.includes(username));
setGroups(userGroups);
})
.catch(error => {
console.error('Error fetching data:', error);
});
};

const addGroup = async () => {
try {
await axios.post(`${apiEndpoint}/group/add`, {
const addGroup = () => {
fetch(`${apiEndpoint}/group/add`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: name,
username: username
});
})
})
.then(response => {
if (!response.ok) {
throw new Error('Failed to create group');
}
return response.json();
})
.then(() => {
setAlertMessage('Group created successfully');
setOpenAlert(true);
} catch (error) {
setError(error.response.data.error);
}
setName('');
})
.catch(error => {
setError(error.message);
});
};

const handleJoinGroup = (groupId) => {
Expand Down Expand Up @@ -88,10 +104,18 @@ const Groups = () => {
{`Error: ${error}`}
</Alert>
)}
{alertMessage && (
<Alert status="success" variant="subtle" mt="2">
{alertMessage}
</Alert>
)}
</Box>

<Box mt="4">
<Text fontSize="3xl" fontWeight="bold" mb="4">{t('pages.groups.joinable')}</Text>
<Text fontSize="3xl" fontWeight="bold" mb="4">{t('pages.groups.joinable')}</Text>
{groups.length === 0 ? (
<Text>{t('pages.groups.nogroups')}</Text>
) : (
<Table variant="simple">
<Thead>
<Tr>
Expand All @@ -102,6 +126,7 @@ const Groups = () => {
</Tr>
</Thead>
<Tbody>

{groups.map((group) => (
<Tr key={group._id}>
<Td>{group.name}</Td>
Expand All @@ -114,7 +139,8 @@ const Groups = () => {
))}
</Tbody>
</Table>
</Box>
)}
</Box>
</Container>
<Footer />
</>
Expand Down
Loading
Loading