JEST: Enable restoreMocks option and fix lint errors (#2333)

* JEST: Enable restoreMocks option and fix lint errors

* Fix test\jest\Save.test.ts
This commit is contained in:
catloversg
2025-10-05 04:38:50 +07:00
committed by GitHub
parent 18b062663d
commit 020b185377
14 changed files with 173 additions and 129 deletions

View File

@@ -21,4 +21,5 @@ module.exports = {
"/utils/Protections$": "<rootDir>/test/__mocks__/NullMock.js",
"@swc/wasm-web": "@swc/core",
},
restoreMocks: true,
};

View File

@@ -3,6 +3,7 @@ import { PlayerObject } from "../../../src/PersonObjects/Player/PlayerObject";
import { Player, setPlayer } from "@player";
import { BlackOperation, Contract, GeneralAction, Operation } from "../../../src/Bladeburner/Actions";
import {
AugmentationName,
BladeburnerActionType,
BladeburnerContractName,
BladeburnerGeneralActionName,
@@ -15,6 +16,8 @@ import { CrimeWork } from "../../../src/Work/CrimeWork";
import type { Action, ActionIdentifier } from "../../../src/Bladeburner/Types";
import type { Skills } from "@nsdefs";
import { BlackOperations } from "../../../src/Bladeburner/data/BlackOperations";
import { applyAugmentation } from "../../../src/Augmentation/AugmentationHelpers";
import { PlayerOwnedAugmentation } from "../../../src/Augmentation/PlayerOwnedAugmentation";
describe("Bladeburner Actions", () => {
const SampleContract = Contract.createId(BladeburnerContractName.Tracking);
@@ -24,6 +27,7 @@ describe("Bladeburner Actions", () => {
const ENOUGH_TIME_TO_FINISH_ACTION = 1e5;
const BASE_STAT_EXP = 1e6;
const HIGH_CHAOS = 1e12;
let bb: Bladeburner;
@@ -83,26 +87,30 @@ describe("Bladeburner Actions", () => {
it("mildly reduces chaos in the current city", () => {
allCitiesHighChaos();
let { chaos } = bb.getCurrentCity();
const { chaos } = bb.getCurrentCity();
complete(diplomacy);
expect(bb.getCurrentCity().chaos).toBeGreaterThan(chaos * 0.9);
expect(bb.getCurrentCity().chaos).toBeLessThan(chaos);
});
it("effect scales significantly with player charisma", () => {
Player.gainCharismaExp(1e500);
gainHighCharismaLevel();
allCitiesHighChaos();
complete(diplomacy);
expect(bb.getCurrentCity().chaos).toBe(0);
expect(bb.getCurrentCity().chaos).toStrictEqual(0);
});
it("does NOT affect chaos in other cities", () => {
const otherCity = <CityName>cities.find((c) => c !== bb.getCurrentCity().name);
const otherCity = cities.find((c) => c !== bb.getCurrentCity().name);
if (!otherCity) {
throw new Error("Invalid otherCity");
}
/** Testing against a guaranteed 0-chaos level of charisma */
Player.gainCharismaExp(1e500);
gainHighCharismaLevel();
allCitiesHighChaos();
complete(diplomacy);
expect(bb.cities[otherCity].chaos).toBeGreaterThan(0);
expect(bb.getCurrentCity().chaos).toStrictEqual(0);
expect(bb.cities[otherCity].chaos).toStrictEqual(HIGH_CHAOS);
});
});
@@ -284,6 +292,15 @@ describe("Bladeburner Actions", () => {
resetCity();
}
function gainHighCharismaLevel() {
for (let i = 1; i <= 1000; ++i) {
const aug = new PlayerOwnedAugmentation(AugmentationName.NeuroFluxGovernor);
aug.level = i;
applyAugmentation(aug);
}
Player.gainCharismaExp(1e6);
}
function resetCity() {
bb.cities[bb.city].chaos = 0;
bb.cities[bb.city].comms = 100;
@@ -295,7 +312,7 @@ describe("Bladeburner Actions", () => {
function allCitiesHighChaos() {
for (const city of Object.values(bb.cities)) {
city.chaos = 1e12;
city.chaos = HIGH_CHAOS;
}
}

View File

@@ -45,7 +45,6 @@ describe("MessageHelpers tests", () => {
it("Should not repeatedly send the Icarus message after the player's first bitnode completion", () => {
initSourceFiles();
Player.sourceFiles.set(1, 1);
jest.spyOn(console, "warn").mockImplementation(() => {}); // Prevent test spam
Player.queueAugmentation(AugmentationName.TheRedPill);
installAugmentations();
Player.gainHackingExp(2 ** 200);

View File

@@ -25,6 +25,9 @@ test("Edge cases of disableLog", function () {
const ws = new WorkerScript(runningScript, 1, NetscriptFunctions);
const ns = ws.env.vars;
if (!ns) {
throw new Error("Invalid ws.env.vars");
}
// Generate logs in a specific pattern that checks edge cases in
// disableLog. We want to check various combinations of things that
@@ -82,6 +85,8 @@ test("Edge cases of disableLog", function () {
"end",
]);
} finally {
if (server) {
DeleteServer(server.hostname);
}
}
});

View File

@@ -1,15 +1,15 @@
import { Player } from "../../../src/Player";
import { NetscriptFunctions } from "../../../src/NetscriptFunctions";
import { RamCosts, getRamCost, RamCostConstants, RamCostTree } from "../../../src/Netscript/RamCostGenerator";
import { RamCosts, getRamCost, RamCostConstants, type RamCostTree } from "../../../src/Netscript/RamCostGenerator";
import { Environment } from "../../../src/Netscript/Environment";
import { RunningScript } from "../../../src/Script/RunningScript";
import { Script } from "../../../src/Script/Script";
import { WorkerScript } from "../../../src/Netscript/WorkerScript";
import type { WorkerScript } from "../../../src/Netscript/WorkerScript";
import { calculateRamUsage } from "../../../src/Script/RamCalculations";
import { ns } from "../../../src/NetscriptFunctions";
import { InternalAPI } from "src/Netscript/APIWrapper";
import { Singularity } from "@nsdefs";
import { ScriptFilePath } from "src/Paths/ScriptFilePath";
import type { InternalAPI } from "../../../src/Netscript/APIWrapper";
import type { Singularity } from "@nsdefs";
import type { ScriptFilePath } from "../../../src/Paths/ScriptFilePath";
type PotentiallyAsyncFunction = (arg?: unknown) => { catch?: PotentiallyAsyncFunction };
@@ -21,12 +21,10 @@ function getFunction(fn: unknown) {
function grabCost<API>(ramEntry: RamCostTree<API>[keyof API]) {
if (typeof ramEntry === "function") return ramEntry();
if (typeof ramEntry === "number") return ramEntry;
throw new Error("Invalid ramcost: " + ramEntry);
throw new Error("Invalid ramcost: " + String(ramEntry));
}
describe("Netscript RAM Calculation/Generation Tests", function () {
jest.spyOn(console, "warn").mockImplementation(() => {});
jest.spyOn(console, "error").mockImplementation(() => {});
Player.sourceFiles.set(4, 3);
// For simulating costs of singularity functions.
const baseCost = RamCostConstants.Base;
@@ -96,12 +94,23 @@ describe("Netscript RAM Calculation/Generation Tests", function () {
workerScript.env.vars = nsExternal;
// Run the function through the workerscript's args
const fnPathAsString = fnPath.join(".");
if (typeof fn === "function") {
let consoleError;
let consoleWarning;
if (fnPathAsString === "ui.setTheme" || fnPathAsString === "ui.setStyles") {
consoleError = jest.spyOn(console, "error").mockImplementation(jest.fn());
}
if (fnPathAsString === "alterReality") {
consoleWarning = jest.spyOn(console, "warn").mockImplementation(jest.fn());
}
tryFunction(fn);
tryFunction(fn);
tryFunction(fn);
consoleError?.mockRestore();
consoleWarning?.mockRestore();
} else {
throw new Error(`Invalid function specified: [${fnPath.toString()}]`);
throw new Error(`Invalid function specified: [${fnPathAsString}]`);
}
if (expectedRamCost !== 0) {
@@ -180,7 +189,7 @@ describe("Netscript RAM Calculation/Generation Tests", function () {
])("%s", (code, expected) => {
const fullCode = `export function main(ns) { ${code} }`;
const result = calculateRamUsage(fullCode, "testfile.js", new Map(), "testserver");
const result = calculateRamUsage(fullCode, "testfile.js" as ScriptFilePath, "testserver", new Map());
expect(result.errorMessage).toBe(undefined);
expect(result.cost).toBe(expected);
});

View File

@@ -2,12 +2,11 @@ import type { Script } from "../../../src/Script/Script";
import type { ScriptFilePath } from "../../../src/Paths/ScriptFilePath";
import { runScriptFromScript, startWorkerScript } from "../../../src/NetscriptWorker";
import { workerScripts } from "../../../src/Netscript/WorkerScripts";
import { config as EvaluatorConfig } from "../../../src/NetscriptJSEvaluator";
import { Server } from "../../../src/Server/Server";
import { RunningScript } from "../../../src/Script/RunningScript";
import { AddToAllServers, DeleteServer, GetServerOrThrow } from "../../../src/Server/AllServers";
import { AlertEvents } from "../../../src/ui/React/AlertManager";
import { initGameEnvironment, setupBasicTestingEnvironment } from "./Utilities";
import { fixDoImportIssue, initGameEnvironment, setupBasicTestingEnvironment } from "../Utilities";
import { Terminal } from "../../../src/Terminal";
import { runScript } from "../../../src/Terminal/commands/runScript";
import { Player } from "@player";
@@ -18,25 +17,7 @@ import { NetscriptFunctions } from "../../../src/NetscriptFunctions";
import type { PositiveInteger } from "../../../src/types";
import { ErrorState } from "../../../src/ErrorHandling/ErrorState";
declare const importActual: (typeof EvaluatorConfig)["doImport"];
// Replace Blob/ObjectURL functions, because they don't work natively in Jest
global.Blob = class extends Blob {
code: string;
constructor(blobParts?: BlobPart[], __options?: BlobPropertyBag) {
super();
this.code = String((blobParts ?? [])[0]);
}
};
global.URL.revokeObjectURL = function () {};
// Critical: We have to overwrite this, otherwise we get Jest's hooked
// implementation, which will not work without passing special flags to Node,
// and tends to crash even if you do.
EvaluatorConfig.doImport = importActual;
global.URL.createObjectURL = function (blob) {
return "data:text/javascript," + encodeURIComponent((blob as unknown as { code: string }).code);
};
fixDoImportIssue();
initGameEnvironment();
@@ -122,11 +103,6 @@ async function expectErrorWhenRunningScript(
errorShown: Promise<unknown>,
errorMessage: string,
): Promise<void> {
/**
* Suppress console.error(). When there is a thrown error in the player's script, we print it to the console. In
* this test, we intentionally throw an error, so we can ignore it.
*/
jest.spyOn(console, "error").mockImplementation(jest.fn());
for (const script of scripts) {
Player.getHomeComputer().writeToScriptFile(script.filePath, script.code);
}
@@ -135,10 +111,16 @@ async function expectErrorWhenRunningScript(
if (!workerScript) {
throw new Error(`Invalid worker script`);
}
/**
* Suppress console.error(). When there is a thrown error in the player's script, we print it to the console. In
* this test, we intentionally throw an error, so we can ignore it.
*/
const consoleError = jest.spyOn(console, "error").mockImplementation(jest.fn());
const result = await Promise.race([
errorShown,
new Promise<void>((resolve) => (workerScript.atExit = new Map([["default", resolve]]))),
]);
consoleError.mockRestore();
expect(result).toBeDefined();
expect(workerScript.scriptRef.logs[0]).toContain(errorMessage);
}

View File

@@ -7,7 +7,7 @@ import { GetServerOrThrow } from "../../../src/Server/AllServers";
import { SpecialServers } from "../../../src/Server/data/SpecialServers";
import { Factions } from "../../../src/Faction/Factions";
import { PlayerOwnedAugmentation } from "../../../src/Augmentation/PlayerOwnedAugmentation";
import { getNS, initGameEnvironment, setupBasicTestingEnvironment } from "./Utilities";
import { getNS, initGameEnvironment, setupBasicTestingEnvironment } from "../Utilities";
import { Terminal } from "../../../src/Terminal";
import type { NSFull } from "../../../src/NetscriptFunctions";
import { Companies } from "../../../src/Company/Companies";

View File

@@ -3,6 +3,8 @@ import type { ScriptFilePath } from "../../../src/Paths/ScriptFilePath";
import { calculateRamUsage } from "../../../src/Script/RamCalculations";
import { RamCosts } from "../../../src/Netscript/RamCostGenerator";
import { Script } from "../../../src/Script/Script";
import { setPlayer } from "@player";
import { PlayerObject } from "../../../src/PersonObjects/Player/PlayerObject";
const BaseCost = 1.6;
const HackCost = 0.1;
@@ -14,8 +16,14 @@ const MaxCost = 1024;
const filename = "testfile.js" as ScriptFilePath;
const folderFilename = "test/testfile.js" as ScriptFilePath;
const server = "testserver";
/**
* Init the player object. When calculating the RAM usage of singularity APIs, RamCostGenerator.ts needs to access some
* properties and functions of the player object.
*/
setPlayer(new PlayerObject());
describe("Parsing NetScript code to work out static RAM costs", function () {
jest.spyOn(console, "error").mockImplementation(() => {});
/** Tests numeric equality, allowing for floating point imprecision - and includes script base cost */
function expectCost(val: number | undefined, expected: number) {
const expectedWithBase = Math.min(expected + BaseCost, MaxCost);
@@ -24,7 +32,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
}
describe("Single files with basic NS functions", function () {
it("Empty main function", async function () {
it("Empty main function", function () {
const code = `
export async function main(ns) { }
`;
@@ -32,7 +40,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, 0);
});
it("Free NS function directly in main", async function () {
it("Free NS function directly in main", function () {
const code = `
export async function main(ns) {
ns.print("Slum snakes r00l!");
@@ -42,7 +50,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, 0);
});
it("Single simple base NS function directly in main", async function () {
it("Single simple base NS function directly in main", function () {
const code = `
export async function main(ns) {
await ns.hack("joesguns");
@@ -52,7 +60,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, HackCost);
});
it("Single simple base NS function directly in main with differing arg name", async function () {
it("Single simple base NS function directly in main with differing arg name", function () {
const code = `
export async function main(X) {
await X.hack("joesguns");
@@ -62,7 +70,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, HackCost);
});
it("Repeated simple base NS function directly in main", async function () {
it("Repeated simple base NS function directly in main", function () {
const code = `
export async function main(ns) {
await ns.hack("joesguns");
@@ -73,7 +81,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, HackCost);
});
it("Multiple simple base NS functions directly in main", async function () {
it("Multiple simple base NS functions directly in main", function () {
const code = `
export async function main(ns) {
await ns.hack("joesguns");
@@ -84,7 +92,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, HackCost + GrowCost);
});
it("Simple base NS functions in a referenced function", async function () {
it("Simple base NS functions in a referenced function", function () {
const code = `
export async function main(ns) {
doHacking(ns);
@@ -97,7 +105,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, HackCost);
});
it("Simple base NS functions in a referenced class", async function () {
it("Simple base NS functions in a referenced class", function () {
const code = `
export async function main(ns) {
await new Hacker(ns).doHacking();
@@ -112,7 +120,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, HackCost);
});
it("Simple base NS functions in a referenced class", async function () {
it("Simple base NS functions in a referenced class", function () {
const code = `
export async function main(ns) {
await new Hacker(ns).doHacking();
@@ -129,7 +137,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
});
describe("Functions that can be confused with NS functions", function () {
it("Function 'get' that can be confused with Stanek.get", async function () {
it("Function 'get' that can be confused with Stanek.get", function () {
const code = `
export async function main(ns) {
get();
@@ -140,7 +148,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, 0);
});
it("Function 'purchaseNode' that can be confused with Hacknet.purchaseNode", async function () {
it("Function 'purchaseNode' that can be confused with Hacknet.purchaseNode", function () {
const code = `
export async function main(ns) {
purchaseNode();
@@ -153,7 +161,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
});
// TODO: once we fix static parsing this should pass
it.skip("Function 'getTask' that can be confused with Sleeve.getTask", async function () {
it.skip("Function 'getTask' that can be confused with Sleeve.getTask", function () {
const code = `
export async function main(ns) {
getTask();
@@ -166,7 +174,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
});
describe("Single files with non-core NS functions", function () {
it("Hacknet NS function with a cost from namespace", async function () {
it("Hacknet NS function with a cost from namespace", function () {
const code = `
export async function main(ns) {
ns.hacknet.purchaseNode(0);
@@ -176,7 +184,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, HacknetCost);
});
it("Sleeve functions with an individual cost", async function () {
it("Sleeve functions with an individual cost", function () {
const code = `
export async function main(ns) {
ns.sleeve.getTask(3);
@@ -188,7 +196,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
});
describe("Imported files", function () {
it("Simple imported function with no cost", async function () {
it("Simple imported function with no cost", function () {
const libCode = `
export function dummy() { return 0; }
`;
@@ -209,7 +217,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, 0);
});
it("Imported ns function", async function () {
it("Imported ns function", function () {
const libCode = `
export async function doHack(ns) { return await ns.hack("joesguns"); }
`;
@@ -230,7 +238,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, HackCost);
});
it("Importing a single function from a library that exports multiple", async function () {
it("Importing a single function from a library that exports multiple", function () {
const libCode = `
export async function doHack(ns) { return await ns.hack("joesguns"); }
export async function doGrow(ns) { return await ns.grow("joesguns"); }
@@ -252,7 +260,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, HackCost);
});
it("Importing all functions from a library that exports multiple", async function () {
it("Importing all functions from a library that exports multiple", function () {
const libCode = `
export async function doHack(ns) { return await ns.hack("joesguns"); }
export async function doGrow(ns) { return await ns.grow("joesguns"); }
@@ -296,7 +304,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
});
// TODO: once we fix static parsing this should pass
it.skip("Importing a function from a library that contains a class", async function () {
it.skip("Importing a function from a library that contains a class", function () {
const libCode = `
export async function doHack(ns) { return await ns.hack("joesguns"); }
class Grower {
@@ -322,7 +330,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, HackCost);
});
it("Importing a function from a library that creates a class in a function", async function () {
it("Importing a function from a library that creates a class in a function", function () {
const libCode = `
export function createClass() {
class Grower {
@@ -353,7 +361,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
expectCost(calculated, GrowCost);
});
it("Importing with a relative path - One Layer Deep", async function () {
it("Importing with a relative path - One Layer Deep", function () {
const libCode = `
export async function testRelative(ns) {
await ns.hack("n00dles")
@@ -375,7 +383,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
).cost;
expectCost(calculated, HackCost);
});
it("Importing with a relative path - Two Layer Deep", async function () {
it("Importing with a relative path - Two Layer Deep", function () {
const libNameOne = "test/libTestOne.js" as ScriptFilePath;
const libNameTwo = "test/libTestTwo.js" as ScriptFilePath;
@@ -412,7 +420,7 @@ describe("Parsing NetScript code to work out static RAM costs", function () {
).cost;
expectCost(calculated, HackCost);
});
it("Importing with a relative path - possible path conflict", async function () {
it("Importing with a relative path - possible path conflict", function () {
const libNameOne = "foo/libTestOne.js" as ScriptFilePath;
const libNameTwo = "foo/libTestTwo.js" as ScriptFilePath;
const incorrect_libNameTwo = "test/libTestTwo.js" as ScriptFilePath;

View File

@@ -2,7 +2,7 @@ import { IStyleSettings, UserInterfaceTheme } from "../../../src/ScriptEditor/Ne
import { Settings } from "../../../src/Settings/Settings";
import { defaultStyles } from "../../../src/Themes/Styles";
import { defaultTheme } from "../../../src/Themes/Themes";
import { getNS, initGameEnvironment, setupBasicTestingEnvironment } from "./Utilities";
import { getNS, initGameEnvironment, setupBasicTestingEnvironment } from "../Utilities";
const themeHexColor = "#abc";
const fontFamily = "monospace";

View File

@@ -1,50 +0,0 @@
import { WorkerScript } from "../../../src/Netscript/WorkerScript";
import { NetscriptFunctions, type NSFull } from "../../../src/NetscriptFunctions";
import type { ScriptFilePath } from "../../../src/Paths/ScriptFilePath";
import { PlayerObject } from "../../../src/PersonObjects/Player/PlayerObject";
import { Player, setPlayer } from "../../../src/Player";
import { RunningScript } from "../../../src/Script/RunningScript";
import { GetServerOrThrow, initForeignServers, prestigeAllServers } from "../../../src/Server/AllServers";
import { SpecialServers } from "../../../src/Server/data/SpecialServers";
import { initSourceFiles } from "../../../src/SourceFile/SourceFiles";
import { FormatsNeedToChange } from "../../../src/ui/formatNumber";
import { Router } from "../../../src/ui/GameRoot";
export function initGameEnvironment() {
// We need to patch this function. Some APIs call it, but it only works properly after the main UI is loaded.
Router.toPage = () => {};
/**
* In src\ui\formatNumber.ts, there are some variables that need to be initialized before other functions can be
* called. We have to call FormatsNeedToChange.emit() to initialize those variables.
*/
FormatsNeedToChange.emit();
initSourceFiles();
}
export function setupBasicTestingEnvironment(): void {
prestigeAllServers();
setPlayer(new PlayerObject());
Player.init();
Player.sourceFiles.set(4, 3);
initForeignServers(Player.getHomeComputer());
}
export function getNS(): NSFull {
const home = GetServerOrThrow(SpecialServers.Home);
home.maxRam = 1024;
const filePath = "test.js" as ScriptFilePath;
home.writeToScriptFile(filePath, "");
const script = home.scripts.get(filePath);
if (!script) {
throw new Error("Invalid script");
}
const runningScript = new RunningScript(script, 1024);
const workerScript = new WorkerScript(runningScript, 1, NetscriptFunctions);
const ns = workerScript.env.vars;
if (!ns) {
throw new Error("Invalid NS instance");
}
return ns;
}

View File

@@ -6,8 +6,12 @@ import { Settings } from "../../src/Settings/Settings";
import { Player, setPlayer } from "../../src/Player";
import { PlayerObject } from "../../src/PersonObjects/Player/PlayerObject";
import { UIEventEmitter, UIEventType } from "../../src/ui/UIEventEmitter";
import { fixDoImportIssue } from "./Utilities";
jest.useFakeTimers();
fixDoImportIssue();
// Direct tests of loading and saving.
// Tests here should try to be comprehensive (cover as much stuff as possible)
// without requiring burdensome levels of maintenance when legitimate changes
@@ -98,7 +102,7 @@ function loadStandardServers() {
{
"ctor": "Script",
"data": {
"code": "/** @param {NS} ns */\\nexport async function main(ns) {\\n return ns.asleep(1000000);\\n}",
"code": "/** @param {NS} ns */\nexport async function main(ns) {\n return ns.asleep(1000000);\n}",
"filename": "script.js",
"module": {},
"dependencies": [

View File

@@ -33,10 +33,6 @@ import {
} from "../../src/StockMarket/StockMarketHelpers";
import { CompanyName, LocationName, OrderType, PositionType } from "../../src/Enums";
// jest.mock("../src/ui/React/createPopup.tsx", () => ({
// createPopup: jest.fn(),
// }));
describe("Stock Market Tests", function () {
const commission = StockMarketConstants.StockMarketCommission;
@@ -451,7 +447,7 @@ describe("Stock Market Tests", function () {
it("should trigger a price update when it has enough cycles", function () {
// Get the initial prices
const initialValues: Record<string, any> = {};
const initialValues: Record<string, { price: number; otlkMag: number; b: boolean }> = {};
for (const stockName in StockMarket) {
const stock = StockMarket[stockName];
if (!(stock instanceof Stock)) {

73
test/jest/Utilities.ts Normal file
View File

@@ -0,0 +1,73 @@
import { WorkerScript } from "../../src/Netscript/WorkerScript";
import { NetscriptFunctions, type NSFull } from "../../src/NetscriptFunctions";
import type { ScriptFilePath } from "../../src/Paths/ScriptFilePath";
import { PlayerObject } from "../../src/PersonObjects/Player/PlayerObject";
import { Player, setPlayer } from "../../src/Player";
import { RunningScript } from "../../src/Script/RunningScript";
import { GetServerOrThrow, initForeignServers, prestigeAllServers } from "../../src/Server/AllServers";
import { SpecialServers } from "../../src/Server/data/SpecialServers";
import { initSourceFiles } from "../../src/SourceFile/SourceFiles";
import { FormatsNeedToChange } from "../../src/ui/formatNumber";
import { Router } from "../../src/ui/GameRoot";
import { config } from "../../src/NetscriptJSEvaluator";
declare const importActual: (typeof config)["doImport"];
export function fixDoImportIssue() {
// Replace Blob/ObjectURL functions, because they don't work natively in Jest
global.Blob = class extends Blob {
code: string;
constructor(blobParts?: BlobPart[], __options?: BlobPropertyBag) {
super();
this.code = String((blobParts ?? [])[0]);
}
};
global.URL.revokeObjectURL = function () {};
// Critical: We have to overwrite this, otherwise we get Jest's hooked
// implementation, which will not work without passing special flags to Node,
// and tends to crash even if you do.
config.doImport = importActual;
global.URL.createObjectURL = function (blob) {
return "data:text/javascript," + encodeURIComponent((blob as unknown as { code: string }).code);
};
}
export function initGameEnvironment() {
// We need to patch this function. Some APIs call it, but it only works properly after the main UI is loaded.
Router.toPage = () => {};
/**
* In src\ui\formatNumber.ts, there are some variables that need to be initialized before other functions can be
* called. We have to call FormatsNeedToChange.emit() to initialize those variables.
*/
FormatsNeedToChange.emit();
initSourceFiles();
}
export function setupBasicTestingEnvironment(): void {
prestigeAllServers();
setPlayer(new PlayerObject());
Player.init();
Player.sourceFiles.set(4, 3);
initForeignServers(Player.getHomeComputer());
}
export function getNS(): NSFull {
const home = GetServerOrThrow(SpecialServers.Home);
home.maxRam = 1024;
const filePath = "test.js" as ScriptFilePath;
home.writeToScriptFile(filePath, "");
const script = home.scripts.get(filePath);
if (!script) {
throw new Error("Invalid script");
}
const runningScript = new RunningScript(script, 1024);
const workerScript = new WorkerScript(runningScript, 1, NetscriptFunctions);
const ns = workerScript.env.vars;
if (!ns) {
throw new Error("Invalid NS instance");
}
return ns;
}

View File

@@ -29,7 +29,7 @@ exports[`load/saveAllServers 1`] = `
{
"ctor": "Script",
"data": {
"code": "/** @param {NS} ns */\\\\nexport async function main(ns) {\\\\n return ns.asleep(1000000);\\\\n}",
"code": "/** @param {NS} ns */\\nexport async function main(ns) {\\n return ns.asleep(1000000);\\n}",
"filename": "script.js",
"server": "home",
"metadata": {
@@ -165,7 +165,7 @@ exports[`load/saveAllServers pruning RunningScripts 1`] = `
{
"ctor": "Script",
"data": {
"code": "/** @param {NS} ns */\\\\nexport async function main(ns) {\\\\n return ns.asleep(1000000);\\\\n}",
"code": "/** @param {NS} ns */\\nexport async function main(ns) {\\n return ns.asleep(1000000);\\n}",
"filename": "script.js",
"server": "home",
"metadata": {