mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-13 01:38:29 +03:00
Full Add-Goal Tests
This commit is contained in:
@@ -159,7 +159,8 @@ export async function ValidateGoalChartsAndCriteria(
|
||||
}
|
||||
|
||||
chartCount = multiCharts.length;
|
||||
} else if (charts.type === "any") {
|
||||
} else {
|
||||
// (charts.type === "any")
|
||||
chartCount = await db.charts[game].count({ playtype });
|
||||
}
|
||||
|
||||
|
||||
+288
-22
@@ -1,6 +1,7 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
import dm from "deepmerge";
|
||||
import db from "external/mongo/db";
|
||||
import { ChartDocument } from "tachi-common";
|
||||
import { ChartDocument, IIDX_GRADES, IIDX_LAMPS } from "tachi-common";
|
||||
import t from "tap";
|
||||
import { CreateFakeAuthCookie } from "test-utils/fake-auth";
|
||||
import mockApi from "test-utils/mock-api";
|
||||
@@ -10,6 +11,7 @@ import {
|
||||
HC511Goal,
|
||||
HC511UserGoal,
|
||||
Testing511SPA,
|
||||
TestingIIDXFolderSP10,
|
||||
TestingIIDXSPMilestone,
|
||||
} from "test-utils/test-data";
|
||||
|
||||
@@ -57,7 +59,7 @@ t.test("POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal", asyn
|
||||
const baseInput = {
|
||||
criteria: {
|
||||
key: "scoreData.percent",
|
||||
value: 1,
|
||||
value: 80,
|
||||
mode: "single",
|
||||
},
|
||||
charts: {
|
||||
@@ -67,30 +69,181 @@ t.test("POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal", asyn
|
||||
};
|
||||
|
||||
function mkInput(caseName: string, merge: any) {
|
||||
return {
|
||||
const input = {
|
||||
caseName,
|
||||
content: dm(baseInput, merge),
|
||||
content: dm(baseInput, merge) as any,
|
||||
};
|
||||
|
||||
// if we've set this prop to undefined, we want to delete it, actually.
|
||||
if (input.content.charts.data === undefined) {
|
||||
delete input.content.charts.data;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
t.beforeEach(() => db.charts.iidx.insert(anotherFakeChart));
|
||||
// @ts-expect-error weird type issues
|
||||
t.beforeEach(() => db.folders.insert(dm(TestingIIDXFolderSP10, {})));
|
||||
|
||||
const multiCharts = {
|
||||
type: "multi",
|
||||
data: [Testing511SPA.chartID, "another_chart"],
|
||||
};
|
||||
|
||||
const anyCharts = {
|
||||
type: "any",
|
||||
data: undefined,
|
||||
};
|
||||
|
||||
const folderCharts = {
|
||||
type: "folder",
|
||||
data: TestingIIDXFolderSP10.folderID,
|
||||
};
|
||||
|
||||
t.test("Should set valid goals.", async (t) => {
|
||||
const validInput = [
|
||||
mkInput("Base Case", baseInput),
|
||||
mkInput("Percent:Single Case", {}),
|
||||
mkInput("Score:Single Case", {
|
||||
criteria: {
|
||||
key: "scoreData.score",
|
||||
value: 1,
|
||||
mode: "",
|
||||
value: 1000,
|
||||
},
|
||||
}),
|
||||
mkInput("LampIndex:Single Case", {
|
||||
criteria: {
|
||||
key: "scoreData.lampIndex",
|
||||
value: IIDX_LAMPS.EX_HARD_CLEAR,
|
||||
},
|
||||
}),
|
||||
mkInput("GradeIndex:Single Case", {
|
||||
criteria: {
|
||||
key: "scoreData.gradeIndex",
|
||||
value: IIDX_GRADES.AAA,
|
||||
},
|
||||
}),
|
||||
mkInput("Percent:Multi Case", {
|
||||
charts: multiCharts,
|
||||
}),
|
||||
// NOT LEGAL FOR IIDX, due to being nonsense! NEEDS SPECIFIC TESTING.
|
||||
// mkInput("Score:Multi Case", {
|
||||
// criteria: {
|
||||
// key: "scoreData.score",
|
||||
// value: 1,
|
||||
// },
|
||||
// charts: multiCharts,
|
||||
// }),
|
||||
mkInput("LampIndex:Multi Case", {
|
||||
criteria: {
|
||||
key: "scoreData.lampIndex",
|
||||
value: IIDX_LAMPS.HARD_CLEAR,
|
||||
},
|
||||
charts: multiCharts,
|
||||
}),
|
||||
mkInput("GradeIndex:Multi Case", {
|
||||
criteria: {
|
||||
key: "scoreData.gradeIndex",
|
||||
value: IIDX_GRADES.AAA,
|
||||
},
|
||||
charts: multiCharts,
|
||||
}),
|
||||
mkInput("Percent:Any Case", {
|
||||
charts: anyCharts,
|
||||
}),
|
||||
// also illegal in iidx, bms and pms.
|
||||
// mkInput("Score:Any Case", {
|
||||
// criteria: {
|
||||
// key: "scoreData.score",
|
||||
// value: 1000,
|
||||
// },
|
||||
// charts: anyCharts,
|
||||
// }),
|
||||
mkInput("LampIndex:Any Case", {
|
||||
criteria: {
|
||||
key: "scoreData.lampIndex",
|
||||
value: IIDX_LAMPS.HARD_CLEAR,
|
||||
},
|
||||
charts: anyCharts,
|
||||
}),
|
||||
mkInput("GradeIndex:Any Case", {
|
||||
criteria: {
|
||||
key: "scoreData.gradeIndex",
|
||||
value: IIDX_GRADES.AAA,
|
||||
},
|
||||
charts: anyCharts,
|
||||
}),
|
||||
mkInput("Percent:Folder Case", {
|
||||
charts: folderCharts,
|
||||
}),
|
||||
// also illegal in iidx, bms and pms.
|
||||
// mkInput("Score:Folder Case", {
|
||||
// criteria: {
|
||||
// key: "scoreData.score",
|
||||
// value: 1000,
|
||||
// },
|
||||
// charts: folderCharts,
|
||||
// }),
|
||||
mkInput("LampIndex:Folder Case", {
|
||||
criteria: {
|
||||
key: "scoreData.lampIndex",
|
||||
value: IIDX_LAMPS.HARD_CLEAR,
|
||||
},
|
||||
charts: folderCharts,
|
||||
}),
|
||||
mkInput("GradeIndex:Folder Case", {
|
||||
criteria: {
|
||||
key: "scoreData.gradeIndex",
|
||||
value: IIDX_GRADES.AAA,
|
||||
},
|
||||
charts: folderCharts,
|
||||
}),
|
||||
];
|
||||
|
||||
for (const input of validInput) {
|
||||
await t.test(`Valid Goal: ${input.caseName}`, async (t) => {
|
||||
const res = await mockApi
|
||||
.post("/api/v1/users/1/games/iidx/SP/targets/goals/add-goal")
|
||||
.set("Cookie", cookie)
|
||||
.send(input.content);
|
||||
|
||||
t.equal(
|
||||
// this looks stupid, but results in better errmsgs.
|
||||
res.statusCode === 200 ? 200 : res.body.description,
|
||||
200,
|
||||
"Should return 200"
|
||||
);
|
||||
|
||||
// don't bother doing circular db checks if this is good.
|
||||
if (res.statusCode !== 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
const existsInDb = await db.goals.findOne({
|
||||
charts: input.content.charts,
|
||||
criteria: input.content.criteria,
|
||||
});
|
||||
|
||||
t.not(existsInDb, null, "A new goal should be added to the database.");
|
||||
|
||||
const subscribed = await db["goal-subs"].findOne({
|
||||
userID: 1,
|
||||
goalID: existsInDb?.goalID ?? "edge_case",
|
||||
});
|
||||
|
||||
t.not(
|
||||
subscribed,
|
||||
null,
|
||||
`Requesting user 1 should be subscribed to their new goal.`
|
||||
);
|
||||
|
||||
t.end();
|
||||
});
|
||||
}
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("Should reject invalid goals.", async (t) => {
|
||||
await db.charts.iidx.insert(anotherFakeChart);
|
||||
|
||||
const invalidInput = [
|
||||
mkInput("negative percent", {
|
||||
criteria: {
|
||||
@@ -107,15 +260,47 @@ t.test("POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal", asyn
|
||||
value: 100.1,
|
||||
},
|
||||
}),
|
||||
mkInput("too big grade", {
|
||||
criteria: {
|
||||
key: "scoreData.gradeIndex",
|
||||
value: IIDX_GRADES.MAX + 1,
|
||||
},
|
||||
}),
|
||||
mkInput("invalid grade", {
|
||||
criteria: {
|
||||
key: "scoreData.gradeIndex",
|
||||
value: 0.5,
|
||||
},
|
||||
}),
|
||||
mkInput("too big lamp", {
|
||||
criteria: {
|
||||
key: "scoreData.lampIndex",
|
||||
value: IIDX_LAMPS.FULL_COMBO + 1,
|
||||
},
|
||||
}),
|
||||
mkInput("invalid lamp", {
|
||||
criteria: {
|
||||
key: "scoreData.lampIndex",
|
||||
value: 0.5,
|
||||
},
|
||||
}),
|
||||
mkInput("too big score", {
|
||||
criteria: {
|
||||
key: "scoreData.gradeIndex",
|
||||
value: 9_000,
|
||||
},
|
||||
}),
|
||||
mkInput("abs without countNum", {
|
||||
criteria: {
|
||||
mode: "abs",
|
||||
},
|
||||
charts: multiCharts,
|
||||
}),
|
||||
mkInput("proportion without countNum", {
|
||||
criteria: {
|
||||
mode: "proportion",
|
||||
},
|
||||
charts: multiCharts,
|
||||
}),
|
||||
mkInput("single with countNum", {
|
||||
criteria: {
|
||||
@@ -123,6 +308,27 @@ t.test("POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal", asyn
|
||||
countNum: 123,
|
||||
},
|
||||
}),
|
||||
mkInput("proportion with negative countNum", {
|
||||
criteria: {
|
||||
mode: "proportion",
|
||||
countNum: -0.5,
|
||||
},
|
||||
charts: multiCharts,
|
||||
}),
|
||||
mkInput("proportion with greater than 1 countNum", {
|
||||
criteria: {
|
||||
mode: "proportion",
|
||||
countNum: 1.1,
|
||||
},
|
||||
charts: multiCharts,
|
||||
}),
|
||||
mkInput("proportion which results in countNum of 0", {
|
||||
criteria: {
|
||||
mode: "proportion",
|
||||
countNum: 0.05,
|
||||
},
|
||||
charts: multiCharts,
|
||||
}),
|
||||
mkInput("nonsense mode", {
|
||||
criteria: {
|
||||
mode: "nonsense",
|
||||
@@ -151,7 +357,7 @@ t.test("POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal", asyn
|
||||
mkInput("charts.data array when type == single", {
|
||||
charts: {
|
||||
type: "single",
|
||||
data: [Testing511SPA.chartID, Testing511SPA.chartID],
|
||||
data: multiCharts.data,
|
||||
},
|
||||
}),
|
||||
mkInput("charts.data array of identical chartIDs", {
|
||||
@@ -166,7 +372,7 @@ t.test("POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal", asyn
|
||||
data: [Testing511SPA.chartID],
|
||||
},
|
||||
}),
|
||||
mkInput("charts.data array of chartIDs that don't exist", {
|
||||
mkInput("charts.data array of chartIDs where some don't exist", {
|
||||
charts: {
|
||||
type: "multi",
|
||||
data: [Testing511SPA.chartID, "not_exist"],
|
||||
@@ -186,30 +392,90 @@ t.test("POST /api/v1/users/:userID/games/:game/:playtype/targets/add-goal", asyn
|
||||
mkInput("multi-score for iidx is illegal", {
|
||||
criteria: {
|
||||
key: "scoreData.score",
|
||||
value: 1,
|
||||
value: 1000,
|
||||
},
|
||||
charts: {
|
||||
type: "multi",
|
||||
data: [Testing511SPA.chartID, "another_chart"],
|
||||
charts: multiCharts,
|
||||
}),
|
||||
mkInput("folder-score for iidx is illegal", {
|
||||
criteria: {
|
||||
key: "scoreData.score",
|
||||
value: 1000,
|
||||
},
|
||||
charts: folderCharts,
|
||||
}),
|
||||
mkInput("any-score for iidx is illegal", {
|
||||
criteria: {
|
||||
key: "scoreData.score",
|
||||
value: 1000,
|
||||
},
|
||||
charts: anyCharts,
|
||||
}),
|
||||
mkInput("charts single but criteria not.", {
|
||||
criteria: {
|
||||
mode: "abs",
|
||||
countNum: 2,
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
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);
|
||||
await t.test(`Invalid Goal: ${input.caseName}`, async (t) => {
|
||||
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.equal(res.statusCode, 400);
|
||||
|
||||
TestSnapshot(t, res.body.description, `Invalid Goal: ${input.caseName}`);
|
||||
TestSnapshot(t, res.body.description, `Invalid Goal: ${input.caseName}`);
|
||||
|
||||
t.end();
|
||||
});
|
||||
}
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("Should reject if user tries to subscribe to already subscribed goal.", async (t) => {
|
||||
const res = await mockApi
|
||||
.post("/api/v1/users/1/games/iidx/SP/targets/goals/add-goal")
|
||||
.set("Cookie", cookie)
|
||||
.send(baseInput);
|
||||
|
||||
t.equal(res.statusCode, 200, "Should allow a subscription the first time.");
|
||||
|
||||
const res2 = await mockApi
|
||||
.post("/api/v1/users/1/games/iidx/SP/targets/goals/add-goal")
|
||||
.set("Cookie", cookie)
|
||||
.send(baseInput);
|
||||
|
||||
t.equal(res2.statusCode, 409, "Should fail the second time.");
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("Should reject if user tries to subscribe to immediately achieved goal.", async (t) => {
|
||||
const res = await mockApi
|
||||
.post("/api/v1/users/1/games/iidx/SP/targets/goals/add-goal")
|
||||
.set("Cookie", cookie)
|
||||
.send(
|
||||
dm(baseInput, {
|
||||
criteria: {
|
||||
key: "scoreData.score",
|
||||
value: 1,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
t.equal(
|
||||
res.statusCode,
|
||||
400,
|
||||
"Should disallow goal subscriptions that would be instantly achieved."
|
||||
);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
|
||||
+3
@@ -114,12 +114,15 @@ router.post(
|
||||
"Expected an array of 2 to 5 strings in charts.data due to charts.type being 'multi'."
|
||||
);
|
||||
} else if (parent.type === "folder") {
|
||||
/* istanbul ignore previous */
|
||||
return (
|
||||
typeof self === "string" ||
|
||||
"Expected a string in charts.data due to charts.type being 'folder'."
|
||||
);
|
||||
}
|
||||
|
||||
// impossible to reach, so doesn't count for coverage.
|
||||
/* istanbul ignore next */
|
||||
return "Unknown charts.type.";
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1 +1,38 @@
|
||||
[]
|
||||
[
|
||||
{
|
||||
"chartID": "c2311194e3897ddb5745b1760d2c0141f933e683",
|
||||
"userID": 1,
|
||||
"calculatedData": {
|
||||
"ktLampRating": 0,
|
||||
"BPI": 10.1
|
||||
},
|
||||
"composedFrom": {
|
||||
"scorePB": "TESTING_SCORE_ID",
|
||||
"lampPB": "TESTING_SCORE_ID"
|
||||
},
|
||||
"highlight": false,
|
||||
"isPrimary": true,
|
||||
"scoreData": {
|
||||
"score": 786,
|
||||
"lamp": "HARD CLEAR",
|
||||
"percent": 50,
|
||||
"grade": "C",
|
||||
"esd": 30,
|
||||
"gradeIndex": 3,
|
||||
"lampIndex": 4,
|
||||
"judgements": {
|
||||
"pgreat": 50,
|
||||
"great": 10
|
||||
},
|
||||
"hitMeta": {}
|
||||
},
|
||||
"rankingData": {
|
||||
"rank": 1,
|
||||
"outOf": 2
|
||||
},
|
||||
"songID": 1,
|
||||
"game": "iidx",
|
||||
"playtype": "SP",
|
||||
"timeAchieved": 10000
|
||||
}
|
||||
]
|
||||
@@ -9,11 +9,23 @@
|
||||
"Invalid Goal: abs with countNum but charts.type == single": "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.",
|
||||
"Invalid Goal: nonsense charts.type": "[charts.type] Expected any of single, multi, folder, any. (Received nonsense)",
|
||||
"Invalid Goal: charts.data when type == any": "[charts.data] Invalid charts.data for type 'any'. Must not have any data! (Received foo)",
|
||||
"Invalid Goal: charts.data array when type == single": "[charts.data] Expected a string in charts.data due to charts.type being 'single'. (Received c2311194e3897ddb5745b1760d2c0141f933e683,c2311194e3897ddb5745b1760d2c0141f933e683)",
|
||||
"Invalid Goal: charts.data array when type == single": "[charts.data] Expected a string in charts.data due to charts.type being 'single'. (Received c2311194e3897ddb5745b1760d2c0141f933e683,another_chart)",
|
||||
"Invalid Goal: charts.data array of identical chartIDs": "Expected charts.data to match 2 charts. Instead, it only matched 1. Are all of these chartIDs valid?",
|
||||
"Invalid Goal: charts.data array of single chartID": "[charts.data] Expected an array of 2 to 5 strings in charts.data due to charts.type being 'multi'. (Received c2311194e3897ddb5745b1760d2c0141f933e683)",
|
||||
"Invalid Goal: charts.data array of chartIDs that don't exist": "Expected charts.data to match 2 charts. Instead, it only matched 1. Are all of these chartIDs valid?",
|
||||
"Invalid Goal: charts.data folder refers to folder that doesn't exist": "A folder with id fake-folder does not exist for iidx:SP.",
|
||||
"Invalid Goal: nonsense charts.data": "A chart with id nonsense does not exist for iidx:SP.",
|
||||
"Invalid Goal: multi-score for iidx is illegal": "Invalid key for iidx with multiple charts. Creating score goals on multiple charts where score is relative to notecount is a terrible idea, and has been disabled."
|
||||
"Invalid Goal: multi-score for iidx is illegal": "Invalid key for iidx with multiple charts. Creating score goals on multiple charts where score is relative to notecount is a terrible idea, and has been disabled.",
|
||||
"Invalid Goal: too big grade": "Invalid value of 10 for grade goal. No such grade exists at that index.",
|
||||
"Invalid Goal: invalid grade": "Invalid value of 0.5 for grade goal. No such grade exists at that index.",
|
||||
"Invalid Goal: too big lamp": "Invalid value of 8 for lamp goal. No such lamp exists at that index.",
|
||||
"Invalid Goal: invalid lamp": "Invalid value of 0.5 for lamp goal. No such lamp exists at that index.",
|
||||
"Invalid Goal: too big score": "Invalid value of 9000 for grade goal. No such grade exists at that index.",
|
||||
"Invalid Goal: proportion with negative countNum": "[criteria.countNum] Expected number to be greater than or equal to 0. (Received -0.5)",
|
||||
"Invalid Goal: proportion with greater than 1 countNum": "Invalid countNum for goal with criteria.mode of 'proportion'. Expected a decimal in (0, 1]",
|
||||
"Invalid Goal: proportion which results in countNum of 0": "countNum is too small for goal. Would result in requiring 0 charts to achieve the goal.",
|
||||
"Invalid Goal: charts.data array of chartIDs where some don't exist": "Expected charts.data to match 2 charts. Instead, it only matched 1. Are all of these chartIDs valid?",
|
||||
"Invalid Goal: folder-score for iidx is illegal": "Invalid key for iidx with multiple charts. Creating score goals on multiple charts where score is relative to notecount is a terrible idea, and has been disabled.",
|
||||
"Invalid Goal: any-score for iidx is illegal": "Invalid key for iidx with multiple charts. Creating score goals on multiple charts where score is relative to notecount is a terrible idea, and has been disabled.",
|
||||
"Invalid Goal: charts single but criteria not.": "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."
|
||||
}
|
||||
Reference in New Issue
Block a user