From 58f934ec89e38b9ab61bcad6a5663631bbabddf4 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Mon, 1 Jul 2024 11:00:05 +0200 Subject: [PATCH 01/21] set up project --- .env.example | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .env.example diff --git a/.env.example b/.env.example deleted file mode 100644 index 60f3a816..00000000 --- a/.env.example +++ /dev/null @@ -1,6 +0,0 @@ -DATABASE_URL="YOUR_DB_URL" - -# We need the following URL environment variable for test purposes: -# - TEST_DATABASE_URL must be a **completely separate** database from any other used in this file - -TEST_DATABASE_URL="YOUR_TEST_DB_URL" From 324db1956c54e36edefc187632c6649fc3fd3f3d Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Mon, 1 Jul 2024 11:28:08 +0200 Subject: [PATCH 02/21] add functions to update customer --- src/controllers/customer.js | 13 +++++++++++-- src/domains/customer.js | 11 ++++++++++- src/routers/customer.js | 5 ++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/controllers/customer.js b/src/controllers/customer.js index 775cfb42..251a2faa 100644 --- a/src/controllers/customer.js +++ b/src/controllers/customer.js @@ -1,5 +1,5 @@ const { PrismaClientKnownRequestError } = require("@prisma/client") -const { createCustomerDb } = require('../domains/customer.js') +const { createCustomerDb, updateCustomerDb } = require('../domains/customer.js') const createCustomer = async (req, res) => { const { @@ -43,6 +43,15 @@ const createCustomer = async (req, res) => { } } +async function updateCustomer(req, res) { + const customerId = Number(req.params.id) + const { name } = req.body + + const updatedCustomer = await updateCustomerDb(customerId, name) + res.status(201).json({customer: updatedCustomer}) +} + module.exports = { - createCustomer + createCustomer, + updateCustomer } diff --git a/src/domains/customer.js b/src/domains/customer.js index c7f315fd..52538652 100644 --- a/src/domains/customer.js +++ b/src/domains/customer.js @@ -21,6 +21,15 @@ const createCustomerDb = async (name, phone, email) => await prisma.customer.cre } }) +const updateCustomerDb = async (customerId, name) => await prisma.customer.update({ + where: {id: customerId}, + data: {name: name}, + include: { + contact: true + } +}) + module.exports = { - createCustomerDb + createCustomerDb, + updateCustomerDb } diff --git a/src/routers/customer.js b/src/routers/customer.js index f14a87fc..0835b1dd 100644 --- a/src/routers/customer.js +++ b/src/routers/customer.js @@ -1,6 +1,7 @@ const express = require("express"); const { - createCustomer + createCustomer, + updateCustomer } = require('../controllers/customer'); const router = express.Router(); @@ -10,4 +11,6 @@ const router = express.Router(); // that looks like http://localhost:4040/customer/register router.post("/register", createCustomer); +router.put('/:id', updateCustomer) + module.exports = router; From 86547fa8b2b0e4658be414a76d0675aa9411c099 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Mon, 1 Jul 2024 11:40:55 +0200 Subject: [PATCH 03/21] add functions to get all movies --- src/controllers/customer.js | 5 ++++- src/controllers/movie.js | 13 +++++++++++++ src/domains/customer.js | 8 ++++++-- src/domains/movie.js | 11 +++++++++++ src/routers/movie.js | 8 ++++++++ src/server.js | 2 ++ 6 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/controllers/movie.js create mode 100644 src/domains/movie.js create mode 100644 src/routers/movie.js diff --git a/src/controllers/customer.js b/src/controllers/customer.js index 251a2faa..096c8497 100644 --- a/src/controllers/customer.js +++ b/src/controllers/customer.js @@ -48,7 +48,10 @@ async function updateCustomer(req, res) { const { name } = req.body const updatedCustomer = await updateCustomerDb(customerId, name) - res.status(201).json({customer: updatedCustomer}) + + res.status(201).json({ + customer: updatedCustomer + }) } module.exports = { diff --git a/src/controllers/movie.js b/src/controllers/movie.js new file mode 100644 index 00000000..62af5a24 --- /dev/null +++ b/src/controllers/movie.js @@ -0,0 +1,13 @@ +const { getAllMoviesDb } = require("../domains/movie") + +async function getAllMovies(req, res) { + const movies = await getAllMoviesDb() + + res.json({ + movies + }) +} + +module.exports = { + getAllMovies + } \ No newline at end of file diff --git a/src/domains/customer.js b/src/domains/customer.js index 52538652..81a133c8 100644 --- a/src/domains/customer.js +++ b/src/domains/customer.js @@ -22,8 +22,12 @@ const createCustomerDb = async (name, phone, email) => await prisma.customer.cre }) const updateCustomerDb = async (customerId, name) => await prisma.customer.update({ - where: {id: customerId}, - data: {name: name}, + where: { + id: customerId + }, + data: { + name: name + }, include: { contact: true } diff --git a/src/domains/movie.js b/src/domains/movie.js new file mode 100644 index 00000000..52f3ab70 --- /dev/null +++ b/src/domains/movie.js @@ -0,0 +1,11 @@ +const prisma = require('../utils/prisma') + +const getAllMoviesDb = async () => await prisma.movie.findMany({ + include: { + screenings: true + } + }) + + module.exports = { + getAllMoviesDb + } \ No newline at end of file diff --git a/src/routers/movie.js b/src/routers/movie.js new file mode 100644 index 00000000..4936c91d --- /dev/null +++ b/src/routers/movie.js @@ -0,0 +1,8 @@ +const express = require("express"); +const { getAllMovies } = require("../controllers/movie"); + +const router = express.Router(); + +router.get('/', getAllMovies) + +module.exports = router; \ No newline at end of file diff --git a/src/server.js b/src/server.js index 93d47a16..6bd5986a 100644 --- a/src/server.js +++ b/src/server.js @@ -17,5 +17,7 @@ app.use(express.urlencoded({ extended: true })); const customerRouter = require('./routers/customer'); app.use('/customers', customerRouter); +const movieRouter = require('./routers/movie.js') +app.use('/movies', movieRouter); module.exports = app From 859a52aca34ff6414b441ed9b69e01462999ea26 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Mon, 1 Jul 2024 11:47:21 +0200 Subject: [PATCH 04/21] add functions to create movie --- src/controllers/movie.js | 15 +++++++++++++-- src/domains/movie.js | 14 ++++++++++++-- src/routers/movie.js | 3 ++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/controllers/movie.js b/src/controllers/movie.js index 62af5a24..66bf0cf0 100644 --- a/src/controllers/movie.js +++ b/src/controllers/movie.js @@ -1,4 +1,4 @@ -const { getAllMoviesDb } = require("../domains/movie") +const { getAllMoviesDb, createMovieDb } = require("../domains/movie") async function getAllMovies(req, res) { const movies = await getAllMoviesDb() @@ -8,6 +8,17 @@ async function getAllMovies(req, res) { }) } +async function createMovie(req, res) { + const { title, runtimeMins } = req.body + + const createdMovie = await createMovieDb(title, runtimeMins) + + res.status(201).json({ + movie: createdMovie + }) +} + module.exports = { - getAllMovies + getAllMovies, + createMovie } \ No newline at end of file diff --git a/src/domains/movie.js b/src/domains/movie.js index 52f3ab70..019acc32 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -4,8 +4,18 @@ const getAllMoviesDb = async () => await prisma.movie.findMany({ include: { screenings: true } - }) +}) + +const createMovieDb = async (title, runtimeMins) => await prisma.movie.create({ + data: { + title: title, + runtimeMins: runtimeMins + }, include: { + screenings: true + } +}) module.exports = { - getAllMoviesDb + getAllMoviesDb, + createMovieDb } \ No newline at end of file diff --git a/src/routers/movie.js b/src/routers/movie.js index 4936c91d..26241f5c 100644 --- a/src/routers/movie.js +++ b/src/routers/movie.js @@ -1,8 +1,9 @@ const express = require("express"); -const { getAllMovies } = require("../controllers/movie"); +const { getAllMovies, createMovie } = require("../controllers/movie"); const router = express.Router(); router.get('/', getAllMovies) +router.post('/', createMovie) module.exports = router; \ No newline at end of file From 7cc7076d73876f8266eb646a91239e7d1832b8b6 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Mon, 1 Jul 2024 11:52:40 +0200 Subject: [PATCH 05/21] add functions to get movie by id --- src/controllers/movie.js | 14 ++++++++++++-- src/domains/movie.js | 12 +++++++++++- src/routers/movie.js | 3 ++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/controllers/movie.js b/src/controllers/movie.js index 66bf0cf0..108e533e 100644 --- a/src/controllers/movie.js +++ b/src/controllers/movie.js @@ -1,4 +1,4 @@ -const { getAllMoviesDb, createMovieDb } = require("../domains/movie") +const { getAllMoviesDb, createMovieDb, getMovieByIdDb } = require("../domains/movie") async function getAllMovies(req, res) { const movies = await getAllMoviesDb() @@ -18,7 +18,17 @@ async function createMovie(req, res) { }) } +async function getMovieById(req, res) { + const movieId = Number(req.params.id) + const movie = await getMovieByIdDb(movieId) + + res.json({ + movie + }) +} + module.exports = { getAllMovies, - createMovie + createMovie, + getMovieById } \ No newline at end of file diff --git a/src/domains/movie.js b/src/domains/movie.js index 019acc32..837067bc 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -14,8 +14,18 @@ const createMovieDb = async (title, runtimeMins) => await prisma.movie.create({ screenings: true } }) + +const getMovieByIdDb = async (movieId) => await prisma.movie.findUnique({ + where: { + id: movieId + }, + include: { + screenings: true + } +}) module.exports = { getAllMoviesDb, - createMovieDb + createMovieDb, + getMovieByIdDb } \ No newline at end of file diff --git a/src/routers/movie.js b/src/routers/movie.js index 26241f5c..9c8d5452 100644 --- a/src/routers/movie.js +++ b/src/routers/movie.js @@ -1,9 +1,10 @@ const express = require("express"); -const { getAllMovies, createMovie } = require("../controllers/movie"); +const { getAllMovies, createMovie, getMovieById } = require("../controllers/movie"); const router = express.Router(); router.get('/', getAllMovies) router.post('/', createMovie) +router.get('/:id', getMovieById) module.exports = router; \ No newline at end of file From 71e0f30c77fc950e9b7a38117bbd99ed78d16f6c Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Mon, 1 Jul 2024 11:57:59 +0200 Subject: [PATCH 06/21] add functions to update movie --- src/controllers/movie.js | 17 +++++++++++++++-- src/domains/movie.js | 15 ++++++++++++++- src/routers/movie.js | 3 ++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/controllers/movie.js b/src/controllers/movie.js index 108e533e..105bcc6c 100644 --- a/src/controllers/movie.js +++ b/src/controllers/movie.js @@ -1,4 +1,4 @@ -const { getAllMoviesDb, createMovieDb, getMovieByIdDb } = require("../domains/movie") +const { getAllMoviesDb, createMovieDb, getMovieByIdDb, updateMovieDb } = require("../domains/movie") async function getAllMovies(req, res) { const movies = await getAllMoviesDb() @@ -20,6 +20,7 @@ async function createMovie(req, res) { async function getMovieById(req, res) { const movieId = Number(req.params.id) + const movie = await getMovieByIdDb(movieId) res.json({ @@ -27,8 +28,20 @@ async function getMovieById(req, res) { }) } +async function updateMovie(req, res) { + const movieId = Number(req.params.id) + const { title, runtimeMins } = req.body + + const updatedMovie = await updateMovieDb(movieId, title, runtimeMins) + + res.status(201).json({ + movie: updatedMovie + }) +} + module.exports = { getAllMovies, createMovie, - getMovieById + getMovieById, + updateMovie } \ No newline at end of file diff --git a/src/domains/movie.js b/src/domains/movie.js index 837067bc..0f99f0bf 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -23,9 +23,22 @@ const getMovieByIdDb = async (movieId) => await prisma.movie.findUnique({ screenings: true } }) + +const updateMovieDb = async (movieId, title, runtimeMins) => await prisma.movie.update({ + where: { + id: movieId + }, data: { + title: title, + runtimeMins: runtimeMins + }, + include: { + screenings: true + } +}) module.exports = { getAllMoviesDb, createMovieDb, - getMovieByIdDb + getMovieByIdDb, + updateMovieDb } \ No newline at end of file diff --git a/src/routers/movie.js b/src/routers/movie.js index 9c8d5452..c0350b2a 100644 --- a/src/routers/movie.js +++ b/src/routers/movie.js @@ -1,10 +1,11 @@ const express = require("express"); -const { getAllMovies, createMovie, getMovieById } = require("../controllers/movie"); +const { getAllMovies, createMovie, getMovieById, updateMovie } = require("../controllers/movie"); const router = express.Router(); router.get('/', getAllMovies) router.post('/', createMovie) router.get('/:id', getMovieById) +router.put('/:id', updateMovie) module.exports = router; \ No newline at end of file From b36e3b9a361e612ee6f63288fa1506deb9a25bbb Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Mon, 1 Jul 2024 12:08:12 +0200 Subject: [PATCH 07/21] add functions to create new screen --- src/controllers/screen.js | 15 +++++++++++++++ src/domains/screen.js | 11 +++++++++++ src/routers/screen.js | 8 ++++++++ src/server.js | 5 ++++- 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/controllers/screen.js create mode 100644 src/domains/screen.js create mode 100644 src/routers/screen.js diff --git a/src/controllers/screen.js b/src/controllers/screen.js new file mode 100644 index 00000000..5a267ea1 --- /dev/null +++ b/src/controllers/screen.js @@ -0,0 +1,15 @@ +const { createScreenDb } = require("../domains/screen") + +async function createScreen(req, res) { + const { number } = req.body + + const createdScreen = await createScreenDb(number) + + res.status(201).json({ + screen: createdScreen + }) +} + +module.exports = { + createScreen + } \ No newline at end of file diff --git a/src/domains/screen.js b/src/domains/screen.js new file mode 100644 index 00000000..4137a82f --- /dev/null +++ b/src/domains/screen.js @@ -0,0 +1,11 @@ +const prisma = require('../utils/prisma') + +const createScreenDb = async (number) => await prisma.screen.create({ + data: { + number: number + } +}) + + module.exports = { + createScreenDb + } \ No newline at end of file diff --git a/src/routers/screen.js b/src/routers/screen.js new file mode 100644 index 00000000..60704ae4 --- /dev/null +++ b/src/routers/screen.js @@ -0,0 +1,8 @@ +const express = require("express"); +const { createScreen } = require("../controllers/screen"); + +const router = express.Router(); + +router.post('/', createScreen) + +module.exports = router; \ No newline at end of file diff --git a/src/server.js b/src/server.js index 6bd5986a..89321a67 100644 --- a/src/server.js +++ b/src/server.js @@ -14,10 +14,13 @@ app.use(express.urlencoded({ extended: true })); // Tell express to use your routers here -const customerRouter = require('./routers/customer'); +const customerRouter = require('./routers/customer.js'); app.use('/customers', customerRouter); const movieRouter = require('./routers/movie.js') app.use('/movies', movieRouter); +const screenRouter = require('./routers/screen.js') +app.use('/screens', screenRouter) + module.exports = app From a20e031807304ca8fd1feb106d75d2b44cb5ad31 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Mon, 1 Jul 2024 12:53:33 +0200 Subject: [PATCH 08/21] add functions to get movies by query parameters and create tests --- src/controllers/movie.js | 5 +- src/domains/movie.js | 17 +++++- test/api/extensions/customer-ext.spec.js | 69 ++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/src/controllers/movie.js b/src/controllers/movie.js index 105bcc6c..ef4c3381 100644 --- a/src/controllers/movie.js +++ b/src/controllers/movie.js @@ -1,7 +1,10 @@ const { getAllMoviesDb, createMovieDb, getMovieByIdDb, updateMovieDb } = require("../domains/movie") async function getAllMovies(req, res) { - const movies = await getAllMoviesDb() + const runtimeLt = Number(req.query.runtimeLt) + const runtimeGt = Number(req.query.runtimeGt) + + const movies = await getAllMoviesDb(runtimeLt, runtimeGt) res.json({ movies diff --git a/src/domains/movie.js b/src/domains/movie.js index 0f99f0bf..71bcbef9 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -1,6 +1,21 @@ const prisma = require('../utils/prisma') -const getAllMoviesDb = async () => await prisma.movie.findMany({ +const getAllMoviesDb = async (runtimeLt, runtimeGt) => await prisma.movie.findMany({ + where: { + OR: [ + { + ...(runtimeLt ? { + runtimeMins: { + lt: runtimeLt + } + } : {})}, + {...(runtimeGt ? { + runtimeMins: { + gt: runtimeGt + } + } : {})} + ] + }, include: { screenings: true } diff --git a/test/api/extensions/customer-ext.spec.js b/test/api/extensions/customer-ext.spec.js index fee884bb..d02f10e0 100644 --- a/test/api/extensions/customer-ext.spec.js +++ b/test/api/extensions/customer-ext.spec.js @@ -1,6 +1,7 @@ const supertest = require("supertest") const app = require("../../../src/server.js") const { createCustomer } = require("../../helpers/createCustomer.js") +const { createMovie } = require("../../helpers/createMovie.js") describe("Customer Endpoint", () => { describe("PUT /customers/:id", () => { @@ -54,3 +55,71 @@ describe("Customer Endpoint", () => { }) }) }) + +describe("Movie Endpoint", () => { + describe("GET /movies?runtimeLt", () => { + it("will return movies with a runtime less than runtimeLt", async () => { + await createMovie("test1", 130) + await createMovie("test2", 135) + await createMovie('test3', 150) + + const response = await supertest(app) + .get('/movies?runtimeLt=140') + + expect(response.status).toEqual(200) + expect(response.body.movies).not.toEqual(undefined) + expect(response.body.movies.length).toEqual(2) + + const [movie1, movie2] = response.body.movies + expect(movie1.title).toEqual('test1') + expect(movie1.runtimeMins).toEqual(130) + + expect(movie2.title).toEqual('test2') + expect(movie2.runtimeMins).toEqual(135) + }) + }) + + describe("GET /movies?runtimeGt", () => { + it("will return movies with a runtime more than runtimeGt", async () => { + await createMovie("test1", 130) + await createMovie("test2", 135) + await createMovie('test3', 150) + + const response = await supertest(app) + .get('/movies?runtimeGt=134') + + expect(response.status).toEqual(200) + expect(response.body.movies).not.toEqual(undefined) + expect(response.body.movies.length).toEqual(2) + + const [movie1, movie2] = response.body.movies + expect(movie1.title).toEqual('test2') + expect(movie1.runtimeMins).toEqual(135) + + expect(movie2.title).toEqual('test3') + expect(movie2.runtimeMins).toEqual(150) + }) + }) + + describe("GET /movies?runtimeLt&runtimeGt", () => { + it("will return movies with a runtime less than runtimeLt and more than runtimeGt", async () => { + await createMovie("test1", 130) + await createMovie("test2", 140) + await createMovie('test3', 150) + + const response = await supertest(app) + .get('/movies?runtimeLt=135&runtimeGt=145') + + expect(response.status).toEqual(200) + expect(response.body.movies).not.toEqual(undefined) + expect(response.body.movies.length).toEqual(2) + + const [movie1, movie2] = response.body.movies + expect(movie1.title).toEqual('test1') + expect(movie1.runtimeMins).toEqual(130) + + expect(movie2.title).toEqual('test3') + expect(movie2.runtimeMins).toEqual(150) + }) + }) +}) From 454cc62e43204bf5cfcb6750ad5da2d3f191d53f Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Mon, 1 Jul 2024 15:52:44 +0200 Subject: [PATCH 09/21] add functions to create screenings and create test --- src/controllers/movie.js | 4 +-- src/domains/movie.js | 23 ++++++++++++--- test/api/extensions/customer-ext.spec.js | 36 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/controllers/movie.js b/src/controllers/movie.js index ef4c3381..f75d91ba 100644 --- a/src/controllers/movie.js +++ b/src/controllers/movie.js @@ -12,9 +12,9 @@ async function getAllMovies(req, res) { } async function createMovie(req, res) { - const { title, runtimeMins } = req.body + const { title, runtimeMins, screenings } = req.body - const createdMovie = await createMovieDb(title, runtimeMins) + const createdMovie = await createMovieDb(title, runtimeMins, screenings) res.status(201).json({ movie: createdMovie diff --git a/src/domains/movie.js b/src/domains/movie.js index 71bcbef9..82373628 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -21,14 +21,29 @@ const getAllMoviesDb = async (runtimeLt, runtimeGt) => await prisma.movie.findMa } }) -const createMovieDb = async (title, runtimeMins) => await prisma.movie.create({ - data: { +const createMovieDb = async (title, runtimeMins, screenings) => { + const movieData = { + data: { title: title, runtimeMins: runtimeMins - }, include: { + }, include: { screenings: true + } } -}) + + if(screenings) { + movieData.data.screenings = { + createMany: { + data: screenings.map((screening) => ({ + startsAt: screening.startsAt, + screenId: screening.screenId + })) + } + } + } + + return await prisma.movie.create(movieData) +} const getMovieByIdDb = async (movieId) => await prisma.movie.findUnique({ where: { diff --git a/test/api/extensions/customer-ext.spec.js b/test/api/extensions/customer-ext.spec.js index d02f10e0..9ea4dcd6 100644 --- a/test/api/extensions/customer-ext.spec.js +++ b/test/api/extensions/customer-ext.spec.js @@ -2,6 +2,7 @@ const supertest = require("supertest") const app = require("../../../src/server.js") const { createCustomer } = require("../../helpers/createCustomer.js") const { createMovie } = require("../../helpers/createMovie.js") +const { createScreen } = require("../../helpers/createScreen.js") describe("Customer Endpoint", () => { describe("PUT /customers/:id", () => { @@ -122,4 +123,39 @@ describe("Movie Endpoint", () => { expect(movie2.runtimeMins).toEqual(150) }) }) + + describe("POST /movies", () => { + it("will add a screening if the property exists in the body", async () => { + const screen1 = await createScreen(1) + const screen2 = await createScreen(2) + + const request = { + title: "Minions", + runtimeMins: 120, + screenings: [ + { + movieId: 1, + screenId: screen1.id, + startsAt: "2022-06-11T18:30:00.000Z" + }, + { + movieId: 1, + screenId: screen2.id, + startsAt: "2023-06-11T18:30:00.000Z" + } + ] + } + + const response = await supertest(app) + .post('/movies') + .send(request) + + expect(response.status).toEqual(201) + expect(response.body.movie).not.toEqual(undefined) + expect(response.body.movie.title).toEqual('Minions') + expect(response.body.movie.runtimeMins).toEqual(120) + expect(response.body.movie.screenings).not.toEqual(undefined) + expect(response.body.movie.screenings.length).toEqual(2) + }) + }) }) From 264c6a08934ef03fbc318d6929fa1577299793cf Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Mon, 1 Jul 2024 18:10:00 +0200 Subject: [PATCH 10/21] add get movie by title and clean up code --- src/controllers/movie.js | 6 +- src/domains/movie.js | 28 ++++-- src/routers/movie.js | 4 +- test/api/extensions/customer-ext.spec.js | 107 +---------------------- test/api/extensions/movie-ext.spec.js | 107 +++++++++++++++++++++++ 5 files changed, 134 insertions(+), 118 deletions(-) create mode 100644 test/api/extensions/movie-ext.spec.js diff --git a/src/controllers/movie.js b/src/controllers/movie.js index f75d91ba..e0fd3154 100644 --- a/src/controllers/movie.js +++ b/src/controllers/movie.js @@ -21,8 +21,8 @@ async function createMovie(req, res) { }) } -async function getMovieById(req, res) { - const movieId = Number(req.params.id) +async function getMovieByIdOrTitle(req, res) { + const movieId = req.params.id const movie = await getMovieByIdDb(movieId) @@ -45,6 +45,6 @@ async function updateMovie(req, res) { module.exports = { getAllMovies, createMovie, - getMovieById, + getMovieByIdOrTitle, updateMovie } \ No newline at end of file diff --git a/src/domains/movie.js b/src/domains/movie.js index 82373628..6ecd46e9 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -45,14 +45,28 @@ const createMovieDb = async (title, runtimeMins, screenings) => { return await prisma.movie.create(movieData) } -const getMovieByIdDb = async (movieId) => await prisma.movie.findUnique({ - where: { - id: movieId - }, - include: { - screenings: true +async function getMovieByIdDb (movieId) { + + if (!isNaN(movieId)) { + return await prisma.movie.findUnique({ + where: { + id: Number(movieId) + }, + include: { + screenings: true + } + }) + } else { + return await prisma.movie.findMany({ + where: { + title: movieId + }, + include: { + screenings: true + } + }) } -}) +} const updateMovieDb = async (movieId, title, runtimeMins) => await prisma.movie.update({ where: { diff --git a/src/routers/movie.js b/src/routers/movie.js index c0350b2a..9ddd48d8 100644 --- a/src/routers/movie.js +++ b/src/routers/movie.js @@ -1,11 +1,11 @@ const express = require("express"); -const { getAllMovies, createMovie, getMovieById, updateMovie } = require("../controllers/movie"); +const { getAllMovies, createMovie, getMovieById, updateMovie, getMovieByIdOrTitle } = require("../controllers/movie"); const router = express.Router(); router.get('/', getAllMovies) router.post('/', createMovie) -router.get('/:id', getMovieById) +router.get('/:id', getMovieByIdOrTitle) router.put('/:id', updateMovie) module.exports = router; \ No newline at end of file diff --git a/test/api/extensions/customer-ext.spec.js b/test/api/extensions/customer-ext.spec.js index 9ea4dcd6..9c977439 100644 --- a/test/api/extensions/customer-ext.spec.js +++ b/test/api/extensions/customer-ext.spec.js @@ -1,8 +1,6 @@ const supertest = require("supertest") const app = require("../../../src/server.js") const { createCustomer } = require("../../helpers/createCustomer.js") -const { createMovie } = require("../../helpers/createMovie.js") -const { createScreen } = require("../../helpers/createScreen.js") describe("Customer Endpoint", () => { describe("PUT /customers/:id", () => { @@ -55,107 +53,4 @@ describe("Customer Endpoint", () => { expect(response.body).toHaveProperty('error') }) }) -}) - -describe("Movie Endpoint", () => { - describe("GET /movies?runtimeLt", () => { - it("will return movies with a runtime less than runtimeLt", async () => { - await createMovie("test1", 130) - await createMovie("test2", 135) - await createMovie('test3', 150) - - const response = await supertest(app) - .get('/movies?runtimeLt=140') - - expect(response.status).toEqual(200) - expect(response.body.movies).not.toEqual(undefined) - expect(response.body.movies.length).toEqual(2) - - const [movie1, movie2] = response.body.movies - expect(movie1.title).toEqual('test1') - expect(movie1.runtimeMins).toEqual(130) - - expect(movie2.title).toEqual('test2') - expect(movie2.runtimeMins).toEqual(135) - }) - }) - - describe("GET /movies?runtimeGt", () => { - it("will return movies with a runtime more than runtimeGt", async () => { - await createMovie("test1", 130) - await createMovie("test2", 135) - await createMovie('test3', 150) - - const response = await supertest(app) - .get('/movies?runtimeGt=134') - - expect(response.status).toEqual(200) - expect(response.body.movies).not.toEqual(undefined) - expect(response.body.movies.length).toEqual(2) - - const [movie1, movie2] = response.body.movies - expect(movie1.title).toEqual('test2') - expect(movie1.runtimeMins).toEqual(135) - - expect(movie2.title).toEqual('test3') - expect(movie2.runtimeMins).toEqual(150) - }) - }) - - describe("GET /movies?runtimeLt&runtimeGt", () => { - it("will return movies with a runtime less than runtimeLt and more than runtimeGt", async () => { - await createMovie("test1", 130) - await createMovie("test2", 140) - await createMovie('test3', 150) - - const response = await supertest(app) - .get('/movies?runtimeLt=135&runtimeGt=145') - - expect(response.status).toEqual(200) - expect(response.body.movies).not.toEqual(undefined) - expect(response.body.movies.length).toEqual(2) - - const [movie1, movie2] = response.body.movies - expect(movie1.title).toEqual('test1') - expect(movie1.runtimeMins).toEqual(130) - - expect(movie2.title).toEqual('test3') - expect(movie2.runtimeMins).toEqual(150) - }) - }) - - describe("POST /movies", () => { - it("will add a screening if the property exists in the body", async () => { - const screen1 = await createScreen(1) - const screen2 = await createScreen(2) - - const request = { - title: "Minions", - runtimeMins: 120, - screenings: [ - { - movieId: 1, - screenId: screen1.id, - startsAt: "2022-06-11T18:30:00.000Z" - }, - { - movieId: 1, - screenId: screen2.id, - startsAt: "2023-06-11T18:30:00.000Z" - } - ] - } - - const response = await supertest(app) - .post('/movies') - .send(request) - - expect(response.status).toEqual(201) - expect(response.body.movie).not.toEqual(undefined) - expect(response.body.movie.title).toEqual('Minions') - expect(response.body.movie.runtimeMins).toEqual(120) - expect(response.body.movie.screenings).not.toEqual(undefined) - expect(response.body.movie.screenings.length).toEqual(2) - }) - }) -}) +}) \ No newline at end of file diff --git a/test/api/extensions/movie-ext.spec.js b/test/api/extensions/movie-ext.spec.js new file mode 100644 index 00000000..dd8352bc --- /dev/null +++ b/test/api/extensions/movie-ext.spec.js @@ -0,0 +1,107 @@ +const supertest = require("supertest") +const app = require("../../../src/server.js") +const { createMovie } = require("../../helpers/createMovie") +const { createScreen } = require("../../helpers/createScreen") + +describe("Movie Endpoint", () => { + describe("GET /movies?runtimeLt", () => { + it("will return movies with a runtime less than runtimeLt", async () => { + await createMovie("test1", 130) + await createMovie("test2", 135) + await createMovie('test3', 150) + + const response = await supertest(app) + .get('/movies?runtimeLt=140') + + expect(response.status).toEqual(200) + expect(response.body.movies).not.toEqual(undefined) + expect(response.body.movies.length).toEqual(2) + + const [movie1, movie2] = response.body.movies + expect(movie1.title).toEqual('test1') + expect(movie1.runtimeMins).toEqual(130) + + expect(movie2.title).toEqual('test2') + expect(movie2.runtimeMins).toEqual(135) + }) + }) + + describe("GET /movies?runtimeGt", () => { + it("will return movies with a runtime more than runtimeGt", async () => { + await createMovie("test1", 130) + await createMovie("test2", 135) + await createMovie('test3', 150) + + const response = await supertest(app) + .get('/movies?runtimeGt=134') + + expect(response.status).toEqual(200) + expect(response.body.movies).not.toEqual(undefined) + expect(response.body.movies.length).toEqual(2) + + const [movie1, movie2] = response.body.movies + expect(movie1.title).toEqual('test2') + expect(movie1.runtimeMins).toEqual(135) + + expect(movie2.title).toEqual('test3') + expect(movie2.runtimeMins).toEqual(150) + }) + }) + + describe("GET /movies?runtimeLt&runtimeGt", () => { + it("will return movies with a runtime less than runtimeLt and more than runtimeGt", async () => { + await createMovie("test1", 130) + await createMovie("test2", 140) + await createMovie('test3', 150) + + const response = await supertest(app) + .get('/movies?runtimeLt=135&runtimeGt=145') + + expect(response.status).toEqual(200) + expect(response.body.movies).not.toEqual(undefined) + expect(response.body.movies.length).toEqual(2) + + const [movie1, movie2] = response.body.movies + expect(movie1.title).toEqual('test1') + expect(movie1.runtimeMins).toEqual(130) + + expect(movie2.title).toEqual('test3') + expect(movie2.runtimeMins).toEqual(150) + }) + }) + + describe("POST /movies", () => { + it("will add a screening if the property exists in the body", async () => { + const screen1 = await createScreen(1) + const screen2 = await createScreen(2) + + const request = { + title: "Minions", + runtimeMins: 120, + screenings: [ + { + movieId: 1, + screenId: screen1.id, + startsAt: "2022-06-11T18:30:00.000Z" + }, + { + movieId: 1, + screenId: screen2.id, + startsAt: "2023-06-11T18:30:00.000Z" + } + ] + } + + const response = await supertest(app) + .post('/movies') + .send(request) + + expect(response.status).toEqual(201) + expect(response.body.movie).not.toEqual(undefined) + expect(response.body.movie.title).toEqual('Minions') + expect(response.body.movie.runtimeMins).toEqual(120) + expect(response.body.movie.screenings).not.toEqual(undefined) + expect(response.body.movie.screenings.length).toEqual(2) + }) + }) +}) From c7e504d095dc5f6c4e8e177a9ed8f8d62ce152b1 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Tue, 2 Jul 2024 09:47:15 +0200 Subject: [PATCH 11/21] create test to get movie by title --- src/domains/movie.js | 18 +++++++++--------- test/api/extensions/movie-ext.spec.js | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/domains/movie.js b/src/domains/movie.js index 6ecd46e9..49b0e605 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -56,16 +56,16 @@ async function getMovieByIdDb (movieId) { screenings: true } }) - } else { - return await prisma.movie.findMany({ - where: { - title: movieId - }, - include: { - screenings: true - } - }) } + + return await prisma.movie.findMany({ + where: { + title: movieId + }, + include: { + screenings: true + } + }) } const updateMovieDb = async (movieId, title, runtimeMins) => await prisma.movie.update({ diff --git a/test/api/extensions/movie-ext.spec.js b/test/api/extensions/movie-ext.spec.js index dd8352bc..fa1dfd19 100644 --- a/test/api/extensions/movie-ext.spec.js +++ b/test/api/extensions/movie-ext.spec.js @@ -104,4 +104,20 @@ describe("Movie Endpoint", () => { expect(response.body.movie.screenings.length).toEqual(2) }) }) + + describe("GET /movies/title", () => { + it("will get movies by title", async () => { + const screen = await createScreen(1) + const created = await createMovie('Dodgeball', 120, screen) + + const response = await supertest(app).get(`/movies/${created.title}`) + + expect(response.status).toEqual(200) + expect(response.body.movie).not.toEqual(undefined) + expect(response.body.movie[0].title).toEqual('Dodgeball') + expect(response.body.movie[0].runtimeMins).toEqual(120) + expect(response.body.movie[0].screenings).not.toEqual(undefined) + expect(response.body.movie[0].screenings.length).toEqual(1) + }) + }) }) From 3ddfb6bacd2dcca9f2be5c7cd8f26eb752eed0e8 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Tue, 2 Jul 2024 10:43:20 +0200 Subject: [PATCH 12/21] add functions to update screenings when updating movie and create tests --- src/controllers/movie.js | 4 +-- src/domains/movie.js | 37 +++++++++++++++++++-------- test/api/extensions/movie-ext.spec.js | 36 ++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/src/controllers/movie.js b/src/controllers/movie.js index e0fd3154..ab2f8cd1 100644 --- a/src/controllers/movie.js +++ b/src/controllers/movie.js @@ -33,9 +33,9 @@ async function getMovieByIdOrTitle(req, res) { async function updateMovie(req, res) { const movieId = Number(req.params.id) - const { title, runtimeMins } = req.body + const { title, runtimeMins, screenings } = req.body - const updatedMovie = await updateMovieDb(movieId, title, runtimeMins) + const updatedMovie = await updateMovieDb(movieId, title, runtimeMins, screenings) res.status(201).json({ movie: updatedMovie diff --git a/src/domains/movie.js b/src/domains/movie.js index 49b0e605..4a41bb8f 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -46,7 +46,6 @@ const createMovieDb = async (title, runtimeMins, screenings) => { } async function getMovieByIdDb (movieId) { - if (!isNaN(movieId)) { return await prisma.movie.findUnique({ where: { @@ -68,17 +67,33 @@ async function getMovieByIdDb (movieId) { }) } -const updateMovieDb = async (movieId, title, runtimeMins) => await prisma.movie.update({ - where: { - id: movieId - }, data: { - title: title, - runtimeMins: runtimeMins - }, - include: { - screenings: true +async function updateMovieDb(movieId, title, runtimeMins, screenings){ + const movieData = { + where: { + id: movieId + }, data: { + title: title, + runtimeMins: runtimeMins + }, + include: { + screenings: true + } } -}) + + if(screenings) { + movieData.data.screenings = { + deleteMany: {}, + createMany: { + data: screenings.map((screening) => ({ + startsAt: screening.startsAt, + screenId: screening.screenId + })) + } + } + } + + return await prisma.movie.update(movieData) +} module.exports = { getAllMoviesDb, diff --git a/test/api/extensions/movie-ext.spec.js b/test/api/extensions/movie-ext.spec.js index fa1dfd19..a0ad8fb2 100644 --- a/test/api/extensions/movie-ext.spec.js +++ b/test/api/extensions/movie-ext.spec.js @@ -120,4 +120,40 @@ describe("Movie Endpoint", () => { expect(response.body.movie[0].screenings.length).toEqual(1) }) }) + + describe("PUT /movies/:id", () => { + it("will update a movie by id and the screeninsg when provided", async () => { + const screen1 = await createScreen(1) + const screen2 = await createScreen(2) + const created = await createMovie('Dodgeball', 120, screen1) + + const request = { + title: 'Scream', + runtimeMins: 113, + screenings: [ + { + movieId: 1, + screenId: screen1.id, + startsAt: "2022-06-11T18:30:00.000Z" + }, + { + movieId: 1, + screenId: screen2.id, + startsAt: "2023-06-11T18:30:00.000Z" + } + ] + } + + const response = await supertest(app) + .put(`/movies/${created.id}`) + .send(request) + + expect(response.status).toEqual(201) + expect(response.body.movie).not.toEqual(undefined) + expect(response.body.movie.title).toEqual('Scream') + expect(response.body.movie.runtimeMins).toEqual(113) + expect(response.body.movie.screenings).not.toEqual(undefined) + expect(response.body.movie.screenings.length).toEqual(2) + }) + }) }) From a2bf500cd95e623cf65832be6472d5064bb00ee0 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Tue, 2 Jul 2024 11:10:48 +0200 Subject: [PATCH 13/21] add functions to create screenings when creating a screen and create tests --- src/controllers/customer.js | 6 ++--- src/controllers/screen.js | 4 +-- src/domains/customer.js | 34 +++++++++++++++++------- src/domains/screen.js | 26 ++++++++++++++++--- test/api/extensions/movie-ext.spec.js | 2 -- test/api/extensions/screen-ext.spec.js | 36 ++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 test/api/extensions/screen-ext.spec.js diff --git a/src/controllers/customer.js b/src/controllers/customer.js index 096c8497..9879620b 100644 --- a/src/controllers/customer.js +++ b/src/controllers/customer.js @@ -45,10 +45,10 @@ const createCustomer = async (req, res) => { async function updateCustomer(req, res) { const customerId = Number(req.params.id) - const { name } = req.body + const { name, contact } = req.body + + const updatedCustomer = await updateCustomerDb(customerId, name, contact) - const updatedCustomer = await updateCustomerDb(customerId, name) - res.status(201).json({ customer: updatedCustomer }) diff --git a/src/controllers/screen.js b/src/controllers/screen.js index 5a267ea1..88574291 100644 --- a/src/controllers/screen.js +++ b/src/controllers/screen.js @@ -1,9 +1,9 @@ const { createScreenDb } = require("../domains/screen") async function createScreen(req, res) { - const { number } = req.body + const { number, screenings } = req.body - const createdScreen = await createScreenDb(number) + const createdScreen = await createScreenDb(number, screenings) res.status(201).json({ screen: createdScreen diff --git a/src/domains/customer.js b/src/domains/customer.js index 81a133c8..f3f08fda 100644 --- a/src/domains/customer.js +++ b/src/domains/customer.js @@ -21,17 +21,31 @@ const createCustomerDb = async (name, phone, email) => await prisma.customer.cre } }) -const updateCustomerDb = async (customerId, name) => await prisma.customer.update({ - where: { - id: customerId - }, - data: { - name: name - }, - include: { - contact: true +async function updateCustomerDb(customerId, name, contact) { + const customerData = { + where: { + id: customerId + }, + data: { + name: name + }, + include: { + contact: true + } } -}) + + if(contact) { + customerData.data.contact = { + update: { + phone: contact.phone, + email: contact.email + } + } + } + + +return await prisma.customer.update(customerData) +} module.exports = { createCustomerDb, diff --git a/src/domains/screen.js b/src/domains/screen.js index 4137a82f..89445e52 100644 --- a/src/domains/screen.js +++ b/src/domains/screen.js @@ -1,10 +1,28 @@ const prisma = require('../utils/prisma') -const createScreenDb = async (number) => await prisma.screen.create({ - data: { - number: number +async function createScreenDb(number, screenings) { + const screenData = { + data: { + number: number + }, + include: { + screenings: true + } } -}) + + if(screenings) { + screenData.data.screenings = { + createMany: { + data: screenings.map((screening) => ({ + startsAt: screening.startsAt, + movieId: screening.movieId + })) + } + } + } + + return await prisma.screen.create(screenData) +} module.exports = { createScreenDb diff --git a/test/api/extensions/movie-ext.spec.js b/test/api/extensions/movie-ext.spec.js index a0ad8fb2..ebd8c298 100644 --- a/test/api/extensions/movie-ext.spec.js +++ b/test/api/extensions/movie-ext.spec.js @@ -132,12 +132,10 @@ describe("Movie Endpoint", () => { runtimeMins: 113, screenings: [ { - movieId: 1, screenId: screen1.id, startsAt: "2022-06-11T18:30:00.000Z" }, { - movieId: 1, screenId: screen2.id, startsAt: "2023-06-11T18:30:00.000Z" } diff --git a/test/api/extensions/screen-ext.spec.js b/test/api/extensions/screen-ext.spec.js new file mode 100644 index 00000000..691fc5d9 --- /dev/null +++ b/test/api/extensions/screen-ext.spec.js @@ -0,0 +1,36 @@ +const supertest = require("supertest") +const app = require("../../../src/server.js") +const { createMovie } = require("../../helpers/createMovie") + +describe("Screen Endpoint", () => { + describe("POST /screens", () => { + it("will create screenings for a movie if the request body has a screenings property", async () => { + const movie1 = await createMovie("test1", 130) + const movie2 = await createMovie("test2", 150) + + const request = { + number: 10, + screenings: [ + { + movieId: movie1.id, + startsAt: "2022-06-11T18:30:00.000Z" + }, + { + movieId: movie2.id, + startsAt: "2023-06-11T18:30:00.000Z" + } + ] + } + + const response = await supertest(app) + .post("/screens") + .send(request) + + expect(response.status).toEqual(201) + expect(response.body.screen).not.toEqual(undefined) + expect(response.body.screen.number).toEqual(10) + expect(response.body.screen.screenings).not.toEqual(undefined) + expect(response.body.screen.screenings.length).toEqual(2) + }) + }) +}) \ No newline at end of file From 464d6a7354aa23c6d31b1b6fbcb9e8eb9e7a2e5b Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Tue, 2 Jul 2024 11:49:49 +0200 Subject: [PATCH 14/21] add functions to create ticket and create tests --- src/controllers/ticket.js | 15 +++++++++++ src/domains/movie.js | 12 ++++----- src/domains/ticket.js | 30 +++++++++++++++++++++ src/routers/ticket.js | 8 ++++++ src/server.js | 3 +++ test/api/extensions/movie-ext.spec.js | 4 +-- test/api/extensions/ticket-ext.spec.js | 37 ++++++++++++++++++++++++++ 7 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 src/controllers/ticket.js create mode 100644 src/domains/ticket.js create mode 100644 src/routers/ticket.js create mode 100644 test/api/extensions/ticket-ext.spec.js diff --git a/src/controllers/ticket.js b/src/controllers/ticket.js new file mode 100644 index 00000000..56c6364f --- /dev/null +++ b/src/controllers/ticket.js @@ -0,0 +1,15 @@ +const { createTicketDb } = require("../domains/ticket") + +async function createTicket(req, res) { + const { screeningId, customerId } = req.body + + const createdTicket = await createTicketDb(screeningId, customerId) + + res.status(201).json({ + ticket: createdTicket + }) +} + +module.exports = { + createTicket + } \ No newline at end of file diff --git a/src/domains/movie.js b/src/domains/movie.js index 4a41bb8f..b41027b7 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -95,9 +95,9 @@ async function updateMovieDb(movieId, title, runtimeMins, screenings){ return await prisma.movie.update(movieData) } - module.exports = { - getAllMoviesDb, - createMovieDb, - getMovieByIdDb, - updateMovieDb - } \ No newline at end of file +module.exports = { +getAllMoviesDb, +createMovieDb, +getMovieByIdDb, +updateMovieDb +} \ No newline at end of file diff --git a/src/domains/ticket.js b/src/domains/ticket.js new file mode 100644 index 00000000..ccf7d3cf --- /dev/null +++ b/src/domains/ticket.js @@ -0,0 +1,30 @@ +const prisma = require('../utils/prisma') + +const createTicketDb = async (screeningId, customerId) => { + const ticketData = { + data: { + screeningId: screeningId, + customerId: customerId + }, include: { + screening: true, + customer: true, + customer: { + include: { + contact: true + } + }, + screening: { + include: { + screen: true, + movie: true + } + } + } + } + + return await prisma.ticket.create(ticketData) +} + +module.exports = { + createTicketDb +} \ No newline at end of file diff --git a/src/routers/ticket.js b/src/routers/ticket.js new file mode 100644 index 00000000..25e9350a --- /dev/null +++ b/src/routers/ticket.js @@ -0,0 +1,8 @@ +const express = require("express"); +const { createTicket } = require("../controllers/ticket"); + +const router = express.Router(); + +router.post('/', createTicket) + +module.exports = router; \ No newline at end of file diff --git a/src/server.js b/src/server.js index 89321a67..f73fc340 100644 --- a/src/server.js +++ b/src/server.js @@ -23,4 +23,7 @@ app.use('/movies', movieRouter); const screenRouter = require('./routers/screen.js') app.use('/screens', screenRouter) +const ticketRouter = require('./routers/ticket.js') +app.use('/tickets', ticketRouter) + module.exports = app diff --git a/test/api/extensions/movie-ext.spec.js b/test/api/extensions/movie-ext.spec.js index ebd8c298..e7841a07 100644 --- a/test/api/extensions/movie-ext.spec.js +++ b/test/api/extensions/movie-ext.spec.js @@ -108,9 +108,9 @@ describe("Movie Endpoint", () => { describe("GET /movies/title", () => { it("will get movies by title", async () => { const screen = await createScreen(1) - const created = await createMovie('Dodgeball', 120, screen) + const movie = await createMovie('Dodgeball', 120, screen) - const response = await supertest(app).get(`/movies/${created.title}`) + const response = await supertest(app).get(`/movies/${movie.title}`) expect(response.status).toEqual(200) expect(response.body.movie).not.toEqual(undefined) diff --git a/test/api/extensions/ticket-ext.spec.js b/test/api/extensions/ticket-ext.spec.js new file mode 100644 index 00000000..9e28a676 --- /dev/null +++ b/test/api/extensions/ticket-ext.spec.js @@ -0,0 +1,37 @@ +const supertest = require("supertest") +const app = require("../../../src/server.js") +const { createCustomer } = require("../../helpers/createCustomer.js") +const { createScreen } = require("../../helpers/createScreen") +const { createMovie } = require("../../helpers/createMovie") + + +describe("Ticket Endpoint", () => { + describe("POST /tickets", () => { + it("can create a ticket", async () => { + const customer = await createCustomer("John", "123456", "john@test.com") + const screen = await createScreen(1) + const movie = await createMovie('Dodgeball', 120, screen) + + + const request = { + screeningId: movie.screenings[0].id, + customerId: customer.id + } + + const response = await supertest(app) + .post('/tickets') + .send(request) + + expect(response.status).toEqual(201) + expect(response.body.ticket.customer).not.toEqual(undefined) + expect(response.body.ticket.customer.name).toEqual("John") + expect(response.body.ticket.customer.contact).not.toEqual(undefined) + expect(response.body.ticket.customer.contact.phone).toEqual("123456") + expect(response.body.ticket.customer.contact.email).toEqual("john@test.com") + expect(response.body.ticket.screening).not.toEqual(undefined) + expect(response.body.ticket.screening.screen.number).toEqual(1) + expect(response.body.ticket.screening.movie.title).toEqual("Dodgeball") + expect(response.body.ticket.screening.movie.runtimeMins).toEqual(120) + }) + }) +}) \ No newline at end of file From 383a5ee09d46c9705d0361a208b89b84a4e71ced Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Tue, 2 Jul 2024 13:35:07 +0200 Subject: [PATCH 15/21] add error handling for missing fields --- package-lock.json | 9 ++++++++ package.json | 1 + src/controllers/customer.js | 5 +++++ src/controllers/movie.js | 9 ++++++++ src/controllers/screen.js | 5 +++++ src/controllers/ticket.js | 5 +++++ src/errors/missingFieldsError.js | 5 +++++ src/server.js | 29 +++++++++++++++++++++++++- test/api/extensions/movie-ext.spec.js | 27 +++++++++++++++++++++++- test/api/extensions/screen-ext.spec.js | 11 ++++++++++ test/api/extensions/ticket-ext.spec.js | 11 ++++++++++ 11 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 src/errors/missingFieldsError.js diff --git a/package-lock.json b/package-lock.json index 0fc727e5..a9b8b9e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", + "express-async-errors": "^3.1.1", "morgan": "^1.10.0" }, "devDependencies": { @@ -2146,6 +2147,14 @@ "node": ">= 0.10.0" } }, + "node_modules/express-async-errors": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/express-async-errors/-/express-async-errors-3.1.1.tgz", + "integrity": "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==", + "peerDependencies": { + "express": "^4.16.2" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", diff --git a/package.json b/package.json index ebaf03be..35df3710 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", + "express-async-errors": "^3.1.1", "morgan": "^1.10.0" } } diff --git a/src/controllers/customer.js b/src/controllers/customer.js index 9879620b..4bf259da 100644 --- a/src/controllers/customer.js +++ b/src/controllers/customer.js @@ -1,5 +1,6 @@ const { PrismaClientKnownRequestError } = require("@prisma/client") const { createCustomerDb, updateCustomerDb } = require('../domains/customer.js') +const MissingFieldsError = require("../errors/missingFieldsError.js") const createCustomer = async (req, res) => { const { @@ -47,6 +48,10 @@ async function updateCustomer(req, res) { const customerId = Number(req.params.id) const { name, contact } = req.body + if (!name || !contact.phone || !contact.email) { + throw new MissingFieldsError('Missing fields in request body') + } + const updatedCustomer = await updateCustomerDb(customerId, name, contact) res.status(201).json({ diff --git a/src/controllers/movie.js b/src/controllers/movie.js index ab2f8cd1..f35f07c3 100644 --- a/src/controllers/movie.js +++ b/src/controllers/movie.js @@ -1,4 +1,5 @@ const { getAllMoviesDb, createMovieDb, getMovieByIdDb, updateMovieDb } = require("../domains/movie") +const MissingFieldsError = require("../errors/missingFieldsError") async function getAllMovies(req, res) { const runtimeLt = Number(req.query.runtimeLt) @@ -14,6 +15,10 @@ async function getAllMovies(req, res) { async function createMovie(req, res) { const { title, runtimeMins, screenings } = req.body + if (!title || !runtimeMins) { + throw new MissingFieldsError('Missing fields in request body') + } + const createdMovie = await createMovieDb(title, runtimeMins, screenings) res.status(201).json({ @@ -35,6 +40,10 @@ async function updateMovie(req, res) { const movieId = Number(req.params.id) const { title, runtimeMins, screenings } = req.body + if (!title || !runtimeMins) { + throw new MissingFieldsError('Missing fields in request body') + } + const updatedMovie = await updateMovieDb(movieId, title, runtimeMins, screenings) res.status(201).json({ diff --git a/src/controllers/screen.js b/src/controllers/screen.js index 88574291..73b1c381 100644 --- a/src/controllers/screen.js +++ b/src/controllers/screen.js @@ -1,8 +1,13 @@ const { createScreenDb } = require("../domains/screen") +const MissingFieldsError = require("../errors/missingFieldsError") async function createScreen(req, res) { const { number, screenings } = req.body + if (!number) { + throw new MissingFieldsError('Missing fields in request body') + } + const createdScreen = await createScreenDb(number, screenings) res.status(201).json({ diff --git a/src/controllers/ticket.js b/src/controllers/ticket.js index 56c6364f..0f3147a9 100644 --- a/src/controllers/ticket.js +++ b/src/controllers/ticket.js @@ -1,8 +1,13 @@ const { createTicketDb } = require("../domains/ticket") +const MissingFieldsError = require("../errors/missingFieldsError") async function createTicket(req, res) { const { screeningId, customerId } = req.body + if (!screeningId || !customerId) { + throw new MissingFieldsError('Missing fields in request body') + } + const createdTicket = await createTicketDb(screeningId, customerId) res.status(201).json({ diff --git a/src/errors/missingFieldsError.js b/src/errors/missingFieldsError.js new file mode 100644 index 00000000..7359cc1a --- /dev/null +++ b/src/errors/missingFieldsError.js @@ -0,0 +1,5 @@ +class MissingFieldsError extends Error { + +} + +module.exports = MissingFieldsError \ No newline at end of file diff --git a/src/server.js b/src/server.js index f73fc340..7b2b7f9f 100644 --- a/src/server.js +++ b/src/server.js @@ -1,4 +1,5 @@ const express = require('express'); +require('express-async-errors'); const app = express(); const cors = require('cors'); @@ -23,7 +24,33 @@ app.use('/movies', movieRouter); const screenRouter = require('./routers/screen.js') app.use('/screens', screenRouter) -const ticketRouter = require('./routers/ticket.js') +const ticketRouter = require('./routers/ticket.js'); app.use('/tickets', ticketRouter) +const MissingFieldsError = require('./errors/missingFieldsError.js'); + +app.use((error, req, res, next) => { + if (error instanceof MissingFieldsError) { + return res.status(400).json({ + error: error.message + }) + } + + // if (error instanceof NotFoundError) { + // return res.status(404).json({ + // error: error.message + // }) + // } + + // if (error instanceof NotUniqueError) { + // return res.status(409).json({ + // error: error.message + // }) + // } + + res.status(500).json({ + message: 'Something went wrong' + }) +}) + module.exports = app diff --git a/test/api/extensions/movie-ext.spec.js b/test/api/extensions/movie-ext.spec.js index e7841a07..56d5a5ae 100644 --- a/test/api/extensions/movie-ext.spec.js +++ b/test/api/extensions/movie-ext.spec.js @@ -103,6 +103,17 @@ describe("Movie Endpoint", () => { expect(response.body.movie.screenings).not.toEqual(undefined) expect(response.body.movie.screenings.length).toEqual(2) }) + + it("will return 400 when there are missing fields in the request body", async () => { + const request = {} + + const response = await supertest(app) + .post('/movies') + .send(request) + + expect(response.status).toEqual(400) + expect(response.body).toHaveProperty('error') + }) }) describe("GET /movies/title", () => { @@ -122,7 +133,7 @@ describe("Movie Endpoint", () => { }) describe("PUT /movies/:id", () => { - it("will update a movie by id and the screeninsg when provided", async () => { + it("will update a movie by id and the screenings when provided", async () => { const screen1 = await createScreen(1) const screen2 = await createScreen(2) const created = await createMovie('Dodgeball', 120, screen1) @@ -153,5 +164,19 @@ describe("Movie Endpoint", () => { expect(response.body.movie.screenings).not.toEqual(undefined) expect(response.body.movie.screenings.length).toEqual(2) }) + + it("will return 400 when there are missing fields in the request body", async () => { + const screen = await createScreen(1) + const movie = await createMovie('Dodgeball', 120, screen) + + const request = {} + + const response = await supertest(app) + .put(`/movies/${movie.id}`) + .send(request) + + expect(response.status).toEqual(400) + expect(response.body).toHaveProperty('error') + }) }) }) diff --git a/test/api/extensions/screen-ext.spec.js b/test/api/extensions/screen-ext.spec.js index 691fc5d9..5dfbfb79 100644 --- a/test/api/extensions/screen-ext.spec.js +++ b/test/api/extensions/screen-ext.spec.js @@ -32,5 +32,16 @@ describe("Screen Endpoint", () => { expect(response.body.screen.screenings).not.toEqual(undefined) expect(response.body.screen.screenings.length).toEqual(2) }) + + it("will return 400 when there are missing fields in the request body", async () => { + const request = {} + + const response = await supertest(app) + .post('/movies') + .send(request) + + expect(response.status).toEqual(400) + expect(response.body).toHaveProperty('error') + }) }) }) \ No newline at end of file diff --git a/test/api/extensions/ticket-ext.spec.js b/test/api/extensions/ticket-ext.spec.js index 9e28a676..defb2f72 100644 --- a/test/api/extensions/ticket-ext.spec.js +++ b/test/api/extensions/ticket-ext.spec.js @@ -33,5 +33,16 @@ describe("Ticket Endpoint", () => { expect(response.body.ticket.screening.movie.title).toEqual("Dodgeball") expect(response.body.ticket.screening.movie.runtimeMins).toEqual(120) }) + + it("will return 400 when there are missing fields in the request body", async () => { + const request = {} + + const response = await supertest(app) + .post('/tickets') + .send(request) + + expect(response.status).toEqual(400) + expect(response.body).toHaveProperty('error') + }) }) }) \ No newline at end of file From c9c48fa01369397ada4951be597455034899f591 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Tue, 2 Jul 2024 15:35:54 +0200 Subject: [PATCH 16/21] add not found error handling and tests --- src/controllers/customer.js | 25 ++++++++---- src/controllers/movie.js | 47 +++++++++++++++++++---- src/domains/customer.js | 4 +- src/domains/movie.js | 55 +++++++++++++++++---------- src/domains/ticket.js | 2 +- src/errors/notFoundError.js | 5 +++ src/server.js | 13 ++++--- test/api/extensions/movie-ext.spec.js | 16 ++++++++ 8 files changed, 121 insertions(+), 46 deletions(-) create mode 100644 src/errors/notFoundError.js diff --git a/src/controllers/customer.js b/src/controllers/customer.js index 4bf259da..75c82401 100644 --- a/src/controllers/customer.js +++ b/src/controllers/customer.js @@ -1,6 +1,7 @@ const { PrismaClientKnownRequestError } = require("@prisma/client") const { createCustomerDb, updateCustomerDb } = require('../domains/customer.js') const MissingFieldsError = require("../errors/missingFieldsError.js") +const NotFoundError = require("../errors/notFoundError.js") const createCustomer = async (req, res) => { const { @@ -10,9 +11,7 @@ const createCustomer = async (req, res) => { } = req.body if (!name || !phone || !email) { - return res.status(400).json({ - error: "Missing fields in request body" - }) + throw new MissingFieldsError('Missing fields in request body') } // Try-catch is a very common way to handle errors in JavaScript. @@ -48,15 +47,25 @@ async function updateCustomer(req, res) { const customerId = Number(req.params.id) const { name, contact } = req.body - if (!name || !contact.phone || !contact.email) { + if (!name) { throw new MissingFieldsError('Missing fields in request body') } - const updatedCustomer = await updateCustomerDb(customerId, name, contact) + try { + const updatedCustomer = await updateCustomerDb(customerId, name, contact) + + res.status(201).json({ + customer: updatedCustomer + }) + } catch (e) { + if (e instanceof PrismaClientKnownRequestError) { + if (e.code === "P2025") { + throw new NotFoundError('Customer with that id does not exist') + } + } - res.status(201).json({ - customer: updatedCustomer - }) + res.status(500).json({ error: e.message }) + } } module.exports = { diff --git a/src/controllers/movie.js b/src/controllers/movie.js index f35f07c3..4a849427 100644 --- a/src/controllers/movie.js +++ b/src/controllers/movie.js @@ -1,5 +1,7 @@ +const { PrismaClientKnownRequestError } = require("@prisma/client/runtime/library") const { getAllMoviesDb, createMovieDb, getMovieByIdDb, updateMovieDb } = require("../domains/movie") const MissingFieldsError = require("../errors/missingFieldsError") +const NotFoundError = require("../errors/notFoundError") async function getAllMovies(req, res) { const runtimeLt = Number(req.query.runtimeLt) @@ -29,11 +31,30 @@ async function createMovie(req, res) { async function getMovieByIdOrTitle(req, res) { const movieId = req.params.id - const movie = await getMovieByIdDb(movieId) + try { + const movie = await getMovieByIdDb(movieId) + + if(movie.length === 0) { + throw new NotFoundError + } + + res.json({ + movie + }) + } catch (e) { + if (e instanceof PrismaClientKnownRequestError) { + if (e.code === "P2025") { + throw new NotFoundError('Movie with that id or title does not exist') + } + } + + if (e instanceof NotFoundError) { + throw new NotFoundError('Movie with that id or title does not exist') + } + + res.status(500).json({ error: e.message }) + } - res.json({ - movie - }) } async function updateMovie(req, res) { @@ -44,11 +65,21 @@ async function updateMovie(req, res) { throw new MissingFieldsError('Missing fields in request body') } - const updatedMovie = await updateMovieDb(movieId, title, runtimeMins, screenings) + try { + const updatedMovie = await updateMovieDb(movieId, title, runtimeMins, screenings) - res.status(201).json({ - movie: updatedMovie - }) + res.status(201).json({ + movie: updatedMovie + }) + } catch (e) { + if (e instanceof PrismaClientKnownRequestError) { + if (e.code === "P2025") { + throw new NotFoundError('Movie with that id or title does not exist') + } + } + + res.status(500).json({ error: e.message }) + } } module.exports = { diff --git a/src/domains/customer.js b/src/domains/customer.js index f3f08fda..fe5e36dd 100644 --- a/src/domains/customer.js +++ b/src/domains/customer.js @@ -1,3 +1,4 @@ +const NotFoundError = require('../errors/notFoundError') const prisma = require('../utils/prisma') /** @@ -43,8 +44,7 @@ async function updateCustomerDb(customerId, name, contact) { } } - -return await prisma.customer.update(customerData) + return await prisma.customer.update(customerData) } module.exports = { diff --git a/src/domains/movie.js b/src/domains/movie.js index b41027b7..d6fef6f2 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -1,27 +1,40 @@ const prisma = require('../utils/prisma') -const getAllMoviesDb = async (runtimeLt, runtimeGt) => await prisma.movie.findMany({ - where: { - OR: [ - { - ...(runtimeLt ? { - runtimeMins: { - lt: runtimeLt - } - } : {})}, - {...(runtimeGt ? { - runtimeMins: { - gt: runtimeGt +async function getAllMoviesDb(runtimeLt, runtimeGt) { + let movieData = null + + if (runtimeLt || runtimeGt) { + movieData = { + where: { + OR: [ + { + ...(runtimeLt ? { + runtimeMins: { + lt: runtimeLt + } + } : {})}, + {...(runtimeGt ? { + runtimeMins: { + gt: runtimeGt + } + } : {})} + ] + }, + include: { + screenings: true + } + }} else { + movieData = { + include: { + screenings: true } - } : {})} - ] - }, - include: { - screenings: true + } } -}) -const createMovieDb = async (title, runtimeMins, screenings) => { + return prisma.movie.findMany(movieData) +} + +async function createMovieDb(title, runtimeMins, screenings) { const movieData = { data: { title: title, @@ -47,7 +60,7 @@ const createMovieDb = async (title, runtimeMins, screenings) => { async function getMovieByIdDb (movieId) { if (!isNaN(movieId)) { - return await prisma.movie.findUnique({ + return await prisma.movie.findUniqueOrThrow({ where: { id: Number(movieId) }, @@ -67,7 +80,7 @@ async function getMovieByIdDb (movieId) { }) } -async function updateMovieDb(movieId, title, runtimeMins, screenings){ +async function updateMovieDb(movieId, title, runtimeMins, screenings) { const movieData = { where: { id: movieId diff --git a/src/domains/ticket.js b/src/domains/ticket.js index ccf7d3cf..99a0be83 100644 --- a/src/domains/ticket.js +++ b/src/domains/ticket.js @@ -1,6 +1,6 @@ const prisma = require('../utils/prisma') -const createTicketDb = async (screeningId, customerId) => { +async function createTicketDb(screeningId, customerId) { const ticketData = { data: { screeningId: screeningId, diff --git a/src/errors/notFoundError.js b/src/errors/notFoundError.js new file mode 100644 index 00000000..0a1f7abc --- /dev/null +++ b/src/errors/notFoundError.js @@ -0,0 +1,5 @@ +class NotFoundError extends Error { + +} + +module.exports = NotFoundError \ No newline at end of file diff --git a/src/server.js b/src/server.js index 7b2b7f9f..4db5e18c 100644 --- a/src/server.js +++ b/src/server.js @@ -28,6 +28,7 @@ const ticketRouter = require('./routers/ticket.js'); app.use('/tickets', ticketRouter) const MissingFieldsError = require('./errors/missingFieldsError.js'); +const NotFoundError = require('./errors/notFoundError.js'); app.use((error, req, res, next) => { if (error instanceof MissingFieldsError) { @@ -36,11 +37,11 @@ app.use((error, req, res, next) => { }) } - // if (error instanceof NotFoundError) { - // return res.status(404).json({ - // error: error.message - // }) - // } + if (error instanceof NotFoundError) { + return res.status(404).json({ + error: error.message + }) + } // if (error instanceof NotUniqueError) { // return res.status(409).json({ @@ -49,7 +50,7 @@ app.use((error, req, res, next) => { // } res.status(500).json({ - message: 'Something went wrong' + error: error.message }) }) diff --git a/test/api/extensions/movie-ext.spec.js b/test/api/extensions/movie-ext.spec.js index 56d5a5ae..f29fd946 100644 --- a/test/api/extensions/movie-ext.spec.js +++ b/test/api/extensions/movie-ext.spec.js @@ -130,6 +130,22 @@ describe("Movie Endpoint", () => { expect(response.body.movie[0].screenings).not.toEqual(undefined) expect(response.body.movie[0].screenings.length).toEqual(1) }) + + it('will return 404 if the movie is not found by id', async () => { + const response = await supertest(app) + .get('/movies/10000') + + expect(response.status).toEqual(404) + expect(response.body).toHaveProperty('error') + }) + + it('will return 404 if the movie is not found by title', async () => { + const response = await supertest(app) + .get('/movies/bkdscjcd') + + expect(response.status).toEqual(404) + expect(response.body).toHaveProperty('error') + }) }) describe("PUT /movies/:id", () => { From b219bcaedb587a90d06b513aad46ed2a514d682d Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Tue, 2 Jul 2024 16:38:50 +0200 Subject: [PATCH 17/21] add not unique error handling and tests --- .../20240702135814_make_unique/migration.sql | 12 ++++++ prisma/schema.prisma | 10 ++--- src/controllers/movie.js | 23 ++++++---- src/controllers/screen.js | 20 +++++++-- src/domains/movie.js | 2 +- src/errors/notUniqueError.js | 5 +++ src/routers/movie.js | 2 +- src/server.js | 43 ++++++++++--------- test/api/extensions/movie-ext.spec.js | 25 +++++++++-- test/api/extensions/screen-ext.spec.js | 16 +++++++ 10 files changed, 114 insertions(+), 44 deletions(-) create mode 100644 prisma/migrations/20240702135814_make_unique/migration.sql create mode 100644 src/errors/notUniqueError.js diff --git a/prisma/migrations/20240702135814_make_unique/migration.sql b/prisma/migrations/20240702135814_make_unique/migration.sql new file mode 100644 index 00000000..f8077248 --- /dev/null +++ b/prisma/migrations/20240702135814_make_unique/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - A unique constraint covering the columns `[title]` on the table `Movie` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[number]` on the table `Screen` will be added. If there are existing duplicate values, this will fail. + +*/ +-- CreateIndex +CREATE UNIQUE INDEX "Movie_title_key" ON "Movie"("title"); + +-- CreateIndex +CREATE UNIQUE INDEX "Screen_number_key" ON "Screen"("number"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index dd9b27f1..55dcab1a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -33,18 +33,18 @@ model Contact { model Movie { id Int @id @default(autoincrement()) screenings Screening[] - title String + title String @unique runtimeMins Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Screen { - id Int @id @default(autoincrement()) - number Int + id Int @id @default(autoincrement()) + number Int @unique screenings Screening[] - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt } model Screening { diff --git a/src/controllers/movie.js b/src/controllers/movie.js index 4a849427..222d13af 100644 --- a/src/controllers/movie.js +++ b/src/controllers/movie.js @@ -2,6 +2,7 @@ const { PrismaClientKnownRequestError } = require("@prisma/client/runtime/librar const { getAllMoviesDb, createMovieDb, getMovieByIdDb, updateMovieDb } = require("../domains/movie") const MissingFieldsError = require("../errors/missingFieldsError") const NotFoundError = require("../errors/notFoundError") +const NotUniqueError = require("../errors/notUniqueError") async function getAllMovies(req, res) { const runtimeLt = Number(req.query.runtimeLt) @@ -21,11 +22,21 @@ async function createMovie(req, res) { throw new MissingFieldsError('Missing fields in request body') } - const createdMovie = await createMovieDb(title, runtimeMins, screenings) + try { + const createdMovie = await createMovieDb(title, runtimeMins, screenings) - res.status(201).json({ - movie: createdMovie - }) + res.status(201).json({ + movie: createdMovie + }) + } catch (e) { + if (e instanceof PrismaClientKnownRequestError) { + if (e.code === "P2002") { + throw new NotUniqueError('A movie with the provided title already exists') + } + } + + res.status(500).json({ error: e.message }) + } } async function getMovieByIdOrTitle(req, res) { @@ -33,10 +44,6 @@ async function getMovieByIdOrTitle(req, res) { try { const movie = await getMovieByIdDb(movieId) - - if(movie.length === 0) { - throw new NotFoundError - } res.json({ movie diff --git a/src/controllers/screen.js b/src/controllers/screen.js index 73b1c381..0838c1a6 100644 --- a/src/controllers/screen.js +++ b/src/controllers/screen.js @@ -1,5 +1,7 @@ +const { PrismaClientKnownRequestError } = require("@prisma/client/runtime/library") const { createScreenDb } = require("../domains/screen") const MissingFieldsError = require("../errors/missingFieldsError") +const NotUniqueError = require("../errors/notUniqueError") async function createScreen(req, res) { const { number, screenings } = req.body @@ -8,11 +10,21 @@ async function createScreen(req, res) { throw new MissingFieldsError('Missing fields in request body') } - const createdScreen = await createScreenDb(number, screenings) + try { + const createdScreen = await createScreenDb(number, screenings) - res.status(201).json({ - screen: createdScreen - }) + res.status(201).json({ + screen: createdScreen + }) + } catch (e) { + if (e instanceof PrismaClientKnownRequestError) { + if (e.code === "P2002") { + throw new NotUniqueError('A screen with the provided number already exists') + } + } + + res.status(500).json({ error: e.message }) + } } module.exports = { diff --git a/src/domains/movie.js b/src/domains/movie.js index d6fef6f2..8b641e0e 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -70,7 +70,7 @@ async function getMovieByIdDb (movieId) { }) } - return await prisma.movie.findMany({ + return await prisma.movie.findUniqueOrThrow({ where: { title: movieId }, diff --git a/src/errors/notUniqueError.js b/src/errors/notUniqueError.js new file mode 100644 index 00000000..a96e8f02 --- /dev/null +++ b/src/errors/notUniqueError.js @@ -0,0 +1,5 @@ +class NotUniqueError extends Error { + +} + +module.exports = NotUniqueError \ No newline at end of file diff --git a/src/routers/movie.js b/src/routers/movie.js index 9ddd48d8..f05e6db4 100644 --- a/src/routers/movie.js +++ b/src/routers/movie.js @@ -1,5 +1,5 @@ const express = require("express"); -const { getAllMovies, createMovie, getMovieById, updateMovie, getMovieByIdOrTitle } = require("../controllers/movie"); +const { getAllMovies, createMovie, updateMovie, getMovieByIdOrTitle } = require("../controllers/movie"); const router = express.Router(); diff --git a/src/server.js b/src/server.js index 4db5e18c..baf9fa91 100644 --- a/src/server.js +++ b/src/server.js @@ -1,34 +1,35 @@ -const express = require('express'); -require('express-async-errors'); -const app = express(); +const express = require('express') +require('express-async-errors') +const app = express() -const cors = require('cors'); -const morgan = require('morgan'); +const cors = require('cors') +const morgan = require('morgan') -app.disable('x-powered-by'); +app.disable('x-powered-by') // Add middleware -app.use(cors()); -app.use(morgan('dev')); -app.use(express.json()); -app.use(express.urlencoded({ extended: true })); +app.use(cors()) +app.use(morgan('dev')) +app.use(express.json()) +app.use(express.urlencoded({ extended: true })) // Tell express to use your routers here -const customerRouter = require('./routers/customer.js'); -app.use('/customers', customerRouter); +const customerRouter = require('./routers/customer.js') +app.use('/customers', customerRouter) const movieRouter = require('./routers/movie.js') -app.use('/movies', movieRouter); +app.use('/movies', movieRouter) const screenRouter = require('./routers/screen.js') app.use('/screens', screenRouter) -const ticketRouter = require('./routers/ticket.js'); +const ticketRouter = require('./routers/ticket.js') app.use('/tickets', ticketRouter) -const MissingFieldsError = require('./errors/missingFieldsError.js'); -const NotFoundError = require('./errors/notFoundError.js'); +const MissingFieldsError = require('./errors/missingFieldsError.js') +const NotFoundError = require('./errors/notFoundError.js') +const NotUniqueError = require('./errors/notUniqueError.js') app.use((error, req, res, next) => { if (error instanceof MissingFieldsError) { @@ -43,11 +44,11 @@ app.use((error, req, res, next) => { }) } - // if (error instanceof NotUniqueError) { - // return res.status(409).json({ - // error: error.message - // }) - // } + if (error instanceof NotUniqueError) { + return res.status(409).json({ + error: error.message + }) + } res.status(500).json({ error: error.message diff --git a/test/api/extensions/movie-ext.spec.js b/test/api/extensions/movie-ext.spec.js index f29fd946..8bbe8982 100644 --- a/test/api/extensions/movie-ext.spec.js +++ b/test/api/extensions/movie-ext.spec.js @@ -114,6 +114,23 @@ describe("Movie Endpoint", () => { expect(response.status).toEqual(400) expect(response.body).toHaveProperty('error') }) + + it("will return 409 when a movie with the provided title already exists", async () => { + const screen = await createScreen(1) + const movie = await createMovie("test1", 130, screen) + + const request = { + title: movie.title, + runtimeMins: movie.runtimeMins + } + + const response = await supertest(app) + .post('/movies') + .send(request) + + expect(response.status).toEqual(409) + expect(response.body).toHaveProperty('error') + }) }) describe("GET /movies/title", () => { @@ -125,10 +142,10 @@ describe("Movie Endpoint", () => { expect(response.status).toEqual(200) expect(response.body.movie).not.toEqual(undefined) - expect(response.body.movie[0].title).toEqual('Dodgeball') - expect(response.body.movie[0].runtimeMins).toEqual(120) - expect(response.body.movie[0].screenings).not.toEqual(undefined) - expect(response.body.movie[0].screenings.length).toEqual(1) + expect(response.body.movie.title).toEqual('Dodgeball') + expect(response.body.movie.runtimeMins).toEqual(120) + expect(response.body.movie.screenings).not.toEqual(undefined) + expect(response.body.movie.screenings.length).toEqual(1) }) it('will return 404 if the movie is not found by id', async () => { diff --git a/test/api/extensions/screen-ext.spec.js b/test/api/extensions/screen-ext.spec.js index 5dfbfb79..3cac262e 100644 --- a/test/api/extensions/screen-ext.spec.js +++ b/test/api/extensions/screen-ext.spec.js @@ -1,6 +1,7 @@ const supertest = require("supertest") const app = require("../../../src/server.js") const { createMovie } = require("../../helpers/createMovie") +const { createScreen } = require("../../helpers/createScreen.js") describe("Screen Endpoint", () => { describe("POST /screens", () => { @@ -43,5 +44,20 @@ describe("Screen Endpoint", () => { expect(response.status).toEqual(400) expect(response.body).toHaveProperty('error') }) + + it("will return 409 when a screen with the provided number already exists", async () => { + const screen = await createScreen(1) + + const request = { + number: screen.number + } + + const response = await supertest(app) + .post('/screens') + .send(request) + + expect(response.status).toEqual(409) + expect(response.body).toHaveProperty('error') + }) }) }) \ No newline at end of file From 43badf33a901a0afee8c203cc5dc99128f9b5e8e Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Tue, 2 Jul 2024 16:47:58 +0200 Subject: [PATCH 18/21] clean up code --- src/controllers/customer.js | 21 ++------------------- src/controllers/movie.js | 12 +----------- src/controllers/screen.js | 4 +--- src/controllers/ticket.js | 2 +- src/domains/customer.js | 7 ------- src/domains/screen.js | 6 +++--- src/routers/customer.js | 3 --- src/server.js | 3 --- 8 files changed, 8 insertions(+), 50 deletions(-) diff --git a/src/controllers/customer.js b/src/controllers/customer.js index 75c82401..2a9f7631 100644 --- a/src/controllers/customer.js +++ b/src/controllers/customer.js @@ -2,6 +2,7 @@ const { PrismaClientKnownRequestError } = require("@prisma/client") const { createCustomerDb, updateCustomerDb } = require('../domains/customer.js') const MissingFieldsError = require("../errors/missingFieldsError.js") const NotFoundError = require("../errors/notFoundError.js") +const NotUniqueError = require("../errors/notUniqueError.js") const createCustomer = async (req, res) => { const { @@ -14,32 +15,16 @@ const createCustomer = async (req, res) => { throw new MissingFieldsError('Missing fields in request body') } - // Try-catch is a very common way to handle errors in JavaScript. - // It allows us to customise how we want errors that are thrown to be handled. - // Read more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch - - // Here, if Prisma throws an error in the process of trying to create a new customer, - // instead of the Prisma error being thrown (and the app potentially crashing) we exit the - // `try` block (bypassing the `res.status` code) and enter the `catch` block. try { const createdCustomer = await createCustomerDb(name, phone, email) res.status(201).json({ customer: createdCustomer }) } catch (e) { - // In this catch block, we are able to specify how different Prisma errors are handled. - // Prisma throws errors with its own codes. P2002 is the error code for - // "Unique constraint failed on the {constraint}". In our case, the {constraint} is the - // email field which we have set as needing to be unique in the prisma.schema. - // To handle this, we return a custom 409 (conflict) error as a response to the client. - // Prisma error codes: https://www.prisma.io/docs/orm/reference/error-reference#common - // HTTP error codes: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses if (e instanceof PrismaClientKnownRequestError) { if (e.code === "P2002") { - return res.status(409).json({ error: "A customer with the provided email already exists" }) + throw new NotUniqueError("A customer with the provided email already exists" ) } } - - res.status(500).json({ error: e.message }) } } @@ -63,8 +48,6 @@ async function updateCustomer(req, res) { throw new NotFoundError('Customer with that id does not exist') } } - - res.status(500).json({ error: e.message }) } } diff --git a/src/controllers/movie.js b/src/controllers/movie.js index 222d13af..e1a7a8a6 100644 --- a/src/controllers/movie.js +++ b/src/controllers/movie.js @@ -34,8 +34,6 @@ async function createMovie(req, res) { throw new NotUniqueError('A movie with the provided title already exists') } } - - res.status(500).json({ error: e.message }) } } @@ -54,12 +52,6 @@ async function getMovieByIdOrTitle(req, res) { throw new NotFoundError('Movie with that id or title does not exist') } } - - if (e instanceof NotFoundError) { - throw new NotFoundError('Movie with that id or title does not exist') - } - - res.status(500).json({ error: e.message }) } } @@ -84,8 +76,6 @@ async function updateMovie(req, res) { throw new NotFoundError('Movie with that id or title does not exist') } } - - res.status(500).json({ error: e.message }) } } @@ -94,4 +84,4 @@ module.exports = { createMovie, getMovieByIdOrTitle, updateMovie - } \ No newline at end of file +} \ No newline at end of file diff --git a/src/controllers/screen.js b/src/controllers/screen.js index 0838c1a6..7eb8496e 100644 --- a/src/controllers/screen.js +++ b/src/controllers/screen.js @@ -22,11 +22,9 @@ async function createScreen(req, res) { throw new NotUniqueError('A screen with the provided number already exists') } } - - res.status(500).json({ error: e.message }) } } module.exports = { createScreen - } \ No newline at end of file +} \ No newline at end of file diff --git a/src/controllers/ticket.js b/src/controllers/ticket.js index 0f3147a9..de5176f4 100644 --- a/src/controllers/ticket.js +++ b/src/controllers/ticket.js @@ -17,4 +17,4 @@ async function createTicket(req, res) { module.exports = { createTicket - } \ No newline at end of file +} \ No newline at end of file diff --git a/src/domains/customer.js b/src/domains/customer.js index fe5e36dd..6fc58d40 100644 --- a/src/domains/customer.js +++ b/src/domains/customer.js @@ -1,10 +1,5 @@ -const NotFoundError = require('../errors/notFoundError') const prisma = require('../utils/prisma') -/** - * This will create a Customer AND create a new Contact, then automatically relate them with each other - * @tutorial https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#create-a-related-record - */ const createCustomerDb = async (name, phone, email) => await prisma.customer.create({ data: { name, @@ -15,8 +10,6 @@ const createCustomerDb = async (name, phone, email) => await prisma.customer.cre } } }, - // We add an `include` outside of the `data` object to make sure the new contact is returned in the result - // This is like doing RETURNING in SQL include: { contact: true } diff --git a/src/domains/screen.js b/src/domains/screen.js index 89445e52..1ae14437 100644 --- a/src/domains/screen.js +++ b/src/domains/screen.js @@ -24,6 +24,6 @@ async function createScreenDb(number, screenings) { return await prisma.screen.create(screenData) } - module.exports = { - createScreenDb - } \ No newline at end of file +module.exports = { +createScreenDb +} \ No newline at end of file diff --git a/src/routers/customer.js b/src/routers/customer.js index 0835b1dd..47df89b1 100644 --- a/src/routers/customer.js +++ b/src/routers/customer.js @@ -6,9 +6,6 @@ const { const router = express.Router(); -// In index.js, we told express that the /customer route should use this router file -// The below /register route extends that, so the end result will be a URL -// that looks like http://localhost:4040/customer/register router.post("/register", createCustomer); router.put('/:id', updateCustomer) diff --git a/src/server.js b/src/server.js index baf9fa91..2be3be41 100644 --- a/src/server.js +++ b/src/server.js @@ -7,14 +7,11 @@ const morgan = require('morgan') app.disable('x-powered-by') -// Add middleware app.use(cors()) app.use(morgan('dev')) app.use(express.json()) app.use(express.urlencoded({ extended: true })) - -// Tell express to use your routers here const customerRouter = require('./routers/customer.js') app.use('/customers', customerRouter) From 0a1bc875bd4bb7f621cb06238c9547f417d63e2c Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Wed, 3 Jul 2024 10:13:03 +0200 Subject: [PATCH 19/21] add function to only get future screentime movies --- package-lock.json | 10 ++++++++++ package.json | 1 + src/domains/movie.js | 10 ++++++++++ test/helpers/createMovie.js | 4 +++- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index a9b8b9e8..819a97e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@prisma/client": "^5.16.1", "cors": "^2.8.5", + "date-fns": "^3.6.0", "dotenv": "^16.3.1", "express": "^4.18.2", "express-async-errors": "^3.1.1", @@ -1850,6 +1851,15 @@ "node": ">= 8" } }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", diff --git a/package.json b/package.json index 35df3710..1ecc824e 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "dependencies": { "@prisma/client": "^5.16.1", "cors": "^2.8.5", + "date-fns": "^3.6.0", "dotenv": "^16.3.1", "express": "^4.18.2", "express-async-errors": "^3.1.1", diff --git a/src/domains/movie.js b/src/domains/movie.js index 8b641e0e..e0f6755b 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -2,6 +2,7 @@ const prisma = require('../utils/prisma') async function getAllMoviesDb(runtimeLt, runtimeGt) { let movieData = null + const currentDate = new Date() if (runtimeLt || runtimeGt) { movieData = { @@ -25,6 +26,15 @@ async function getAllMoviesDb(runtimeLt, runtimeGt) { } }} else { movieData = { + where: { + screenings: { + some: { + startsAt: { + gt: currentDate + } + } + } + }, include: { screenings: true } diff --git a/test/helpers/createMovie.js b/test/helpers/createMovie.js index 06903fea..066a80a0 100644 --- a/test/helpers/createMovie.js +++ b/test/helpers/createMovie.js @@ -1,6 +1,8 @@ const prisma = require("../../src/utils/prisma") +const { addDays } = require("date-fns") const createMovie = async (title, runtimeMins, screen = null) => { + const date = addDays(new Date(), 10) const movieData = { data: { title: title, @@ -15,7 +17,7 @@ const createMovie = async (title, runtimeMins, screen = null) => { movieData.data.screenings = { create: [ { - startsAt: "2022-06-11T18:30:00.000Z", + startsAt: date, screenId: screen.id } ] From fa9879166a275b941f4dc135cb516c0ef136ebd7 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Wed, 3 Jul 2024 10:54:40 +0200 Subject: [PATCH 20/21] create review model and seed --- .../20240703083212_reviews/migration.sql | 17 ++++++ prisma/schema.prisma | 13 ++++ prisma/seed.js | 60 +++++++++++++++++-- src/domains/movie.js | 3 +- test/api/extensions/review-ext.spec.js | 0 5 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 prisma/migrations/20240703083212_reviews/migration.sql create mode 100644 test/api/extensions/review-ext.spec.js diff --git a/prisma/migrations/20240703083212_reviews/migration.sql b/prisma/migrations/20240703083212_reviews/migration.sql new file mode 100644 index 00000000..3ad22f96 --- /dev/null +++ b/prisma/migrations/20240703083212_reviews/migration.sql @@ -0,0 +1,17 @@ +-- CreateTable +CREATE TABLE "Review" ( + "id" SERIAL NOT NULL, + "content" TEXT NOT NULL, + "customerId" INTEGER NOT NULL, + "movieId" INTEGER NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Review_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "Review" ADD CONSTRAINT "Review_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Review" ADD CONSTRAINT "Review_movieId_fkey" FOREIGN KEY ("movieId") REFERENCES "Movie"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 55dcab1a..e87433e1 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -16,6 +16,7 @@ model Customer { name String contact Contact? tickets Ticket[] + reviews Review[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } @@ -35,6 +36,7 @@ model Movie { screenings Screening[] title String @unique runtimeMins Int + reviews Review[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } @@ -68,3 +70,14 @@ model Ticket { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } + +model Review { + id Int @id @default(autoincrement()) + content String + customer Customer @relation(fields: [customerId], references: [id]) + customerId Int + movie Movie @relation(fields: [movieId], references: [id]) + movieId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} diff --git a/prisma/seed.js b/prisma/seed.js index 31e28bfa..03483ca9 100644 --- a/prisma/seed.js +++ b/prisma/seed.js @@ -2,16 +2,19 @@ const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); async function seed() { - await createCustomer(); + const customers = await createCustomer(); const movies = await createMovies(); const screens = await createScreens(); await createScreenings(screens, movies); + await createReviews(customers, movies) process.exit(0); } async function createCustomer() { - const customer = await prisma.customer.create({ + const customers = []; + + const customer1 = await prisma.customer.create({ data: { name: 'Alice', contact: { @@ -26,9 +29,33 @@ async function createCustomer() { } }); - console.log('Customer created', customer); + const customer2 = await prisma.customer.create({ + data: { + name: 'John', + contact: { + create: { + email: 'john@boolean.co.uk', + phone: '1233687890' + } + } + }, + include: { + contact: true + } + }); + + const rawCustomers = [ + customer1, + customer2 + ] + + for (const rawCustomer of rawCustomers) { + customers.push(rawCustomer); + } + + console.log('Customer created', customers); - return customer; + return customers; } async function createMovies() { @@ -97,6 +124,31 @@ async function createScreenings(screens, movies) { } } +async function createReviews(customers, movies) { + for (const customer of customers) { + for (let i = 0; i < movies.length; i++) { + + const review = await prisma.review.create({ + data: { + content: "best movie ever", + movie: { + connect: { + id: movies[i].id + } + }, + customer: { + connect: { + id: customer.id + } + } + } + }); + + console.log('Review created', review); + } + } +} + seed() .catch(async e => { console.error(e); diff --git a/src/domains/movie.js b/src/domains/movie.js index e0f6755b..ace959e6 100644 --- a/src/domains/movie.js +++ b/src/domains/movie.js @@ -14,7 +14,8 @@ async function getAllMoviesDb(runtimeLt, runtimeGt) { lt: runtimeLt } } : {})}, - {...(runtimeGt ? { + { + ...(runtimeGt ? { runtimeMins: { gt: runtimeGt } diff --git a/test/api/extensions/review-ext.spec.js b/test/api/extensions/review-ext.spec.js new file mode 100644 index 00000000..e69de29b From ec73e4522158faf0cbb458649bd672ed19934c87 Mon Sep 17 00:00:00 2001 From: Myrthe Dullaart Date: Wed, 3 Jul 2024 11:24:01 +0200 Subject: [PATCH 21/21] create test for creating a review --- src/controllers/review.js | 20 ++++++++++++++++++ src/domains/review.js | 17 +++++++++++++++ src/routers/review.js | 8 +++++++ src/server.js | 3 +++ test/api/extensions/review-ext.spec.js | 29 ++++++++++++++++++++++++++ test/setupTests.js | 1 + 6 files changed, 78 insertions(+) create mode 100644 src/controllers/review.js create mode 100644 src/domains/review.js create mode 100644 src/routers/review.js diff --git a/src/controllers/review.js b/src/controllers/review.js new file mode 100644 index 00000000..63fbe104 --- /dev/null +++ b/src/controllers/review.js @@ -0,0 +1,20 @@ +const MissingFieldsError = require("../errors/missingFieldsError") +const { createReviewDb } = require("../domains/review") + +async function createReview(req, res) { + const { content, customerId, movieId } = req.body + + if (!content || !customerId || !movieId) { + throw new MissingFieldsError('Missing fields in request body') + } + + const createdReview = await createReviewDb(content, customerId, movieId) + + res.status(201).json({ + review: createdReview + }) +} + +module.exports = { + createReview +} \ No newline at end of file diff --git a/src/domains/review.js b/src/domains/review.js new file mode 100644 index 00000000..05ed8bf8 --- /dev/null +++ b/src/domains/review.js @@ -0,0 +1,17 @@ +const prisma = require('../utils/prisma') + +async function createReviewDb(content, customerId, movieId) { + const reviewData = { + data: { + content: content, + customerId: customerId, + movieId: movieId + }, + } + + return await prisma.review.create(reviewData) +} + +module.exports = { +createReviewDb +} \ No newline at end of file diff --git a/src/routers/review.js b/src/routers/review.js new file mode 100644 index 00000000..2890ce58 --- /dev/null +++ b/src/routers/review.js @@ -0,0 +1,8 @@ +const express = require("express"); +const { createReview } = require("../controllers/review"); + +const router = express.Router(); + +router.post('/', createReview) + +module.exports = router; \ No newline at end of file diff --git a/src/server.js b/src/server.js index 2be3be41..5d62377a 100644 --- a/src/server.js +++ b/src/server.js @@ -24,6 +24,9 @@ app.use('/screens', screenRouter) const ticketRouter = require('./routers/ticket.js') app.use('/tickets', ticketRouter) +const reviewRouter = require('./routers/review.js') +app.use('/reviews', reviewRouter) + const MissingFieldsError = require('./errors/missingFieldsError.js') const NotFoundError = require('./errors/notFoundError.js') const NotUniqueError = require('./errors/notUniqueError.js') diff --git a/test/api/extensions/review-ext.spec.js b/test/api/extensions/review-ext.spec.js index e69de29b..3e6a5a1e 100644 --- a/test/api/extensions/review-ext.spec.js +++ b/test/api/extensions/review-ext.spec.js @@ -0,0 +1,29 @@ +const supertest = require("supertest") +const app = require("../../../src/server.js") +const { createMovie } = require("../../helpers/createMovie.js") +const { createScreen } = require("../../helpers/createScreen.js") +const { createCustomer } = require("../../helpers/createCustomer.js") + +describe("Reviews Endpoint", () => { + describe("POST /reviews", () => { + it("will create a review", async () => { + const screen = await createScreen(1) + const movie = await createMovie("Minions", 150, screen) + const customer = await createCustomer("John", "123456", "john@test.com") + + const request = { + content: "Worst movie ever", + movieId: movie.id, + customerId: customer.id + } + + const response = await supertest(app) + .post("/reviews") + .send(request) + + expect(response.status).toEqual(201) + expect(response.body.review).not.toEqual(undefined) + expect(response.body.review.content).toEqual('Worst movie ever') + }) + }) +}) diff --git a/test/setupTests.js b/test/setupTests.js index 2be95321..0edacb87 100644 --- a/test/setupTests.js +++ b/test/setupTests.js @@ -4,6 +4,7 @@ const deleteTables = () => { const deleteTables = [ prisma.ticket.deleteMany(), prisma.screening.deleteMany(), + prisma.review.deleteMany(), prisma.movie.deleteMany(), prisma.screen.deleteMany(), prisma.contact.deleteMany(),