Draft snapshot tests

This commit is contained in:
zkldi
2022-04-13 12:50:24 +01:00
parent ba5828973b
commit 2bbae1019a
3 changed files with 509 additions and 7 deletions
@@ -0,0 +1,356 @@
import dm from "deepmerge";
import db from "external/mongo/db";
import t from "tap";
import { CreateFakeAuthCookie } from "test-utils/fake-auth";
import mockApi from "test-utils/mock-api";
import ResetDBState from "test-utils/resets";
import {
HC511Goal,
HC511UserGoal,
Testing511SPA,
TestingIIDXSPMilestone,
} from "test-utils/test-data";
// @ts-expect-error Not sure why the types break here, but they do.
const dupedGoal = dm({}, HC511Goal);
// @ts-expect-error Not sure why the types break here, but they do.
const dupedGoalSub = dm({}, HC511UserGoal);
t.test("GET /api/v1/users/:userID/games/:game/:playtype/targets/goals", (t) => {
t.beforeEach(ResetDBState);
t.test("Should retrieve this user's goal subscriptions.", async (t) => {
await db.goals.insert(dupedGoal);
await db["goal-subs"].insert(dupedGoalSub);
const res = await mockApi.get("/api/v1/users/1/games/iidx/SP/targets/goals");
t.equal(res.statusCode, 200);
t.strictSame(res.body.body, {
goals: [HC511Goal],
goalSubs: [HC511UserGoal],
});
t.end();
});
t.end();
});
t.test("POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal", async (t) => {
t.beforeEach(ResetDBState);
const cookie = await CreateFakeAuthCookie(mockApi);
const baseInput = {
criteria: {
key: "scoreData.percent",
value: 1,
mode: "single",
},
charts: {
type: "single",
data: Testing511SPA.chartID,
},
};
function mkInput(caseName: string, merge: any) {
return {
caseName,
content: dm(baseInput, merge),
};
}
t.test("Should set valid goals.", async (t) => {
const validInput = [
mkInput("Base Case", baseInput),
mkInput("Score:Single Case", {
criteria: {
key: "scoreData.score",
value: 1,
mode: "",
},
}),
];
t.end();
});
t.test("Should reject invalid goals.", async (t) => {
const invalidInput = [
mkInput("negative percent", {
criteria: {
value: -1,
},
}),
mkInput("percent of 0 is a non-goal", {
criteria: {
value: 0,
},
}),
mkInput("percent greater than 100", {
criteria: {
value: 100.1,
},
}),
mkInput("abs without countNum", {
criteria: {
mode: "abs",
},
}),
mkInput("proportion without countNum", {
criteria: {
mode: "proportion",
},
}),
mkInput("single with countNum", {
criteria: {
mode: "single",
countNum: 123,
},
}),
mkInput("nonsense mode", {
criteria: {
mode: "nonsense",
},
}),
mkInput("abs with countNum but charts.type == single", {
criteria: {
mode: "abs",
countNum: 1,
},
charts: {
type: "single",
},
}),
mkInput("nonsense charts.type", {
charts: {
type: "nonsense",
},
}),
mkInput("charts.data when type == any", {
charts: {
type: "any",
data: "foo",
},
}),
mkInput("charts.data array when type == single", {
charts: {
type: "single",
data: [Testing511SPA.chartID, Testing511SPA.chartID],
},
}),
mkInput("charts.data array of identical chartIDs", {
charts: {
type: "multi",
data: [Testing511SPA.chartID, Testing511SPA.chartID],
},
}),
mkInput("charts.data array of single chartID", {
charts: {
type: "multi",
data: [Testing511SPA.chartID],
},
}),
mkInput("charts.data array of chartIDs that don't exist", {
charts: {
type: "multi",
data: [Testing511SPA.chartID, "not_exist"],
},
}),
mkInput("charts.data folder refers to folder that doesn't exist", {
charts: {
type: "folder",
data: "fake-folder",
},
}),
mkInput("nonsense charts.data", {
charts: {
data: "nonsense",
},
}),
];
for (const input of invalidInput) {
// eslint-disable-next-line no-await-in-loop
const res = await mockApi
.post("/api/v1/users/1/games/iidx/SP/targets/goals/add-goal")
.set("Cookie", cookie)
.send(input.content);
t.equal(res.statusCode, 400);
t.matchSnapshot(res.body.description, `Invalid Goal: ${input.caseName}`);
}
t.end();
});
t.end();
});
t.test("GET /api/v1/users/:userID/games/:game/:playtype/targets/goals/:goalID", (t) => {
t.beforeEach(ResetDBState);
t.test("Should retrieve this user's goal subscription.", async (t) => {
await db.goals.insert(dupedGoal);
await db["goal-subs"].insert(dupedGoalSub);
const res = await mockApi.get(
`/api/v1/users/1/games/iidx/SP/targets/goals/${HC511Goal.goalID}`
);
t.equal(res.statusCode, 200);
t.hasStrict(res.body.body, {
goal: HC511Goal,
goalSub: HC511UserGoal,
milestones: [],
user: {
id: 1,
},
});
t.end();
});
t.test("Should return parent milestones if goal has any.", async (t) => {
await db.goals.insert(dupedGoal);
await db["goal-subs"].insert(
// @ts-expect-error Not sure why the types break here, but they do.
dm(HC511UserGoal, {
parentMilestones: [TestingIIDXSPMilestone.milestoneID],
})
);
await db.milestones.insert(dm(TestingIIDXSPMilestone, {}));
const res = await mockApi.get(
`/api/v1/users/1/games/iidx/SP/targets/goals/${HC511Goal.goalID}`
);
t.equal(res.statusCode, 200);
t.hasStrict(res.body.body, {
goal: HC511Goal,
goalSub: HC511UserGoal,
milestones: [TestingIIDXSPMilestone],
user: {
id: 1,
},
});
t.end();
});
t.test("Should panic if goal refers to a parent milestone that doesn't exist.", async (t) => {
await db.goals.insert(dupedGoal);
await db["goal-subs"].insert(
// @ts-expect-error Not sure why the types break here, but they do.
dm(HC511UserGoal, {
parentMilestones: [TestingIIDXSPMilestone.milestoneID],
})
);
const res = await mockApi.get(
`/api/v1/users/1/games/iidx/SP/targets/goals/${HC511Goal.goalID}`
);
t.equal(res.statusCode, 500);
t.end();
});
t.test("Should return 404 if the user is not subscribed to this goal ID.", async (t) => {
const res = await mockApi.get(`/api/v1/users/1/games/iidx/SP/targets/goals/INVALID_GOAL`);
t.equal(res.statusCode, 404);
t.end();
});
t.end();
});
t.test("DELETE /api/v1/users/:userID/games/:game/:playtype/targets/goals/:goalID", async (t) => {
t.beforeEach(ResetDBState);
const cookie = await CreateFakeAuthCookie(mockApi);
t.test("Should delete a goal subscription if subscribed.", async (t) => {
await db.goals.insert(dupedGoal);
await db["goal-subs"].insert(dupedGoalSub);
const res = await mockApi
.delete(`/api/v1/users/1/games/iidx/SP/targets/goals/${dupedGoalSub.goalID}`)
.set("Cookie", cookie);
t.equal(res.statusCode, 200);
const dbRes = await db["goal-subs"].findOne({
userID: 1,
goalID: dupedGoal.goalID,
});
t.equal(dbRes, null, "Should delete the goal sub from the database.");
t.end();
});
t.test("Should reject a goal deletion if goal has parent milestones.", async (t) => {
await db.goals.insert(dupedGoal);
await db["goal-subs"].insert(
// @ts-expect-error deepmerge type error
dm(dupedGoalSub, {
parentMilestones: [TestingIIDXSPMilestone.milestoneID],
})
);
const res = await mockApi
.delete(`/api/v1/users/1/games/iidx/SP/targets/goals/${dupedGoalSub.goalID}`)
.set("Cookie", cookie);
t.equal(res.statusCode, 400);
t.equal(
res.body.description,
"This goal is part of a milestone you are subscribed to. It can only be removed by unsubscribing from the relevant milestones."
);
const dbRes = await db["goal-subs"].findOne({
userID: 1,
goalID: dupedGoal.goalID,
});
t.not(dbRes, null, "Should NOT delete the goal sub from the database.");
t.end();
});
t.test("Should reject a goal deletion if not subscribed.", async (t) => {
await db.goals.insert(dupedGoal);
await db["goal-subs"].insert(dupedGoalSub);
const res = await mockApi
.delete(`/api/v1/users/1/games/iidx/SP/targets/goals/INVALID_GOAL`)
.set("Cookie", cookie);
t.equal(res.statusCode, 404);
t.end();
});
t.test("Should reject a goal deletion if not authed.", async (t) => {
await db.goals.insert(dupedGoal);
await db["goal-subs"].insert(dupedGoalSub);
const res = await mockApi.delete(
`/api/v1/users/1/games/iidx/SP/targets/goals/${dupedGoalSub.goalID}`
);
t.equal(res.statusCode, 401);
t.end();
});
t.end();
});
@@ -9,7 +9,7 @@ import p from "prudence";
import { RequirePermissions } from "server/middleware/auth";
import prValidate from "server/middleware/prudence-validate";
import { GoalDocument, MilestoneDocument } from "tachi-common";
import { GetGoalForIDGuaranteed, GetMilestoneForIDGuaranteed } from "utils/db";
import { GetGoalForIDGuaranteed } from "utils/db";
import { AssignToReqTachiData, GetUGPT } from "utils/req-tachi-data";
import { RequireAuthedAsUser } from "../../../../../middleware";
@@ -88,7 +88,7 @@ router.post(
);
}
// proper validation later.
// proper valid/ation later.
return p.gte(0)(self);
},
},
@@ -120,6 +120,8 @@ router.post(
);
}
// technically impossible, so let's ignore it.
/* istanbul ignore next */
return "Unknown charts.type.";
},
},
@@ -218,9 +220,19 @@ router.get("/:goalID", GetGoalSubscription, async (req, res) => {
let milestones: MilestoneDocument[] = [];
if (goalSub.parentMilestones.length !== 0) {
milestones = await Promise.all(
goalSub.parentMilestones.map((e) => GetMilestoneForIDGuaranteed(e))
);
milestones = await db.milestones.find({
milestoneID: { $in: goalSub.parentMilestones },
});
if (milestones.length !== goalSub.parentMilestones.length) {
logger.error(
`Goal '${goalSub.goalID} (uid:${goalSub.userID})' refers to parent milestones that don't exist?`
);
return res.status(500).json({
success: false,
description: `Something went wrong when fetching parent milestones. This has been reported.`,
});
}
}
const goal = await GetGoalForIDGuaranteed(goalSub.goalID);
@@ -247,7 +259,6 @@ router.delete(
RequireAuthedAsUser,
GetGoalSubscription,
RequirePermissions("manage_targets"),
prValidate({ goalID: "string" }),
async (req, res) => {
const goalID = req.params.goalID;
const { user, game, playtype } = GetUGPT(req);
@@ -260,7 +271,7 @@ router.delete(
});
if (!goalSub) {
return res.status(400).json({
return res.status(404).json({
success: false,
description: `You aren't subscribed to this goal.`,
});
@@ -0,0 +1,135 @@
/* IMPORTANT
* This snapshot file is auto-generated, but designed for humans.
* It should be checked into source control and tracked carefully.
* Re-generate by setting TAP_SNAPSHOT=1 and running tests.
* Make sure to inspect the output below. Do not ignore changes!
*/
'use strict'
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: abs with countNum but charts.type == single 1`] = `
Invalid countNum for goal with criteria.mode of 'abs'. Expected a whole number less than the total amount of charts available and greater than 1.
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: abs without countNum 1`] = `
[criteria.countNum] Expected number to be greater than or equal to 0. (Received nothing)
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data array of chartIDs that don't exist 1`] = `
Expected charts.data to match 2 charts. Instead, it only matched 1. Are all of these chartIDs valid?
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data array of identical chartIDs 1`] = `
Expected charts.data to match 2 charts. Instead, it only matched 1. Are all of these chartIDs valid?
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data array of single chartID 1`] = `
[charts.data] Expected an array of 2 to 5 strings in charts.data due to charts.type being 'multi'. (Received c2311194e3897ddb5745b1760d2c0141f933e683)
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data array when type == single 1`] = `
[charts.data] Expected a string in charts.data due to charts.type being 'single'. (Received c2311194e3897ddb5745b1760d2c0141f933e683,c2311194e3897ddb5745b1760d2c0141f933e683)
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data folder refers to folder that doesn't exist 1`] = `
A folder with id fake-folder does not exist for iidx:SP.
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data when type == any 1`] = `
[charts.data] Invalid charts.data for type 'any'. Must not have any data! (Received foo)
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: negative percent 1`] = `
[criteria.value] Expected number to be greater than or equal to 0. (Received -1)
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: nonsense charts.data 1`] = `
A chart with id nonsense does not exist for iidx:SP.
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: nonsense charts.type 1`] = `
[charts.type] Expected any of single, multi, folder, any. (Received nonsense)
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: nonsense mode 1`] = `
[criteria.mode] Expected any of single, abs, proportion. (Received nonsense)
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: percent greater than 100 1`] = `
Invalid value of 100.1 for percent goal. Percents must be between 0 and 100.
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: percent of 0 is a non-goal 1`] = `
Invalid value of 0 for percent goal. Percents must be between 0 and 100.
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: proportion without countNum 1`] = `
[criteria.countNum] Expected number to be greater than or equal to 0. (Received nothing)
`
exports[`src/test-utils/single-process-tap.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: single with countNum 1`] = `
[criteria.countNum] Invalid countNum for mode 'single'. Must not have one! (Received 123)
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: abs with countNum but charts.type == single 1`] = `
Invalid countNum for goal with criteria.mode of 'abs'. Expected a whole number less than the total amount of charts available and greater than 1.
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: abs without countNum 1`] = `
[criteria.countNum] Expected number to be greater than or equal to 0. (Received nothing)
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data array of chartIDs that don't exist 1`] = `
Expected charts.data to match 2 charts. Instead, it only matched 1. Are all of these chartIDs valid?
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data array of identical chartIDs 1`] = `
Expected charts.data to match 2 charts. Instead, it only matched 1. Are all of these chartIDs valid?
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data array of single chartID 1`] = `
[charts.data] Expected an array of 2 to 5 strings in charts.data due to charts.type being 'multi'. (Received c2311194e3897ddb5745b1760d2c0141f933e683)
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data array when type == single 1`] = `
[charts.data] Expected a string in charts.data due to charts.type being 'single'. (Received c2311194e3897ddb5745b1760d2c0141f933e683,c2311194e3897ddb5745b1760d2c0141f933e683)
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data folder refers to folder that doesn't exist 1`] = `
A folder with id fake-folder does not exist for iidx:SP.
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: charts.data when type == any 1`] = `
[charts.data] Invalid charts.data for type 'any'. Must not have any data! (Received foo)
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: negative percent 1`] = `
[criteria.value] Expected number to be greater than or equal to 0. (Received -1)
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: nonsense charts.data 1`] = `
A chart with id nonsense does not exist for iidx:SP.
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: nonsense charts.type 1`] = `
[charts.type] Expected any of single, multi, folder, any. (Received nonsense)
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: nonsense mode 1`] = `
[criteria.mode] Expected any of single, abs, proportion. (Received nonsense)
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: percent greater than 100 1`] = `
Invalid value of 100.1 for percent goal. Percents must be between 0 and 100.
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: percent of 0 is a non-goal 1`] = `
Invalid value of 0 for percent goal. Percents must be between 0 and 100.
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: proportion without countNum 1`] = `
[criteria.countNum] Expected number to be greater than or equal to 0. (Received nothing)
`
exports[`src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/goals/router.test.ts TAP POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal Should reject invalid goals. > Invalid Goal: single with countNum 1`] = `
[criteria.countNum] Invalid countNum for mode 'single'. Must not have one! (Received 123)
`