import { Application } from "express"; import { knex } from "../../db"; import request from "supertest"; // supertest is a framework that allows to easily test web apis import { createApp } from "../app"; import SkinModel from "../../data/SkinModel"; import * as S3 from "../../s3"; import * as Auth from "../auth"; import { processUserUploads } from "../processUserUploads"; import UserContext from "../../data/UserContext"; import { searchIndex } from "../../algolia"; jest.mock("../../s3"); jest.mock("../../algolia"); jest.mock("../processUserUploads"); jest.mock("../auth"); let app: Application; const handler = jest.fn(); const log = jest.fn(); const logError = jest.fn(); let username: string | undefined; beforeEach(async () => { jest.clearAllMocks(); username = ""; app = createApp({ eventHandler: handler, extraMiddleware: (req, res, next) => { req.session.username = username; next(); }, logger: { log, logError }, }); await knex.migrate.latest(); await knex.seed.run(); }); describe("/authed", () => { test("logged in ", async () => { const { body } = await request(app).get("/authed").expect(200); expect(body).toEqual({ username: "" }); }); test("not logged in", async () => { username = undefined; const { body } = await request(app).get("/authed").expect(200); expect(body).toEqual({ username: null }); }); }); test.skip("/auth", async () => { const { body } = await request(app) .get("/auth") .expect(302) .expect( "Location", "https://discord.com/api/oauth2/authorize?client_id=%3CDUMMY_DISCORD_CLIENT_ID%3E&redirect_uri=https%3A%2F%2Fapi.webampskins.org%2Fauth%2Fdiscord&response_type=code&scope=identify%20guilds" ); expect(body).toEqual({}); }); describe.skip("/auth/discord", () => { test("valid code", async () => { const response = await request(app) .get("/auth/discord") .query({ code: "" }) .expect(302) .expect("Location", "https://skins.webamp.org/review/"); // TODO: Assert that we get cookie headers. I think that will not work now // because express does not think it's secure in a test env. expect(Auth.auth).toHaveBeenCalledWith(""); expect(response.body).toEqual({}); }); test("missing code", async () => { const { body } = await request(app).get("/auth/discord").expect(400); expect(Auth.auth).not.toHaveBeenCalled(); expect(body).toEqual({ message: "Expected to get a code" }); }); }); describe("/skins/", () => { test("no query params", async () => { const { body } = await request(app).get("/skins/"); expect(body).toMatchInlineSnapshot(` Object { "skinCount": 6, "skins": Array [ Object { "fileName": "tweeted.wsz", "md5": "a_tweeted_md5", "nsfw": false, }, Object { "fileName": "Zelda_Amp_3.wsz", "md5": "48bbdbbeb03d347e59b1eebda4d352d0", "nsfw": false, }, Object { "fileName": "path.wsz", "md5": "a_fake_md5", "nsfw": false, }, Object { "fileName": "approved.wsz", "md5": "an_approved_md5", "nsfw": false, }, Object { "fileName": "rejected.wsz", "md5": "a_rejected_md5", "nsfw": false, }, Object { "fileName": "nsfw.wsz", "md5": "a_nsfw_md5", "nsfw": true, }, ], } `); }); test("first and offset", async () => { const { body } = await request(app) .get("/skins/") .query({ first: 2, offset: 1 }); expect(body).toMatchInlineSnapshot(` Object { "skinCount": 6, "skins": Array [ Object { "fileName": "Zelda_Amp_3.wsz", "md5": "48bbdbbeb03d347e59b1eebda4d352d0", "nsfw": false, }, Object { "fileName": "path.wsz", "md5": "a_fake_md5", "nsfw": false, }, ], } `); }); }); // This is deprecated and fails in CI due to printing as localize date string. test.skip("/skins/a_fake_md5/debug", async () => { const { body } = await request(app) .get("/skins/a_fake_md5/debug") .expect(200); expect(body).toMatchSnapshot(); }); test("/skins/a_fake_md5/report", async () => { const { body } = await request(app) .post("/skins/a_fake_md5/report") .expect(200); expect(handler).toHaveBeenCalledWith({ type: "REVIEW_REQUESTED", md5: "a_fake_md5", }); expect(body).toEqual({}); // TODO: Where does the text response go? }); test("/skins/a_fake_md5/approve", async () => { const ctx = new UserContext(); const { body } = await request(app) .post("/skins/a_fake_md5/approve") .expect(200); expect(handler).toHaveBeenCalledWith({ type: "APPROVED_SKIN", md5: "a_fake_md5", }); expect(body).toEqual({ message: "The skin has been approved." }); const skin = await SkinModel.fromMd5(ctx, "a_fake_md5"); expect(await skin?.getTweetStatus()).toEqual("APPROVED"); }); describe("/to_review", () => { test("logged in ", async () => { const { body } = await request(app).get("/to_review").expect(200); expect(body).toEqual({ filename: expect.any(String), md5: expect.any(String), }); }); test("not logged in ", async () => { username = undefined; const { body } = await request(app).get("/to_review").expect(403); expect(body).toEqual({ message: "You must be logged in" }); }); }); test("/skins/a_md5_that_does_not_exist/approve (404)", async () => { const { body } = await request(app) .post("/skins/a_md5_that_does_not_exist/approve") .expect(404); expect(body).toEqual({}); expect(handler).not.toHaveBeenCalled(); }); test("/skins/a_fake_md5/reject", async () => { const ctx = new UserContext(); const { body } = await request(app) .post("/skins/a_fake_md5/reject") .expect(200); expect(handler).toHaveBeenCalledWith({ type: "REJECTED_SKIN", md5: "a_fake_md5", }); expect(body).toEqual({ message: "The skin has been rejected." }); // TODO: Where does the text response go? const skin = await SkinModel.fromMd5(ctx, "a_fake_md5"); expect(await skin?.getTweetStatus()).toEqual("REJECTED"); }); test("/skins/a_md5_that_does_not_exist/reject (404)", async () => { const { body } = await request(app) .post("/skins/a_md5_that_does_not_exist/reject") .expect(404); expect(body).toEqual({}); expect(handler).not.toHaveBeenCalled(); }); test("/skins/a_fake_md5/nsfw", async () => { const ctx = new UserContext(); const { body } = await request(app) .post("/skins/a_fake_md5/nsfw") .expect(200); expect(handler).toHaveBeenCalledWith({ type: "MARKED_SKIN_NSFW", md5: "a_fake_md5", }); expect(searchIndex.partialUpdateObjects).toHaveBeenCalledWith([ { nsfw: true, objectID: "a_fake_md5" }, ]); expect(body).toEqual({ message: "The skin has been marked as NSFW." }); const skin = await SkinModel.fromMd5(ctx, "a_fake_md5"); expect(await skin?.getTweetStatus()).toEqual("NSFW"); }); // TODO: Actually upload some skins? test("/skins/status", async () => { const { body } = await request(app) .post("/skins/status") .send({ hashes: ["a_fake_md5", "a_missing_md5"] }); expect(body).toEqual({}); }); test("/approved", async () => { const { body } = await request(app).get("/approved").expect(200); expect(body).toEqual(["an_approved_md5", "a_tweeted_md5"]); }); test("/skins/a_fake_md5", async () => { let response = await request(app).get("/skins/a_fake_md5"); expect(response.body).toEqual({ fileName: "path.wsz", md5: "a_fake_md5", nsfw: false, }); response = await request(app).get("/skins/a_nsfw_md5"); expect(response.body).toEqual({ fileName: "nsfw.wsz", md5: "a_nsfw_md5", nsfw: true, }); await request(app).get("/skins/does_not_exist_md5").expect(404); }); test("/skins/get_upload_urls", async () => { const { body } = await request(app) .post("/skins/get_upload_urls") .send({ skins: { "3b73bcd43c30b85d4cad3083e8ac9695": "a_fake_new_file.wsz", "48bbdbbeb03d347e59b1eebda4d352d0": "a_new_name_for_a_file_that_exists.wsz", }, }); expect(S3.getSkinUploadUrl).toHaveBeenCalledWith( "3b73bcd43c30b85d4cad3083e8ac9695", expect.any(Number) ); expect(body).toEqual({ "3b73bcd43c30b85d4cad3083e8ac9695": { id: expect.any(Number), url: "", }, }); }); test("An Upload Flow", async () => { // Request an upload URL const md5 = "3b73bcd43c30b85d4cad3083e8ac9695"; const filename = "a_fake_new_file.wsz"; const skins = { [md5]: filename }; const getUrlsResponse = await request(app) .post("/skins/get_upload_urls") .send({ skins }); const id = getUrlsResponse.body[md5].id; expect(getUrlsResponse.body).toEqual({ [md5]: { id: expect.any(Number), url: "" }, }); const requestedUpload = await knex("skin_uploads").where({ id }).first(); expect(requestedUpload).toEqual({ filename, id, skin_md5: md5, status: "URL_REQUESTED", }); // Report that we've uploaded the skin to S3 (we lie) const uploadedResponse = await request(app) .post(`/skins/${md5}/uploaded`) .query({ id }) .send({ skins }); expect(uploadedResponse.body).toEqual({ done: true }); expect(processUserUploads).toHaveBeenCalled(); const reportedUpload = await knex("skin_uploads").where({ id }).first(); expect(reportedUpload).toEqual({ filename, id, skin_md5: md5, status: "UPLOAD_REPORTED", }); }); test("/stylegan.json", async () => { const response = await request(app).get("/stylegan.json"); expect(response.body).toMatchInlineSnapshot(` Array [ Object { "fileName": "Zelda_Amp_3.wsz", "md5": "48bbdbbeb03d347e59b1eebda4d352d0", "nsfw": false, "url": "https://r2.webampskins.org/screenshots/48bbdbbeb03d347e59b1eebda4d352d0.png", }, Object { "fileName": "path.wsz", "md5": "a_fake_md5", "nsfw": false, "url": "https://r2.webampskins.org/screenshots/a_fake_md5.png", }, Object { "fileName": "nsfw.wsz", "md5": "a_nsfw_md5", "nsfw": true, "url": "https://r2.webampskins.org/screenshots/a_nsfw_md5.png", }, Object { "fileName": "rejected.wsz", "md5": "a_rejected_md5", "nsfw": false, "url": "https://r2.webampskins.org/screenshots/a_rejected_md5.png", }, Object { "fileName": "tweeted.wsz", "md5": "a_tweeted_md5", "nsfw": false, "url": "https://r2.webampskins.org/screenshots/a_tweeted_md5.png", }, Object { "fileName": "approved.wsz", "md5": "an_approved_md5", "nsfw": false, "url": "https://r2.webampskins.org/screenshots/an_approved_md5.png", }, ] `); });