Files
feuerwerk/tests/core/resolve.test.ts
T
rootandClaude Fable 5.1 d4b1ffa051 Z-order via position.z and reset-to-default for asset properties
- Position is now { x, y, z }; higher z draws on top, ties keep hierarchy order
- Viewport sorts the objects layer deterministically (syncDrawOrder)
- Inspector shows a Z field; asset properties that differ from the schema
  default are marked bold with a reset button (ResetAssetPropertyCommand)
- isModified() helper, unit tests, E2E checks and seed updated

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 11:42:18 +02:00

70 lines
3.1 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { buildAsset } from '../../src/core/commands/assetCommands';
import { createSceneObject } from '../../src/core/model/SceneObject';
import { coerceValue, defaultsFor, schemaFor } from '../../src/core/properties/PropertySchema';
import { inheritedValue, isModified, isOverridden, resolveAssetProps, resolveSceneObjectProps } from '../../src/core/properties/resolve';
describe('PropertySchema', () => {
it('has no position on any asset type', () => {
for (const type of ['scene', 'camera', 'sprite'] as const) {
const keys = schemaFor(type).map((d) => d.key);
expect(keys).not.toContain('x');
expect(keys).not.toContain('y');
expect(keys).not.toContain('position');
}
});
it('provides defaults for every key', () => {
expect(defaultsFor('sprite')).toEqual({ width: 100, height: 100, color: 0xe0553f });
});
it('coerces values against the definition', () => {
const width = schemaFor('sprite').find((d) => d.key === 'width')!;
expect(coerceValue(width, -5)).toBe(1);
expect(coerceValue(width, '42')).toBe(42);
expect(coerceValue(width, 'abc')).toBe(100);
const color = schemaFor('sprite').find((d) => d.key === 'color')!;
expect(coerceValue(color, '#ff0000')).toBe(0xff0000);
expect(coerceValue(color, 0x1ffffff)).toBe(0xffffff);
});
});
describe('resolve', () => {
it('fills asset props with defaults and ignores unknown keys', () => {
const sprite = buildAsset('sprite', 'Box');
sprite.props = { width: 50, bogus: 1 };
expect(resolveAssetProps(sprite)).toEqual({ width: 50, height: 100, color: 0xe0553f });
});
it('applies sparse overrides on top of asset values', () => {
const sprite = buildAsset('sprite', 'Box');
sprite.props.color = 0x00ff00;
const object = createSceneObject('o1', sprite.id, { x: 10, y: 20 });
expect(resolveSceneObjectProps(sprite, object)).toEqual({ width: 100, height: 100, color: 0x00ff00 });
object.overrides.color = 0x0000ff;
expect(resolveSceneObjectProps(sprite, object).color).toBe(0x0000ff);
expect(isOverridden(object, 'color')).toBe(true);
expect(isOverridden(object, 'width')).toBe(false);
expect(inheritedValue(sprite, 'color')).toBe(0x00ff00);
});
it('detects asset values that differ from the schema default', () => {
const sprite = buildAsset('sprite', 'Box');
expect(isModified(sprite, 'width')).toBe(false); // explicit default counts as unmodified
sprite.props.width = 250;
expect(isModified(sprite, 'width')).toBe(true);
delete sprite.props.height; // missing → resolved from default → unmodified
expect(isModified(sprite, 'height')).toBe(false);
expect(isModified(sprite, 'bogus')).toBe(false);
});
it('keeps position on the scene object only', () => {
const sprite = buildAsset('sprite', 'Box');
const object = createSceneObject('o1', sprite.id, { x: 10, y: 20 });
expect(object.position).toEqual({ x: 10, y: 20, z: 0 });
expect('position' in sprite).toBe(false);
expect(resolveSceneObjectProps(sprite, object)).not.toHaveProperty('x');
});
});