Skip to content

Commit a9d0ccd

Browse files
committed
test: add TC39 decorator tests and fix tsconfig.test.json lib
1 parent e60bba5 commit a9d0ccd

4 files changed

Lines changed: 151 additions & 2 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Quick inline test to verify TC39 decorators work correctly.
3+
* Run with: npx ts-node --esm --project tsconfig.test.json packages/dev/core/test/unit/Decorators/decorators.inline-test.ts
4+
*/
5+
6+
// Test 1: Symbol.metadata polyfill
7+
(Symbol as any).metadata ??= Symbol.for("Symbol.metadata");
8+
9+
// Test 2: A simple TC39 class field decorator
10+
function trackField(displayName: string) {
11+
return function <This, V>(_value: undefined, context: ClassFieldDecoratorContext<This, V>) {
12+
const key = `__tracked_${String(context.name)}`;
13+
if (!Object.hasOwn(context.metadata, key)) {
14+
(context.metadata as any)[key] = displayName;
15+
}
16+
};
17+
}
18+
19+
// Test 3: A TC39 accessor decorator (like expandToProperty)
20+
function doubleAccessor<This, V extends number>(
21+
_value: ClassAccessorDecoratorTarget<This, V>,
22+
_context: ClassAccessorDecoratorContext<This, V>
23+
): ClassAccessorDecoratorResult<This, V> {
24+
return {
25+
get(this: This): V {
26+
return (_value.get.call(this) * 2) as V;
27+
},
28+
set(this: This, value: V) {
29+
_value.set.call(this, value);
30+
},
31+
};
32+
}
33+
34+
class TestClass {
35+
@trackField("My Number")
36+
myNum: number = 42;
37+
38+
@doubleAccessor
39+
accessor doubled: number = 5;
40+
}
41+
42+
// Verify metadata
43+
const metadata = (TestClass as any)[Symbol.metadata];
44+
console.assert(metadata !== undefined, "Symbol.metadata should be set on class");
45+
console.assert((metadata as any).__tracked_myNum === "My Number", "Field decorator should store metadata");
46+
47+
// Verify accessor
48+
const instance = new TestClass();
49+
console.assert(instance.doubled === 10, `Accessor should return doubled value, got ${instance.doubled}`);
50+
instance.doubled = 7;
51+
console.assert(instance.doubled === 14, `After setting 7, accessor should return 14, got ${instance.doubled}`);
52+
53+
// Test 4: Inheritance
54+
class ChildClass extends TestClass {
55+
@trackField("Child Prop")
56+
childProp: string = "hello";
57+
}
58+
59+
const childMeta = (ChildClass as any)[Symbol.metadata];
60+
console.assert(childMeta !== undefined, "Child should have metadata");
61+
console.assert((childMeta as any).__tracked_childProp === "Child Prop", "Child metadata should have its own properties");
62+
63+
// Walk the prototype chain
64+
const parentMeta = Object.getPrototypeOf(childMeta);
65+
console.assert(parentMeta !== null, "Child metadata prototype should be parent metadata");
66+
console.assert((parentMeta as any).__tracked_myNum === "My Number", "Parent metadata should be accessible via prototype chain");
67+
68+
console.log("All decorator tests passed!");
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* Quick sanity test for TC39 decorator migration.
3+
* Tests the core decorator functions work correctly with Symbol.metadata.
4+
*/
5+
import { serialize, serializeAsColor3, expandToProperty } from "core/Misc/decorators";
6+
import { GetDirectStore, GetMergedStore } from "core/Misc/decorators.functions";
7+
import { Color3 } from "core/Maths/math.color";
8+
9+
describe("TC39 Decorator Migration", () => {
10+
describe("serialize decorator", () => {
11+
it("should store serialization metadata via Symbol.metadata", () => {
12+
class TestClass {
13+
@serialize()
14+
public myProp: number = 42;
15+
16+
@serialize("renamedProp")
17+
public anotherProp: string = "hello";
18+
}
19+
20+
const store = GetDirectStore(new TestClass());
21+
expect(store).toBeDefined();
22+
expect(store["myProp"]).toBeDefined();
23+
expect(store["myProp"].type).toBe(0); // default type
24+
expect(store["renamedProp"]).toBeDefined();
25+
});
26+
27+
it("should merge stores from parent and child classes", () => {
28+
class Parent {
29+
@serialize()
30+
public parentProp: number = 1;
31+
}
32+
33+
class Child extends Parent {
34+
@serialize()
35+
public childProp: number = 2;
36+
}
37+
38+
const child = new Child();
39+
const merged = GetMergedStore(child);
40+
expect(merged["parentProp"]).toBeDefined();
41+
expect(merged["childProp"]).toBeDefined();
42+
});
43+
});
44+
45+
describe("serializeAsColor3 decorator", () => {
46+
it("should serialize color3 properties", () => {
47+
class ColorClass {
48+
@serializeAsColor3()
49+
public color: Color3 = new Color3(1, 0, 0);
50+
}
51+
52+
const store = GetDirectStore(new ColorClass());
53+
expect(store["color"]).toBeDefined();
54+
});
55+
});
56+
57+
describe("expandToProperty decorator", () => {
58+
it("should create getter/setter that reads from backing field", () => {
59+
class ExpandClass {
60+
// @ts-expect-error Accessed dynamically by expandToProperty decorator
61+
private _myCallback() {
62+
// no-op
63+
}
64+
65+
@expandToProperty("_myCallback")
66+
public accessor myExpanded: number;
67+
68+
// @ts-expect-error Backing field accessed dynamically by expandToProperty
69+
private _myExpanded: number = 10;
70+
}
71+
72+
const instance = new ExpandClass();
73+
expect(instance.myExpanded).toBe(10);
74+
75+
instance.myExpanded = 20;
76+
expect(instance.myExpanded).toBe(20);
77+
});
78+
});
79+
});

packages/dev/smartFilters/test/unit/customShaderBlock.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { SmartFilter } from "../../src/smartFilter.js";
44
import { ImportCustomBlockDefinition } from "../../src/serialization/importCustomBlockDefinition.js";
55
import { CustomShaderBlock } from "../../src/blockFoundation/customShaderBlock.js";
66
import { SerializedShaderBlockDefinitionV1 } from "../../src/serialization/v1/shaderBlockSerialization.types";
7-
import { IPropertyDescriptionForEdition, PropertyTypeForEdition, getSmartFilterEditableProperties } from "../../src/editorUtils/editableInPropertyPage.js";
7+
import { PropertyTypeForEdition, getSmartFilterEditableProperties } from "../../src/editorUtils/editableInPropertyPage.js";
88

99
const glslValidFloatDefaultValue = `
1010
// { "smartFilterBlockType": "TestBlock", "namespace": "Bug.Repro" }

tsconfig.test.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
"es2017",
1616
"es2022.error",
1717
"es2022.array",
18-
"es2021.string"
18+
"es2021.string",
19+
"esnext.decorators",
20+
"es2022.object"
1921
]
2022
}
2123
}

0 commit comments

Comments
 (0)