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" diff --git a/prisma/migrations/20240814183117_model/migration.sql b/prisma/migrations/20240814183117_model/migration.sql new file mode 100644 index 00000000..f8077248 --- /dev/null +++ b/prisma/migrations/20240814183117_model/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..12612b4c 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -33,7 +33,7 @@ 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 @@ -41,7 +41,7 @@ model Movie { model Screen { id Int @id @default(autoincrement()) - number Int + number Int @unique screenings Screening[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt diff --git a/src/controllers/customer.js b/src/controllers/customer.js index 775cfb42..16392687 100644 --- a/src/controllers/customer.js +++ b/src/controllers/customer.js @@ -1,17 +1,16 @@ -const { PrismaClientKnownRequestError } = require("@prisma/client") -const { createCustomerDb } = require('../domains/customer.js') +const { PrismaClientKnownRequestError } = require("@prisma/client"); +const { + createCustomerDb, + updatedCustomerdb, +} = require("../domains/customer.js"); const createCustomer = async (req, res) => { - const { - name, - phone, - email - } = req.body + const { name, phone, email } = req.body; if (!name || !phone || !email) { return res.status(400).json({ - error: "Missing fields in request body" - }) + error: "Missing fields in request body", + }); } // Try-catch is a very common way to handle errors in JavaScript. @@ -22,9 +21,9 @@ const createCustomer = async (req, res) => { // 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) + const createdCustomer = await createCustomerDb(name, phone, email); - res.status(201).json({ customer: createdCustomer }) + 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 @@ -35,14 +34,44 @@ const createCustomer = async (req, res) => { // 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" }) + return res + .status(409) + .json({ error: "A customer with the provided email already exists" }); } } - res.status(500).json({ error: e.message }) + res.status(500).json({ error: e.message }); } -} +}; + +const updateCustomer = async (req, res) => { + try { + const id = Number(req.params.id); + const { name, contact } = req.body; + + if (!name) { + return res.status(400).json({ + error: "Missing fields in request body", + }); + } + + const updatedCustomer = await updatedCustomerdb(id, name, contact); + + res.status(201).json({ customer: updatedCustomer }); + } catch (err) { + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2025") { + return res.status(404).json({ + error: "A customer with that id does not exist", + }); + } + } + //This error message will run if something goes wrong with the errors. + res.status(500).json({ error: err.message }); + } +}; module.exports = { - createCustomer -} + createCustomer, + updateCustomer, +}; diff --git a/src/controllers/movies.js b/src/controllers/movies.js new file mode 100644 index 00000000..3c533c42 --- /dev/null +++ b/src/controllers/movies.js @@ -0,0 +1,116 @@ +const { PrismaClientKnownRequestError } = require("@prisma/client"); +const prisma = require("../utils/prisma"); + + +const { + getAllMoviesdb, + createdMoviedb, + getMoviedb, + updatedMoviedb, +} = require("../domains/movies"); + +const getAllMovies = async (req, res) => { + try { + const runtimeLt = Number(req.query.runtimeLt); + const runtimeGt = Number(req.query.runtimeGt); + + const allMovies = await getAllMoviesdb(runtimeLt, runtimeGt); + + res.status(200).json({ movies: allMovies }); + } catch (err) { + console.log("Error:", err); + } +}; + +const createMovie = async (req, res) => { + const { title, runtimeMins, screenings } = req.body; + + if (!title || !runtimeMins) { + return res.status(400).json({ + error: "Missing fields in request body", + }); + } + + try { + const createdMovie = await createdMoviedb(title, runtimeMins, screenings); + + res.status(201).json({ movie: createdMovie }); + } catch (err) { + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2002") { + return res.status(409).json({ + error: "A movie with the provided title already exists", + }); + } + } + res.status(500).json({ error: err.message }); + } +}; + +const getMovieByID = async (req, res) => { + try { + const id = req.params.id; + + const movie = await getMoviedb(id); + res.status(200).json({ movie: movie }); + } catch (err) { + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2025") { + return res.status(404).json({ + error: "A movie with that id does not exist", + }); + } + } + res.status(500).json({ error: err.message }); + } +}; + +const updateMovie = async (req, res) => { + const id = Number(req.params.id); + const { title, runtimeMins, screenings } = req.body; + + if (!title || !runtimeMins) { + return res.status(400).json({ + error: "Missing fields in request body", + }); + } + + const existingTitle = await prisma.movie.findUnique({ + where: { + title: title, + }, + }); + + if(existingTitle) { + return res.status(409).json({ + error: "Title already exists", + }); + } + + try { + const updatedMovie = await updatedMoviedb( + id, + title, + runtimeMins, + screenings + ); + + res.status(201).json({ movie: updatedMovie }); + } catch (err) { + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2025") { + return res.status(404).json({ + error: "A movie with that id does not exist", + }); + } + } + res.status(500).json({ error: err.message }); + } +}; + +module.exports = { + getAllMovies, + createMovie, + getMovieByID, + updateMovie, +}; diff --git a/src/controllers/screens.js b/src/controllers/screens.js new file mode 100644 index 00000000..816e7649 --- /dev/null +++ b/src/controllers/screens.js @@ -0,0 +1,31 @@ +const { PrismaClientKnownRequestError } = require("@prisma/client"); +const { createdScreendb } = require("../domains/screens"); + +const createScreen = async (req, res) => { + const { number, screenings } = req.body; + + if (!number) { + return res.status(400).json({ + error: "Missing fields in request body", + }); + } + + try { + const createdScreen = await createdScreendb(number, screenings); + + res.status(201).json({ screen: createdScreen }); + } catch (err) { + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2002") { + return res.status(409).json({ + error: "A screen with the provided number already exists", + }); + } + } + res.status(500).json({ error: err.message }); + } +}; + +module.exports = { + createScreen, +}; diff --git a/src/controllers/tickets.js b/src/controllers/tickets.js new file mode 100644 index 00000000..78929ec9 --- /dev/null +++ b/src/controllers/tickets.js @@ -0,0 +1,31 @@ +const { PrismaClientKnownRequestError } = require("@prisma/client"); +const { createdTicketdb } = require("../domains/tickets"); + +const createTicket = async (req, res) => { + const { screeningId, customerId } = req.body; + if (!screeningId || !customerId) { + return res.status(400).json({ + error: "Missing fields in request body", + }); + } + + try { + const createdTicket = await createdTicketdb(screeningId, customerId); + + res.status(201).json({ ticket: createdTicket }); + } catch (err) { + if (err instanceof PrismaClientKnownRequestError) { + if (err.code === "P2003") { + return res.status(404).json({ + error: "A customer or screening does not exist with the provided id", + }); + } + } + res.status(500).json({ error: err.message }); + + } +}; + +module.exports = { + createTicket, +}; diff --git a/src/domains/customer.js b/src/domains/customer.js index c7f315fd..aeebd1ae 100644 --- a/src/domains/customer.js +++ b/src/domains/customer.js @@ -21,6 +21,32 @@ const createCustomerDb = async (name, phone, email) => await prisma.customer.cre } }) +const updatedCustomerdb = async (id, name, contact) => { + const customerData = { + name, + }; + + if (contact) { + customerData.contact = { + update: { + data: contact, + }, + }; + } + + return await prisma.customer.update({ + data: customerData, + where: { + id, + }, + include: { + contact: true, + }, + }); +}; + + module.exports = { - createCustomerDb + createCustomerDb, + updatedCustomerdb } diff --git a/src/domains/movies.js b/src/domains/movies.js new file mode 100644 index 00000000..85a1871a --- /dev/null +++ b/src/domains/movies.js @@ -0,0 +1,124 @@ +const prisma = require("../utils/prisma"); + +const getAllMoviesdb = async (runtimeLt, runtimeGt) => { + const runTimeClauses = { + ...(runtimeLt + ? { + lt: runtimeLt, + } + : {}), + + ...(runtimeGt + ? { + gt: runtimeGt, + } + : {}), + }; + + console.log("run time clauses", runTimeClauses); + const currentDate = new Date(); + + if (runtimeGt || runtimeLt) { + return await prisma.movie.findMany({ + where: { + runtimeMins: runTimeClauses, + }, + include: { + screenings: true, + }, + }); + } else { + return await prisma.movie.findMany({ + // where: { + // screenings: { + // some: { + // startsAt: { + // gt: currentDate + // } + // } + // } + // }, + include: { + screenings: true, + }, + }); + } +}; + +const createdMoviedb = async (title, runtimeMins, screenings) => { + const movieData = { + title, + runtimeMins, + }; + + if (screenings) { + movieData.screenings = { + createMany: { + data: screenings, + }, + }; + } + + return await prisma.movie.create({ + data: movieData, + include: { + screenings: true, + }, + }); +}; + +const getMoviedb = async (id) => { + //NaN means if not a number. !Nan means if a number. + if (!isNaN(id)) { + return await prisma.movie.findUniqueOrThrow({ + where: { + id: Number(id), + }, + include: { + screenings: true, + }, + }); + } else { + return await prisma.movie.findUniqueOrThrow({ + where: { + title: id, + }, + include: { + screenings: true, + }, + }); + } +}; + +const updatedMoviedb = async (id, title, runtimeMins, screenings) => { + const movieData = { + title, + runtimeMins, + }; + + if (screenings) { + movieData.screenings = { + deleteMany: {}, + createMany: { + data: screenings, + }, + }; + } + + return await prisma.movie.update({ + data: movieData, + where: { + id, + }, + include: { + screenings: true, + }, + }); +}; + +module.exports = { + getAllMoviesdb, + createdMoviedb, + getMoviedb, + updatedMoviedb, +}; diff --git a/src/domains/screens.js b/src/domains/screens.js new file mode 100644 index 00000000..d8e73ac1 --- /dev/null +++ b/src/domains/screens.js @@ -0,0 +1,27 @@ +const prisma = require("../utils/prisma"); + +const createdScreendb = async (number, screenings) => { + const screenData = { + number, + }; + + if (screenings) { + screenData.screenings = { + createMany: { + data: screenings, + }, + }; + } + + return await prisma.screen.create({ + data: screenData, + include: { + screenings: true + } + }); +}; + + + module.exports = { + createdScreendb + }; diff --git a/src/domains/tickets.js b/src/domains/tickets.js new file mode 100644 index 00000000..5712a707 --- /dev/null +++ b/src/domains/tickets.js @@ -0,0 +1,28 @@ +const prisma = require("../utils/prisma"); + +const createdTicketdb = async (screeningId, customerId) => + await prisma.ticket.create({ + data: { + screeningId, + customerId, + }, + include: { + screening: true, + screening: { + include: { + movie: true, + screen: true, + }, + }, + customer: true, + customer: { + include: { + contact: true, + }, + }, + }, + }); + +module.exports = { + createdTicketdb, +}; diff --git a/src/routers/customer.js b/src/routers/customer.js index f14a87fc..7851de61 100644 --- a/src/routers/customer.js +++ b/src/routers/customer.js @@ -1,6 +1,6 @@ const express = require("express"); const { - createCustomer + createCustomer, updateCustomer } = require('../controllers/customer'); const router = express.Router(); @@ -10,4 +10,7 @@ const router = express.Router(); // that looks like http://localhost:4040/customer/register router.post("/register", createCustomer); +//Update a customer +router.put("/:id", updateCustomer); + module.exports = router; diff --git a/src/routers/movies.js b/src/routers/movies.js new file mode 100644 index 00000000..5f244ad8 --- /dev/null +++ b/src/routers/movies.js @@ -0,0 +1,22 @@ +const router = require("express").Router(); +const { + getAllMovies, + createMovie, + getMovieByID, + updateMovie +} = require("../controllers/movies"); + +//Get all movies +router.get("/", getAllMovies); + +//Create a movie +router.post("/", createMovie); + +//Get movie by ID: +router.get("/:id", getMovieByID); + +//Update movie by ID: +router.put("/:id", updateMovie) + + +module.exports = router; \ No newline at end of file diff --git a/src/routers/screens.js b/src/routers/screens.js new file mode 100644 index 00000000..5d42f670 --- /dev/null +++ b/src/routers/screens.js @@ -0,0 +1,9 @@ +const router = require("express").Router(); +const { + createScreen +} = require("../controllers/screens"); + +//Create a screen +router.post("/", createScreen); + +module.exports = router; \ No newline at end of file diff --git a/src/routers/tickets.js b/src/routers/tickets.js new file mode 100644 index 00000000..8fbce938 --- /dev/null +++ b/src/routers/tickets.js @@ -0,0 +1,7 @@ +const router = require("express").Router(); +const { createTicket } = require("../controllers/tickets"); + +//Create a ticket +router.post("/", createTicket); + +module.exports = router; diff --git a/src/server.js b/src/server.js index 93d47a16..e684dfa6 100644 --- a/src/server.js +++ b/src/server.js @@ -1,21 +1,27 @@ -const express = require('express'); +const express = require("express"); 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(morgan("dev")); app.use(express.json()); app.use(express.urlencoded({ extended: true })); - // Tell express to use your routers here -const customerRouter = require('./routers/customer'); -app.use('/customers', customerRouter); +const customerRouter = require("./routers/customer"); +app.use("/customers", customerRouter); + +const moviesRouter = require("./routers/movies"); +app.use("/movies", moviesRouter); + +const screensRouter = require("./routers/screens"); +app.use("/screens", screensRouter); +const ticketsRouter = require("./routers/tickets"); app.use("/tickets", ticketsRouter) -module.exports = app +module.exports = app; diff --git a/test/api/extensions/movies-ext.spec.js b/test/api/extensions/movies-ext.spec.js new file mode 100644 index 00000000..029c7f0c --- /dev/null +++ b/test/api/extensions/movies-ext.spec.js @@ -0,0 +1,210 @@ +const supertest = require("supertest"); +const app = require("../../../src/server.js"); +const { createMovie } = require("../../helpers/createMovie.js"); +const { createScreen } = require("../../helpers/createScreen.js"); + +describe("Movies Endpoint", () => { + describe("GET /movies?runtimeLt", () => { + it("will retrieve a list of movies with runtime less than runtimeLt", async () => { + await createMovie("Movie 1", 130); + await createMovie("Movie 2", 113); + await createMovie("Movie 3", 84); + + const response = await supertest(app).get("/movies?runtimeLt=115"); + + expect(response.status).toEqual(200); + expect(response.body.movies).not.toEqual(undefined); + expect(response.body.movies.length).toEqual(2); + + const [movie2, movie3] = response.body.movies; + expect(movie2.title).toEqual("Movie 2"); + expect(movie2.runtimeMins).toEqual(113); + + expect(movie3.title).toEqual("Movie 3"); + expect(movie3.runtimeMins).toEqual(84); + }); + }); + + describe("GET /movies?runtimeGt", () => { + it("will retrieve a list of movies with runtime more than runtimeGt", async () => { + await createMovie("Movie 1", 130); + await createMovie("Movie 2", 113); + await createMovie("Movie 3", 84); + + const response = await supertest(app).get("/movies?runtimeGt=90"); + + 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("Movie 1"); + expect(movie1.runtimeMins).toEqual(130); + + expect(movie2.title).toEqual("Movie 2"); + expect(movie2.runtimeMins).toEqual(113); + }); + }); + + describe("GET /movies?runtimeLt&runtimeGt", () => { + it("will retrieve a list of movies with a runtime between runtimeLt and runtimeGt", async () => { + await createMovie("Movie 1", 130); + await createMovie("Movie 2", 113); + await createMovie("Movie 3", 84); + + const response = await supertest(app).get( + "/movies?runtimeLt=160&runtimeGt=90" + ); + + 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("Movie 1"); + expect(movie1.runtimeMins).toEqual(130); + + expect(movie2.title).toEqual("Movie 2"); + expect(movie2.runtimeMins).toEqual(113); + }); + }); + + describe("POST /movies", () => { + it("will add screenings if screenings exist in the body", async () => { + const screen1 = await createScreen(1); + const screen2 = await createScreen(2); + + const request = { + title: "Top Gun", + runtimeMins: 110, + screenings: [ + { screenId: screen1.id, startsAt: "2024-08-11T15:30:00.000Z" }, + { screenId: screen2.id, startsAt: "2024-08-17T18: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("Top Gun"); + expect(response.body.movie.runtimeMins).toEqual(110); + 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"); + }); + + it("will return 409 when a movie with hte provided title already exists", async () => { + const movie1 = await createMovie("Movie 1", 130); + + const request = { + title: "Movie 1", + runtimeMins: 130, + }; + + const response = await supertest(app).post(`/movies`).send(request); + + expect(response.status).toEqual(409); + expect(response.body).toHaveProperty("error"); + }); + }); + + describe("GET /movies/title", () => { + it("will get movies by title", async () => { + const screen = await createScreen(1); + const movie = await createMovie("Dodgeball", 120, screen); + + const response = await supertest(app).get(`/movies/${movie.title}`); + + expect(response.status).toEqual(200); + expect(response.body.movie).not.toEqual(undefined); + expect(response.body.movie.title).toEqual("Dodgeball"); + expect(response.body.movie.runtimeMins).toEqual(120); + expect(response.body.movie.screenings).not.toEqual(undefined); + }); + + it("will return 404 if the movie or title is not found", async () => { + const response = await supertest(app).get(`/movies/10000`); + + expect(response.status).toEqual(404); + expect(response.body).toHaveProperty("error"); + }); + }); + + describe("PUT /movies/:id", () => { + it("will update a movie by id and screening if provided", async () => { + const screen1 = await createScreen(1); + const screen2 = await createScreen(2); + const movie = await createMovie("Dodgeball", 120, screen1); + + const request = { + title: "Scream", + runtimeMins: 113, + screenings: [ + { screenId: screen1.id, startsAt: "2024-08-11T15:30:00.000Z" }, + { screenId: screen2.id, startsAt: "2024-08-17T18:30:00.000Z" }, + ], + }; + + const response = await supertest(app) + .put(`/movies/${movie.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); + }); + + it("will return 404 if the movie with that id is not found", async () => { + const request = { + title: "Updated name", + runtimeMins: 120, + }; + + const response = await supertest(app).put(`/movies/10000`).send(request); + + expect(response.status).toEqual(404); + expect(response.body).toHaveProperty("error"); + }); + + it("will return 400 when there are missing fields in the request body", async () => { + const movie = await createMovie("Dodgeball", 120); + const request = {}; + + const response = await supertest(app) + .put(`/movies/${movie.id}`) + .send(request); + + 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 screen1 = await createScreen(1); + const movie1 = await createMovie("Movie 1", 130, screen1); + + const request = { + title: movie1.title, + runtimeMins: movie1.runtimeMins, + }; + + const response = await supertest(app) + .put(`/movies/${movie1.id}`) + .send(request); + + expect(response.status).toEqual(409); + expect(response.body).toHaveProperty("error"); + }); + }); +}); diff --git a/test/api/extensions/screens-ext.spec.js b/test/api/extensions/screens-ext.spec.js new file mode 100644 index 00000000..c0011505 --- /dev/null +++ b/test/api/extensions/screens-ext.spec.js @@ -0,0 +1,50 @@ +const supertest = require("supertest"); +const app = require("../../../src/server.js"); +const { createMovie } = require("../../helpers/createMovie.js"); +const { createScreen } = require("../../helpers/createScreen.js"); + +describe("Screens Endpoint", () => { + describe("POST /screens", () => { + it("will create a screen and screening if provided", async () => { + const movie1 = await createMovie("Movie 1", 130); + const movie2 = await createMovie("Movie 2", 113); + + const request = { + number: 15, + screenings: [ + { movieId: movie1.id, startsAt: "2024-08-11T15:30:00.000Z" }, + { movieId: movie2.id, startsAt: "2024-08-17T18: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(15); + 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(`/screens`).send(request); + + 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 screen1 = await createScreen(1); + const request = { + number: screen1.number, + }; + + const response = await supertest(app).post(`/screens`).send(request); + + expect(response.status).toEqual(409); + expect(response.body).toHaveProperty("error"); + }); + }); +}); diff --git a/test/api/extensions/tickets-ext.spec.js b/test/api/extensions/tickets-ext.spec.js new file mode 100644 index 00000000..fdc8c4c2 --- /dev/null +++ b/test/api/extensions/tickets-ext.spec.js @@ -0,0 +1,57 @@ +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("Tickets Endpoint", () => { + describe("POST /tickets", () => { + it("will create a ticket and include the data for the customer, contact details, movie, screening and screen", async () => { + const screen = await createScreen(1); + const customer = await createCustomer("John", "123456", "john@test.com"); + const movie = await createMovie("Movie 1", 130, 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).not.toEqual(undefined); + 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("Movie 1"); + expect(response.body.ticket.screening.movie.runtimeMins).toEqual(130); + expect(response.body.ticket.screening.screen.number).toEqual(1); + expect(response.body.ticket.customer).not.toEqual(undefined); + expect(response.body.ticket.customer.name).toEqual("John"); + expect(response.body.ticket.customer.contact.phone).toEqual("123456"); + expect(response.body.ticket.customer.contact.email).toEqual( + "john@test.com" + ); + }); + + it("will return 404 if the movie with that id is not found", async () => { + const request = { + screeningId: 1000, + customerId: 1001 + }; + + const response = await supertest(app).post(`/tickets`).send(request); + + expect(response.status).toEqual(404); + expect(response.body).toHaveProperty("error"); + }); + + 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"); + }); + }); +});