-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from isdi-coders-2023/feature/cors
add endpoint
- Loading branch information
Showing
8 changed files
with
444 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ | ||
/* eslint-disable @typescript-eslint/consistent-type-assertions */ | ||
import { type Request, type Response, type NextFunction } from 'express'; | ||
import { BooksController } from './books.controller.js'; | ||
import { type Repo } from '../repositories/baseRepo.js'; | ||
import { type ObjectSchema } from 'joi'; | ||
import { type Book, type BookCreateDto } from '../entities/book.js'; | ||
import { bookCreateDtoSchema } from '../entities/book.schema.js'; | ||
jest.mock('../entities/book.schema.js', () => ({ | ||
bookCreateDtoSchema: { | ||
validate: jest.fn().mockReturnValue({ error: null, value: {} }), | ||
} as unknown as ObjectSchema<BookCreateDto>, | ||
bookUpdateDtoSchema: { | ||
validate: jest.fn().mockReturnValue({ error: null, value: {} }), | ||
} as unknown as ObjectSchema<BookCreateDto>, | ||
})); | ||
|
||
describe('Given an instance of the class BooksController', () => { | ||
const repo = { | ||
readAll: jest.fn(), | ||
readById: jest.fn(), | ||
create: jest.fn(), | ||
update: jest.fn(), | ||
delete: jest.fn(), | ||
} as unknown as Repo<Book, BookCreateDto>; | ||
|
||
const req = {} as unknown as Request; | ||
const res = { | ||
json: jest.fn(), | ||
status: jest.fn().mockReturnThis(), | ||
} as unknown as Response; | ||
const next = jest.fn(); | ||
|
||
const controller = new BooksController(repo); | ||
|
||
test('Then it should be an instance of the class', () => { | ||
expect(controller).toBeInstanceOf(BooksController); | ||
}); | ||
|
||
describe('When we use the method create', () => { | ||
describe('And body is not valid', () => { | ||
test('Then it should call next with an error', async () => { | ||
req.body = {}; | ||
(bookCreateDtoSchema.validate as jest.Mock).mockReturnValueOnce({ | ||
error: new Error('validation error'), | ||
value: {}, | ||
}); | ||
|
||
await controller.create(req, res, next); | ||
expect(next).toHaveBeenCalledWith( | ||
expect.objectContaining({ | ||
message: expect.stringContaining('validation error'), | ||
}) | ||
); | ||
}); | ||
}); | ||
|
||
describe('And body is valid', () => { | ||
test.skip('Then it should call repo.create', async () => { | ||
const book = { | ||
title: 'Test Book', | ||
author: 'Test Author', | ||
} as BookCreateDto; | ||
|
||
req.body = book; | ||
await controller.create(req, res, next); | ||
expect(repo.create).toHaveBeenCalledWith(book); | ||
expect(res.status).toHaveBeenCalledWith(201); | ||
expect(res.json).toHaveBeenCalledWith(expect.any(Object)); | ||
}); | ||
}); | ||
|
||
describe('And an error is thrown during creation', () => { | ||
test('Then it should call next with an error', async () => { | ||
(repo.create as jest.Mock).mockRejectedValueOnce( | ||
new Error('Create error') | ||
); | ||
const book = { | ||
title: 'Test Book', | ||
author: 'Test Author', | ||
} as BookCreateDto; | ||
|
||
req.body = book; | ||
await controller.create(req, res, next); | ||
expect(next).toHaveBeenCalledWith(expect.any(Error)); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { type NextFunction, type Request, type Response } from 'express'; | ||
import createDebug from 'debug'; | ||
import { type BookCreateDto, type Book } from '../entities/book.js'; | ||
import { | ||
bookCreateDtoSchema, | ||
bookUpdateDtoSchema, | ||
} from '../entities/book.schema.js'; | ||
import { type Repo } from '../repositories/baseRepo.js'; | ||
import { BaseController } from './baseController.js'; | ||
|
||
const debug = createDebug('BOOKS:books:controller'); | ||
|
||
export class BooksController extends BaseController<Book, BookCreateDto> { | ||
constructor(protected readonly repo: Repo<Book, BookCreateDto>) { | ||
super(repo, bookCreateDtoSchema, bookUpdateDtoSchema); | ||
|
||
debug('Instantiated book controller'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
import { type PrismaClient } from '@prisma/client'; | ||
import { BooksSqlRepo } from './books.sql.repo.js'; | ||
import { HttpError } from '../middleware/errors.middleware.js'; | ||
import { type BookCreateDto } from '../entities/book.js'; | ||
|
||
const mockPrisma = { | ||
book: { | ||
findMany: jest.fn().mockResolvedValue([]), | ||
findUnique: jest.fn().mockResolvedValue({ | ||
id: '1', | ||
title: 'Test Book', | ||
year: 2021, | ||
isbn: '1234567890', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'A test book', | ||
}), | ||
create: jest.fn().mockResolvedValue({ | ||
id: '1', | ||
title: 'New Book', | ||
year: 2021, | ||
isbn: '0987654321', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'A new book', | ||
}), | ||
update: jest.fn().mockResolvedValue({ | ||
id: '1', | ||
title: 'Updated Book', | ||
year: 2021, | ||
isbn: '1234567890', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'An updated book', | ||
}), | ||
delete: jest.fn().mockResolvedValue({ | ||
id: '1', | ||
title: 'Deleted Book', | ||
year: 2021, | ||
isbn: '1234567890', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'A deleted book', | ||
}), | ||
}, | ||
} as unknown as PrismaClient; | ||
|
||
describe('Given an instance of the class BooksSqlRepo', () => { | ||
const repo = new BooksSqlRepo(mockPrisma); | ||
|
||
test('Then it should be an instance of the class', () => { | ||
expect(repo).toBeInstanceOf(BooksSqlRepo); | ||
}); | ||
|
||
describe('When we use the method readAll', () => { | ||
test('Then it should call prisma.findMany', async () => { | ||
const result = await repo.readAll(); | ||
expect(mockPrisma.book.findMany).toHaveBeenCalled(); | ||
expect(result).toEqual([]); | ||
}); | ||
}); | ||
|
||
describe('When we use the method readById with a valid ID', () => { | ||
test('Then it should call prisma.findUnique', async () => { | ||
const result = await repo.readById('1'); | ||
expect(mockPrisma.book.findUnique).toHaveBeenCalled(); | ||
expect(result).toEqual({ | ||
id: '1', | ||
title: 'Test Book', | ||
year: 2021, | ||
isbn: '1234567890', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'A test book', | ||
}); | ||
}); | ||
}); | ||
|
||
describe('When we use the method readById with an invalid ID', () => { | ||
test('Then it should throw an error', async () => { | ||
(mockPrisma.book.findUnique as jest.Mock).mockResolvedValueOnce(null); | ||
await expect(repo.readById('2')).rejects.toThrow( | ||
new HttpError(404, 'Not Found', 'Book 2 not found') | ||
); | ||
}); | ||
}); | ||
|
||
describe('When we use the method create', () => { | ||
test('Then it should call prisma.create', async () => { | ||
const data: BookCreateDto = { | ||
title: 'New Book', | ||
year: 2021, | ||
isbn: '0987654321', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'A new book', | ||
}; | ||
const result = await repo.create(data); | ||
expect(mockPrisma.book.create).toHaveBeenCalled(); | ||
expect(result).toEqual({ | ||
id: '1', | ||
title: 'New Book', | ||
year: 2021, | ||
isbn: '0987654321', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'A new book', | ||
}); | ||
}); | ||
|
||
test('Then it should throw an error if create fails', async () => { | ||
(mockPrisma.book.create as jest.Mock).mockRejectedValueOnce( | ||
new Error('Failed to create book') | ||
); | ||
|
||
const data: BookCreateDto = { | ||
title: 'New Book', | ||
year: 2021, | ||
isbn: '0987654321', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'A new book', | ||
}; | ||
|
||
await expect(repo.create(data)).rejects.toThrow( | ||
new HttpError(500, 'Internal Server Error', 'Error creating book') | ||
); | ||
|
||
expect(mockPrisma.book.create).toHaveBeenCalled(); | ||
}); | ||
}); | ||
|
||
describe('When we use the method update with a valid ID', () => { | ||
test('Then it should call prisma.update', async () => { | ||
const data: BookCreateDto = { | ||
title: 'Updated Book', | ||
year: 2021, | ||
isbn: '1234567890', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'An updated book', | ||
}; | ||
const result = await repo.update('1', data); | ||
expect(mockPrisma.book.update).toHaveBeenCalled(); | ||
expect(result).toEqual({ | ||
id: '1', | ||
title: 'Updated Book', | ||
year: 2021, | ||
isbn: '1234567890', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'An updated book', | ||
}); | ||
}); | ||
}); | ||
|
||
describe('When we use the method update with an invalid ID', () => { | ||
test.skip('Then it should throw an error', async () => { | ||
(mockPrisma.book.findUnique as jest.Mock).mockResolvedValueOnce(null); | ||
const data: BookCreateDto = { | ||
title: 'Updated Book', | ||
year: 2021, | ||
isbn: '1234567890', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'An updated book', | ||
}; | ||
await expect(repo.update('2', data)).rejects.toThrow( | ||
new HttpError(404, 'Not Found', 'Book 2 not found') | ||
); | ||
}); | ||
}); | ||
|
||
describe('When we use the method delete with a valid ID', () => { | ||
test.skip('Then it should call prisma.delete', async () => { | ||
const result = await repo.delete('1'); | ||
expect(mockPrisma.book.delete).toHaveBeenCalled(); | ||
expect(result).toEqual({ | ||
id: '1', | ||
title: 'Deleted Book', | ||
year: 2021, | ||
isbn: '1234567890', | ||
author: 'Author', | ||
avatar: 'avatar.png', | ||
description: 'A deleted book', | ||
}); | ||
}); | ||
}); | ||
|
||
describe('When we use the method delete with an invalid ID', () => { | ||
test('Then it should throw an error', async () => { | ||
(mockPrisma.book.findUnique as jest.Mock).mockResolvedValueOnce(null); | ||
await expect(repo.delete('2')).rejects.toThrow( | ||
new HttpError(404, 'Not Found', 'Book 2 not found') | ||
); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.