import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import { test } from "node:test"; const sourceRoot = new URL("../src/", import.meta.url); async function read(relativePath) { return readFile(new URL(relativePath, sourceRoot), "utf8"); } test("simulation is a dedicated Polygon workspace with a bounded feature slice", async () => { const [productModel, workspaceHub, workspace, catalog, styles] = await Promise.all([ read("productModel.ts"), read("workspaces/Workspaces.tsx"), read("workspaces/simulation/SimulationWorkspace.tsx"), read("components/simulation/SimulationCatalog.tsx"), read("styles.css"), ]); assert.match(productModel, /id: "simulations"[\s\S]*root: "polygon"[\s\S]*kind: "simulations"/); assert.match(workspaceHub, /case "simulations":[\s\S]*/); assert.match(catalog, /simulation-catalog__table/); assert.match(workspace, /archivesFromDrop/); assert.match(workspace, /uploadSimulationProjectSource/); assert.match(catalog, /colSpan=\{3\}/); assert.match(catalog, /Ожидает обработки/); assert.match(catalog, /Прогресс \$\{roundedPercent\}% \|/); assert.match(catalog, /Осталось примерно \$\{minutes\} мин/); assert.match(catalog, /simulation-catalog__progress-track/); assert.doesNotMatch(catalog, /disabled=\{ACTIVE_STATUSES\.has/); assert.match(workspace, / { const [core, window, sourceFiles] = await Promise.all([ read("core/simulation/projects.ts"), read("components/simulation/SimulationProjectWindow.tsx"), read("core/simulation/sourceFiles.ts"), ]); assert.match(core, /const API_ROOT = "\/api\/v1\/simulation-worlds\/projects"/); assert.match(core, /method: "HEAD"/); assert.match(core, /method: "PATCH"/); assert.match(core, /"Upload-Offset"/); assert.match(core, /estimatedSecondsRemaining/); assert.match(core, /smoothedBytesPerSecond \* 0\.7 \+ currentBytesPerSecond \* 0\.3/); assert.match(core, /estimateSimulationProcessing/); assert.match(core, /jobCreatedAtUtc/); assert.match(core, /stateStartedAtUtc/); assert.match(core, /REFERENCE_STREAM_SECONDS = 2_317/); assert.doesNotMatch(core, /Authorization|Bearer|18090|Worker 006/); assert.match(window, /accept="\.zip,\.rar,\.7z"/); assert.match(window, /webkitdirectory/); assert.match(sourceFiles, /webkitGetAsEntry/); assert.match(sourceFiles, /entry\?\.isDirectory/); assert.match(sourceFiles, /const file = item\.getAsFile\(\)/); assert.match(sourceFiles, /MAX_SIMULATION_SOURCE_BYTES = 16 \* 1024 \*\* 3/); assert.match(sourceFiles, /item\.kind === "file"/); assert.match(sourceFiles, /ровно одна сцена \.lcc или \.lcc2/); assert.match(sourceFiles, /отдельные архивы ZIP, RAR или 7z/); assert.doesNotMatch(window, /Загружаем источник/); assert.match(window, /считаем время/); }); test("failed simulation can restart from its retained Mission Core source", async () => { const [core, workspace] = await Promise.all([ read("core/simulation/projects.ts"), read("workspaces/simulation/SimulationWorkspace.tsx"), ]); assert.match(core, /retrySimulationProject/); assert.match(core, /\$\{API_ROOT\}\/\$\{encodeURIComponent\(projectId\)\}\/build/); assert.match(workspace, /Повторить сборку/); }); test("PlayCanvas owns the realtime scene graph without an iframe or React entity tree", async () => { const [runtime, ugv, viewport, ugvSettings, projects, styles, packageDocument] = await Promise.all([ read("components/simulation/PlayCanvasRuntime.ts"), read("components/simulation/SimulationUgvController.ts"), read("components/simulation/SimulationViewport.tsx"), read("components/simulation/SimulationUgvSettingsPanel.tsx"), read("core/simulation/projects.ts"), read("styles/simulation.css"), readFile(new URL("../package.json", import.meta.url), "utf8"), ]); assert.match(packageDocument, /"playcanvas": "2\.21\.4"/); assert.doesNotMatch(packageDocument, /@playcanvas\/react/); assert.match(runtime, /new Application\(canvas/); assert.match(runtime, /setCanvasFillMode\(FILLMODE_NONE/); assert.match(runtime, /setCanvasResolution\(RESOLUTION_AUTO\)/); assert.match(runtime, /new Asset\([^,]+, "gsplat"/); assert.match(runtime, /camera\.script\?\.create\(CameraControls/); assert.match(runtime, /const HOME_POSITION = new Vec3\(0, 1, 0\)/); assert.match(runtime, /const HOME_FOCUS = new Vec3\(1, 1, 0\)/); assert.match(runtime, /maximum: \{[^}]*lodRangeMin: 0, lodRangeMax: 5, pixelRatio: 2, splatBudget: 4_000_000, targetFps: 60/); assert.match(runtime, /app\.scene\.gsplat\.splatBudget = profile\.splatBudget/); assert.match(runtime, /app\.autoRender = false/); assert.match(runtime, /app\.on\("update", this\.updateFrame\)/); assert.match(runtime, /if \(!cameraChanged && this\.controlMode === "free"\) return/); assert.doesNotMatch(runtime, /app\.on\("frameupdate"/); assert.match(runtime, /WEBGL_lose_context/); assert.match(runtime, /selected\.horizontal[^\n]+frame\.mouse\[0\] \*= -1/); assert.match(runtime, /selected\.vertical[^\n]+frame\.mouse\[1\] \*= -1/); assert.match(runtime, /setCameraInversion/); assert.match(runtime, /async setViewMode\([\s\S]*this\.viewMode = mode/); assert.doesNotMatch(runtime.match(/async setViewMode\([\s\S]*?\n }/)?.[0] ?? "", /resetCameraInteraction/); assert.match(runtime, /controller\.fire\("state"\)/); assert.match(runtime, /state\.mouse\.fill\(0\)/); assert.match(runtime, /new Asset\([\s\S]*"container"/); assert.match(runtime, /instantiateModelEntity/); assert.match(runtime, /applyWorldTransform/); assert.match(runtime, /setLayerWorldTransform/); assert.match(runtime, /playCanvasEulerTransform/); assert.match(runtime, /setFromEulerAngles/); assert.match(runtime, /DracoDecoderModule/); assert.match(runtime, /draco_decoder_gltf\.wasm/); assert.match(runtime, /ensureCollision/); assert.match(runtime, /setControlMode/); assert.match(runtime, /setUgvPreset/); assert.match(runtime, /SimulationUgvController/); assert.match(runtime, /for \(const model of this\.collisionVisuals\) model\.enabled = visible/); assert.match(runtime, /instantiateModelEntity/); assert.match(runtime, /this\.ugvController\?\.disable\(\)/); assert.match(runtime, /this\.collisionMaterial\.blendType = combined \? BLEND_NORMAL : BLEND_NONE/); assert.match(runtime, /private requestRender\(\): void/); assert.match(runtime, /app\.root\.addChild/); assert.match(runtime, /dispose\(\)/); assert.doesNotMatch(`${runtime}\n${viewport}`, /iframe|\(project\.viewerSettings\.quality\)/); assert.match(viewport, /runtimeRef\.current\?\.home\(\)/); assert.match(viewport, /Настройки сцены/); assert.match(viewport, /Гауссовый слой/); assert.match(viewport, /Слой коллизий/); assert.match(viewport, /Инверсия управления по горизонтали/); assert.match(viewport, /Инверсия управления по вертикали/); assert.match(viewport, /ROTATION_AXES/); assert.match(viewport, /PlayCanvas|PlayCanvas загружает|Streamed SOG/); assert.match(ugv, /AMMO_MODULE_ROOT = "\/vendor\/playcanvas\/ammo\/2026-08-25"/); assert.match(ugv, /new this\.ammo\.btRaycastVehicle/); assert.match(ugv, /type: "mesh"/); assert.match(ugv, /MeshoptSimplifier\.simplify/); assert.match(ugv, /PHYSICS_PROXY_MAX_TRIANGLES = 240_000/); assert.match(ugv, /createPhysicsProxyMesh/); assert.match(ugv, /findSafeSpawnPosition/); assert.match(ugv, /physics\.raycastFirst/); assert.match(ugv, /runCleanup\("destroy static physics mesh", \(\) => mesh\.destroy\(\)\)/); assert.match(ugv, /type: "static"/); assert.match(ugv, /mass: this\.settings\.massKg/); assert.match(ugv, /suspensionRestLength/); assert.match(ugv, /requestedTurn = Number\(this\.isPressed\("KeyA", "ArrowLeft"\)\) - Number\(this\.isPressed\("KeyD", "ArrowRight"\)\)/); assert.match(ugv, /leftCommand = clamp\(forwardCommand - turnCommand/); assert.match(ugv, /rightCommand = clamp\(forwardCommand \+ turnCommand/); assert.match(ugv, /this\.settings\.invertSteering/); assert.match(ugv, /this\.settings\.maxSpeedMetersPerSecond/); assert.match(ugv, /this\.settings\.maxTurnRateDegrees/); assert.match(ugv, /desiredSpeed = forwardInput \* maxSpeed/); assert.match(ugv, /maximumAcceleration = clamp\(1\.4 \+ maxSpeed \* 0\.35, 1\.8, 4\.2\)/); assert.match(ugv, /SERVICE_BRAKE_DECELERATION_MPS2 = 1\.8/); assert.match(ugv, /horizontalSpeed - deceleration \* Math\.max\(0, deltaSeconds\)/); assert.match(ugv, /this\.vehicle\.setBrake\(0, index\)/); assert.doesNotMatch(ugv, /massKg \* 3/); assert.match(ugv, /pureTurn = !braking && forwardInput === 0 && turnInput !== 0/); assert.match(ugv, /desiredYawRate = -turnInput \* maxTurnRate/); assert.match(ugv, /this\.orbitYaw = \(this\.orbitYaw - deltaX \* 0\.006\)/); assert.match(ugv, /CAMERA_RETURN_DELAY_SECONDS = 1\.2/); assert.match(ugv, /CAMERA_RETURN_DURATION_SECONDS = 2/); assert.match(ugv, /approachAngle\(this\.orbitYaw, rearOrbitYaw/); assert.match(ugv, /this\.canvas\.addEventListener\("pointerdown", this\.onOrbitPointerDown\)/); assert.match(ugv, /this\.canvas\.addEventListener\("wheel", this\.onOrbitWheel/); assert.match(ugv, /vehicleGeometryChanged/); assert.match(ugv, /removeAction\(this\.vehicle as NativeObject\)/); assert.match(ugv, /runCleanup\("destroy static physics proxy", \(\) => entity\.destroy\(\)\)/); assert.match(ugv, /runCleanup\("destroy vehicle entity"/); assert.match(ugvSettings, /Физика UGV/); assert.match(ugvSettings, /Дифференциальный привод/); assert.match(ugvSettings, /Масса конструкции/); assert.match(ugvSettings, /Общая высота/); assert.match(ugvSettings, /Клиренс/); assert.match(ugvSettings, /Скорость движения/); assert.match(ugvSettings, /Скорость разворота/); assert.match(ugvSettings, /exactValueBounds=\{SIMULATION_UGV_EXACT_VALUE_LIMITS\.maxSpeedMetersPerSecond\}/); assert.match(projects, /maxSpeedMetersPerSecond: \{ min: 0, max: 1_000_000_000 \}/); assert.match(ugvSettings, /Инверсия управления A\/D/); assert.match(ugvSettings, /Сохранить пресет/); assert.match(ugvSettings, /