mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
8ab0021af6
Splits the 492-line useNavigator god-hook into a useBetween-backed useNavigatorStore closure plus three flat-shape filters (useNavigatorData, useNavigatorUiState, useNavigatorActions), mirroring the wired-tools layout. sendSearch + reloadCurrentSearch are extracted as named actions out of NavigatorView locals. Door-mode handling is removed from this store and lives in useDoorState (committed previously) - see GetGuestRoomResultEvent and GenericErrorEvent dual-subscription with mutually exclusive filters. The simpleAlert dependency is lifted out of the useBetween scope via a module-level _simpleAlert ref + _injectSimpleAlert() to avoid nested useBetween calls that corrupt use-between's module-level dispatcher state. The ref is null in tests (no events fire during smoke tests) and is populated in production by the navigator consumer before any alert is needed. The barrel index.ts no longer re-exports useNavigator. The 13 consumers will fail typecheck until the next commit migrates them; the hook files themselves are clean. Smoke test covers filter shapes. INTENTIONAL INTERMEDIATE-BROKEN COMMIT: yarn typecheck is RED at this SHA on the 13 consumer files. The next commit (consumer migration sweep) brings it back to green.
562 lines
23 KiB
TypeScript
562 lines
23 KiB
TypeScript
/**
|
|
* Stub of `@nitrots/nitro-renderer` for Vitest.
|
|
*
|
|
* The real package eagerly loads Pixi v8 + a few hundred Habbo message
|
|
* parsers/composers at module import time, which jsdom cannot host:
|
|
* any `tests/**` file that transitively pulls a renderer symbol throws
|
|
* before a single assertion runs.
|
|
*
|
|
* This module replaces it via `resolve.alias` in `vitest.config.mts`.
|
|
* We provide explicit named exports for the symbols a test currently
|
|
* needs (logger, event dispatcher, doorbell event class); everything
|
|
* else mentioned in the comments below is a generic stub kept just to
|
|
* keep the side-effectful imports happy as `src/api/index.ts` and
|
|
* friends are pulled in transitively by the barrel cascade.
|
|
*
|
|
* Grow this file as new tests require additional symbols. Prefer adding
|
|
* a real (deterministic) stub over wiring `vi.fn()` — it keeps the
|
|
* mocks readable and avoids state bleed between cases.
|
|
*/
|
|
|
|
import { vi } from 'vitest';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Logger
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export const NitroLogger = {
|
|
log: vi.fn(),
|
|
warn: vi.fn(),
|
|
error: vi.fn(),
|
|
enableContexts: vi.fn(),
|
|
setDebug: vi.fn()
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Event dispatcher
|
|
// ---------------------------------------------------------------------------
|
|
//
|
|
// `GetEventDispatcher()` in the real SDK returns the renderer-wide event
|
|
// bus. Tests use `mockEventDispatcher.dispatchEvent(event)` to simulate
|
|
// a server push. `clearMockEventDispatcher()` resets the listener map
|
|
// between cases so subscriptions from a previous test don't leak.
|
|
|
|
type Listener = (event: any) => void;
|
|
|
|
// NitroEvent listeners — registered via GetEventDispatcher() / useNitroEvent.
|
|
// Cleared by clearMockEventDispatcher() between test cases.
|
|
const listeners = new Map<string, Set<Listener>>();
|
|
|
|
// MessageEvent listeners — registered via GetCommunication().registerMessageEvent
|
|
// (i.e. useMessageEvent). NOT cleared by clearMockEventDispatcher() so that
|
|
// useBetween-based hooks (which register effects once and persist the
|
|
// singleton across tests) keep their subscriptions alive throughout the
|
|
// suite. State isolation between tests is maintained by the useBetween
|
|
// instance preserving INITIAL values across renders (each test's renderHook
|
|
// shares the same useBetween singleton — tests that check a specific
|
|
// post-dispatch state rely on the event changing it, not on a reset).
|
|
const msgListeners = new Map<string, Set<Listener>>();
|
|
|
|
export const mockEventDispatcher = {
|
|
addEventListener(type: string, handler: Listener)
|
|
{
|
|
let bucket = listeners.get(type);
|
|
|
|
if(!bucket)
|
|
{
|
|
bucket = new Set();
|
|
listeners.set(type, bucket);
|
|
}
|
|
|
|
bucket.add(handler);
|
|
},
|
|
removeEventListener(type: string, handler: Listener)
|
|
{
|
|
listeners.get(type)?.delete(handler);
|
|
},
|
|
dispatchEvent(event: { type: string })
|
|
{
|
|
// Fire NitroEvent listeners first, then MessageEvent listeners.
|
|
const bucket = listeners.get(event.type);
|
|
if(bucket) for(const handler of bucket) handler(event);
|
|
|
|
const msgBucket = msgListeners.get(event.type);
|
|
if(msgBucket) for(const handler of msgBucket) handler(event);
|
|
},
|
|
hasListeners(type: string)
|
|
{
|
|
return (listeners.get(type)?.size ?? 0) > 0 ||
|
|
(msgListeners.get(type)?.size ?? 0) > 0;
|
|
}
|
|
};
|
|
|
|
// Clears only the NitroEvent listener map (GetEventDispatcher / useNitroEvent
|
|
// registrations). MessageEvent listeners (useMessageEvent / GetCommunication)
|
|
// are intentionally preserved so useBetween-based hooks stay subscribed.
|
|
export const clearMockEventDispatcher = () =>
|
|
{
|
|
listeners.clear();
|
|
};
|
|
|
|
export const GetEventDispatcher = vi.fn(() => mockEventDispatcher);
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Event type enums (string-keyed Proxies)
|
|
// ---------------------------------------------------------------------------
|
|
//
|
|
// The real `*EventType` is a `class { static readonly FOO = '...'; … }`
|
|
// with stable wire strings. Tests only need each constant to be a
|
|
// unique string so dispatch + listener agree.
|
|
|
|
const makeEnumProxy = (label: string) => new Proxy({}, {
|
|
get: (_, prop) => typeof prop === 'string' ? `mock:${ label }:${ prop }` : undefined
|
|
}) as Record<string, string>;
|
|
|
|
export const NitroEventType = makeEnumProxy('NitroEventType');
|
|
export const MouseEventType = makeEnumProxy('MouseEventType');
|
|
export const TouchEventType = makeEnumProxy('TouchEventType');
|
|
export const RoomObjectPlacementSource = makeEnumProxy('RoomObjectPlacementSource');
|
|
export const RoomObjectType = makeEnumProxy('RoomObjectType');
|
|
export const RoomObjectVariable = makeEnumProxy('RoomObjectVariable');
|
|
export const RoomTradingLevelEnum = makeEnumProxy('RoomTradingLevelEnum');
|
|
export const HabboClubLevelEnum = makeEnumProxy('HabboClubLevelEnum');
|
|
export const FurnitureType = makeEnumProxy('FurnitureType');
|
|
export const PetType = makeEnumProxy('PetType');
|
|
export const AvatarFigurePartType = makeEnumProxy('AvatarFigurePartType');
|
|
export const AvatarScaleType = makeEnumProxy('AvatarScaleType');
|
|
export const AvatarSetType = makeEnumProxy('AvatarSetType');
|
|
export const AvatarAction = makeEnumProxy('AvatarAction');
|
|
export const RoomWidgetEnumItemExtradataParameter = makeEnumProxy('RoomWidgetEnumItemExtradataParameter');
|
|
|
|
// Numeric enums — values mirror the real renderer SDK so comparisons
|
|
// (`controllerLevel >= GUILD_ADMIN`, category branching) keep working.
|
|
|
|
export class RoomControllerLevel
|
|
{
|
|
static readonly NONE = 0;
|
|
static readonly GUEST = 1;
|
|
static readonly GUILD_MEMBER = 2;
|
|
static readonly GUILD_ADMIN = 3;
|
|
static readonly ROOM_OWNER = 4;
|
|
static readonly MODERATOR = 5;
|
|
}
|
|
|
|
// Mirrors `packages/api/src/nitro/session/enum/SecurityLevel.ts`. Kept
|
|
// around so any consumer that still imports the renderer enum
|
|
// (non-deprecated code path) compiles cleanly under the mock.
|
|
export class SecurityLevel
|
|
{
|
|
static readonly NONE = 0;
|
|
static readonly CELEBRITY = 1;
|
|
static readonly PARTNER = 2;
|
|
static readonly BUS_PARTNER = 3;
|
|
static readonly EMPLOYEE = 4;
|
|
static readonly MODERATOR = 5;
|
|
static readonly PLAYER_SUPPORT = 6;
|
|
static readonly COMMUNITY = 7;
|
|
static readonly ADMINISTRATOR = 8;
|
|
static readonly SUPER_USER = 9;
|
|
}
|
|
|
|
export class RoomObjectCategory
|
|
{
|
|
static readonly MINIMUM = 0;
|
|
static readonly ROOM = 10;
|
|
static readonly UNIT = 20;
|
|
static readonly FLOOR = 30;
|
|
static readonly WALL = 40;
|
|
static readonly MAXIMUM = 50;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Doorbell event class
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export class RoomSessionDoorbellEvent
|
|
{
|
|
// Wire strings copied from the real class so any consumer that
|
|
// ignores the indirection through the `.DOORBELL` static still
|
|
// matches.
|
|
static readonly DOORBELL = 'RSDE_DOORBELL';
|
|
static readonly RSDE_ACCEPTED = 'RSDE_ACCEPTED';
|
|
static readonly RSDE_REJECTED = 'RSDE_REJECTED';
|
|
|
|
// Mirrors the real constructor signature `(type, session, userName)`
|
|
// so `tsgo` is happy. Tests can pass `null` for the session: the
|
|
// SUT only reads `.userName` and `.type`.
|
|
constructor(public readonly type: string, public readonly _session: unknown, public readonly userName: string) {}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Generic classes — placeholders for symbols that need to exist as
|
|
// constructors so module-level `new X(...)` calls don't crash during
|
|
// the barrel cascade, but whose behavior tests don't yet exercise.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
class StubClass
|
|
{
|
|
constructor(..._args: unknown[]) {}
|
|
}
|
|
|
|
export class NitroAlphaFilter extends StubClass {}
|
|
export class NitroContainer extends StubClass {}
|
|
export class NitroRectangle extends StubClass {}
|
|
export class NitroSprite extends StubClass {}
|
|
export class NitroTexture extends StubClass {}
|
|
export class NitroSoundEvent extends StubClass {}
|
|
export class NitroEvent extends StubClass {}
|
|
|
|
// MessageEvent — stores the handler so GetCommunication (below) can
|
|
// route dispatches through mockEventDispatcher. Each concrete subclass
|
|
// exposes a `.type` equal to its constructor name so dispatchEvent
|
|
// can match registered listeners.
|
|
export class MessageEvent
|
|
{
|
|
private _callBack: Function | null;
|
|
|
|
constructor(callBack?: Function)
|
|
{
|
|
this._callBack = callBack ?? null;
|
|
}
|
|
|
|
public get callBack(): Function | null { return this._callBack; }
|
|
|
|
// Each concrete subclass is identified by its class name.
|
|
public get type(): string { return this.constructor.name; }
|
|
|
|
// Concrete subclasses override this; the no-arg construction path used
|
|
// by makeParserlessEvent in tests leaves it returning null — tests
|
|
// override it with (ev as any).getParser = () => parser.
|
|
public getParser(): any { return null; }
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// IMessageEvent-based event classes used by useDoorState
|
|
//
|
|
// The real renderer classes take a `callBack` constructor arg and store it
|
|
// in MessageEvent._callBack. The communication manager later calls
|
|
// `event.callBack(event)` when the matching packet arrives.
|
|
//
|
|
// In tests we construct them with NO args (makeParserlessEvent does
|
|
// `new klass()`) and override `getParser`. GetCommunication (below)
|
|
// registers `event.callBack` on mockEventDispatcher under `event.type`
|
|
// (the class name). When the test calls
|
|
// `mockEventDispatcher.dispatchEvent(ev)`, listeners for that class name
|
|
// fire, receiving `ev` — and the implementation reads `ev.getParser()`.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export class DoorbellMessageEvent extends MessageEvent {}
|
|
export class RoomDoorbellAcceptedEvent extends MessageEvent {}
|
|
export class FlatAccessDeniedMessageEvent extends MessageEvent {}
|
|
export class GenericErrorEvent extends MessageEvent {}
|
|
export class GetGuestRoomResultEvent extends MessageEvent {}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Navigator event classes — MessageEvent subclasses needed by useNavigatorStore
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export class CanCreateRoomEventEvent extends MessageEvent {}
|
|
export class FavouriteChangedEvent extends MessageEvent {}
|
|
export class FavouritesEvent extends MessageEvent {}
|
|
export class FlatCreatedEvent extends MessageEvent {}
|
|
export class NavigatorHomeRoomEvent extends MessageEvent {}
|
|
export class NavigatorMetadataEvent extends MessageEvent {}
|
|
export class NavigatorOpenRoomCreatorEvent extends MessageEvent {}
|
|
export class NavigatorSearchesEvent extends MessageEvent {}
|
|
export class NavigatorSearchEvent extends MessageEvent {}
|
|
export class RoomEnterErrorEvent extends MessageEvent {}
|
|
export class RoomEntryInfoMessageEvent extends MessageEvent {}
|
|
export class RoomForwardEvent extends MessageEvent {}
|
|
export class RoomScoreEvent extends MessageEvent {}
|
|
export class RoomSettingsUpdatedEvent extends MessageEvent {}
|
|
export class UserEventCatsEvent extends MessageEvent {}
|
|
export class UserFlatCatsEvent extends MessageEvent {}
|
|
export class UserInfoEvent extends MessageEvent {}
|
|
export class UserPermissionsEvent extends MessageEvent {}
|
|
|
|
export class RoomEngineObjectEvent extends StubClass {}
|
|
export class CreateLinkEvent extends StubClass {}
|
|
export class EventDispatcher extends StubClass {}
|
|
export class AdvancedMap extends StubClass {}
|
|
export class AvatarFigureContainer extends StubClass {}
|
|
export class Vector3d extends StubClass {}
|
|
export class ObjectDataFactory extends StubClass {}
|
|
|
|
// RoomDataParser — real static constants needed by useDoorState and its tests.
|
|
export class RoomDataParser
|
|
{
|
|
static readonly DOORBELL_STATE = 1;
|
|
static readonly PASSWORD_STATE = 2;
|
|
}
|
|
|
|
export class RoomModerationSettings extends StubClass {}
|
|
export class StringDataType extends StubClass {}
|
|
|
|
// Navigator data/parser stubs
|
|
export class NavigatorCategoryDataParser extends StubClass {}
|
|
export class NavigatorEventCategoryDataParser extends StubClass {}
|
|
export class NavigatorSavedSearch extends StubClass {}
|
|
export class NavigatorSearchResultSet extends StubClass {}
|
|
export class NavigatorTopLevelContext extends StubClass {}
|
|
export class CantConnectMessageParser extends StubClass
|
|
{
|
|
static readonly REASON_FULL = 1;
|
|
static readonly REASON_QUEUE_ERROR = 2;
|
|
static readonly REASON_BANNED = 3;
|
|
}
|
|
|
|
export class LegacyExternalInterface
|
|
{
|
|
static readonly available = false;
|
|
static call(..._args: unknown[]): void {}
|
|
}
|
|
export class SellablePetPaletteData extends StubClass {}
|
|
export class PetFigureData extends StubClass {}
|
|
export class PetData extends StubClass {}
|
|
export class NodeData extends StubClass {}
|
|
export class ItemDataStructure extends StubClass {}
|
|
export class HabboGroupEntryData extends StubClass {}
|
|
export class FriendParser extends StubClass {}
|
|
export class FriendCategoryData extends StubClass {}
|
|
export class FriendRequestData extends StubClass {}
|
|
export class FurnitureListItemParser extends StubClass {}
|
|
export class BotData extends StubClass {}
|
|
export class AchievementData extends StubClass {}
|
|
export class CatalogPageMessageProductData extends StubClass {}
|
|
export class GiftWrappingConfigurationParser extends StubClass {}
|
|
export class WiredFilter extends StubClass {}
|
|
export class HabboWebTools extends StubClass {}
|
|
|
|
// Composers — symbol-only constructors; only their identity matters in the
|
|
// codebase ("did the SUT call SendMessageComposer(new FooComposer(args))").
|
|
export class AddFavouriteRoomMessageComposer extends StubClass {}
|
|
export class DeleteFavouriteRoomMessageComposer extends StubClass {}
|
|
export class FollowFriendMessageComposer extends StubClass {}
|
|
export class GetUserEventCatsMessageComposer extends StubClass {}
|
|
export class GetUserFlatCatsMessageComposer extends StubClass {}
|
|
export class NavigatorSearchComposer extends StubClass {}
|
|
export class DesktopViewComposer extends StubClass {}
|
|
export class FurniturePlacePaintComposer extends StubClass {}
|
|
export class GetGuestRoomMessageComposer extends StubClass {}
|
|
export class GetProductOfferComposer extends StubClass {}
|
|
export class GroupFavoriteComposer extends StubClass {}
|
|
export class GroupInformationComposer extends StubClass {}
|
|
export class GroupJoinComposer extends StubClass {}
|
|
export class GroupUnfavoriteComposer extends StubClass {}
|
|
export class UserProfileComposer extends StubClass {}
|
|
|
|
// `ChooserSelectionFilter` is used as a string enum in some call sites.
|
|
export const ChooserSelectionFilter = makeEnumProxy('ChooserSelectionFilter');
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Floor plan constants
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export const FloorAction = makeEnumProxy('FloorAction');
|
|
|
|
export const TILE_SIZE = 32;
|
|
|
|
export const HEIGHT_SCHEME = 'x0123456789abcdefghijklmnopq';
|
|
|
|
export const MAX_NUM_TILE_PER_AXIS = 64;
|
|
|
|
export const COLORMAP: object = {
|
|
'x': '101010',
|
|
'0': '0065ff', '1': '0091ff', '2': '00bcff', '3': '00e8ff',
|
|
'4': '00ffea', '5': '00ffbf', '6': '00ff93', '7': '00ff68',
|
|
'8': '00ff3d', '9': '19ff00',
|
|
'a': '44ff00', 'b': '70ff00', 'c': '9bff00', 'd': 'f2ff00',
|
|
'e': 'ffe000', 'f': 'ffb500', 'g': 'ff8900', 'h': 'ff5e00',
|
|
'i': 'ff3200', 'j': 'ff0700', 'k': 'ff0023', 'l': 'ff007a',
|
|
'm': 'ff00a5', 'n': 'ff00d1', 'o': 'ff00fc',
|
|
'p': 'd600ff', 'q': 'aa00ff'
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Floor plan editor — composer stubs and event classes
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// Composer stubs for floor-plan-editor message events
|
|
export class GetRoomEntryTileMessageComposer extends StubClass {}
|
|
export class GetOccupiedTilesMessageComposer extends StubClass {}
|
|
export class UpdateFloorPropertiesMessageComposer extends StubClass
|
|
{
|
|
public tilemap: string;
|
|
public doorX: number;
|
|
public doorY: number;
|
|
public dir: number;
|
|
public thicknessWall: number;
|
|
public thicknessFloor: number;
|
|
public wallHeight: number;
|
|
constructor(tilemap: string, doorX: number, doorY: number, dir: number, thicknessWall: number, thicknessFloor: number, wallHeight: number)
|
|
{
|
|
super();
|
|
this.tilemap = tilemap;
|
|
this.doorX = doorX;
|
|
this.doorY = doorY;
|
|
this.dir = dir;
|
|
this.thicknessWall = thicknessWall;
|
|
this.thicknessFloor = thicknessFloor;
|
|
this.wallHeight = wallHeight;
|
|
}
|
|
}
|
|
|
|
// Event class stubs for useMessageEvent registration
|
|
export class FloorHeightMapEvent extends StubClass {}
|
|
export class RoomVisualizationSettingsEvent extends StubClass {}
|
|
export class RoomEntryTileMessageEvent extends StubClass {}
|
|
export class RoomOccupiedTilesMessageEvent extends StubClass {}
|
|
export const RoomEngineEvent = makeEnumProxy('RoomEngineEvent');
|
|
|
|
// Link tracker stubs
|
|
export type ILinkEventTracker = { linkReceived: (url: string) => void; eventUrlPrefix: string };
|
|
export const AddLinkEventTracker = vi.fn();
|
|
export const RemoveLinkEventTracker = vi.fn();
|
|
|
|
// Thickness conversion helpers — mirror the renderer's real mapping
|
|
export const convertNumbersForSaving = (v: number): number =>
|
|
{
|
|
switch(v)
|
|
{
|
|
case 0: return -2;
|
|
case 1: return -1;
|
|
case 3: return 1;
|
|
default: return 0;
|
|
}
|
|
};
|
|
|
|
export const convertSettingToNumber = (v: number): number =>
|
|
{
|
|
switch(v)
|
|
{
|
|
case 0.25: return 0;
|
|
case 0.5: return 1;
|
|
case 2: return 3;
|
|
default: return 2;
|
|
}
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Singleton getters
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const stubManager = () =>
|
|
{
|
|
const sentinel = new Proxy(() => undefined, {
|
|
get(target, prop)
|
|
{
|
|
if(prop === 'then') return undefined;
|
|
const cached = (target as any)[prop];
|
|
if(cached !== undefined) return cached;
|
|
// Most fields read from a real manager are either methods
|
|
// (return functions) or sub-objects (return proxies). We
|
|
// return another callable proxy so chained access works.
|
|
const value = stubManager();
|
|
(target as any)[prop] = value;
|
|
return value;
|
|
},
|
|
apply()
|
|
{
|
|
return undefined;
|
|
}
|
|
});
|
|
|
|
return sentinel;
|
|
};
|
|
|
|
export const GetAssetManager = vi.fn(stubManager);
|
|
export const GetAvatarRenderManager = vi.fn(stubManager);
|
|
// GetCommunication — routes IMessageEvent registration through the
|
|
// msgListeners map (separate from the NitroEvent listeners map) so that
|
|
// clearMockEventDispatcher() does NOT wipe these subscriptions. This
|
|
// keeps useBetween-based hooks (like useDoorState) subscribed across
|
|
// test cases without needing to recreate the useBetween singleton.
|
|
//
|
|
// A WeakMap stores the wrapper fn keyed by the MessageEvent instance so
|
|
// that removeMessageEvent can remove the exact listener added by
|
|
// registerMessageEvent.
|
|
const _msgEventWrappers = new WeakMap<MessageEvent, (ev: any) => void>();
|
|
|
|
export const GetCommunication = vi.fn(() => ({
|
|
registerMessageEvent(event: MessageEvent)
|
|
{
|
|
if(!event.callBack) return;
|
|
const wrapper = (ev: any) => event.callBack!(ev);
|
|
_msgEventWrappers.set(event, wrapper);
|
|
let bucket = msgListeners.get(event.type);
|
|
if(!bucket) { bucket = new Set(); msgListeners.set(event.type, bucket); }
|
|
bucket.add(wrapper);
|
|
},
|
|
removeMessageEvent(event: MessageEvent)
|
|
{
|
|
const wrapper = _msgEventWrappers.get(event);
|
|
if(wrapper) msgListeners.get(event.type)?.delete(wrapper);
|
|
}
|
|
}));
|
|
export const GetConfiguration = vi.fn(stubManager);
|
|
export const GetLocalizationManager = vi.fn(stubManager);
|
|
export const GetRoomEngine = vi.fn(stubManager);
|
|
export const GetRoomMessageHandler = vi.fn(stubManager);
|
|
export const GetRoomSessionManager = vi.fn(stubManager);
|
|
|
|
// RoomPreviewer — only the bits the editor's FloorplanRoomPreview
|
|
// component touches. PREVIEW_COUNTER is a static field that the
|
|
// real renderer increments to allocate unique preview-room IDs;
|
|
// keeping it as a mutable static lets the editor mount/unmount
|
|
// repeatedly across tests without colliding.
|
|
export class RoomPreviewer
|
|
{
|
|
static PREVIEW_COUNTER = 0;
|
|
|
|
constructor(public readonly _engine: unknown, public readonly _id: number) {}
|
|
|
|
public updatePreviewModel(_model: string, _wallHeight: number, _scale?: boolean): void {}
|
|
public modifyRoomCanvas(_w: number, _h: number): void {}
|
|
public getRoomCanvas(_w: number, _h: number): unknown { return null; }
|
|
public getRenderingCanvas(): unknown { return null; }
|
|
public updatePreviewRoomView(): void {}
|
|
public changeRoomObjectDirection(): void {}
|
|
public changeRoomObjectState(): void {}
|
|
public dispose(): void {}
|
|
}
|
|
export const GetSessionDataManager = vi.fn(stubManager);
|
|
export const GetTickerTime = vi.fn(() => 0);
|
|
export const GetTicker = vi.fn(stubManager);
|
|
export const GetRenderer = vi.fn(stubManager);
|
|
export class NitroTicker {}
|
|
// TextureUtils — a real-enough stub of the createRenderTexture
|
|
// roundtrip. Tests that mount LayoutRoomPreviewerView allocate a
|
|
// texture on mount and destroy it on unmount; without a real
|
|
// `.destroy` method the unmount cleanup throws.
|
|
export const TextureUtils = {
|
|
createRenderTexture: (_w: number, _h: number) => ({
|
|
destroy: (_options?: unknown) => undefined
|
|
}),
|
|
generateImage: () => null
|
|
};
|
|
export const NitroVersion = stubManager();
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Type-only re-exports (interfaces erase at compile time, but listing them
|
|
// here documents what the codebase imports through the type channel).
|
|
//
|
|
// IAvatarFigureContainer · IEventDispatcher · IFigurePart · IFigurePartSet ·
|
|
// IFurnitureData · IFurnitureItemData · IGraphicAsset · IMessageComposer ·
|
|
// IMessageEvent · IObjectData · IPartColor · IPollQuestion · IProductData ·
|
|
// IRoomEngine · IRoomModerationSettings · IRoomObject · IRoomObjectController ·
|
|
// IRoomObjectSpriteVisualization · IRoomPetData · IRoomSession · IRoomUserData
|
|
//
|
|
// No need to alias them — TypeScript only consults them in the type
|
|
// system, and the production `tsconfig.json` resolves them against the
|
|
// real renderer via `node_modules/@nitrots/nitro-renderer/src`.
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Catch-all
|
|
// ---------------------------------------------------------------------------
|
|
//
|
|
// Anything else still resolves to `undefined`. If a test fails with
|
|
// "X is not a constructor" / "X.SOMETHING is not a function", add the
|
|
// missing symbol above with a real stub. Avoid the temptation to
|
|
// blanket-mock everything — explicit stubs surface intent and let
|
|
// failing tests pinpoint what behavior they actually rely on.
|