mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-23 03:52:50 +00:00
refactor: convert to npm-workspaces monorepo (engine/core-public/shared/client/server)
Restructure the single src/ tree into an npm-workspaces monorepo under
packages/, rename core -> engine, extract a types-only core-public layer,
and break the pre-existing engine -> client dependency cycle.
Structure (packages/):
core-public public API/wire schemas + shared enums (clean leaf)
shared framework-agnostic helpers (clean leaf)
engine deterministic simulation (was src/core)
client rendering/UI (was src/client)
server coordination (was src/server)
Dependency DAG: engine -> {core-public, shared}; client -> {core-public,
shared, engine}; server -> {core-public, engine}.
- npm workspaces: root package.json workspaces + per-package package.json;
tsconfig.base.json holds shared options + path aliases
(core-public/* shared/* engine/* client/* server/*) resolved uniformly by
tsc, Vite (resolve.tsconfigPaths), Vitest, and tsx. Lockfile regenerated.
- core-public: moved Schemas/ApiSchemas/CosmeticSchemas/StatsSchemas/
ClanApiSchemas/WorkerSchemas/Base64/PatternDecoder; extracted the enums
(GameTypes), GameEvent type, emoji table, and GraphicsOverrides schema.
Engine re-exports the moved enums/types so existing imports keep working.
- Broke engine -> client cycle:
- renderNumber/renderTroops -> shared/format
- NameBoxCalculator moved into engine
- username validation returns translation key + params; client translates
- applyStateUpdate moved to client (operates on the render-only PlayerState)
- Config/UnitGrid/execution-Util/GameImpl now use structural read
interfaces (engine/game/ReadViews: PlayerLike/UnitLike/GameLike) instead
of importing client view classes; client imports view classes from a new
client/view barrel; deleted the engine/game/GameView re-export shim.
- Build/deploy updated: vite.config, index.html, eslint, Dockerfile
(copies packages/ + tsconfig.base.json before npm ci), .vscode, tests.
Verified: tsc --noEmit clean; 1364 + 65 tests pass; production vite build
succeeds; engine has zero client/server imports; core-public and shared are
dependency leaves.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
cb9cab9aca
commit
a7f992e9b0
@@ -1,4 +1,4 @@
|
||||
import { installSafariPinchZoomBlocker } from "../../src/client/utilities/DisableSafariPinchZoom";
|
||||
import { installSafariPinchZoomBlocker } from "client/utilities/DisableSafariPinchZoom";
|
||||
|
||||
const GESTURE_EVENTS = ["gesturestart", "gesturechange", "gestureend"] as const;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { JoinLobbyModal } from "../../src/client/JoinLobbyModal";
|
||||
import { JoinLobbyModal } from "client/JoinLobbyModal";
|
||||
|
||||
describe("JoinLobbyModal server time offset", () => {
|
||||
let nowMs = 0;
|
||||
|
||||
@@ -7,7 +7,7 @@ vi.mock("@lit-labs/virtualizer/virtualize.js", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../src/client/Utils", () => ({
|
||||
vi.mock("client/Utils", () => ({
|
||||
translateText: vi.fn((key: string) => {
|
||||
const translations: Record<string, string> = {
|
||||
"leaderboard_modal.win_score_tooltip":
|
||||
@@ -39,7 +39,7 @@ vi.mock("../../src/client/Utils", () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("../../src/client/Api", () => {
|
||||
vi.mock("client/Api", () => {
|
||||
const getApiBase = () => "http://localhost:3000";
|
||||
return {
|
||||
getApiBase: vi.fn(getApiBase),
|
||||
@@ -64,7 +64,7 @@ vi.mock("../../src/client/Api", () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../src/client/ClanApi", () => {
|
||||
vi.mock("client/ClanApi", () => {
|
||||
const getApiBase = () => "http://localhost:3000";
|
||||
return {
|
||||
fetchClanLeaderboard: vi.fn(async () => {
|
||||
@@ -101,8 +101,8 @@ beforeEach(() => {
|
||||
);
|
||||
});
|
||||
|
||||
import "../../src/client/components/baseComponents/Modal";
|
||||
import { LeaderboardModal } from "../../src/client/LeaderboardModal";
|
||||
import "client/components/baseComponents/Modal";
|
||||
import { LeaderboardModal } from "client/LeaderboardModal";
|
||||
|
||||
describe("LeaderboardModal", () => {
|
||||
let modal: LeaderboardModal;
|
||||
@@ -210,7 +210,7 @@ describe("LeaderboardModal", () => {
|
||||
|
||||
it("should use translateText for tooltip internationalization", async () => {
|
||||
// Verify translation keys are correct
|
||||
const { translateText } = await import("../../src/client/Utils");
|
||||
const { translateText } = await import("client/Utils");
|
||||
|
||||
expect(translateText("leaderboard_modal.win_score_tooltip")).toBe(
|
||||
"Weighted wins based on clan participation and match difficulty",
|
||||
@@ -223,7 +223,7 @@ describe("LeaderboardModal", () => {
|
||||
|
||||
describe("Player Data Mapping", () => {
|
||||
it("should map ranked leaderboard data and set current user entry", async () => {
|
||||
const { getUserMe } = await import("../../src/client/Api");
|
||||
const { getUserMe } = await import("client/Api");
|
||||
(getUserMe as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
player: { publicId: "player-2" },
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { normalizeNewsMarkdown } from "../../src/client/NewsMarkdown";
|
||||
import { normalizeNewsMarkdown } from "client/NewsMarkdown";
|
||||
|
||||
describe("normalizeNewsMarkdown", () => {
|
||||
it("converts openfront pull request URLs to short markdown links", () => {
|
||||
|
||||
@@ -25,7 +25,7 @@ const loadPlatform = async ({
|
||||
userAgentData,
|
||||
maxTouchPoints,
|
||||
});
|
||||
const { Platform } = await import("../../src/client/Platform");
|
||||
const { Platform } = await import("client/Platform");
|
||||
return Platform;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("../../../src/client/Api", () => ({
|
||||
vi.mock("client/Api", () => ({
|
||||
getApiBase: vi.fn(() => "http://localhost:3000"),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/client/Auth", () => ({
|
||||
vi.mock("client/Auth", () => ({
|
||||
getAuthHeader: vi.fn(async () => "Bearer test-token"),
|
||||
}));
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
banClanMember,
|
||||
fetchClanBans,
|
||||
unbanClanMember,
|
||||
} from "../../../src/client/ClanApi";
|
||||
} from "client/ClanApi";
|
||||
|
||||
const okJson = (data: unknown, status = 200) => ({
|
||||
ok: true,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("../../../src/client/Api", () => ({
|
||||
vi.mock("client/Api", () => ({
|
||||
getApiBase: vi.fn(() => "http://localhost:3000"),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/client/Auth", () => ({
|
||||
vi.mock("client/Auth", () => ({
|
||||
getAuthHeader: vi.fn(async () => "Bearer test-token"),
|
||||
}));
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
transferLeadership,
|
||||
updateClan,
|
||||
withdrawClanRequest,
|
||||
} from "../../../src/client/ClanApi";
|
||||
} from "client/ClanApi";
|
||||
|
||||
const okJson = (data: unknown, status = 200) => ({
|
||||
ok: true,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("../../../src/client/Api", () => ({
|
||||
vi.mock("client/Api", () => ({
|
||||
getApiBase: vi.fn(() => "http://localhost:3000"),
|
||||
getUserMe: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/client/Auth", () => ({
|
||||
vi.mock("client/Auth", () => ({
|
||||
getAuthHeader: vi.fn(async () => "Bearer test-token"),
|
||||
}));
|
||||
|
||||
import { getUserMe } from "../../../src/client/Api";
|
||||
import { getUserMe } from "client/Api";
|
||||
import {
|
||||
checkClanTagOwnership,
|
||||
fetchClanDetail,
|
||||
@@ -19,8 +19,8 @@ import {
|
||||
fetchClanMembers,
|
||||
fetchClanRequests,
|
||||
fetchClans,
|
||||
} from "../../../src/client/ClanApi";
|
||||
import type { UserMeResponse } from "../../../src/core/ApiSchemas";
|
||||
} from "client/ClanApi";
|
||||
import type { UserMeResponse } from "core-public/ApiSchemas";
|
||||
|
||||
const userWithClans = (tags: string[]): UserMeResponse =>
|
||||
({
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
ClanInfoSchema,
|
||||
ClanJoinRequestSchema,
|
||||
ClanMemberSchema,
|
||||
} from "../../../src/core/ClanApiSchemas";
|
||||
} from "core-public/ClanApiSchemas";
|
||||
|
||||
describe("ClanInfoSchema", () => {
|
||||
const base = {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { flushAsync } from "./ClanModalTestUtils";
|
||||
|
||||
// ─── Mocks (defined before imports so vi.mock hoisting applies) ─────────────
|
||||
|
||||
vi.mock("../../../src/client/Utils", () => ({
|
||||
vi.mock("client/Utils", () => ({
|
||||
// Echo the key so we can assert on translation slugs.
|
||||
translateText: vi.fn((key: string) => key),
|
||||
showToast: vi.fn(),
|
||||
@@ -13,22 +13,22 @@ vi.mock("../../../src/client/Utils", () => ({
|
||||
getMapName: vi.fn((m: string | undefined) => m ?? null),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/client/Auth", () => ({
|
||||
vi.mock("client/Auth", () => ({
|
||||
getAuthHeader: vi.fn(async () => "Bearer test-token"),
|
||||
userAuth: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/client/ClanApi", () => ({
|
||||
vi.mock("client/ClanApi", () => ({
|
||||
fetchClanGames: vi.fn(async () => ({ results: [], nextCursor: null })),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/client/TerrainMapFileLoader", () => ({
|
||||
vi.mock("client/TerrainMapFileLoader", () => ({
|
||||
terrainMapFileLoader: {
|
||||
getMapData: vi.fn(() => ({ webpPath: "/maps/test.webp" })),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/client/ClientEnv", () => ({
|
||||
vi.mock("client/ClientEnv", () => ({
|
||||
ClientEnv: {
|
||||
workerPath: vi.fn(() => "w0"),
|
||||
},
|
||||
@@ -36,7 +36,7 @@ vi.mock("../../../src/client/ClientEnv", () => ({
|
||||
|
||||
// ClanShared re-exports from BaseModal; stub it directly so we don't pull
|
||||
// BaseModal's dependency graph into this unit test.
|
||||
vi.mock("../../../src/client/components/clan/ClanShared", async () => {
|
||||
vi.mock("client/components/clan/ClanShared", async () => {
|
||||
const { html } = await import("lit");
|
||||
return {
|
||||
renderLoadingSpinner: vi.fn(() => html`<div data-testid="spinner"></div>`),
|
||||
@@ -46,7 +46,7 @@ vi.mock("../../../src/client/components/clan/ClanShared", async () => {
|
||||
|
||||
// CopyButton is a custom element; stub it so its dependency graph (Auth,
|
||||
// API, etc.) doesn't get pulled in transitively.
|
||||
vi.mock("../../../src/client/components/CopyButton", () => ({}));
|
||||
vi.mock("client/components/CopyButton", () => ({}));
|
||||
|
||||
// jsdom doesn't ship IntersectionObserver — provide the minimum surface
|
||||
// the component touches (observe / disconnect). Tests below trigger the
|
||||
@@ -75,12 +75,12 @@ vi.stubGlobal("IntersectionObserver", FakeIntersectionObserver);
|
||||
|
||||
// ─── Imports under test ──────────────────────────────────────────────────────
|
||||
|
||||
import type { ClanGame, ClanGamesResponse } from "../../../src/client/ClanApi";
|
||||
import { fetchClanGames } from "../../../src/client/ClanApi";
|
||||
import type { ClanGame, ClanGamesResponse } from "client/ClanApi";
|
||||
import { fetchClanGames } from "client/ClanApi";
|
||||
import {
|
||||
ClanGameHistoryView,
|
||||
type ClanGameHistoryCache,
|
||||
} from "../../../src/client/components/clan/ClanGameHistoryView";
|
||||
} from "client/components/clan/ClanGameHistoryView";
|
||||
|
||||
// ─── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -17,16 +17,16 @@ import {
|
||||
} from "./ClanModalTestUtils";
|
||||
|
||||
vi.mock("@lit-labs/virtualizer/virtualize.js", () => virtualizerMockFactory());
|
||||
vi.mock("../../../src/client/Api", () => apiMockFactory());
|
||||
vi.mock("../../../src/client/ClanApi", () => clanApiMockFactory());
|
||||
vi.mock("../../../src/client/Utils", () => utilsMockFactory());
|
||||
vi.mock("../../../src/client/Auth", () => authMockFactory());
|
||||
vi.mock("../../../src/client/CrazyGamesSDK", () => crazyGamesSdkMockFactory());
|
||||
vi.mock("client/Api", () => apiMockFactory());
|
||||
vi.mock("client/ClanApi", () => clanApiMockFactory());
|
||||
vi.mock("client/Utils", () => utilsMockFactory());
|
||||
vi.mock("client/Auth", () => authMockFactory());
|
||||
vi.mock("client/CrazyGamesSDK", () => crazyGamesSdkMockFactory());
|
||||
|
||||
stubLocalStorage();
|
||||
|
||||
import type { ClanInfo } from "../../../src/client/ClanApi";
|
||||
import { ClanModal } from "../../../src/client/ClanModal";
|
||||
import type { ClanInfo } from "client/ClanApi";
|
||||
import { ClanModal } from "client/ClanModal";
|
||||
|
||||
describe("ClanModal — handlers", () => {
|
||||
let modal: ClanModal;
|
||||
@@ -50,7 +50,7 @@ describe("ClanModal — handlers", () => {
|
||||
describe("handleApprove increments selectedClan.memberCount", () => {
|
||||
it("increments memberCount by 1 after successful approveClanRequest", async () => {
|
||||
const { approveClanRequest, fetchClanRequests } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
await import("client/ClanApi");
|
||||
(approveClanRequest as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
(fetchClanRequests as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [
|
||||
@@ -86,7 +86,7 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
it("does not increment memberCount when approveClanRequest fails", async () => {
|
||||
const { approveClanRequest, fetchClanRequests } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
await import("client/ClanApi");
|
||||
(approveClanRequest as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
error: "clan_modal.error_generic",
|
||||
});
|
||||
@@ -120,7 +120,7 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
it("treats undefined memberCount as 0 and increments to 1", async () => {
|
||||
const { approveClanRequest, fetchClanRequests } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
await import("client/ClanApi");
|
||||
(approveClanRequest as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
(fetchClanRequests as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [
|
||||
@@ -154,7 +154,7 @@ describe("ClanModal — handlers", () => {
|
||||
let manageView: Element;
|
||||
|
||||
beforeEach(async () => {
|
||||
const { fetchClanMembers } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanMembers } = await import("client/ClanApi");
|
||||
(fetchClanMembers as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [
|
||||
{
|
||||
@@ -188,7 +188,7 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("handleBan calls banClanMember after confirm-dialog confirm", async () => {
|
||||
const { banClanMember } = await import("../../../src/client/ClanApi");
|
||||
const { banClanMember } = await import("client/ClanApi");
|
||||
(banClanMember as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
|
||||
// Step 1: Click Ban button to open confirm dialog
|
||||
@@ -216,7 +216,7 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("handleBan aborts when confirm-dialog cancel is clicked", async () => {
|
||||
const { banClanMember } = await import("../../../src/client/ClanApi");
|
||||
const { banClanMember } = await import("client/ClanApi");
|
||||
|
||||
// Step 1: Click Ban button to open confirm dialog
|
||||
const banButton = Array.from(modal.querySelectorAll("button")).find(
|
||||
@@ -237,7 +237,7 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("handleBan sends undefined reason when confirm text is empty", async () => {
|
||||
const { banClanMember } = await import("../../../src/client/ClanApi");
|
||||
const { banClanMember } = await import("client/ClanApi");
|
||||
(banClanMember as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
|
||||
// Step 1: Click Ban button
|
||||
@@ -265,7 +265,7 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
it("handleBan syncs memberCount via clan-updated event on success", async () => {
|
||||
const { banClanMember, fetchClanMembers } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
await import("client/ClanApi");
|
||||
(banClanMember as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
// Server returns the post-ban member total (was 5, now 4).
|
||||
(fetchClanMembers as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
@@ -303,7 +303,7 @@ describe("ClanModal — handlers", () => {
|
||||
describe("handleUnban", () => {
|
||||
it("removes ban from list and decrements total on success", async () => {
|
||||
const { unbanClanMember, fetchClanBans } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
await import("client/ClanApi");
|
||||
(unbanClanMember as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
(fetchClanBans as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [
|
||||
@@ -341,7 +341,7 @@ describe("ClanModal — handlers", () => {
|
||||
let manageView: Element;
|
||||
|
||||
beforeEach(async () => {
|
||||
const { fetchClanMembers } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanMembers } = await import("client/ClanApi");
|
||||
(fetchClanMembers as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [
|
||||
{
|
||||
@@ -369,7 +369,7 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
it("calls kickMember and syncs memberCount on success", async () => {
|
||||
const { kickMember, fetchClanMembers } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
await import("client/ClanApi");
|
||||
(kickMember as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
(fetchClanMembers as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [],
|
||||
@@ -402,7 +402,7 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
it("does not mutate state when kickMember fails", async () => {
|
||||
const { kickMember, fetchClanMembers } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
await import("client/ClanApi");
|
||||
(kickMember as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
error: "clan_modal.error_generic",
|
||||
});
|
||||
@@ -436,7 +436,7 @@ describe("ClanModal — handlers", () => {
|
||||
let manageView: Element;
|
||||
|
||||
beforeEach(async () => {
|
||||
const { fetchClanMembers } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanMembers } = await import("client/ClanApi");
|
||||
(fetchClanMembers as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [],
|
||||
total: 3,
|
||||
@@ -467,7 +467,7 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("calls disbandClan, clears selection, and returns to list on success", async () => {
|
||||
const { disbandClan } = await import("../../../src/client/ClanApi");
|
||||
const { disbandClan } = await import("client/ClanApi");
|
||||
(disbandClan as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
|
||||
// Open the disband confirm dialog on the manage view.
|
||||
@@ -495,7 +495,7 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("preserves selection when disbandClan fails", async () => {
|
||||
const { disbandClan } = await import("../../../src/client/ClanApi");
|
||||
const { disbandClan } = await import("client/ClanApi");
|
||||
(disbandClan as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
error: "clan_modal.error_generic",
|
||||
});
|
||||
@@ -525,7 +525,7 @@ describe("ClanModal — handlers", () => {
|
||||
let requestsView: Element;
|
||||
|
||||
beforeEach(async () => {
|
||||
const { fetchClanRequests } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanRequests } = await import("client/ClanApi");
|
||||
(fetchClanRequests as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [
|
||||
{ publicId: "applicant-1", createdAt: "2024-06-01T00:00:00Z" },
|
||||
@@ -543,7 +543,7 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("removes the request and decrements totals on success", async () => {
|
||||
const { denyClanRequest } = await import("../../../src/client/ClanApi");
|
||||
const { denyClanRequest } = await import("client/ClanApi");
|
||||
(denyClanRequest as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
|
||||
const denyButton = Array.from(modal.querySelectorAll("button")).find(
|
||||
@@ -564,7 +564,7 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("does not mutate state when denyClanRequest fails", async () => {
|
||||
const { denyClanRequest } = await import("../../../src/client/ClanApi");
|
||||
const { denyClanRequest } = await import("client/ClanApi");
|
||||
(denyClanRequest as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
error: "clan_modal.error_generic",
|
||||
});
|
||||
@@ -589,7 +589,7 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
describe("handleJoin", () => {
|
||||
beforeEach(async () => {
|
||||
const { fetchClanDetail } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanDetail } = await import("client/ClanApi");
|
||||
(fetchClanDetail as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
|
||||
makeClan({ isOpen: true, memberCount: 5 }),
|
||||
);
|
||||
@@ -602,7 +602,7 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
it("switches detail view into member mode immediately after open-clan join", async () => {
|
||||
const { joinClan, fetchClanMembers } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
await import("client/ClanApi");
|
||||
(joinClan as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
status: "joined",
|
||||
});
|
||||
@@ -651,7 +651,7 @@ describe("ClanModal — handlers", () => {
|
||||
describe("handleLeave", () => {
|
||||
beforeEach(async () => {
|
||||
const { fetchClanDetail, fetchClanMembers } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
await import("client/ClanApi");
|
||||
(fetchClanDetail as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
|
||||
makeClan(),
|
||||
);
|
||||
@@ -680,7 +680,7 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("calls leaveClan, removes role, and returns to list on success", async () => {
|
||||
const { leaveClan } = await import("../../../src/client/ClanApi");
|
||||
const { leaveClan } = await import("client/ClanApi");
|
||||
(leaveClan as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
|
||||
const leaveButton = Array.from(modal.querySelectorAll("button")).find(
|
||||
@@ -704,7 +704,7 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("preserves selection when leaveClan fails", async () => {
|
||||
const { leaveClan } = await import("../../../src/client/ClanApi");
|
||||
const { leaveClan } = await import("client/ClanApi");
|
||||
(leaveClan as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
error: "clan_modal.error_generic",
|
||||
});
|
||||
@@ -732,7 +732,7 @@ describe("ClanModal — handlers", () => {
|
||||
let transferView: Element;
|
||||
|
||||
beforeEach(async () => {
|
||||
const { fetchClanMembers } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanMembers } = await import("client/ClanApi");
|
||||
(fetchClanMembers as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [
|
||||
{
|
||||
@@ -766,7 +766,7 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
it("clears confirmAction and removes the dialog after confirming", async () => {
|
||||
const { transferLeadership } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
await import("client/ClanApi");
|
||||
(transferLeadership as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
|
||||
const dialog = modal.querySelector("confirm-dialog");
|
||||
@@ -786,7 +786,7 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
it("clears confirmAction when cancel is clicked, without calling the API", async () => {
|
||||
const { transferLeadership } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
await import("client/ClanApi");
|
||||
|
||||
const dialog = modal.querySelector("confirm-dialog");
|
||||
expect(dialog).toBeTruthy();
|
||||
|
||||
@@ -15,15 +15,15 @@ import {
|
||||
} from "./ClanModalTestUtils";
|
||||
|
||||
vi.mock("@lit-labs/virtualizer/virtualize.js", () => virtualizerMockFactory());
|
||||
vi.mock("../../../src/client/Api", () => apiMockFactory());
|
||||
vi.mock("../../../src/client/ClanApi", () => clanApiMockFactory());
|
||||
vi.mock("../../../src/client/Utils", () => utilsMockFactory());
|
||||
vi.mock("../../../src/client/Auth", () => authMockFactory());
|
||||
vi.mock("../../../src/client/CrazyGamesSDK", () => crazyGamesSdkMockFactory());
|
||||
vi.mock("client/Api", () => apiMockFactory());
|
||||
vi.mock("client/ClanApi", () => clanApiMockFactory());
|
||||
vi.mock("client/Utils", () => utilsMockFactory());
|
||||
vi.mock("client/Auth", () => authMockFactory());
|
||||
vi.mock("client/CrazyGamesSDK", () => crazyGamesSdkMockFactory());
|
||||
|
||||
stubLocalStorage();
|
||||
|
||||
import { ClanModal } from "../../../src/client/ClanModal";
|
||||
import { ClanModal } from "client/ClanModal";
|
||||
|
||||
describe("ClanModal — rendering", () => {
|
||||
let modal: ClanModal;
|
||||
@@ -51,7 +51,7 @@ describe("ClanModal — rendering", () => {
|
||||
// Directly invoke renderClanCard via the instance and insert the result
|
||||
// into a container so we can query it. We do this by populating myClans
|
||||
// and myClanRoles state so the list view renders real cards.
|
||||
const { getUserMe } = await import("../../../src/client/Api");
|
||||
const { getUserMe } = await import("client/Api");
|
||||
(getUserMe as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
player: {
|
||||
publicId: "test-player",
|
||||
@@ -88,7 +88,7 @@ describe("ClanModal — rendering", () => {
|
||||
});
|
||||
|
||||
it("shows 'clan_modal.open' badge when clan is open and user has no role", async () => {
|
||||
const { fetchClans } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClans } = await import("client/ClanApi");
|
||||
(fetchClans as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [makeClan({ tag: "OTH", name: "Other Clan", isOpen: true })],
|
||||
total: 1,
|
||||
@@ -107,7 +107,7 @@ describe("ClanModal — rendering", () => {
|
||||
});
|
||||
|
||||
it("shows 'clan_modal.invite_only' badge when clan is closed and user has no role", async () => {
|
||||
const { fetchClans } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClans } = await import("client/ClanApi");
|
||||
(fetchClans as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [makeClan({ tag: "INV", name: "Invite Clan", isOpen: false })],
|
||||
total: 1,
|
||||
@@ -187,7 +187,7 @@ describe("ClanModal — rendering", () => {
|
||||
});
|
||||
|
||||
it("does NOT show a role badge when myClanRoles has no entry for the clan", async () => {
|
||||
const { fetchClans } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClans } = await import("client/ClanApi");
|
||||
(fetchClans as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [makeClan({ tag: "INV", name: "Invite Clan", isOpen: false })],
|
||||
total: 1,
|
||||
@@ -227,7 +227,7 @@ describe("ClanModal — rendering", () => {
|
||||
expect(modal.textContent).not.toContain("undefined");
|
||||
// translateText mock swallows args and returns the key, so verify it
|
||||
// was called with count: 0 (the fallback) rather than count: undefined.
|
||||
const { translateText } = await import("../../../src/client/Utils");
|
||||
const { translateText } = await import("client/Utils");
|
||||
const calls = (translateText as ReturnType<typeof vi.fn>).mock.calls;
|
||||
const memberCountCall = calls.find(
|
||||
(c) => c[0] === "clan_modal.member_count",
|
||||
@@ -237,7 +237,7 @@ describe("ClanModal — rendering", () => {
|
||||
});
|
||||
|
||||
it("shows 0 in the stats row of the detail view when memberCount is undefined", async () => {
|
||||
const { fetchClanDetail } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanDetail } = await import("client/ClanApi");
|
||||
(fetchClanDetail as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
|
||||
makeClan({ memberCount: undefined }),
|
||||
);
|
||||
@@ -251,7 +251,7 @@ describe("ClanModal — rendering", () => {
|
||||
});
|
||||
|
||||
it("shows 0 in the manage members header when memberCount is undefined", async () => {
|
||||
const { fetchClanMembers } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanMembers } = await import("client/ClanApi");
|
||||
(fetchClanMembers as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [],
|
||||
total: 0,
|
||||
@@ -277,7 +277,7 @@ describe("ClanModal — rendering", () => {
|
||||
|
||||
describe("Open/Closed toggle ARIA attributes in manage view", () => {
|
||||
beforeEach(async () => {
|
||||
const { fetchClanMembers } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanMembers } = await import("client/ClanApi");
|
||||
(fetchClanMembers as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [],
|
||||
total: 0,
|
||||
@@ -355,7 +355,7 @@ describe("ClanModal — rendering", () => {
|
||||
|
||||
describe("Ban feature — bans view", () => {
|
||||
it("renders Banned Players button in manage view", async () => {
|
||||
const { fetchClanMembers } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanMembers } = await import("client/ClanApi");
|
||||
(fetchClanMembers as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [],
|
||||
total: 0,
|
||||
@@ -374,7 +374,7 @@ describe("ClanModal — rendering", () => {
|
||||
});
|
||||
|
||||
it("renders ban list with unban button in bans view", async () => {
|
||||
const { fetchClanBans } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanBans } = await import("client/ClanApi");
|
||||
(fetchClanBans as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [
|
||||
{
|
||||
@@ -400,7 +400,7 @@ describe("ClanModal — rendering", () => {
|
||||
});
|
||||
|
||||
it("renders empty state when no bans", async () => {
|
||||
const { fetchClanBans } = await import("../../../src/client/ClanApi");
|
||||
const { fetchClanBans } = await import("client/ClanApi");
|
||||
(fetchClanBans as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [],
|
||||
total: 0,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { vi } from "vitest";
|
||||
import type { ClanInfo } from "../../../src/client/ClanApi";
|
||||
import type { ClanModal } from "../../../src/client/ClanModal";
|
||||
import type { ClanInfo } from "client/ClanApi";
|
||||
import type { ClanModal } from "client/ClanModal";
|
||||
|
||||
// ─── Mock factories ─────────────────────────────────────────────────────────
|
||||
// Each factory returns a fresh object of vi.fn()s. Test files pass these to
|
||||
|
||||
@@ -4,12 +4,12 @@ import type {
|
||||
ClanJoinRequest,
|
||||
ClanMember,
|
||||
ClanMemberStats,
|
||||
} from "../../../src/client/ClanApi";
|
||||
} from "client/ClanApi";
|
||||
import {
|
||||
filterMembersBySearch,
|
||||
filterRequestsBySearch,
|
||||
renderMemberStats,
|
||||
} from "../../../src/client/components/clan/ClanShared";
|
||||
} from "client/components/clan/ClanShared";
|
||||
|
||||
const members: ClanMember[] = [
|
||||
{ publicId: "Alice123", role: "leader", joinedAt: "2024-01-01T00:00:00Z" },
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FluentSlider } from "../../../src/client/components/FluentSlider";
|
||||
import { FluentSlider } from "client/components/FluentSlider";
|
||||
|
||||
// Mock the translateText function
|
||||
vi.mock("../../../src/client/Utils", () => ({
|
||||
vi.mock("client/Utils", () => ({
|
||||
translateText: vi.fn((key: string) => key),
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import newsItems from "../../../resources/news.json";
|
||||
import newsItems from "resources/news.json";
|
||||
import {
|
||||
getVisibleNewsItems,
|
||||
NewsItem,
|
||||
} from "../../../src/client/components/NewsBox";
|
||||
} from "client/components/NewsBox";
|
||||
|
||||
const DISMISSED_NEWS_KEY = "dismissedNewsItems";
|
||||
const allItems = newsItems as NewsItem[];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { shouldPreserveGhostAfterBuild } from "../../../src/client/controllers/BuildPreviewController";
|
||||
import { UnitType } from "../../../src/core/game/Game";
|
||||
import { shouldPreserveGhostAfterBuild } from "client/controllers/BuildPreviewController";
|
||||
import { UnitType } from "engine/game/Game";
|
||||
|
||||
describe("BuildPreviewController ghost preservation (locked nuke / Enter confirm)", () => {
|
||||
describe("shouldPreserveGhostAfterBuild", () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WarshipSelectionController } from "../../../src/client/controllers/WarshipSelectionController";
|
||||
import { UnitSelectionEvent } from "../../../src/client/InputHandler";
|
||||
import { WarshipSelectionController } from "client/controllers/WarshipSelectionController";
|
||||
import { UnitSelectionEvent } from "client/InputHandler";
|
||||
|
||||
describe("WarshipSelectionController", () => {
|
||||
let game: any;
|
||||
|
||||
@@ -6,20 +6,20 @@ import {
|
||||
MenuElementParams,
|
||||
rootMenuElement,
|
||||
Slot,
|
||||
} from "../../../src/client/hud/layers/RadialMenuElements";
|
||||
import { UnitType } from "../../../src/core/game/Game";
|
||||
import { TileRef } from "../../../src/core/game/GameMap";
|
||||
import { GameView, PlayerView } from "../../../src/core/game/GameView";
|
||||
} from "client/hud/layers/RadialMenuElements";
|
||||
import { UnitType } from "engine/game/Game";
|
||||
import { TileRef } from "engine/game/GameMap";
|
||||
import { GameView, PlayerView } from "client/view";
|
||||
|
||||
vi.mock("../../../src/client/Utils", () => ({
|
||||
vi.mock("client/Utils", () => ({
|
||||
translateText: vi.fn((key: string) => key),
|
||||
renderNumber: vi.fn((num: number) => num.toString()),
|
||||
}));
|
||||
|
||||
vi.mock("../../../src/client/hud/layers/BuildMenu", async () => {
|
||||
vi.mock("client/hud/layers/BuildMenu", async () => {
|
||||
const { UnitType } = await vi.importActual<
|
||||
typeof import("../../../src/core/game/Game")
|
||||
>("../../../src/core/game/Game");
|
||||
typeof import("engine/game/Game")
|
||||
>("engine/game/Game");
|
||||
return {
|
||||
flattenedBuildTable: [
|
||||
{
|
||||
@@ -600,8 +600,8 @@ describe("RadialMenuElements", () => {
|
||||
describe("Translation integration", () => {
|
||||
it("should use translateText for tooltip items in build menu", async () => {
|
||||
const { translateText } = await vi.importMock<
|
||||
typeof import("../../../src/client/Utils")
|
||||
>("../../../src/client/Utils");
|
||||
typeof import("client/Utils")
|
||||
>("client/Utils");
|
||||
|
||||
(translateText as Mock).mockClear();
|
||||
|
||||
@@ -615,8 +615,8 @@ describe("RadialMenuElements", () => {
|
||||
|
||||
it("should use translateText for tooltip items in attack menu", async () => {
|
||||
const { translateText } = await vi.importMock<
|
||||
typeof import("../../../src/client/Utils")
|
||||
>("../../../src/client/Utils");
|
||||
typeof import("client/Utils")
|
||||
>("client/Utils");
|
||||
|
||||
(translateText as Mock).mockClear();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GameUpdateType } from "../../../../src/core/game/GameUpdates";
|
||||
import { GameUpdateType } from "engine/game/GameUpdates";
|
||||
|
||||
vi.mock("lit", () => ({
|
||||
html: () => {},
|
||||
@@ -21,8 +21,8 @@ vi.mock("lit/directives/unsafe-html.js", () => ({
|
||||
UnsafeHTMLDirective: class {},
|
||||
}));
|
||||
|
||||
import { ActionableEvents } from "../../../../src/client/hud/layers/ActionableEvents";
|
||||
import { MessageType } from "../../../../src/core/game/Game";
|
||||
import { ActionableEvents } from "client/hud/layers/ActionableEvents";
|
||||
import { MessageType } from "engine/game/Game";
|
||||
|
||||
describe("ActionableEvents - alliance renewal cleanup (allianceID based)", () => {
|
||||
function makeRenewal(
|
||||
|
||||
@@ -2,8 +2,8 @@ import { describe, expect, test } from "vitest";
|
||||
import {
|
||||
alignClusterOrder,
|
||||
Slot,
|
||||
} from "../../../../src/client/controllers/AttackingTroopsController";
|
||||
import { Cell } from "../../../../src/core/game/Game";
|
||||
} from "client/controllers/AttackingTroopsController";
|
||||
import { Cell } from "engine/game/Game";
|
||||
|
||||
// Slots only need the `dst` fields populated for `alignClusterOrder` — it
|
||||
// compares the new positions against the previous targets to decide whether
|
||||
|
||||
@@ -15,23 +15,23 @@ vi.mock("lit/decorators.js", () => ({
|
||||
query: () => () => {},
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/client/Utils", () => ({
|
||||
vi.mock("client/Utils", () => ({
|
||||
translateText: vi.fn((key: string) => key),
|
||||
renderDuration: vi.fn(),
|
||||
renderNumber: vi.fn(),
|
||||
renderTroops: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/client/components/ui/ActionButton", () => ({
|
||||
vi.mock("client/components/ui/ActionButton", () => ({
|
||||
actionButton: vi.fn((props: unknown) => props),
|
||||
}));
|
||||
|
||||
import { actionButton } from "../../../../src/client/components/ui/ActionButton";
|
||||
import { PlayerModerationModal } from "../../../../src/client/hud/layers/PlayerModerationModal";
|
||||
import { PlayerPanel } from "../../../../src/client/hud/layers/PlayerPanel";
|
||||
import { SendKickPlayerIntentEvent } from "../../../../src/client/Transport";
|
||||
import { PlayerType } from "../../../../src/core/game/Game";
|
||||
import { PlayerView } from "../../../../src/core/game/GameView";
|
||||
import { actionButton } from "client/components/ui/ActionButton";
|
||||
import { PlayerModerationModal } from "client/hud/layers/PlayerModerationModal";
|
||||
import { PlayerPanel } from "client/hud/layers/PlayerPanel";
|
||||
import { SendKickPlayerIntentEvent } from "client/Transport";
|
||||
import { PlayerType } from "engine/game/Game";
|
||||
import { PlayerView } from "client/view";
|
||||
|
||||
describe("PlayerPanel - kick player moderation", () => {
|
||||
let panel: PlayerPanel;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { RankedType } from "../../../../src/core/game/Game";
|
||||
import { RankedType } from "engine/game/Game";
|
||||
|
||||
vi.mock("../../../../src/client/Utils", () => ({
|
||||
vi.mock("client/Utils", () => ({
|
||||
translateText: vi.fn((key: string) => {
|
||||
const translations: Record<string, string> = {
|
||||
"win_modal.exit": "Exit",
|
||||
@@ -16,17 +16,17 @@ vi.mock("../../../../src/client/Utils", () => ({
|
||||
TUTORIAL_VIDEO_URL: "https://example.com/tutorial",
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/client/Api", () => ({
|
||||
vi.mock("client/Api", () => ({
|
||||
getUserMe: vi.fn(async () => null),
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/client/Cosmetics", () => ({
|
||||
vi.mock("client/Cosmetics", () => ({
|
||||
fetchCosmetics: vi.fn(async () => []),
|
||||
handlePurchase: vi.fn(),
|
||||
patternRelationship: vi.fn(() => ({})),
|
||||
}));
|
||||
|
||||
vi.mock("../../../../src/client/CrazyGamesSDK", () => ({
|
||||
vi.mock("client/CrazyGamesSDK", () => ({
|
||||
crazyGamesSDK: {
|
||||
happytime: vi.fn(),
|
||||
requestAd: vi.fn(),
|
||||
|
||||
@@ -12,15 +12,15 @@
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { computePlayerStatus } from "../../../../../src/client/render/frame/derive/PlayerStatus";
|
||||
import { computePlayerStatus } from "client/render/frame/derive/PlayerStatus";
|
||||
import type {
|
||||
PlayerState,
|
||||
UnitState,
|
||||
} from "../../../../../src/client/render/types";
|
||||
} from "client/render/types";
|
||||
import {
|
||||
UT_ATOM_BOMB,
|
||||
UT_WARSHIP,
|
||||
} from "../../../../../src/client/render/types";
|
||||
} from "client/render/types";
|
||||
|
||||
function ps(overrides: Partial<PlayerState> = {}): PlayerState {
|
||||
return {
|
||||
|
||||
@@ -40,9 +40,9 @@ vi.mock("howler", () => {
|
||||
});
|
||||
|
||||
// Mock the Sounds module so tests don't depend on actual asset paths
|
||||
vi.mock("../../../src/client/sound/Sounds", async (importOriginal) => {
|
||||
vi.mock("client/sound/Sounds", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import("../../../src/client/sound/Sounds")>();
|
||||
await importOriginal<typeof import("client/sound/Sounds")>();
|
||||
return {
|
||||
...actual,
|
||||
soundEffectUrls: new Map([
|
||||
@@ -62,14 +62,14 @@ vi.mock("../../../src/client/sound/Sounds", async (importOriginal) => {
|
||||
import {
|
||||
MAX_CONCURRENT_SOUNDS,
|
||||
SoundManager,
|
||||
} from "../../../src/client/sound/SoundManager";
|
||||
} from "client/sound/SoundManager";
|
||||
import {
|
||||
PlaySoundEffectEvent,
|
||||
SetBackgroundMusicVolumeEvent,
|
||||
SetSoundEffectsVolumeEvent,
|
||||
} from "../../../src/client/sound/Sounds";
|
||||
import { EventBus } from "../../../src/core/EventBus";
|
||||
import { UserSettings } from "../../../src/core/game/UserSettings";
|
||||
} from "client/sound/Sounds";
|
||||
import { EventBus } from "engine/EventBus";
|
||||
import { UserSettings } from "engine/game/UserSettings";
|
||||
|
||||
function createUserSettings(musicVolume = 0, sfxVolume = 1): UserSettings {
|
||||
const settings = new UserSettings();
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { UnitType } from "../../../src/core/game/Game";
|
||||
import { GameUpdateType } from "../../../src/core/game/GameUpdates";
|
||||
import { UnitType } from "engine/game/Game";
|
||||
import { GameUpdateType } from "engine/game/GameUpdates";
|
||||
import {
|
||||
makeEmptyGu,
|
||||
makeGameView,
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { PlayerView } from "../../../src/client/view/PlayerView";
|
||||
import { PlayerType } from "../../../src/core/game/Game";
|
||||
import { GameUpdateType } from "../../../src/core/game/GameUpdates";
|
||||
import { PlayerView } from "client/view/PlayerView";
|
||||
import { PlayerType } from "engine/game/Game";
|
||||
import { GameUpdateType } from "engine/game/GameUpdates";
|
||||
import {
|
||||
makeEmptyGu,
|
||||
makeGameView,
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { UnitView } from "../../../src/client/view/UnitView";
|
||||
import { UnitView } from "client/view/UnitView";
|
||||
import {
|
||||
TrainType,
|
||||
TransportShipState,
|
||||
UnitType,
|
||||
WarshipState,
|
||||
} from "../../../src/core/game/Game";
|
||||
} from "engine/game/Game";
|
||||
import { makeGameView, makeUnitUpdate, stubConfig } from "../../util/viewStubs";
|
||||
|
||||
describe("UnitView accessors", () => {
|
||||
|
||||
Reference in New Issue
Block a user