Files
KateLegend2_proj/tests/__mocks__/cc.ts
T
2026-06-07 22:10:03 +08:00

255 lines
7.5 KiB
TypeScript

/**
* Lightweight `cc` module mock used by Jest to allow platform-agnostic
* modules (`common/*`, `data/*`, some `logic/*`) to be unit-tested without
* pulling in the full Cocos Creator engine.
*
* Anything that actually touches `cc.Node` / scene graph must **not** live
* in a module that is directly tested by Jest; put it behind a thin facade
* instead (see `common/StorageMgr.ts` which isolates `sys.localStorage`).
*/
class FakeEventTarget {
private listeners = new Map<string, Array<(...args: unknown[]) => void>>();
on(event: string, cb: (...args: unknown[]) => void): void {
const list = this.listeners.get(event) ?? [];
list.push(cb);
this.listeners.set(event, list);
}
off(event: string, cb?: (...args: unknown[]) => void): void {
if (!cb) {
this.listeners.delete(event);
return;
}
const list = this.listeners.get(event);
if (!list) return;
this.listeners.set(
event,
list.filter((fn) => fn !== cb)
);
}
emit(event: string, ...args: unknown[]): void {
const list = this.listeners.get(event);
if (!list) return;
for (const fn of list) {
fn(...args);
}
}
}
export const EventTarget = FakeEventTarget;
export const _decorator = {
ccclass: (_name?: string) => (target: unknown) => target as any,
property: (_opts?: unknown) => (_target: unknown, _key: string) => {},
};
/**
* Minimal stand-in for `cc.Node`. Only the surface actually exercised by
* Scene Entry components is modelled so unit tests stay deterministic.
*/
export class Node {
public name: string = '';
public active: boolean = true;
public layer: number = 0;
public isValid: boolean = true;
public scale: Vec3 = new Vec3(1, 1, 1);
constructor(name?: string) {
this.name = name ?? '';
}
public addChild(_child: Node): void {}
public removeFromParent(): void {}
public destroy(): void { this.isValid = false; }
public on(_ev: string, _cb: (...args: unknown[]) => void, _target?: unknown): void {}
public off(_ev: string, _cb?: (...args: unknown[]) => void): void {}
public getComponent<T>(_ctor: new (...args: unknown[]) => T): T | null { return null; }
public addComponent<T>(_ctor: new (...args: unknown[]) => T): T { return {} as T; }
public setPosition(..._args: unknown[]): void {}
public setScale(..._args: unknown[]): void {}
public static EventType = {
TOUCH_START: 'touch-start',
TOUCH_MOVE: 'touch-move',
TOUCH_END: 'touch-end',
TOUCH_CANCEL: 'touch-cancel',
};
}
/**
* Minimal stand-in for `cc.Component`. Provides `.node` so Scene Entry TS
* types resolve. Runtime behaviour is injected by the Cocos Creator editor.
*/
export class Component {
public node: Node = new Node();
public enabled: boolean = true;
}
export const director = {
addPersistRootNode: (..._args: unknown[]) => {},
loadScene: (..._args: unknown[]) => {},
};
export const view = {
setDesignResolutionSize: (..._args: unknown[]) => {},
};
export const screen = {
orientation: 0,
};
export const game = {
frameRate: 60,
};
export const sys = {
localStorage: {
_store: new Map<string, string>(),
getItem(key: string): string | null {
return (sys.localStorage as any)._store.get(key) ?? null;
},
setItem(key: string, value: string): void {
(sys.localStorage as any)._store.set(key, value);
},
removeItem(key: string): void {
(sys.localStorage as any)._store.delete(key);
},
clear(): void {
(sys.localStorage as any)._store.clear();
},
},
};
export const settings = {};
export const Settings = {};
export const profiler = {};
// ---------------------------------------------------------------------
// Additional stubs for types imported by Scene Entry components. All the
// methods below are NO-OPs; the Cocos Creator editor injects the real
// implementations at runtime. Having them declared here keeps the TS
// language server happy and lets Jest exercise scene-entry unit tests.
// ---------------------------------------------------------------------
export class Color {
public r: number;
public g: number;
public b: number;
public a: number;
constructor(r: number = 255, g: number = 255, b: number = 255, a: number = 255) {
this.r = r; this.g = g; this.b = b; this.a = a;
}
public static WHITE = new Color(255, 255, 255, 255);
public static BLACK = new Color(0, 0, 0, 255);
}
export class Vec3 {
public x: number;
public y: number;
public z: number;
constructor(x: number = 0, y: number = 0, z: number = 0) {
this.x = x; this.y = y; this.z = z;
}
}
export class UITransform {
public width: number = 0;
public height: number = 0;
public setContentSize(_w: number, _h: number): void {}
}
export class Label {
public string: string = '';
public fontSize: number = 24;
public lineHeight: number = 28;
public color: Color = Color.WHITE;
public horizontalAlign: number = 0;
public verticalAlign: number = 0;
public useSystemFont: boolean = true;
public enableWrapText: boolean = true;
}
export class Button {
public transition: number = 0;
public target: Node | null = null;
public zoomScale: number = 1;
public static Transition = { NONE: 0, COLOR: 1, SPRITE: 2, SCALE: 3 };
}
export class Graphics {
public fillColor: Color = Color.WHITE;
public strokeColor: Color = Color.BLACK;
public lineWidth: number = 1;
public rect(_x: number, _y: number, _w: number, _h: number): void {}
public fill(): void {}
public stroke(): void {}
}
export class Sprite {
public spriteFrame: unknown = null;
public type: number = 0;
public sizeMode: number = 0;
public color: Color = Color.WHITE;
public static Type = { SIMPLE: 0, SLICED: 1, TILED: 2, FILLED: 3 };
public static SizeMode = { CUSTOM: 0, TRIMMED: 1, RAW: 2 };
}
export class Rect {
public x: number;
public y: number;
public width: number;
public height: number;
constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0) {
this.x = x; this.y = y; this.width = width; this.height = height;
}
}
export class Size {
public width: number;
public height: number;
constructor(width: number = 0, height: number = 0) {
this.width = width; this.height = height;
}
}
export class SpriteFrame {
public texture: unknown = null;
public rect: Rect = new Rect();
public originalSize: Size = new Size();
}
export class Texture2D {
public image: unknown = null;
public width: number = 0;
public height: number = 0;
public static PixelFormat = { RGBA8888: 35 };
}
export class ImageAsset {
constructor(_opts?: unknown) {}
}
export class JsonAsset {
public json: unknown = null;
}
export class Canvas {}
export class EventTouch {}
/** Global input event source (Cocos Creator 3.8). */
export const input = {
on: (_ev: string, _cb: (...args: unknown[]) => void, _target?: unknown): void => {},
off: (_ev: string, _cb?: (...args: unknown[]) => void, _target?: unknown): void => {},
};
export const Input = {
EventType: {
TOUCH_START: 'touch-start',
TOUCH_MOVE: 'touch-move',
TOUCH_END: 'touch-end',
TOUCH_CANCEL: 'touch-cancel',
},
};
export const resources = {
load: (_path: string, _type: unknown, _cb: (err: Error | null, asset: unknown) => void): void => {},
};