bitburner-src/test/jest/Messages/MessageHelper.test.ts
David Walker 06553d9700
BUGFIX: Fix "Router called before initialization" race (#1474)
If the game takes long enough to load, certain counters can become
eligible to run as soon as Engine.start() runs. When this happens,
eventually Router.page() is called, which throws an Error since Router
isn't initialized yet. (Dropping a breakpoint before Engine.start() and
waiting at least 30 seconds is enough to reliably repro, but I have seen
this both live and in tests.)

This fixes it so that Router.page() is valid immediately, returning a
value of Page.LoadingScreen. It also removes the isInitialized field,
since this is now redundant. Trying to switch pages is still an error,
but that doesn't happen without user input, whereas checking the current
page is quite common.

This also consolidates a check for "should we show toasts" behind a
function in Router, making the logic central and equal for a few
usecases. This means (for instance) that the "autosave is disabled"
logic won't run during infiltration. (The toast should have already been
suppressed.)
2024-07-07 22:13:37 -07:00

65 lines
2.2 KiB
TypeScript

import { checkForMessagesToSend } from "../../../src/Message/MessageHelpers";
import * as dialogBoxCreate from "../../../src/ui/React/DialogBox";
import { Player } from "@player";
import "../../../src/ui/GameRoot";
import { AugmentationName } from "@enums";
import { AddToAllServers } from "../../../src/Server/AllServers";
import { Server } from "../../../src/Server/Server";
import { installAugmentations } from "../../../src/Augmentation/AugmentationHelpers";
import { initSourceFiles } from "../../../src/SourceFile/SourceFiles";
jest.mock("../../../src/ui/GameRoot", () => ({
Router: {
page: () => ({}),
toPage: () => ({}),
hidingMessages: () => false,
},
}));
jest.mock("../../../src/ui/React/DialogBox", () => ({
dialogBoxCreate: jest.fn(),
}));
AddToAllServers(new Server({ hostname: "home" }));
describe("MessageHelpers tests", () => {
afterEach(() => {
jest.clearAllMocks();
});
it("Should repeatedly send the Icarus message on the player's first bitnode", () => {
Player.queueAugmentation(AugmentationName.TheRedPill);
installAugmentations();
Player.gainHackingExp(2 ** 200);
const showMessageSpy = jest.spyOn(dialogBoxCreate, "dialogBoxCreate");
checkForMessagesToSend();
checkForMessagesToSend();
// Called once for installing augmentations, and once for each
// checkForMessagesToSend() sending an Icarus message
expect(showMessageSpy).toHaveBeenCalledTimes(3);
});
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);
const showMessageSpy = jest.spyOn(dialogBoxCreate, "dialogBoxCreate");
checkForMessagesToSend();
checkForMessagesToSend();
checkForMessagesToSend();
checkForMessagesToSend();
// Called once for installing augmentations, and only once for any number of
// checkForMessagesToSend() ( sending an Icarus message only the first time)
expect(showMessageSpy).toHaveBeenCalledTimes(2);
});
});