Files
webeditor3d/tests/domain/delete-project-asset.test.ts
Victor Giers 41e87b1b21 auto-git:
[change] tests/domain/delete-project-asset.test.ts
2026-04-22 12:35:44 +02:00

242 lines
7.3 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { BoxGeometry } from "three";
import { deleteProjectAssetFromProjectDocument } from "../../src/assets/delete-project-asset";
import { createModelInstance } from "../../src/assets/model-instances";
import {
createProjectAssetStorageKey,
type AudioAssetRecord,
type ImageAssetRecord
} from "../../src/assets/project-assets";
import {
createEmptyProjectDocument,
type ProjectDocument
} from "../../src/document/scene-document";
import { createDefaultWorldSettings } from "../../src/document/world-settings";
import {
createNpcEntity,
createSoundEmitterEntity,
createTeleportTargetEntity,
createTriggerVolumeEntity
} from "../../src/entities/entity-instances";
import {
createPlayAnimationInteractionLink,
createPlaySoundInteractionLink,
createStopAnimationInteractionLink,
createStopSoundInteractionLink,
createTeleportPlayerInteractionLink
} from "../../src/interactions/interaction-links";
import { createFixtureLoadedModelAssetFromGeometry } from "../helpers/model-collider-fixtures";
function createProjectDocumentFixture() {
const baseProjectDocument = createEmptyProjectDocument({
sceneName: "Asset Cleanup Scene"
});
const sceneId = baseProjectDocument.activeSceneId;
const baseScene = baseProjectDocument.scenes[sceneId];
const { asset: modelAsset } = createFixtureLoadedModelAssetFromGeometry(
"asset-model-cleanup",
new BoxGeometry(1, 2, 1)
);
const imageAsset: ImageAssetRecord = {
id: "asset-image-cleanup",
kind: "image",
sourceName: "panorama-cleanup.png",
mimeType: "image/png",
storageKey: createProjectAssetStorageKey("asset-image-cleanup"),
byteLength: 2048,
metadata: {
kind: "image",
width: 1024,
height: 512,
hasAlpha: false,
warnings: []
}
};
const audioAsset: AudioAssetRecord = {
id: "asset-audio-cleanup",
kind: "audio",
sourceName: "cleanup-loop.ogg",
mimeType: "audio/ogg",
storageKey: createProjectAssetStorageKey("asset-audio-cleanup"),
byteLength: 4096,
metadata: {
kind: "audio",
durationSeconds: 6.5,
channelCount: 2,
sampleRateHz: 44100,
warnings: []
}
};
const modelInstance = createModelInstance({
id: "model-instance-cleanup",
assetId: modelAsset.id
});
const triggerVolume = createTriggerVolumeEntity({
id: "entity-trigger-cleanup"
});
const teleportTarget = createTeleportTargetEntity({
id: "entity-teleport-cleanup"
});
const soundEmitter = createSoundEmitterEntity({
id: "entity-sound-cleanup",
audioAssetId: audioAsset.id,
autoplay: true,
loop: true
});
const npc = createNpcEntity({
id: "entity-npc-cleanup",
actorId: "actor-cleanup-guide",
modelAssetId: modelAsset.id
});
const projectDocument: ProjectDocument = {
...baseProjectDocument,
assets: {
...baseProjectDocument.assets,
[modelAsset.id]: modelAsset,
[imageAsset.id]: imageAsset,
[audioAsset.id]: audioAsset
},
scenes: {
...baseProjectDocument.scenes,
[sceneId]: {
...baseScene,
world: {
...baseScene.world,
background: {
mode: "image",
assetId: imageAsset.id,
environmentIntensity: 0.8
},
timeOfDay: {
...baseScene.world.timeOfDay,
dawn: {
...baseScene.world.timeOfDay.dawn,
background: {
mode: "image",
assetId: imageAsset.id,
environmentIntensity: 0.55
}
}
}
},
modelInstances: {
[modelInstance.id]: modelInstance
},
entities: {
[triggerVolume.id]: triggerVolume,
[teleportTarget.id]: teleportTarget,
[soundEmitter.id]: soundEmitter,
[npc.id]: npc
},
interactionLinks: {
"link-play-animation": createPlayAnimationInteractionLink({
id: "link-play-animation",
sourceEntityId: triggerVolume.id,
targetModelInstanceId: modelInstance.id,
clipName: "Idle"
}),
"link-stop-animation": createStopAnimationInteractionLink({
id: "link-stop-animation",
sourceEntityId: triggerVolume.id,
targetModelInstanceId: modelInstance.id
}),
"link-play-sound": createPlaySoundInteractionLink({
id: "link-play-sound",
sourceEntityId: triggerVolume.id,
targetSoundEmitterId: soundEmitter.id
}),
"link-stop-sound": createStopSoundInteractionLink({
id: "link-stop-sound",
sourceEntityId: triggerVolume.id,
targetSoundEmitterId: soundEmitter.id
}),
"link-teleport": createTeleportPlayerInteractionLink({
id: "link-teleport",
sourceEntityId: triggerVolume.id,
targetEntityId: teleportTarget.id
})
}
}
}
};
return {
sceneId,
projectDocument,
modelAsset,
imageAsset,
audioAsset,
modelInstance,
npc,
soundEmitter
};
}
describe("deleteProjectAssetFromProjectDocument", () => {
it("removes deleted model assets from model instances and animation links", () => {
const fixture = createProjectDocumentFixture();
const nextProjectDocument = deleteProjectAssetFromProjectDocument(
fixture.projectDocument,
fixture.modelAsset.id
);
const nextScene = nextProjectDocument.scenes[fixture.sceneId];
expect(nextProjectDocument.assets[fixture.modelAsset.id]).toBeUndefined();
expect(nextScene.modelInstances).toEqual({});
expect(nextScene.entities[fixture.npc.id]).toMatchObject({
kind: "npc",
modelAssetId: null
});
expect(Object.keys(nextScene.interactionLinks).sort()).toEqual([
"link-play-sound",
"link-stop-sound",
"link-teleport"
]);
});
it("resets image backgrounds when deleting a referenced image asset", () => {
const fixture = createProjectDocumentFixture();
const nextProjectDocument = deleteProjectAssetFromProjectDocument(
fixture.projectDocument,
fixture.imageAsset.id
);
const nextScene = nextProjectDocument.scenes[fixture.sceneId];
expect(nextProjectDocument.assets[fixture.imageAsset.id]).toBeUndefined();
expect(nextScene.world.background).toEqual(
createDefaultWorldSettings().background
);
expect(nextScene.world.timeOfDay.dawn.background).toEqual({
mode: "image",
assetId: "",
environmentIntensity: 0.55
});
});
it("silences sound emitters and removes sound links when deleting an audio asset", () => {
const fixture = createProjectDocumentFixture();
const nextProjectDocument = deleteProjectAssetFromProjectDocument(
fixture.projectDocument,
fixture.audioAsset.id
);
const nextScene = nextProjectDocument.scenes[fixture.sceneId];
expect(nextProjectDocument.assets[fixture.audioAsset.id]).toBeUndefined();
expect(nextScene.entities[fixture.soundEmitter.id]).toMatchObject({
kind: "soundEmitter",
audioAssetId: null,
autoplay: false,
loop: true
});
expect(Object.keys(nextScene.interactionLinks).sort()).toEqual([
"link-play-animation",
"link-stop-animation",
"link-teleport"
]);
});
});