Reverting album page, adding more tests#
All checks were successful
Music Collection CI Workflow / test (./backend) (push) Successful in 29s
Music Collection CI Workflow / test (./frontend) (push) Successful in 36s
Music Collection CI Workflow / build-and-push-images (./backend/Dockerfile, git.anatid.net/tabris/music-collection-backend, ./backend) (push) Successful in 50s
Music Collection CI Workflow / build-and-push-images (./frontend/Dockerfile, git.anatid.net/tabris/music-collection-frontend, ./frontend) (push) Successful in 1m48s
Music Collection CI Workflow / deploy (push) Successful in 25s

This commit is contained in:
Phill Pover 2025-04-07 03:24:30 +01:00
parent 870811bb94
commit 43fbfbb467
2 changed files with 36 additions and 26 deletions

View File

@ -3,9 +3,14 @@ import { getRepositoryToken } from '@nestjs/typeorm';
import { AlbumController } from './album.controller'; import { AlbumController } from './album.controller';
import { AlbumService } from './album.service'; import { AlbumService } from './album.service';
import { Album } from './album.entity'; import { Album } from './album.entity';
import { Repository } from 'typeorm'; import { CreateAlbumDto } from './dto/create-album.dto';
import { UpdateAlbumDto } from './dto/update-album.dto';
import { DeleteResult, Repository } from 'typeorm';
const mockAlbum = new Album(); const mockAlbum = new Album();
const mockCreateAlbumDto = new CreateAlbumDto();
const mockUpdateAlbumDto = new UpdateAlbumDto();
const mockDeleteResult = new DeleteResult();
describe('AlbumController', () => { describe('AlbumController', () => {
let controller: AlbumController; let controller: AlbumController;
@ -22,9 +27,11 @@ describe('AlbumController', () => {
useValue: { useValue: {
find: jest.fn().mockResolvedValue([mockAlbum]), find: jest.fn().mockResolvedValue([mockAlbum]),
findOne: jest.fn().mockResolvedValue(mockAlbum), findOne: jest.fn().mockResolvedValue(mockAlbum),
create: jest.fn().mockResolvedValue(1), findOneBy: jest.fn().mockResolvedValue({ id: 1, title: 'some album', artist: 'some artist', genre: 'some genre' }),
create: jest.fn().mockResolvedValue(mockAlbum),
save: jest.fn().mockResolvedValue({ id: 1, title: 'some album', artist: 'some artist', genre: 'some genre' }),
update: jest.fn().mockResolvedValue("Album updated successfully"), update: jest.fn().mockResolvedValue("Album updated successfully"),
remove: jest.fn().mockResolvedValue(null), delete: jest.fn().mockResolvedValue(mockDeleteResult),
}, },
}, },
] ]
@ -41,13 +48,32 @@ describe('AlbumController', () => {
describe('findAll', () => { describe('findAll', () => {
it('should return an array of Albums', async () => { it('should return an array of Albums', async () => {
expect(await service.findAll()).toStrictEqual([mockAlbum]); expect(await controller.findAll()).toStrictEqual([mockAlbum]);
}) })
}) })
describe('findOneById', () => { describe('findOneById', () => {
it('should return an Album', async () => { it('should return an Album', async () => {
expect(await service.findOneById(1)).toStrictEqual(mockAlbum); expect(await controller.findOneById(1)).toStrictEqual(mockAlbum);
})
})
describe('create', () => {
it('should return the Album ID', async () => {
expect(await controller.create(mockCreateAlbumDto)).toStrictEqual(1);
})
})
describe('update', () => {
it('should return the success message', async () => {
mockUpdateAlbumDto.id = 1;
expect(await controller.update(1, mockUpdateAlbumDto)).toStrictEqual("Album updated successfully");
})
})
describe('remove', () => {
it('should return a DeleteResult', async () => {
expect(await controller.remove(1)).toStrictEqual(mockDeleteResult);
}) })
}) })
}); });

View File

@ -3,7 +3,7 @@
import { FormEvent, MouseEvent, useState, useEffect } from 'react'; import { FormEvent, MouseEvent, useState, useEffect } from 'react';
import Link from 'next/link'; import Link from 'next/link';
import { Album } from '@/entities/album.entity'; import { Album } from '@/entities/album.entity';
import { createAlbum, deleteAlbum, getAlbum, getAlbums, updateAlbum } from '@/app/actions'; import { createAlbum, getAlbum, getAlbums, updateAlbum } from '@/app/actions';
import Button from 'react-bootstrap/Button'; import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal'; import Modal from 'react-bootstrap/Modal';
import { IconButton } from '@mui/material'; import { IconButton } from '@mui/material';
@ -19,7 +19,6 @@ export default function Page() {
const [formAlbumArtist, setFormAlbumArtist] = useState(""); const [formAlbumArtist, setFormAlbumArtist] = useState("");
const [formAlbumGenre, setFormAlbumGenre] = useState(""); const [formAlbumGenre, setFormAlbumGenre] = useState("");
const [formModalTitle, setFormModalTitle] = useState("Add Album"); const [formModalTitle, setFormModalTitle] = useState("Add Album");
const [formModalButtonLabel, setFormModalButtonLabel] = useState("Add");
useEffect(() => { useEffect(() => {
async function fetchAlbums() { async function fetchAlbums() {
@ -39,8 +38,7 @@ export default function Page() {
const formData = new FormData(event.currentTarget); const formData = new FormData(event.currentTarget);
try { try {
console.log(formData); if (!formData.get('id')) {
if (formData.get('id') == "") {
const data = await createAlbum(formData); const data = await createAlbum(formData);
console.log(data); console.log(data);
} else { } else {
@ -54,7 +52,6 @@ export default function Page() {
const handleCreate = async () => { const handleCreate = async () => {
setFormModalTitle("Add Album"); setFormModalTitle("Add Album");
setFormModalButtonLabel("Add");
setFormAlbumId(""); setFormAlbumId("");
setFormAlbumTitle(""); setFormAlbumTitle("");
setFormAlbumArtist(""); setFormAlbumArtist("");
@ -68,7 +65,6 @@ export default function Page() {
try { try {
const data = await getAlbum(parseInt(id)); const data = await getAlbum(parseInt(id));
setFormModalTitle("Edit Album"); setFormModalTitle("Edit Album");
setFormModalButtonLabel("Save");
setFormAlbumId(data.id) setFormAlbumId(data.id)
setFormAlbumTitle(data.title); setFormAlbumTitle(data.title);
setFormAlbumArtist(data.artist); setFormAlbumArtist(data.artist);
@ -82,19 +78,6 @@ export default function Page() {
} }
} }
const handleDelete = async (event: MouseEvent<HTMLElement>) => {
const id = event.currentTarget.getAttribute('album-id');
if (id) {
try {
await deleteAlbum(parseInt(id));
} catch (error) {
console.error(`Error deleting album with ID ${id}:`, error);
}
} else {
console.error("Couldn't get ID of clicked element");
}
}
if (!albums) return <div>Loading...</div> if (!albums) return <div>Loading...</div>
return ( return (
@ -132,7 +115,7 @@ export default function Page() {
<IconButton aria-label="Edit Album" size="small" album-id={album.id.toString()} onClick={handleEdit}> <IconButton aria-label="Edit Album" size="small" album-id={album.id.toString()} onClick={handleEdit}>
<Edit fontSize="inherit" color="success"/> <Edit fontSize="inherit" color="success"/>
</IconButton> </IconButton>
<IconButton aria-label="Delete Album" size="small" album-id={album.id.toString()} onClick={handleDelete}> <IconButton aria-label="Delete Album" size="small" album-id={album.id.toString()} onClick={handleEdit}>
<Delete fontSize="inherit" color="success"/> <Delete fontSize="inherit" color="success"/>
</IconButton> </IconButton>
</td> </td>
@ -140,6 +123,7 @@ export default function Page() {
))} ))}
</tbody> </tbody>
</table> </table>
</div> </div>
<Modal <Modal
@ -168,7 +152,7 @@ export default function Page() {
<label htmlFor="album-genre">Genre</label><input type="text" name="genre" id="album-genre" defaultValue={formAlbumGenre} /> <label htmlFor="album-genre">Genre</label><input type="text" name="genre" id="album-genre" defaultValue={formAlbumGenre} />
</div> </div>
</div> </div>
<Button variant="primary" type="submit">{formModalButtonLabel}</Button> <Button variant="primary" type="submit">Create</Button>
</form> </form>
</div> </div>
</Modal.Body> </Modal.Body>