mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-28 19:01:34 +00:00
test(dialog): cover HA theme and enlarged text (#609)
Extend the authentic pinned-HA diagnostic with explicit light and dark palettes, a 32 px root-font case, one-scroller geometry assertions, and reviewed evidence images. Correct stale AC references in the mutation descriptions. Issue: #609 User-Visible: no
This commit is contained in:
@@ -31,9 +31,12 @@ It opens the real Room settings form and checks the settled WebAwesome surface:
|
||||
560 px desktop width, the 940 px/viewport height cap, zero duplicate HA body
|
||||
padding, one HA-owned scroller, a distinct form canvas, footer containment and
|
||||
edge-to-edge layouts at 480×800 and 390×844. It also keeps HA's own fullscreen
|
||||
behaviour for a 1280×480 viewport. `--capture` writes the two reviewed diagnostic
|
||||
behaviour for a 1280×480 viewport. `--capture` writes the three reviewed diagnostic
|
||||
images under `docs/design/600-settings-dialogs/pairs/`; without it the command
|
||||
is read-only. The fast Validate witness is
|
||||
is read-only. The authentic diagnostic explicitly applies the light palette,
|
||||
then repeats desktop geometry in the dark palette with a 32 px root font and
|
||||
proves that canvas contrast, the single HA scroller and the footer survive.
|
||||
The fast Validate witness is
|
||||
`demo/smoke_ha_form_shell_parity.mjs`; neither diagnostic is a golden producer.
|
||||
|
||||
From a checkout with the usual `npm ci` dependencies and Playwright Chromium:
|
||||
|
||||
@@ -55,9 +55,15 @@ const inspect = async () => page.evaluate(() => {
|
||||
const cardStyle = getComputedStyle(formCard);
|
||||
const panelBox = panel.getBoundingClientRect();
|
||||
const overflowNodes = [];
|
||||
const scrollOwners = [];
|
||||
const visit = (root) => {
|
||||
for (const node of root.querySelectorAll('*')) {
|
||||
const box = node.getBoundingClientRect();
|
||||
const style = getComputedStyle(node);
|
||||
if (node.scrollHeight > node.clientHeight + 1 && /auto|scroll/.test(style.overflowY)) {
|
||||
scrollOwners.push({ tag: node.localName, id: node.id, className: String(node.className || ''),
|
||||
scrollHeight: node.scrollHeight, clientHeight: node.clientHeight });
|
||||
}
|
||||
// wa-dialog itself stays in document flow at the demo host's 8 px page
|
||||
// inset; its rendered native dialog is fixed and is the geometry users see.
|
||||
if (node.localName !== 'wa-dialog' && box.width > 0
|
||||
@@ -85,12 +91,32 @@ const inspect = async () => page.evaluate(() => {
|
||||
formBodyOverflowY: formBodyStyle.overflowY,
|
||||
formBodyBackground: formBodyStyle.backgroundColor,
|
||||
cardBackground: cardStyle.backgroundColor,
|
||||
rootFontSize: getComputedStyle(document.documentElement).fontSize,
|
||||
colorScheme: getComputedStyle(document.documentElement).colorScheme,
|
||||
scrollOwners,
|
||||
horizontalOverflow: overflowNodes.length > 0,
|
||||
documentWidth: [document.documentElement.scrollWidth, document.body.scrollWidth],
|
||||
overflowNodes: overflowNodes.slice(0, 20),
|
||||
};
|
||||
});
|
||||
|
||||
const setPresentation = async ({ theme, textSize }) => page.evaluate(async ({ theme, textSize }) => {
|
||||
const dark = theme === 'dark';
|
||||
const colors = dark ? ['#3ea6ff', '#e6e7eb', '#9aa4ad', '#202126', '#3a3d45', '#11151b', '#2b2d33']
|
||||
: ['#0b73b8', '#202124', '#5f6368', '#ffffff', '#d7d9de', '#eef1f4', '#e7eaee'];
|
||||
['primary-color', 'primary-text-color', 'secondary-text-color', 'card-background-color',
|
||||
'divider-color', 'primary-background-color', 'secondary-background-color']
|
||||
.forEach((key, index) => document.documentElement.style.setProperty(`--${key}`, colors[index]));
|
||||
document.documentElement.style.setProperty('--ha-card-background', colors[3]);
|
||||
document.documentElement.style.colorScheme = theme;
|
||||
document.documentElement.style.fontSize = `${textSize}px`;
|
||||
document.body.style.background = colors[5];
|
||||
const card = window.__card;
|
||||
card.hass = { ...card.hass, themes: { ...card.hass?.themes, darkMode: dark } };
|
||||
card.requestUpdate();
|
||||
await card.updateComplete;
|
||||
}, { theme, textSize });
|
||||
|
||||
const clipPanel = async (name, state) => {
|
||||
if (!capture) return;
|
||||
const clip = {
|
||||
@@ -122,6 +148,7 @@ try {
|
||||
return ha?.open === true
|
||||
&& ha.shadowRoot.querySelector('wa-dialog')?.shadowRoot.querySelector('dialog')?.matches(':modal');
|
||||
});
|
||||
await setPresentation({ theme: 'light', textSize: 16 });
|
||||
await settle();
|
||||
|
||||
const desktop = await inspect();
|
||||
@@ -134,10 +161,36 @@ try {
|
||||
assert.equal(desktop.haBodyOverflowY, 'auto');
|
||||
assert.equal(desktop.formBodyOverflowY, 'visible');
|
||||
assert.notEqual(desktop.formBodyBackground, desktop.cardBackground);
|
||||
assert.equal(desktop.cardBackground, 'rgb(255, 255, 255)');
|
||||
assert.ok(desktop.colorScheme.includes('light'), `desktop scheme ${desktop.colorScheme}`);
|
||||
assert.equal(desktop.rootFontSize, '16px');
|
||||
assert.equal(desktop.scrollOwners.length, 1, JSON.stringify(desktop.scrollOwners));
|
||||
assert.ok(desktop.haBodyScroll[0] > desktop.haBodyScroll[1], `desktop scroll ${desktop.haBodyScroll}`);
|
||||
assert.ok(desktop.footer.bottom <= desktop.panel.bottom + 1);
|
||||
await clipPanel('room-ha-light.png', desktop);
|
||||
|
||||
await setPresentation({ theme: 'dark', textSize: 32 });
|
||||
await settle();
|
||||
const darkText200 = await inspect();
|
||||
assert.ok(Math.abs(darkText200.panel.width - 560) <= 1,
|
||||
`dark 200% width ${darkText200.panel.width}`);
|
||||
assert.ok(darkText200.panel.height <= 941,
|
||||
`dark 200% height ${darkText200.panel.height}`);
|
||||
assert.equal(darkText200.rootFontSize, '32px');
|
||||
assert.ok(darkText200.colorScheme.includes('dark'), `dark scheme ${darkText200.colorScheme}`);
|
||||
assert.equal(darkText200.cardBackground, 'rgb(32, 33, 38)');
|
||||
assert.notEqual(darkText200.formBodyBackground, darkText200.cardBackground);
|
||||
assert.equal(darkText200.haBodyOverflowY, 'auto');
|
||||
assert.equal(darkText200.formBodyOverflowY, 'visible');
|
||||
assert.equal(darkText200.scrollOwners.length, 1, JSON.stringify(darkText200.scrollOwners));
|
||||
assert.ok(darkText200.haBodyScroll[0] > darkText200.haBodyScroll[1],
|
||||
`dark 200% scroll ${darkText200.haBodyScroll}`);
|
||||
assert.equal(darkText200.horizontalOverflow, false, JSON.stringify(darkText200.overflowNodes));
|
||||
assert.ok(darkText200.footer.bottom <= darkText200.panel.bottom + 1);
|
||||
await clipPanel('room-ha-dark-text-200.png', darkText200);
|
||||
|
||||
await setPresentation({ theme: 'light', textSize: 16 });
|
||||
|
||||
await page.setViewportSize({ width: 480, height: 800 });
|
||||
await settle();
|
||||
const edge = await inspect();
|
||||
@@ -170,6 +223,7 @@ try {
|
||||
authenticHaFrontend: fixture.provenance,
|
||||
capture,
|
||||
desktop,
|
||||
darkText200,
|
||||
edge480: edge,
|
||||
mobile390: mobile,
|
||||
shortViewport: short,
|
||||
|
||||
@@ -51,12 +51,14 @@ node demo/verify_ha_form_shell_609.mjs --capture
|
||||
| Режим | Поверхность | Проверенный результат |
|
||||
|---|---:|---|
|
||||
| desktop 1600×1000 | 560×940 | канва вокруг карточек, один скроллер `.body` HA, footer внутри |
|
||||
| dark + text 200%, 1600×1000 | 560×940 | root font 32 px, один HA-скроллер, footer внутри, канва не сливается с карточками |
|
||||
| граница 480×800 | 480×800 | fullscreen, радиус 0, горизонтального переполнения нет |
|
||||
| mobile 390×844 | 390×844 | fullscreen, радиус 0, footer внутри |
|
||||
| низкое окно 1280×480 | 1280×480 | штатный fullscreen HA сохранён |
|
||||
|
||||
Снимки приёмки: `pairs/room-ha-light.png` и
|
||||
`pairs/room-ha-mobile-light.png`. Это диагностические доказательства, а не
|
||||
Снимки приёмки: `pairs/room-ha-light.png`,
|
||||
`pairs/room-ha-dark-text-200.png` и `pairs/room-ha-mobile-light.png`. Это
|
||||
диагностические доказательства, а не
|
||||
golden-базы; 13 нативных golden-сцен остаются неизменными. Быстрый обязательный
|
||||
свидетель тех же публичных CSS-контрактов —
|
||||
`demo/smoke_ha_form_shell_parity.mjs`, а перечень пяти потребителей оболочки
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 47 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 33 KiB |
@@ -75,7 +75,7 @@ const MUTANT_DEFINITIONS = [
|
||||
{
|
||||
id: 'ha-form-shell-width-falls-back-to-generic',
|
||||
guard: 'node demo/smoke_ha_form_shell_parity.mjs',
|
||||
because: '#609 AC1/AC8: the authentic HA branch must consume the reviewed 560 px form '
|
||||
because: '#609 AC1: the authentic HA branch must consume the reviewed 560 px form '
|
||||
+ 'width; falling back to HA generic medium width recreates the released/native mismatch',
|
||||
patches: [{
|
||||
file: 'src/hp-dialog.ts',
|
||||
@@ -97,7 +97,7 @@ const MUTANT_DEFINITIONS = [
|
||||
{
|
||||
id: 'ha-form-shell-mobile-keeps-desktop-inset',
|
||||
guard: 'node demo/smoke_ha_form_shell_parity.mjs',
|
||||
because: '#609 AC4/AC8: at 480 px and below the form shell is edge-to-edge; retaining the '
|
||||
because: '#609 AC4: at 480 px and below the form shell is edge-to-edge; retaining the '
|
||||
+ 'desktop 48 px height inset clips the reviewed mobile surface and footer',
|
||||
patches: [{
|
||||
file: 'src/hp-dialog.ts',
|
||||
|
||||
Reference in New Issue
Block a user