sendou.ink/app/modules/analyzer/abilityChunksCalc.test.ts
William Lam 2da0738dc6
Ability Chunks Required section in Build Analyzer (#1120)
* Added Ability Chunks Required section in Build Analyzer

* Renamed a variable to be more precisely correct

* Added reference

* Removed some extra Javadoc comments

* Prettier fix

* We now only render the AbilityChunksRequired section only if the main abilities array contains a value other than "UNKNOWN"

* Improved React keys naming for performance reasons

* Ability Chunks map is now converted to an array & sorted by value (descending) before it gets rendered as visual components

* Fixed typing error

* Moved logical function to a new file in the analyzer module called abilityChunksCalc.ts
- Refactored for loop content to be cleaner
- Removed & changed some comments

* More for loop refactoring

* We now pass the entire build into abilityChunksCalc.ts

* Refactored map() to flatMap() so we avoid unknowns/null/undefined

* Refactored code to process mainAbilities and subAbilities

* Fixed subability list construction logic & typing in updateAbilityChunksMap()

* Got my first unit test working

* Added working unit tests, also changed sort order slightly

* Added a "real" build for testing

* Removed residual console.warn() call

* Moved constants to abilityChunksCalc.ts

* Ability chunk calculation is now correct for sub abilities

* Uncommented tests & improved their descriptions

* Rearranged expected output to match sorted order for clarity (even though it doesn't have to be)

* Fixed Prettier error

* Spacing

* Moved comments around

* More spacing

* Prettier error on test file

* Improved check in the tests

* Added a second "real" build to tests for good measure

* Added error message to empty array test

* Updated comments again

* More comments updated

* Update test name

* Ability Chunks section is now shown if we have at least one selected ability (handles edge case for primary slot-only abilities being the only chosen ability)
2022-11-16 00:10:48 +02:00

134 lines
4.0 KiB
TypeScript

import { suite } from "uvu";
import * as assert from "uvu/assert";
import type { BuildAbilitiesTupleWithUnknown } from "../in-game-lists";
import type { AbilityWithUnknown } from "../in-game-lists/types";
import { getAbilityChunksMapAsArray } from "./abilityChunksCalc";
// Utility function that performs an order-agnostic check to see
// if the abilityChunksArray contains all elements from the expected output.
function validateAbilityChunksArray(
abilityChunksArray: [AbilityWithUnknown, number][],
expectedOutput: (string | number)[][]
) {
for (const output of expectedOutput) {
const typedOutput = output as [AbilityWithUnknown, number];
const isFoundInAbilityChunksArray = abilityChunksArray.filter(
(result) => JSON.stringify(result) === JSON.stringify(typedOutput)
).length;
const errorString = `${JSON.stringify(
typedOutput
)} was not found in the actual output.\nExpected output: ${JSON.stringify(
expectedOutput
)}\nActual Output: ${JSON.stringify(abilityChunksArray)}`;
assert.ok(isFoundInAbilityChunksArray, errorString);
}
}
const GetAbilityChunksMapAsArray = suite("getAbilityChunksMapAsArray()");
GetAbilityChunksMapAsArray("Empty build results in an empty array", () => {
const emptyBuild = [
["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
] as unknown as BuildAbilitiesTupleWithUnknown;
const abilityChunksArray = getAbilityChunksMapAsArray(emptyBuild);
assert.equal(abilityChunksArray, [], "Ability chunks array is not empty.");
});
GetAbilityChunksMapAsArray(
"Main Ability stackable ability chunk calculation is correct",
() => {
const build = [
["ISS", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
["ISM", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
] as unknown as BuildAbilitiesTupleWithUnknown;
const expectedOutput = [
["ISM", 45],
["ISS", 45],
];
const abilityChunksArray = getAbilityChunksMapAsArray(build);
validateAbilityChunksArray(abilityChunksArray, expectedOutput);
}
);
GetAbilityChunksMapAsArray(
"Ninja Squid ability chunk calculation is correct (for a primary slot-only ability)",
() => {
const build = [
["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
["NS", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"],
] as unknown as BuildAbilitiesTupleWithUnknown;
const expectedOutput = [
["RSU", 15],
["IRU", 15],
["SSU", 15],
];
const abilityChunksArray = getAbilityChunksMapAsArray(build);
validateAbilityChunksArray(abilityChunksArray, expectedOutput);
}
);
GetAbilityChunksMapAsArray(
"Ability chunk calculation is correct for a real build. Each gear has 1, 2 or 3 ability chunks of same type",
() => {
const slayerBuild = [
["LDE", "SSU", "SSU", "SSU"],
["NS", "QR", "QR", "ISM"],
["SJ", "SSU", "RES", "QSJ"],
] as unknown as BuildAbilitiesTupleWithUnknown;
const expectedOutput = [
["SSU", 85],
["IRU", 30],
["QR", 30],
["ISM", 25],
["QSJ", 25],
["IA", 15],
["ISS", 15],
["RSU", 15],
["SRU", 15],
["RES", 10],
];
const abilityChunksArray = getAbilityChunksMapAsArray(slayerBuild);
validateAbilityChunksArray(abilityChunksArray, expectedOutput);
}
);
GetAbilityChunksMapAsArray(
"Ability chunk calculation is correct for a real build (Splatling)",
() => {
const splatlingBuild = [
["RSU", "QSJ", "SSU", "RSU"],
["RSU", "ISM", "ISM", "RSU"],
["OS", "SSU", "SSU", "RES"],
] as unknown as BuildAbilitiesTupleWithUnknown;
const expectedOutput = [
["RSU", 110],
["SSU", 40],
["ISM", 30],
["BRU", 15],
["IRU", 15],
["SPU", 15],
["QSJ", 10],
["RES", 10],
];
const abilityChunksArray = getAbilityChunksMapAsArray(splatlingBuild);
validateAbilityChunksArray(abilityChunksArray, expectedOutput);
}
);
GetAbilityChunksMapAsArray.run();