import { afterEach, beforeAll, describe, expect, it, mock } from "bun:test"; import request, { Response } from "supertest"; import app, { startApp } from "../src/app"; import imageService from "../src/services/ImageService"; import populateDatabase from "./populateDatabase"; import { Image } from "../src/models/ImageModel"; import { faker } from "@faker-js/faker"; const imageServiceOriginal = imageService; let token: string; beforeAll(async () => { await startApp(); await populateDatabase(); const tok = await request(app) .post("/login") .send({ app: "tester", secret: "test" }); token = tok.body.token; }); afterEach(() => { mock.restore(); mock.module("../src/services/ImageService", () => ({ default: imageServiceOriginal, })); }); describe("/login works as instended", async () => { let correctRespose: Response; beforeAll(async () => { correctRespose = await request(app) .post("/login") .send({ app: "tester", secret: "test" }); }); it("should return 200 for correct login", async () => { expect(correctRespose.status).toBe(200); }); it("should contain a token", () => { expect(correctRespose.body).toHaveProperty("token"); }); it("should return 403 for invalid credentials", async () => { const res = await request(app).post("/login").send({}); expect(res.status).toBe(403); }); }); describe("GET / shows all of the endpoints", async () => { const res = await request(app).get("/"); it("should be", async () => { expect(res.body).toHaveProperty("endpoints"); }); it("should be an array", () => { expect(Array.isArray(res.body.endpoints)).toBeTrue(); }); }); describe("GET /images works properly", async () => { const res = await request(app).get("/images"); it("should be an array", () => { expect(Array.isArray(res.body.images)).toBeTrue(); }); it("should return a 200", async () => { expect(res.statusCode).toBe(200); }); it("should return 500 for an error on the service", async () => { mock.module("../src/services/ImageService", () => ({ default: { findAll: () => { throw new Error("This is an expected testing error"); }, }, })); const res = await request(app).get("/images"); expect(res.status).toBe(500); }); it("should return 400 for an invalid status param value", async () => { const res = await request(app).get("/images?status=foo"); expect(res.statusCode).toBe(400); }); it("should return 200 for a request with valid status param", async () => { const status = faker.helpers.arrayElement(["consumed", "available", "unavailable"]) const res = await request(app).get(`/images?status=${status}`); expect(res.statusCode).toBe(200); }); it("should only have the requested status in the images", async () => { const status = faker.helpers.arrayElement(["consumed", "available", "unavailable"]) const res = await request(app).get(`/images?status=${status}`); expect(res.body.images .map((image: Image) => image.status) .every((imageStatus: string) => imageStatus === status)).toBeTrue(); }); it("should return 400 for a floating point value in limit value", async () => { const res = await request(app).get("/images?limit=2.4"); expect(res.statusCode).toBe(400); }); it("should return 400 for a negative value in limit value", async () => { const res = await request(app).get("/images?limit=-1"); expect(res.statusCode).toBe(400); }); it("should return 400 for a NaN limit value", async () => { const res = await request(app).get("/images?limit=foo"); expect(res.statusCode).toBe(400); }); it("should return 200 for a request with valid limit param", async () => { const limit = faker.number.int({ min: 5, max: 50 }); const res = await request(app).get(`/images?limit=${limit}`); expect(res.statusCode).toBe(200); }); it("should return 200 for a request with valid limit param", async () => { const limit = faker.number.int({ min: 5, max: 50 }); const res = await request(app).get(`/images?limit=${limit}`); expect(res.body.images.length).toBeLessThanOrEqual(limit); }); it("should return 200 for a request with both valid params", async () => { const res = await request(app).get("/images?limit=3&status=available"); expect(res.statusCode).toBe(200); }); it("should return the same ids using limit=0 and using no limit parameter", async () => { const resLimit0 = await request(app).get("/images?limit=0"); const resNoLimit = await request(app).get("/images"); const ids1 = resNoLimit.body.images.map((image: Image) => image._id); const ids2 = resLimit0.body.images.map((image: Image) => image._id); expect(ids1.length).toBe(ids2.length); ids1.forEach((id: string) => expect(ids2).toContain(id)); }) }); describe("POST /images works properly", () => { it("should return 401 for unauthenticated requests", async () => { const res = await request(app) .post("/images") .send({ url: "https://test.url.com/0", status: "available", tags: ["2girls", "touhou"], }); expect(res.status).toBe(401); }); it("should return 403 for invalid tokens", async () => { const res = await request(app) .post("/images") .set("authorization", `Bearer token`) .send({ url: "https://test.url.com/0", status: "available", tags: ["2girls", "touhou"], }); expect(res.status).toBe(403); }); it("should return 201 for new image", async () => { const res = await request(app) .post("/images") .set("authorization", `Bearer ${token}`) .send({ url: "https://test.url.com/1", status: "available", tags: ["2girls", "touhou"], }); expect(res.status).toBe(201); }); it("should return 409 for a repeated images", async () => { await request(app) .post("/images") .set("authorization", `Bearer ${token}`) .send({ url: "https://test.url.com/2", status: "available", tags: ["2girls", "touhou"], }); const res = await request(app) .post("/images") .set("authorization", `Bearer ${token}`) .send({ url: "https://test.url.com/2", status: "available", tags: ["2girls", "touhou"], }); expect(res.status).toBe(409); }); it("should return 500 for an error on the service", async () => { mock.module("../src/services/ImageService", () => ({ default: { add: () => { throw new Error("This is an expected testing error"); }, }, })); const res = await request(app) .post("/images") .set("authorization", `Bearer ${token}`) .send({ url: "https://test.url.com/3", status: "available", tags: ["2girls", "touhou"], }); expect(res.status).toBe(500); }); it("should return 400 for malformed requests", async () => { mock.restore(); const res = await request(app) .post("/images") .set("authorization", `Bearer ${token}`) .send({ url: "https://test.url.com/4", status: "wrong", tags: ["2girls", "touhou"], }); expect(res.status).toBe(400); }); }); describe("GET /images/:id works properly", () => { it("should return 200 for existing ids", async () => { const list = await request(app).get("/images"); const id = list.body.images[0]._id; const res = await request(app).get(`/images/${id}`); expect(res.status).toBe(200); }); it("should return 404 for non-existing ids", async () => { const list = await request(app).get("/images"); const id = "000000000000000000000000"; // this was the least posible to exist ID if (!(id in list.body.images)) { const res = await request(app).get(`/images/${id}`); expect(res.status).toBe(404); } }); it("should return 400 for malformed ids", async () => { const res = await request(app).get("/images/98439384"); expect(res.status).toBe(400); }); });