Files
feuerwerk/tests/core/references.test.ts
T
adminandClaude Opus 5.5 1aae97b335
game-maker / gate (push) Successful in 2m52s
game-maker / suite (push) Successful in 8m58s
Open a sprite's texture or shader from the menus and inspector (#221)
A sprite's texture and shader were only reachable by hunting for them
in the asset panel. Every place that shows such a reference now leads
straight to it.

- Object menu (hierarchy and scene view): "Open texture" and "Open
  shader" sit right below "Open asset" when the sprite has one. The
  object's own values count, so an overridden shader opens the
  override.
- Asset context menu: the same entries at the top.
- Inspector: every asset field with a value shows its label as a blue,
  underlined link. One click selects the asset, a double click opens
  it. An override stays gold and gets the underline too.
- The first click rebuilds the inspector, so the second one lands on a
  different row. The inspector catches that second click before any
  row sees it.
- New pure rule `references.ts`: the asset behind a reference field. A
  frame leads to its sheet. Kinds without a tab (palette, font, sound)
  get no menu entry.
- `followsPress` in `clicks.ts` keeps the double-click window and
  tolerance in one place.
- `activateAsset` in `actions.ts`: opening means the same everywhere
  as a double click in the asset panel, so a scene also becomes the
  active one. The asset panel uses it too.

Tests:
- ./check.sh: 150 files, 2226 tests, CHECK EXIT 0 (before 148/2214).
- 12 new unit tests: 6 for the reference rule, 4 for the link in
  createFieldRow, 2 for followsPress.
- 5 new e2e checks in 28l-ii: both menus, the link's look, click
  selects, double click opens.
- e2e 1-16,26,28,35,39,40 on the final build: ALL PASSED, 732 checks.
- Counter-probes: no "Open ..." entries, no underline and a second
  click never recognised each fail exactly at their checks.
- Check total 1341 (CI counted 1336 at fd6af84), computed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 16:44:19 +02:00

90 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** Which asset a reference field points at – what "Open texture" and the inspector link open (#221). */
import { describe, expect, it } from 'vitest';
import { CreateAssetCommand, CreateTextureCommand } from '../../src/core/commands/assetCommands';
import { AddFrameCommand } from '../../src/core/commands/frameCommands';
import type { PixelArtAsset } from '../../src/core/model/Asset';
import { findAsset } from '../../src/core/model/Project';
import { type PropertyDef, schemaForAsset } from '../../src/core/properties/PropertySchema';
import { referencedAssetId, referencesOf } from '../../src/core/properties/references';
import { resolveAssetProps } from '../../src/core/properties/resolve';
import { SHADER_KEY } from '../../src/core/properties/shaders';
import { makeSpriteScene } from '../helpers';
const FILE = `${'ab'.repeat(32)}.png`;
const TEXTURE: PropertyDef = { key: 'texture', label: 'Texture', kind: 'texture', default: '' };
const SHADER: PropertyDef = {
key: SHADER_KEY,
label: 'Shader',
kind: 'asset',
default: '',
assetTypes: ['shader'],
};
function setup() {
const fixture = makeSpriteScene();
const texture = new CreateTextureCommand('Sheet', { file: FILE, width: 64, height: 32 });
fixture.stack.execute(texture);
const frame = new AddFrameCommand(texture.asset.id, { x: 0, y: 0, w: 16, h: 16 }, 'Idle');
fixture.stack.execute(frame);
const shader = new CreateAssetCommand('shader', 'Glow');
fixture.stack.execute(shader);
const art = new CreateAssetCommand('pixelart', 'Art');
fixture.stack.execute(art);
return {
...fixture,
textureId: texture.asset.id,
frameId: frame.frameId,
shaderId: shader.asset.id,
art: art.asset as PixelArtAsset,
};
}
describe('referencedAssetId', () => {
it('is the asset a reference names', () => {
const f = setup();
expect(referencedAssetId(f.project, TEXTURE, f.textureId)).toBe(f.textureId);
expect(referencedAssetId(f.project, SHADER, f.shaderId)).toBe(f.shaderId);
});
it('is the sheet for a frame of a texture or of pixel art', () => {
const f = setup();
expect(referencedAssetId(f.project, TEXTURE, f.frameId)).toBe(f.textureId);
f.art.frames.push({ id: 'second', cels: {} });
expect(referencedAssetId(f.project, TEXTURE, 'second')).toBe(f.art.id);
});
it('is nothing for an empty or dangling reference', () => {
const f = setup();
expect(referencedAssetId(f.project, TEXTURE, '')).toBeNull();
expect(referencedAssetId(f.project, SHADER, 'gone')).toBeNull();
});
it('only resolves frames in a texture field', () => {
const f = setup();
expect(referencedAssetId(f.project, SHADER, f.frameId)).toBeNull();
});
it('is nothing for a field that names no asset, whatever it holds', () => {
const f = setup();
const text: PropertyDef = { key: 'name', label: 'Name', kind: 'text', default: '' };
expect(referencedAssetId(f.project, text, f.textureId)).toBeNull();
});
});
describe('referencesOf', () => {
it("lists a sprite asset's texture and shader in schema order, and nothing unset", () => {
const f = setup();
const sprite = findAsset(f.project, f.spriteId)!;
const refs = () =>
referencesOf(f.project, schemaForAsset(f.project, sprite), resolveAssetProps(f.project, sprite));
sprite.props.texture = '';
expect(refs()).toEqual([]);
sprite.props[SHADER_KEY] = f.shaderId;
sprite.props.texture = f.frameId;
expect(refs()).toEqual([
{ label: 'Texture', assetId: f.textureId },
{ label: 'Shader', assetId: f.shaderId },
]);
});
});