aether-shards/test/grid/VoxelManager.test.js

123 lines
3.7 KiB
JavaScript
Raw Permalink Normal View History

2025-12-16 23:52:58 +00:00
import { expect } from "@esm-bundle/chai";
import { VoxelManager } from "../../src/grid/VoxelManager.js";
import { VoxelGrid } from "../../src/grid/VoxelGrid.js";
2025-12-17 19:26:42 +00:00
import * as THREE from "three";
2025-12-16 23:52:58 +00:00
describe("Phase 1: VoxelManager Rendering (WebGL)", function () {
// Increase timeout to 60s for slow WebGL initialization in headless/software mode
this.timeout(60000);
2025-12-16 23:52:58 +00:00
let grid;
let scene;
let manager;
2025-12-17 19:26:42 +00:00
let renderer;
before(function () {
// Allow extra time specifically for the first context creation
this.timeout(30000);
2025-12-17 19:26:42 +00:00
// 1. Setup a real WebGL Renderer (Headless)
const canvas = document.createElement("canvas");
// FORCE WebGL 2 (Required for Three.js r163+)
const context = canvas.getContext("webgl2");
2025-12-17 19:26:42 +00:00
if (!context) {
console.warn(
"WebGL 2 not supported in this test environment. Skipping render checks."
2025-12-17 19:26:42 +00:00
);
this.skip();
return;
2025-12-17 19:26:42 +00:00
}
2025-12-16 23:52:58 +00:00
2025-12-17 19:26:42 +00:00
renderer = new THREE.WebGLRenderer({ canvas, context });
2025-12-16 23:52:58 +00:00
});
after(function () {
if (renderer) {
renderer.dispose();
// Explicitly force context loss to free up resources for other test files
if (renderer.forceContextLoss) renderer.forceContextLoss();
}
});
2025-12-17 19:26:42 +00:00
beforeEach(() => {
grid = new VoxelGrid(4, 4, 4);
scene = new THREE.Scene();
manager = new VoxelManager(grid, scene);
2025-12-16 23:52:58 +00:00
});
it("CoA 1: update() should create separate InstancedMeshes for different IDs", () => {
grid.setCell(0, 0, 0, 1); // ID 1 (Stone)
grid.setCell(1, 0, 0, 2); // ID 2 (Dirt)
2025-12-16 23:52:58 +00:00
// In the new multi-material manager, update() handles initialization
manager.update();
// Should have 2 children in the scene (one mesh per ID) + Focus Target
// Filter to just find meshes
const meshes = scene.children.filter((c) => c.isInstancedMesh);
expect(meshes.length).to.equal(2);
2025-12-16 23:52:58 +00:00
});
2025-12-17 19:26:42 +00:00
it("CoA 2: update() should correctly position instances", () => {
grid.setCell(2, 2, 2, 1); // Specific position
manager.update();
2025-12-16 23:52:58 +00:00
// Find the mesh corresponding to ID 1
const mesh = scene.children.find((c) => c.isInstancedMesh);
2025-12-17 19:26:42 +00:00
const matrix = new THREE.Matrix4();
// Since there is only 1 voxel of ID 1, it will be at instance index 0
mesh.getMatrixAt(0, matrix);
2025-12-16 23:52:58 +00:00
2025-12-17 19:26:42 +00:00
const position = new THREE.Vector3().setFromMatrixPosition(matrix);
2025-12-16 23:52:58 +00:00
expect(position.x).to.equal(2);
expect(position.y).to.equal(2);
expect(position.z).to.equal(2);
2025-12-16 23:52:58 +00:00
});
2025-12-17 19:26:42 +00:00
it("CoA 3: render loop should not crash", () => {
// Verify we can actually call render() without WebGL errors
const camera = new THREE.PerspectiveCamera();
manager.update();
2025-12-16 23:52:58 +00:00
2025-12-17 19:26:42 +00:00
expect(() => renderer.render(scene, camera)).to.not.throw();
2025-12-16 23:52:58 +00:00
});
it("CoA 4: updateMaterials() should apply texture to material", () => {
// Mock a generated asset
const mockCanvas = document.createElement("canvas");
const assets = {
textures: {
floor: mockCanvas,
},
};
// Create a floor voxel (ID 2)
grid.setCell(0, 0, 0, 2);
manager.updateMaterials(assets);
const mesh = scene.children.find((c) => c.isInstancedMesh);
// Material could be single or array (multi-material)
// ID 2 uses an array [side, side, top, bottom, front, back]
const mat = Array.isArray(mesh.material) ? mesh.material[2] : mesh.material;
expect(mat.map).to.exist;
expect(mat.map.image).to.equal(mockCanvas);
});
it("CoA 5: Should create a Focus Target at the center of the grid", () => {
// Grid is 4x4x4. Center is roughly 2, 0, 2.
manager.update();
expect(manager.focusTarget).to.exist;
expect(manager.focusTarget.parent).to.equal(scene);
expect(manager.focusTarget.position.x).to.equal(2);
expect(manager.focusTarget.position.z).to.equal(2);
});
2025-12-16 23:52:58 +00:00
});