mirror of
https://github.com/home-assistant/frontend.git
synced 2026-06-25 17:51:39 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d15276b74a | |||
| 17bc5f52d9 | |||
| 0dbeeabb4e |
+102
-23
@@ -5,8 +5,62 @@
|
||||
* yarn test:e2e:app
|
||||
*/
|
||||
import { test, expect, type Page } from "@playwright/test";
|
||||
import type { MoreInfoView } from "../../src/dialogs/more-info/const";
|
||||
import { PANEL_TIMEOUT, QUICK_TIMEOUT, SHELL_TIMEOUT } from "./helpers";
|
||||
|
||||
/**
|
||||
* Each More info view renders one root element inside the dialog, plus one or
|
||||
* more characteristic descendants that prove the view actually populated rather
|
||||
* than rendering an empty shell. `text`, when set, asserts the element's text
|
||||
* instead of just its presence.
|
||||
*/
|
||||
const MORE_INFO_VIEW_ELEMENTS: {
|
||||
view: MoreInfoView;
|
||||
element: string;
|
||||
content: { selector: string; text?: string }[];
|
||||
}[] = [
|
||||
{
|
||||
view: "info",
|
||||
element: "ha-more-info-info",
|
||||
content: [
|
||||
{ selector: "more-info-light" },
|
||||
{ selector: "span.title", text: "Test Light" },
|
||||
],
|
||||
},
|
||||
{
|
||||
view: "history",
|
||||
element: "ha-more-info-history-and-logbook",
|
||||
// The demo loads the history component but not logbook.
|
||||
content: [{ selector: "ha-more-info-history" }],
|
||||
},
|
||||
{
|
||||
view: "settings",
|
||||
element: "ha-more-info-settings",
|
||||
// The scenario mocks config/entity_registry/get, so the real registry
|
||||
// panel renders instead of the "no unique ID" warning.
|
||||
content: [{ selector: "entity-registry-settings" }],
|
||||
},
|
||||
{
|
||||
view: "related",
|
||||
element: "ha-related-items",
|
||||
// search/related is mocked to return no relations, so the empty list
|
||||
// renders.
|
||||
content: [{ selector: "ha-related-items >> ha-list" }],
|
||||
},
|
||||
{
|
||||
view: "add_to",
|
||||
element: "ha-more-info-add-to",
|
||||
// Admin users get the default add-to action list.
|
||||
content: [{ selector: "ha-add-to-action-list" }],
|
||||
},
|
||||
{
|
||||
view: "details",
|
||||
element: "ha-more-info-details",
|
||||
// The details view renders the state and attributes cards.
|
||||
content: [{ selector: "ha-card" }],
|
||||
},
|
||||
];
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -156,31 +210,56 @@ test.describe("Lovelace dashboard", () => {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
test.describe("Light more-info dialog", () => {
|
||||
test("opens more-info dialog for a light entity", async ({ page }) => {
|
||||
// The light-more-info scenario seeds light.test_light synchronously.
|
||||
await goToPanel(page, "/?scenario=light-more-info#/lovelace");
|
||||
for (const { view, element, content } of MORE_INFO_VIEW_ELEMENTS) {
|
||||
test(`opens more-info ${view} view for a light entity`, async ({
|
||||
page,
|
||||
}) => {
|
||||
// The light-more-info scenario seeds light.test_light synchronously.
|
||||
await goToPanel(page, "/?scenario=light-more-info#/lovelace");
|
||||
|
||||
// Fire the standard hass-more-info event from the app root. The HA shell
|
||||
// listens for this and opens ha-more-info-dialog via its dialog manager.
|
||||
await page.evaluate(() => {
|
||||
const el = document.querySelector("ha-test");
|
||||
el?.dispatchEvent(
|
||||
new CustomEvent("hass-more-info", {
|
||||
detail: { entityId: "light.test_light" },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
})
|
||||
);
|
||||
const dialog = page.locator("ha-more-info-dialog");
|
||||
|
||||
// Fire the standard hass-more-info event from the app root with an
|
||||
// explicit view. The HA shell opens ha-more-info-dialog on the requested
|
||||
// view directly, so the test does not depend on the admin/demo-hidden
|
||||
// header controls.
|
||||
//
|
||||
// The event is one-shot: if it lands before the shell's hass-more-info
|
||||
// listener is attached it is silently dropped. Re-dispatching is
|
||||
// idempotent (showDialog just resets the dialog to the requested view),
|
||||
// so poll the dispatch until the requested view actually renders.
|
||||
await expect(async () => {
|
||||
await page.evaluate((v) => {
|
||||
const el = document.querySelector("ha-test");
|
||||
el?.dispatchEvent(
|
||||
new CustomEvent("hass-more-info", {
|
||||
detail: { entityId: "light.test_light", view: v },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
})
|
||||
);
|
||||
}, view);
|
||||
|
||||
await expect(dialog).toBeAttached({ timeout: QUICK_TIMEOUT });
|
||||
await expect(dialog.locator(element)).toBeAttached({
|
||||
timeout: QUICK_TIMEOUT,
|
||||
});
|
||||
}).toPass({ timeout: SHELL_TIMEOUT });
|
||||
|
||||
// Each view should render its own characteristic content, not just an
|
||||
// empty shell.
|
||||
for (const { selector, text } of content) {
|
||||
const locator = dialog.locator(selector).first();
|
||||
if (text) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await expect(locator).toContainText(text, { timeout: QUICK_TIMEOUT });
|
||||
} else {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await expect(locator).toBeAttached({ timeout: QUICK_TIMEOUT });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const dialog = page.locator("ha-more-info-dialog");
|
||||
await expect(dialog).toBeAttached({ timeout: SHELL_TIMEOUT });
|
||||
|
||||
// Confirm it actually rendered our entity, not a generic empty dialog.
|
||||
await expect(dialog.locator("span.title")).toContainText("Test Light", {
|
||||
timeout: QUICK_TIMEOUT,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -25,6 +25,7 @@ import { mockLovelace } from "../../../../demo/src/stubs/lovelace";
|
||||
import { mockMediaPlayer } from "../../../../demo/src/stubs/media_player";
|
||||
import { mockPersistentNotification } from "../../../../demo/src/stubs/persistent_notification";
|
||||
import { mockRecorder } from "../../../../demo/src/stubs/recorder";
|
||||
import { mockSearch } from "../../../../demo/src/stubs/search";
|
||||
import { mockSensor } from "../../../../demo/src/stubs/sensor";
|
||||
import { mockSystemLog } from "../../../../demo/src/stubs/system_log";
|
||||
import { mockTemplate } from "../../../../demo/src/stubs/template";
|
||||
@@ -100,6 +101,7 @@ export class HaTest extends HomeAssistantAppEl {
|
||||
mockConfigEntries(hass);
|
||||
mockIcons(hass);
|
||||
mockPersistentNotification(hass);
|
||||
mockSearch(hass);
|
||||
|
||||
// Load default entities from the sections config
|
||||
hass.addEntities(energyEntities());
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { ExtEntityRegistryEntry } from "../../../../../src/data/entity/entity_registry";
|
||||
import type { MockHomeAssistant } from "../../../../../src/fake_data/provide_hass";
|
||||
|
||||
export type Scenario = (hass: MockHomeAssistant) => Promise<void> | void;
|
||||
@@ -56,6 +57,36 @@ const lightMoreInfoScenario: Scenario = async (hass) => {
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
// The base entity registry stub only mocks the list/get_entries commands, so
|
||||
// the more-info settings view falls back to its "no unique ID" warning. Mock
|
||||
// the single-entry lookup (config/entity_registry/get) so the settings view
|
||||
// renders the real entity-registry-settings panel.
|
||||
const registryEntry: ExtEntityRegistryEntry = {
|
||||
created_at: 0,
|
||||
modified_at: 0,
|
||||
id: "test_light",
|
||||
entity_id: "light.test_light",
|
||||
unique_id: "test_light_unique_id",
|
||||
name: null,
|
||||
icon: null,
|
||||
platform: "demo",
|
||||
config_entry_id: null,
|
||||
config_subentry_id: null,
|
||||
device_id: null,
|
||||
area_id: null,
|
||||
labels: [],
|
||||
disabled_by: null,
|
||||
hidden_by: null,
|
||||
entity_category: null,
|
||||
has_entity_name: false,
|
||||
original_name: "Test Light",
|
||||
options: null,
|
||||
categories: {},
|
||||
capabilities: {},
|
||||
aliases: [],
|
||||
};
|
||||
hass.mockWS("config/entity_registry/get", () => registryEntry);
|
||||
};
|
||||
|
||||
// ── Registry ──────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user