Files
frontend/test/data/image_upload.test.ts
T
Paulus SchoutsenandClaude a7eb100132 Correct entity domain and helper API types in the frontend (#54293)
Compare the entity domain and helper data modules with the domains
that produce the attributes, and fix the mismatches.

Add supported feature flags the domains define and the frontend did
not list, and add attributes the domains report. Remove attributes
that are service fields rather than state, and the light colour
temperature keys core replaced with the kelvin forms.

Correct the weather forecast, where the event carries the whole list
and the wind speed is a number, and correct the image update command,
which sent the wrong id.


Claude-Session: https://claude.ai/code/session_01YDqKNfAAvMV7zJJNodsHfK

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-26 10:40:32 +02:00

161 lines
5.0 KiB
TypeScript

import { describe, it, expect, vi, afterEach } from "vitest";
import {
getIdFromUrl,
generateImageThumbnailUrl,
fetchImages,
createImage,
updateImage,
deleteImage,
getImageData,
URL_PREFIX,
MEDIA_PREFIX,
} from "../../src/data/image_upload";
import type { HomeAssistant } from "../../src/types";
describe("image_upload", () => {
afterEach(() => {
vi.restoreAllMocks();
});
describe("getIdFromUrl", () => {
it("should extract id from URL_PREFIX", () => {
const url = `${URL_PREFIX}12345/some/path`;
const id = getIdFromUrl(url);
expect(id).toBe("12345");
});
it("should extract id from MEDIA_PREFIX", () => {
const url = `${MEDIA_PREFIX}/12345`;
const id = getIdFromUrl(url);
expect(id).toBe("12345");
});
it("should return undefined for invalid url", () => {
const url = "invalid_url";
const id = getIdFromUrl(url);
expect(id).toBeUndefined();
});
});
describe("generateImageThumbnailUrl", () => {
it("should generate thumbnail URL with size", () => {
const url = generateImageThumbnailUrl("12345", 100);
expect(url).toBe("/api/image/serve/12345/100x100");
});
it("should generate original image URL", () => {
const url = generateImageThumbnailUrl("12345", undefined, true);
expect(url).toBe("/api/image/serve/12345/original");
});
it("should throw error if size is not provided and original is false", () => {
expect(() => generateImageThumbnailUrl("12345")).toThrow(
"Size must be provided if original is false"
);
});
});
describe("fetchImages", () => {
it("should fetch images", async () => {
const hass = {
callWS: vi.fn().mockResolvedValue([]),
} as unknown as HomeAssistant;
const images = await fetchImages(hass);
expect(hass.callWS).toHaveBeenCalledWith({ type: "image/list" });
expect(images).toEqual([]);
});
});
describe("createImage", () => {
it("should create an image", async () => {
const file = new File([""], "image.png", { type: "image/png" });
const hass = {
fetchWithAuth: vi.fn().mockResolvedValue({
status: 200,
json: vi.fn().mockResolvedValue({ id: "12345" }),
}),
} as unknown as HomeAssistant;
const image = await createImage(hass, file);
expect(hass.fetchWithAuth).toHaveBeenCalled();
expect(image).toEqual({ id: "12345" });
});
it("should throw error if image is too large", async () => {
const file = new File([""], "image.png", { type: "image/png" });
const hass = {
fetchWithAuth: vi.fn().mockResolvedValue({ status: 413 }),
localize: vi.fn((key: string, values?: Record<string, string>) => {
if (key === "ui.common.upload_image_too_large") {
return `Uploaded image is too large (${values?.name})`;
}
return "Unknown error";
}),
} as unknown as HomeAssistant;
await expect(createImage(hass, file)).rejects.toThrow(
"Uploaded image is too large (image.png)"
);
});
it("should throw error if fetch fails", async () => {
const file = new File([""], "image.png", { type: "image/png" });
const hass = {
fetchWithAuth: vi.fn().mockResolvedValue({ status: 500 }),
localize: vi.fn(() => "Unknown error"),
} as unknown as HomeAssistant;
await expect(createImage(hass, file)).rejects.toThrow("Unknown error");
});
});
describe("updateImage", () => {
it("should update an image", async () => {
const hass = {
callWS: vi.fn().mockResolvedValue({}),
} as unknown as HomeAssistant;
const updates = { name: "new name" };
await updateImage(hass, "12345", updates);
expect(hass.callWS).toHaveBeenCalledWith({
type: "image/update",
image_id: "12345",
...updates,
});
});
});
describe("deleteImage", () => {
it("should delete an image", async () => {
const hass = {
callWS: vi.fn().mockResolvedValue({}),
} as unknown as HomeAssistant;
await deleteImage(hass, "12345");
expect(hass.callWS).toHaveBeenCalledWith({
type: "image/delete",
image_id: "12345",
});
});
});
describe("getImageData", () => {
const hass = {
hassUrl: vi.fn((url) => url),
} as unknown as HomeAssistant;
it("should fetch image data", async () => {
global.fetch = vi.fn().mockResolvedValue({
ok: true,
blob: vi.fn().mockResolvedValue(new Blob()),
});
const data = await getImageData(hass, "http://example.com/image.png");
expect(global.fetch).toHaveBeenCalledWith("http://example.com/image.png");
expect(data).toBeInstanceOf(Blob);
});
it("should throw error if fetch fails", async () => {
global.fetch = vi
.fn()
.mockResolvedValue({ ok: false, statusText: "Not Found" });
await expect(
getImageData(hass, "http://example.com/image.png")
).rejects.toThrow("Failed to fetch image: Not Found");
});
});
});