Files
houseplan-card/test/iso-openings.test.mjs
T
Sergey Matyunin c9a00b2a37
Validate / hacs (push) Failing after 15s
Validate / docs (push) Failing after 20s
Validate / provenance (push) Successful in 54s
Validate / process-gate (push) Failing after 50s
Validate / changes (push) Successful in 46s
Validate / hassfest (push) Failing after 14s
Validate / frontend (push) Successful in 5m54s
Validate / backend (push) Failing after 8m1s
Validate / smoke (push) Failing after 4m25s
Validate / golden (push) Failing after 4m26s
Validate / performance_smoke (push) Failing after 8m39s
feat: add open passage openings
Issue: #157
User-Visible: yes
2026-08-17 16:45:41 +03:00

96 lines
4.5 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import {
buildIsoOpeningBasis, isoOpeningBounds, projectIsoOpening, resolveIsoDecoration,
} from '../test-build/iso-openings.js';
import { openingAmount } from '../test-build/logic.js';
import { projectPlanPoint } from '../test-build/iso-projection.js';
const opening = (patch = {}) => ({
id: 'op-1', sourceIndex: 0, type: 'door', x: 100, y: 80,
angle: 0, length: 60, flipH: false, flipV: false,
face: { ox: 0, oy: 5, side: 1 }, ...patch,
});
test('door basis is immutable and live amount preserves the exact jamb anchor', () => {
const basis = buildIsoOpeningBasis(opening());
assert.equal(Object.isFrozen(basis.leaves), true);
const closed = projectIsoOpening(basis, 0)[0];
const open = projectIsoOpening(basis, 1)[0];
const hinge = projectPlanPoint(basis.leaves[0].hinge, basis.leaves[0].bottom)
.map((value) => Number(value.toFixed(4))).join(' ');
assert.match(closed.d, new RegExp(`^M ${hinge.replace('.', '\\.')}`));
assert.match(open.d, new RegExp(`^M ${hinge.replace('.', '\\.')}`));
assert.notEqual(open.d, closed.d);
assert.equal(basis.leaves[0].top, 64 * 0.92);
});
test('window and gate retain two leaves, fixed height bounds and gate 10 degree turn', () => {
const windowBasis = buildIsoOpeningBasis(opening({ type: 'window' }));
const gateBasis = buildIsoOpeningBasis(opening({ type: 'gate', flipV: true }));
assert.equal(windowBasis.leaves.length, 2);
assert.equal(windowBasis.leaves.every((leaf) => leaf.bottom === 64 * 0.27
&& leaf.top === 64 * 0.78), true);
assert.deepEqual(gateBasis.leaves.map((leaf) => Math.abs(leaf.turnDeg)), [10, 10]);
assert.equal(gateBasis.leaves.every((leaf) => leaf.top === 64 * 0.88), true);
assert.equal(projectIsoOpening(gateBasis, 1).length, 2);
});
test('passage keeps the wall cut but never creates an isometric panel', () => {
const passageBasis = buildIsoOpeningBasis(opening({ type: 'passage' }));
assert.deepEqual(passageBasis.leaves, []);
assert.deepEqual(projectIsoOpening(passageBasis, 0), []);
assert.deepEqual(projectIsoOpening(passageBasis, 1), []);
assert.equal(isoOpeningBounds([passageBasis]), null);
});
test('state-independent opening bounds contain closed and open leaf tips', () => {
const basis = buildIsoOpeningBasis(opening());
const bounds = isoOpeningBounds([basis]);
assert.ok(bounds);
for (const amount of [0, 0.5, 1]) {
const panel = projectIsoOpening(basis, amount)[0];
assert.match(panel.d, /^M /);
}
const leaf = basis.leaves[0];
assert.ok(bounds.x <= leaf.hinge[0] - 60 && bounds.x + bounds.w >= leaf.hinge[0] + 60);
assert.ok(bounds.y <= leaf.hinge[1] - 60 && bounds.y + bounds.h >= leaf.hinge[1] + 60);
assert.equal(isoOpeningBounds([]), null);
});
test('flips move structural jamb/basis while HA state changes only projected leaves', () => {
const normal = buildIsoOpeningBasis(opening());
const flipped = buildIsoOpeningBasis(opening({ flipH: true, flipV: true }));
assert.notDeepEqual(flipped.leaves.map((leaf) => leaf.hinge),
normal.leaves.map((leaf) => leaf.hinge));
const basisSnapshot = structuredClone(normal);
const noContact = projectIsoOpening(normal, openingAmount('door', null));
const unavailable = projectIsoOpening(normal, openingAmount('door', 'unavailable'));
const closed = projectIsoOpening(normal, openingAmount('door', 'off'));
const inverted = projectIsoOpening(normal, openingAmount('door', 'off', true));
assert.deepEqual(unavailable, noContact);
assert.notDeepEqual(closed, inverted);
assert.deepEqual(normal, basisSnapshot);
});
test('decoration degradation never removes structure or creates floating panels', () => {
assert.deepEqual(resolveIsoDecoration({
showBorders: true, hideOpenings: false, filtersSupported: true, forcedColors: false,
}), {
structural: true, panels: true, shadows: true, materialNuance: true, floorSymbols: false,
});
assert.deepEqual(resolveIsoDecoration({
showBorders: true, hideOpenings: false, filtersSupported: false, forcedColors: false,
}), {
structural: true, panels: true, shadows: false, materialNuance: true, floorSymbols: false,
});
assert.deepEqual(resolveIsoDecoration({
showBorders: false, hideOpenings: false, filtersSupported: true, forcedColors: false,
}), {
structural: false, panels: false, shadows: false, materialNuance: false, floorSymbols: true,
});
assert.equal(resolveIsoDecoration({
showBorders: true, hideOpenings: true, filtersSupported: true, forcedColors: false,
}).panels, false);
});