mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
143 lines
5.8 KiB
JavaScript
143 lines
5.8 KiB
JavaScript
// #301: contacts and locks in the real opening dialog are searchable by both
|
|
// friendly name and entity_id without losing the resolver's priority order.
|
|
import { launch, checkAll, finish } from './serve.mjs';
|
|
|
|
const { page, browser } = await launch();
|
|
const out = await page.evaluate(async () => {
|
|
const c = window.__card;
|
|
const sr = () => c.shadowRoot || c.renderRoot;
|
|
const settle = async () => {
|
|
c.requestUpdate();
|
|
await c.updateComplete;
|
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
};
|
|
const search = async (kind, query) => {
|
|
const input = sr().querySelector(`[data-opening-panel="${kind}"] .opening-entity-search`);
|
|
input.value = query;
|
|
input.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
|
await settle();
|
|
};
|
|
const rows = (kind) => [...sr().querySelectorAll(
|
|
`[data-opening-panel="${kind}"] .opening-entity-candidate[data-opening-entity]:not([data-opening-entity=""])`,
|
|
)];
|
|
|
|
c.hass = {
|
|
...c.hass,
|
|
states: {
|
|
...c.hass.states,
|
|
'binary_sensor.hp301_z_door': {
|
|
entity_id: 'binary_sensor.hp301_z_door', state: 'off',
|
|
attributes: { friendly_name: 'Prioritycheck Z door', device_class: 'door' },
|
|
},
|
|
'binary_sensor.hp301_a_motion': {
|
|
entity_id: 'binary_sensor.hp301_a_motion', state: 'off',
|
|
attributes: { friendly_name: 'Prioritycheck A motion', device_class: 'motion' },
|
|
},
|
|
'binary_sensor.hp301_window': {
|
|
entity_id: 'binary_sensor.hp301_window', state: 'off',
|
|
attributes: { friendly_name: 'Salon Contact', device_class: 'window' },
|
|
},
|
|
'lock.hp301_front': {
|
|
entity_id: 'lock.hp301_front', state: 'locked',
|
|
attributes: { friendly_name: 'HP301 Front Lock' },
|
|
},
|
|
},
|
|
};
|
|
const space = c._serverCfg.spaces.find((item) => item.id === 'f1');
|
|
// This interaction is about entity selectors, not zero-wall hosting. Make
|
|
// the synthetic room edges explicitly physical before adding the door;
|
|
// under model v9 an omitted thickness is intentionally a zero wall.
|
|
c._serverCfg.model_version = 7;
|
|
delete space.wall_segments;
|
|
delete space.open_spans;
|
|
space.walls = (space.rooms || []).flatMap((room) => {
|
|
delete room.wall_ids;
|
|
return room.poly.map((a, index) => ({
|
|
key: `${room.id}-${index}`,
|
|
a, b: room.poly[(index + 1) % room.poly.length], cm: 15,
|
|
}));
|
|
});
|
|
space.openings = [{
|
|
id: 'hp301-door', type: 'door', x: 0.22, y: 0.14, angle: 0, length: 0.09,
|
|
}];
|
|
c._cfgEpoch++;
|
|
c._setMode('plan');
|
|
await settle();
|
|
const opening = c._openingsR.find((item) => item.type === 'door');
|
|
if (!opening) return { realDoorFixtureExists: false };
|
|
c._editOpening(opening);
|
|
await settle();
|
|
|
|
const result = {
|
|
realDoorFixtureExists: true,
|
|
bothPickersShown: sr().querySelectorAll('.opening-entity-drop').length === 2,
|
|
panelsInitiallyClosed: !sr().querySelector('.opening-entity-panel'),
|
|
};
|
|
|
|
sr().querySelector('[data-opening-picker="contact"]').click();
|
|
await settle();
|
|
result.openDoesNotForceFocus = !sr().querySelector('.opening-entity-search').matches(':focus');
|
|
await search('contact', 'prioritycheck');
|
|
const ordered = rows('contact');
|
|
result.contactOrderPreserved = ordered.length === 2
|
|
&& ordered[0].dataset.openingEntity === 'binary_sensor.hp301_z_door'
|
|
&& ordered[1].dataset.openingEntity === 'binary_sensor.hp301_a_motion';
|
|
result.rowsExplainEntityId = ordered.every((row) =>
|
|
row.querySelector('.cs')?.textContent === row.dataset.openingEntity);
|
|
|
|
await search('contact', 'binary_sensor.hp301_window');
|
|
const byId = rows('contact');
|
|
result.searchByEntityId = byId.length === 1
|
|
&& byId[0].querySelector('.cl')?.textContent === 'Salon Contact';
|
|
byId[0].click();
|
|
await settle();
|
|
result.contactSelectedAndClosed = c._openingDialog.contact === 'binary_sensor.hp301_window'
|
|
&& !sr().querySelector('[data-opening-panel="contact"]');
|
|
result.closedButtonExplainsEntityId = sr().querySelector('[data-opening-picker="contact"] .ref')
|
|
?.textContent === 'binary_sensor.hp301_window';
|
|
|
|
sr().querySelector('[data-opening-picker="contact"]').click();
|
|
await settle();
|
|
await search('contact', 'no such hp301 entity');
|
|
const contactPanel = sr().querySelector('[data-opening-panel="contact"]');
|
|
const firstChoice = contactPanel.querySelector('.candlist > .opening-entity-candidate');
|
|
result.emptyStateKeepsNoneFirst = firstChoice?.dataset.openingEntity === ''
|
|
&& !!contactPanel.querySelector('.opening-entity-empty');
|
|
firstChoice.click();
|
|
await settle();
|
|
result.noneClearsContact = c._openingDialog.contact === ''
|
|
&& !sr().querySelector('[data-opening-panel="contact"]');
|
|
|
|
sr().querySelector('[data-opening-picker="contact"]').click();
|
|
await settle();
|
|
await search('contact', 'hp301_window');
|
|
rows('contact')[0].click();
|
|
await settle();
|
|
sr().querySelector('[data-opening-picker="lock"]').click();
|
|
await settle();
|
|
await search('lock', 'front lock');
|
|
const lockRows = rows('lock');
|
|
result.lockSearchWorks = lockRows.length === 1
|
|
&& lockRows[0].dataset.openingEntity === 'lock.hp301_front';
|
|
lockRows[0].click();
|
|
await settle();
|
|
result.lockSelectedAndClosed = c._openingDialog.lock === 'lock.hp301_front'
|
|
&& !sr().querySelector('[data-opening-panel="lock"]');
|
|
|
|
sr().querySelector('.dialog-action-commit .btn.on').click();
|
|
await settle();
|
|
const saved = c._curSpaceCfg.openings.find((item) => item.id === opening.id);
|
|
result.savedSameFields = saved?.contact === 'binary_sensor.hp301_window'
|
|
&& saved?.lock === 'lock.hp301_front';
|
|
result.dialogClosedAfterSave = !c._openingDialog;
|
|
|
|
c._editOpening(c._openingsR.find((item) => item.id === opening.id));
|
|
c._openingDialog = { ...c._openingDialog, type: 'passage' };
|
|
await settle();
|
|
result.passageStillHasNoBindingPickers = !sr().querySelector('.opening-entity-drop');
|
|
c._openingDialog = null;
|
|
return result;
|
|
});
|
|
|
|
await finish(browser, checkAll(out));
|