mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-08-18 17:53:29 +00:00
build: migrate build system to Vite and test runner to Vitest & Remove depracated husky usage (#2703)
- Replace Webpack with Vite for faster client bundling and HMR. - Migrate tests from Jest to Vitest and update configuration. - Update Web Worker instantiation to standard ESM syntax. - Implement Env utility in `src/core` for safe, hybrid environment variable access (Vite vs Node). - Refactor configuration loaders to remove direct `process.env` dependencies in shared code. - Update TypeScript environment definitions and project scripts for the new toolchain. - Remove the [depracated usage of the husky](https://github.com/typicode/husky/releases/tag/v9.0.1). ## Description: migrate build system to Vite and test runner to Vitest & Remove depracated husky usage ## Please complete the following: - [X] I have added screenshots for all UI updates - [X] I process any text displayed to the user through translateText() and I've added it to the en.json file - [ ] I have added relevant tests to the test directory - [X] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: wraith4081 --------- Co-authored-by: evanpelle <evanpelle@gmail.com>
This commit is contained in:
@@ -1,6 +1,3 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
import { ProgressBar } from "../../../src/client/graphics/ProgressBar";
|
||||
|
||||
describe("ProgressBar", () => {
|
||||
@@ -15,9 +12,9 @@ describe("ProgressBar", () => {
|
||||
});
|
||||
|
||||
it("should initialize and draw the background", () => {
|
||||
const spyClearRect = jest.spyOn(ctx, "clearRect");
|
||||
const spyFillRect = jest.spyOn(ctx, "fillRect");
|
||||
const spyFillStyle = jest.spyOn(ctx, "fillStyle", "set");
|
||||
const spyClearRect = vi.spyOn(ctx, "clearRect");
|
||||
const spyFillRect = vi.spyOn(ctx, "fillRect");
|
||||
const spyFillStyle = vi.spyOn(ctx, "fillStyle", "set");
|
||||
const bar = new ProgressBar(["#ff0000", "#00ff00"], ctx, 2, 2, 80, 10, 0.5);
|
||||
expect(spyClearRect).toHaveBeenCalledWith(0, 0, 82, 12);
|
||||
expect(spyFillRect).toHaveBeenCalledWith(1, 1, 80, 10);
|
||||
@@ -28,7 +25,7 @@ describe("ProgressBar", () => {
|
||||
|
||||
it("should set progress and draw the progress bar", () => {
|
||||
const bar = new ProgressBar(["#ff0000", "#00ff00"], ctx, 2, 2, 80, 10);
|
||||
const spyFillRect = jest.spyOn(ctx, "fillRect");
|
||||
const spyFillRect = vi.spyOn(ctx, "fillRect");
|
||||
bar.setProgress(0.5);
|
||||
expect(bar.getProgress()).toBe(0.5);
|
||||
expect(spyFillRect).toHaveBeenCalledWith(
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
import { vi, type Mock } from "vitest";
|
||||
import {
|
||||
attackMenuElement,
|
||||
buildMenuElement,
|
||||
@@ -13,13 +11,15 @@ import { UnitType } from "../../../src/core/game/Game";
|
||||
import { TileRef } from "../../../src/core/game/GameMap";
|
||||
import { GameView, PlayerView } from "../../../src/core/game/GameView";
|
||||
|
||||
jest.mock("../../../src/client/Utils", () => ({
|
||||
translateText: jest.fn((key: string) => key),
|
||||
renderNumber: jest.fn((num: number) => num.toString()),
|
||||
vi.mock("../../../src/client/Utils", () => ({
|
||||
translateText: vi.fn((key: string) => key),
|
||||
renderNumber: vi.fn((num: number) => num.toString()),
|
||||
}));
|
||||
|
||||
jest.mock("../../../src/client/graphics/layers/BuildMenu", () => {
|
||||
const { UnitType } = jest.requireActual("../../../src/core/game/Game");
|
||||
vi.mock("../../../src/client/graphics/layers/BuildMenu", async () => {
|
||||
const { UnitType } = await vi.importActual<
|
||||
typeof import("../../../src/core/game/Game")
|
||||
>("../../../src/core/game/Game");
|
||||
return {
|
||||
flattenedBuildTable: [
|
||||
{
|
||||
@@ -68,14 +68,14 @@ jest.mock("../../../src/client/graphics/layers/BuildMenu", () => {
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock("nanoid", () => ({
|
||||
customAlphabet: jest.fn(() => jest.fn(() => "mock-id")),
|
||||
vi.mock("nanoid", () => ({
|
||||
customAlphabet: vi.fn(() => vi.fn(() => "mock-id")),
|
||||
}));
|
||||
|
||||
jest.mock("dompurify", () => ({
|
||||
vi.mock("dompurify", () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
sanitize: jest.fn((str: string) => str),
|
||||
sanitize: vi.fn((str: string) => str),
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -90,29 +90,29 @@ describe("RadialMenuElements", () => {
|
||||
beforeEach(() => {
|
||||
mockPlayer = {
|
||||
id: () => 1,
|
||||
isAlliedWith: jest.fn(() => false),
|
||||
isPlayer: jest.fn(() => true),
|
||||
isAlliedWith: vi.fn(() => false),
|
||||
isPlayer: vi.fn(() => true),
|
||||
} as unknown as PlayerView;
|
||||
|
||||
mockGame = {
|
||||
inSpawnPhase: jest.fn(() => false),
|
||||
owner: jest.fn(() => mockPlayer),
|
||||
isLand: jest.fn(() => true),
|
||||
config: jest.fn(() => ({
|
||||
inSpawnPhase: vi.fn(() => false),
|
||||
owner: vi.fn(() => mockPlayer),
|
||||
isLand: vi.fn(() => true),
|
||||
config: vi.fn(() => ({
|
||||
theme: () => ({
|
||||
territoryColor: () => ({
|
||||
lighten: () => ({ alpha: () => ({ toRgbString: () => "#fff" }) }),
|
||||
}),
|
||||
}),
|
||||
isUnitDisabled: jest.fn(() => false),
|
||||
isUnitDisabled: vi.fn(() => false),
|
||||
})),
|
||||
} as unknown as GameView;
|
||||
|
||||
mockBuildMenu = {
|
||||
canBuildOrUpgrade: jest.fn(() => true),
|
||||
cost: jest.fn(() => 100),
|
||||
count: jest.fn(() => 5),
|
||||
sendBuildOrUpgrade: jest.fn(),
|
||||
canBuildOrUpgrade: vi.fn(() => true),
|
||||
cost: vi.fn(() => 100),
|
||||
count: vi.fn(() => 5),
|
||||
sendBuildOrUpgrade: vi.fn(),
|
||||
};
|
||||
|
||||
mockPlayerActions = {
|
||||
@@ -148,7 +148,7 @@ describe("RadialMenuElements", () => {
|
||||
playerPanel: {} as any,
|
||||
chatIntegration: {} as any,
|
||||
eventBus: {} as any,
|
||||
closeMenu: jest.fn(),
|
||||
closeMenu: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -161,19 +161,19 @@ describe("RadialMenuElements", () => {
|
||||
});
|
||||
|
||||
it("should be disabled during spawn phase", () => {
|
||||
mockGame.inSpawnPhase = jest.fn(() => true);
|
||||
mockGame.inSpawnPhase = vi.fn(() => true);
|
||||
expect(attackMenuElement.disabled(mockParams)).toBe(true);
|
||||
});
|
||||
|
||||
it("should be enabled when not in spawn phase", () => {
|
||||
mockGame.inSpawnPhase = jest.fn(() => false);
|
||||
mockGame.inSpawnPhase = vi.fn(() => false);
|
||||
expect(attackMenuElement.disabled(mockParams)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return attack submenu with attack units only", () => {
|
||||
const enemyPlayer = {
|
||||
id: () => 2,
|
||||
isPlayer: jest.fn(() => true),
|
||||
isPlayer: vi.fn(() => true),
|
||||
} as unknown as PlayerView;
|
||||
mockParams.selected = enemyPlayer;
|
||||
|
||||
@@ -203,7 +203,7 @@ describe("RadialMenuElements", () => {
|
||||
it("should not include construction units in attack menu", () => {
|
||||
const enemyPlayer = {
|
||||
id: () => 2,
|
||||
isPlayer: jest.fn(() => true),
|
||||
isPlayer: vi.fn(() => true),
|
||||
} as unknown as PlayerView;
|
||||
mockParams.selected = enemyPlayer;
|
||||
|
||||
@@ -237,12 +237,12 @@ describe("RadialMenuElements", () => {
|
||||
});
|
||||
|
||||
it("should be disabled during spawn phase", () => {
|
||||
mockGame.inSpawnPhase = jest.fn(() => true);
|
||||
mockGame.inSpawnPhase = vi.fn(() => true);
|
||||
expect(buildMenuElement.disabled(mockParams)).toBe(true);
|
||||
});
|
||||
|
||||
it("should be enabled when not in spawn phase", () => {
|
||||
mockGame.inSpawnPhase = jest.fn(() => false);
|
||||
mockGame.inSpawnPhase = vi.fn(() => false);
|
||||
expect(buildMenuElement.disabled(mockParams)).toBe(false);
|
||||
});
|
||||
|
||||
@@ -313,9 +313,9 @@ describe("RadialMenuElements", () => {
|
||||
it("should show attack and boat menu on enemy territory", () => {
|
||||
const enemyPlayer = {
|
||||
id: () => 2,
|
||||
isPlayer: jest.fn(() => true),
|
||||
isPlayer: vi.fn(() => true),
|
||||
} as unknown as PlayerView;
|
||||
mockGame.owner = jest.fn(() => enemyPlayer);
|
||||
mockGame.owner = vi.fn(() => enemyPlayer);
|
||||
|
||||
const subMenu = rootMenuElement.subMenu!(mockParams);
|
||||
const buildMenu = subMenu.find((item) => item.id === Slot.Build);
|
||||
@@ -337,8 +337,8 @@ describe("RadialMenuElements", () => {
|
||||
it("should handle ally menu correctly", () => {
|
||||
const allyPlayer = {
|
||||
id: () => 2,
|
||||
isAlliedWith: jest.fn(() => true),
|
||||
isPlayer: jest.fn(() => true),
|
||||
isAlliedWith: vi.fn(() => true),
|
||||
isPlayer: vi.fn(() => true),
|
||||
} as unknown as PlayerView;
|
||||
mockParams.selected = allyPlayer;
|
||||
|
||||
@@ -367,7 +367,7 @@ describe("RadialMenuElements", () => {
|
||||
it("should execute attack action correctly", () => {
|
||||
const enemyPlayer = {
|
||||
id: () => 2,
|
||||
isPlayer: jest.fn(() => true),
|
||||
isPlayer: vi.fn(() => true),
|
||||
} as unknown as PlayerView;
|
||||
mockParams.selected = enemyPlayer;
|
||||
|
||||
@@ -389,7 +389,7 @@ describe("RadialMenuElements", () => {
|
||||
|
||||
it("should not execute action when buildable unit is not found", () => {
|
||||
mockPlayerActions.buildableUnits = [];
|
||||
mockBuildMenu.canBuildOrUpgrade = jest.fn(() => false);
|
||||
mockBuildMenu.canBuildOrUpgrade = vi.fn(() => false);
|
||||
|
||||
const subMenu = buildMenuElement.subMenu!(mockParams);
|
||||
const cityElement = subMenu.find((item) => item.id === "build_City");
|
||||
@@ -420,7 +420,7 @@ describe("RadialMenuElements", () => {
|
||||
it("should generate correct tooltip items for attack elements", () => {
|
||||
const enemyPlayer = {
|
||||
id: () => 2,
|
||||
isPlayer: jest.fn(() => true),
|
||||
isPlayer: vi.fn(() => true),
|
||||
} as unknown as PlayerView;
|
||||
mockParams.selected = enemyPlayer;
|
||||
|
||||
@@ -452,7 +452,7 @@ describe("RadialMenuElements", () => {
|
||||
it("should use correct colors for attack elements", () => {
|
||||
const enemyPlayer = {
|
||||
id: () => 2,
|
||||
isPlayer: jest.fn(() => true),
|
||||
isPlayer: vi.fn(() => true),
|
||||
} as unknown as PlayerView;
|
||||
mockParams.selected = enemyPlayer;
|
||||
|
||||
@@ -465,7 +465,7 @@ describe("RadialMenuElements", () => {
|
||||
});
|
||||
|
||||
it("should not set color when element is disabled", () => {
|
||||
mockBuildMenu.canBuildOrUpgrade = jest.fn(() => false);
|
||||
mockBuildMenu.canBuildOrUpgrade = vi.fn(() => false);
|
||||
|
||||
const subMenu = buildMenuElement.subMenu!(mockParams);
|
||||
const cityElement = subMenu.find((item) => item.id === "build_City");
|
||||
@@ -475,10 +475,12 @@ describe("RadialMenuElements", () => {
|
||||
});
|
||||
|
||||
describe("Translation integration", () => {
|
||||
it("should use translateText for tooltip items in build menu", () => {
|
||||
const { translateText } = jest.requireMock("../../../src/client/Utils");
|
||||
it("should use translateText for tooltip items in build menu", async () => {
|
||||
const { translateText } = await vi.importMock<
|
||||
typeof import("../../../src/client/Utils")
|
||||
>("../../../src/client/Utils");
|
||||
|
||||
(translateText as jest.Mock).mockClear();
|
||||
(translateText as Mock).mockClear();
|
||||
|
||||
buildMenuElement.subMenu!(mockParams);
|
||||
|
||||
@@ -488,14 +490,16 @@ describe("RadialMenuElements", () => {
|
||||
expect(translateText).toHaveBeenCalledWith("unit_type.factory_desc");
|
||||
});
|
||||
|
||||
it("should use translateText for tooltip items in attack menu", () => {
|
||||
const { translateText } = jest.requireMock("../../../src/client/Utils");
|
||||
it("should use translateText for tooltip items in attack menu", async () => {
|
||||
const { translateText } = await vi.importMock<
|
||||
typeof import("../../../src/client/Utils")
|
||||
>("../../../src/client/Utils");
|
||||
|
||||
(translateText as jest.Mock).mockClear();
|
||||
(translateText as Mock).mockClear();
|
||||
|
||||
const enemyPlayer = {
|
||||
id: () => 2,
|
||||
isPlayer: jest.fn(() => true),
|
||||
isPlayer: vi.fn(() => true),
|
||||
} as unknown as PlayerView;
|
||||
mockParams.selected = enemyPlayer;
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
import { UILayer } from "../../../src/client/graphics/layers/UILayer";
|
||||
import { UnitSelectionEvent } from "../../../src/client/InputHandler";
|
||||
import { UnitView } from "../../../src/core/game/GameView";
|
||||
@@ -28,7 +25,7 @@ describe("UILayer", () => {
|
||||
ticks: () => 1,
|
||||
updatesSinceLastTick: () => undefined,
|
||||
};
|
||||
eventBus = { on: jest.fn() };
|
||||
eventBus = { on: vi.fn() };
|
||||
transformHandler = {};
|
||||
});
|
||||
|
||||
@@ -50,7 +47,7 @@ describe("UILayer", () => {
|
||||
owner: () => ({}),
|
||||
};
|
||||
const event = { isSelected: true, unit };
|
||||
ui.drawSelectionBox = jest.fn();
|
||||
ui.drawSelectionBox = vi.fn();
|
||||
ui["onUnitSelection"](event as UnitSelectionEvent);
|
||||
expect(ui.drawSelectionBox).toHaveBeenCalledWith(unit);
|
||||
});
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
jest.mock("lit", () => ({
|
||||
vi.mock("lit", () => ({
|
||||
html: () => {},
|
||||
LitElement: class {},
|
||||
}));
|
||||
|
||||
jest.mock("lit/decorators.js", () => ({
|
||||
vi.mock("lit/decorators.js", () => ({
|
||||
customElement: () => (clazz: any) => clazz,
|
||||
query: () => () => {},
|
||||
state: () => () => {},
|
||||
property: () => () => {},
|
||||
}));
|
||||
|
||||
jest.mock("lit/directive.js", () => ({
|
||||
vi.mock("lit/directive.js", () => ({
|
||||
DirectiveResult: class {},
|
||||
}));
|
||||
|
||||
jest.mock("lit/directives/unsafe-html.js", () => ({
|
||||
vi.mock("lit/directives/unsafe-html.js", () => ({
|
||||
unsafeHTML: () => {},
|
||||
UnsafeHTMLDirective: class {},
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user