import { describe, expect, it } from 'vitest'; import { CreateAssetCommand, CreateTextureCommand } from '../../src/core/commands/assetCommands'; import { CommandError } from '../../src/core/commands/Command'; import { findAsset } from '../../src/core/model/Project'; import { spriteFromTexture } from '../../src/core/properties/aspect'; import { makeProject } from '../helpers'; const FILE = `${'b'.repeat(64)}.webp`; describe('CreateTextureCommand', () => { it('adds a texture asset carrying the uploaded image, and removes it again', () => { const { project, stack } = makeProject(); const command = new CreateTextureCommand('Hero', { file: FILE, width: 64, height: 32 }); stack.execute(command); const asset = findAsset(project, command.asset.id); expect(asset).toMatchObject({ type: 'texture', name: 'Hero', file: FILE, width: 64, height: 32 }); // The schema default comes along, so the new texture is a complete asset – nothing to fill in later. expect(asset?.props).toEqual({ filter: 'linear' }); stack.undo(); expect(project.assets).toHaveLength(0); stack.redo(); expect(findAsset(project, command.asset.id)?.name).toBe('Hero'); }); it('rejects a file name the server cannot have produced – in execute, not in the constructor', () => { const { project, stack } = makeProject(); const command = new CreateTextureCommand('Hero', { file: '../secrets.png', width: 1, height: 1 }); expect(() => stack.execute(command)).toThrow(CommandError); expect(project.assets).toHaveLength(0); }); it('keeps two assets for the same file apart', () => { const { project, stack } = makeProject(); stack.execute(new CreateTextureCommand('Hero', { file: FILE, width: 8, height: 8 })); stack.execute(new CreateTextureCommand('Hero copy', { file: FILE, width: 8, height: 8 })); expect(project.assets.map((a) => a.id)).toHaveLength(2); expect(new Set(project.assets.map((a) => a.id)).size).toBe(2); }); }); describe('CreateAssetCommand with starting props', () => { it('creates a sprite wearing the texture at its pixel size, and removes it again', () => { const { project, stack } = makeProject(); const texture = new CreateTextureCommand('Hero', { file: FILE, width: 64, height: 32 }); stack.execute(texture); const sprite = new CreateAssetCommand('sprite', 'Hero 2', spriteFromTexture(project, texture.asset.id)); stack.execute(sprite); expect(findAsset(project, sprite.asset.id)?.props).toEqual({ enabled: true, width: 64, height: 32, color: 0xffffff, texture: texture.asset.id, shader: '', }); stack.undo(); expect(findAsset(project, sprite.asset.id)).toBeUndefined(); stack.redo(); expect(findAsset(project, sprite.asset.id)?.props.texture).toBe(texture.asset.id); }); it('passes each value through the schema', () => { const { project, stack } = makeProject(); const sprite = new CreateAssetCommand('sprite', 'Tiny', { width: -5 }); stack.execute(sprite); expect(findAsset(project, sprite.asset.id)?.props.width).toBe(1); }); it('rejects a property the type does not have, leaving the project untouched', () => { const { project, stack } = makeProject(); expect(() => stack.execute(new CreateAssetCommand('sprite', 'Odd', { zoom: 2 }))).toThrow(CommandError); expect(project.assets).toHaveLength(0); }); });