mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-28 19:01:34 +00:00
96 lines
5.3 KiB
JavaScript
96 lines
5.3 KiB
JavaScript
import { launch, checkAll, finish } from './serve.mjs';
|
||
const { page, browser } = await launch();
|
||
const res = await page.evaluate(async () => {
|
||
const out = {};
|
||
const c = window.__card;
|
||
// комната без зоны на f1
|
||
c._serverCfg = { ...c._serverCfg, spaces: c._serverCfg.spaces.map((s) => s.id !== 'f1' ? s : ({
|
||
...s, rooms: [...s.rooms, { id: 'rc', name: 'Cupboard', area: null, poly: [[0.05,0.62],[0.2,0.62],[0.2,0.9],[0.05,0.9]] }],
|
||
})).map((s) => s.id !== 'garden' ? s : ({
|
||
...s, rooms: [...s.rooms,
|
||
{ id: 'garden-shed-a', name: 'Shed A', area: null, poly: [[0.60,0.55],[0.80,0.55],[0.80,0.75],[0.60,0.75]] },
|
||
{ id: 'garden-shed-b', name: 'Shed B', area: null, poly: [[0.25,0.55],[0.45,0.55],[0.45,0.75],[0.25,0.75]] },
|
||
],
|
||
})) };
|
||
c._regSignature = ''; c._maybeRebuildDevices(); await c.updateComplete;
|
||
// список комнат в диалоге содержит подзону
|
||
c._setMode('devices');
|
||
c._openMarkerDialog(); await c.updateComplete;
|
||
const rooms = c._allRoomsFlat();
|
||
out.subareaListed = rooms.some((r) => r.value === 'f1#@rc');
|
||
// создать виртуальный маркер в подзону
|
||
c._markerDialog = { ...c._markerDialog, name: 'Vacuum dock', binding: 'virtual', room: 'f1#@rc' };
|
||
await c._saveMarker(); await c.updateComplete;
|
||
const m = c._serverCfg.markers.find((x) => x.name === 'Vacuum dock');
|
||
out.markerRoomId = m?.room_id;
|
||
out.markerAreaNull = m ? m.area === null : null;
|
||
// позиция — в центре подзоны (норм. центр rc: x=0.125, y=0.76)
|
||
const pos = c._layout[m.id];
|
||
out.posInRoom = pos && Math.abs(pos.x - 0.125) < 0.03 && Math.abs(pos.y - 0.76) < 0.03;
|
||
// девайс отрисован
|
||
const dev = c._devices.find((d) => d.id === m.id);
|
||
out.deviceBuilt = !!dev && dev.space === 'f1';
|
||
// reopen диалога восстанавливает выбор
|
||
c._openMarkerDialog(dev);
|
||
out.reopenRoom = c._markerDialog?.room;
|
||
c._markerDialog = null;
|
||
|
||
// Реальное HA-устройство с registry Area вручную переносится в комнату без
|
||
// Area другого пространства. Registry metadata не должна вернуть его в f1.
|
||
const source = c._devices.find((d) => d.id === 'd_light1');
|
||
c._openMarkerDialog(source); await c.updateComplete;
|
||
const roomSelect = c.renderRoot.querySelector('#marker-room');
|
||
roomSelect.value = 'garden#@garden-shed-a';
|
||
roomSelect.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
||
await c.updateComplete;
|
||
out.realRoomChangeMarkedTouched = c._markerDialog?.roomTouched === true;
|
||
await c._saveMarker(); await c.updateComplete;
|
||
const haMarker = c._serverCfg.markers.find((x) => x.binding === 'device:d_light1');
|
||
const moved = c._devices.find((d) => d.id === haMarker?.id);
|
||
const crossPos = c._layout[haMarker?.id];
|
||
out.haMarkerSaved = !!haMarker
|
||
&& haMarker.space === 'garden' && haMarker.area === null && haMarker.room_id === 'garden-shed-a';
|
||
out.haRuntimePlacement = !!moved
|
||
&& moved.space === 'garden' && moved.area === '' && moved.marker?.room_id === 'garden-shed-a';
|
||
out.crossSpaceCentered = !!crossPos && crossPos.s === 'garden'
|
||
&& Math.abs(crossPos.x - 0.70) < 0.03 && Math.abs(crossPos.y - 0.65) < 0.03;
|
||
|
||
c._openMarkerDialog(moved); await c.updateComplete;
|
||
out.haReopenRoom = c._markerDialog?.room === 'garden#@garden-shed-a';
|
||
c._markerDialog = null;
|
||
|
||
// Защитный негативный кейс: transient runtime-пара с room_id из другого
|
||
// пространства не роняет диалог и не переписывает сохранённый marker.
|
||
const persistedBeforeInvalidOpen = JSON.stringify(haMarker);
|
||
c._openMarkerDialog({ ...moved, space: 'f1' }); await c.updateComplete;
|
||
const invalidSelect = c.shadowRoot?.querySelector('#marker-room');
|
||
out.invalidPairPlaceholder = invalidSelect?.value === '';
|
||
out.invalidPairReadOnly = JSON.stringify(
|
||
c._serverCfg.markers.find((x) => x.binding === 'device:d_light1'),
|
||
) === persistedBeforeInvalidOpen;
|
||
c._markerDialog = null; await c.updateComplete;
|
||
|
||
// Смена комнаты внутри того же пространства сохраняет уже закреплённую
|
||
// позицию, хотя room_id меняется.
|
||
c._openMarkerDialog(moved); await c.updateComplete;
|
||
const secondRoomSelect = c.renderRoot.querySelector('#marker-room');
|
||
secondRoomSelect.value = 'garden#@garden-shed-b';
|
||
secondRoomSelect.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
||
await c.updateComplete;
|
||
await c._saveMarker(); await c.updateComplete;
|
||
const sameSpaceMarker = c._serverCfg.markers.find((x) => x.binding === 'device:d_light1');
|
||
const sameSpacePos = c._layout[sameSpaceMarker?.id];
|
||
const sameSpaceDevice = c._devices.find((d) => d.id === sameSpaceMarker?.id);
|
||
out.sameSpaceRoomSaved = sameSpaceMarker?.room_id === 'garden-shed-b'
|
||
&& sameSpaceDevice?.space === 'garden' && sameSpaceDevice?.area === '';
|
||
out.sameSpacePositionKept = !!sameSpacePos
|
||
&& sameSpacePos.s === crossPos.s && sameSpacePos.x === crossPos.x && sameSpacePos.y === crossPos.y;
|
||
return out;
|
||
});
|
||
// значения зафиксированы прогоном на v1.43.1 и сверены с кодом (audit T1)
|
||
checkAll(res, {
|
||
"markerRoomId": "rc",
|
||
"reopenRoom": "f1#@rc",
|
||
});
|
||
await finish(browser, res);
|