243 lines
7.3 KiB
TypeScript
243 lines
7.3 KiB
TypeScript
import TextManager from "$components/text/TextManager.svelte";
|
||
import { fireEvent, render, screen } from "@testing-library/svelte";
|
||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||
|
||
// Mock the stores
|
||
vi.mock("$stores/panelStore", () => ({
|
||
textSettingsStore: {
|
||
subscribe: vi.fn((callback) => {
|
||
callback({
|
||
fontSize: 18,
|
||
fontFamily: "Arial",
|
||
color: "#ffffff",
|
||
textAlign: "center",
|
||
paddingX: 10,
|
||
verticalOffset: 0,
|
||
});
|
||
return () => {}; // unsubscribe function
|
||
}),
|
||
update: vi.fn(),
|
||
},
|
||
updateAllTextSettings: vi.fn(),
|
||
}));
|
||
|
||
describe("TextManager", () => {
|
||
let mockOnTextAdd: (text: string, settings?: any) => void;
|
||
let mockOnTextUpdate: (id: string, text: string) => void;
|
||
let mockOnTextDelete: (id: string) => void;
|
||
|
||
beforeEach(() => {
|
||
mockOnTextAdd = vi.fn();
|
||
mockOnTextUpdate = vi.fn();
|
||
mockOnTextDelete = vi.fn();
|
||
});
|
||
|
||
it("should render with empty text list", () => {
|
||
const { container } = render(TextManager, {
|
||
props: {
|
||
texts: [],
|
||
onTextAdd: mockOnTextAdd,
|
||
onTextUpdate: mockOnTextUpdate,
|
||
onTextDelete: mockOnTextDelete,
|
||
},
|
||
});
|
||
|
||
expect(container).toBeTruthy();
|
||
});
|
||
|
||
it("should render with existing texts", () => {
|
||
const mockTexts = [
|
||
{ id: "text-1", text: "First text" },
|
||
{ id: "text-2", text: "Second text" },
|
||
];
|
||
|
||
const { container } = render(TextManager, {
|
||
props: {
|
||
texts: mockTexts,
|
||
onTextAdd: mockOnTextAdd,
|
||
onTextUpdate: mockOnTextUpdate,
|
||
onTextDelete: mockOnTextDelete,
|
||
},
|
||
});
|
||
|
||
expect(container).toBeTruthy();
|
||
});
|
||
|
||
it("should call onTextAdd when add text form is submitted", async () => {
|
||
const { container } = render(TextManager, {
|
||
props: {
|
||
texts: [],
|
||
onTextAdd: mockOnTextAdd,
|
||
onTextUpdate: mockOnTextUpdate,
|
||
onTextDelete: mockOnTextDelete,
|
||
},
|
||
});
|
||
|
||
// Find text input and add button
|
||
const textInputs = container.querySelectorAll('input[type="text"], textarea');
|
||
const buttons = screen.getAllByRole("button");
|
||
|
||
if (textInputs.length > 0 && buttons.length > 0) {
|
||
await fireEvent.input(textInputs[0], { target: { value: "New text" } });
|
||
await fireEvent.click(buttons[0]);
|
||
|
||
expect(mockOnTextAdd).toHaveBeenCalledWith("New text", expect.any(Object));
|
||
}
|
||
});
|
||
|
||
it("should show error for empty text", async () => {
|
||
const { container } = render(TextManager, {
|
||
props: {
|
||
texts: [],
|
||
onTextAdd: mockOnTextAdd,
|
||
onTextUpdate: mockOnTextUpdate,
|
||
onTextDelete: mockOnTextDelete,
|
||
},
|
||
});
|
||
|
||
// Find add button and click without entering text
|
||
const buttons = screen.getAllByRole("button");
|
||
if (buttons.length > 0) {
|
||
await fireEvent.click(buttons[0]);
|
||
|
||
// Should not call onTextAdd for empty text
|
||
expect(mockOnTextAdd).not.toHaveBeenCalled();
|
||
}
|
||
});
|
||
|
||
it("should handle text update", async () => {
|
||
const mockTexts = [{ id: "text-1", text: "Original text" }];
|
||
|
||
const { container } = render(TextManager, {
|
||
props: {
|
||
texts: mockTexts,
|
||
onTextAdd: mockOnTextAdd,
|
||
onTextUpdate: mockOnTextUpdate,
|
||
onTextDelete: mockOnTextDelete,
|
||
},
|
||
});
|
||
|
||
// Find text inputs for existing texts
|
||
const textInputs = container.querySelectorAll('input[type="text"], textarea');
|
||
if (textInputs.length > 0) {
|
||
await fireEvent.input(textInputs[0], { target: { value: "Updated text" } });
|
||
|
||
// Should call onTextUpdate with the text ID and new text
|
||
expect(mockOnTextUpdate).toHaveBeenCalledWith("text-1", "Updated text");
|
||
}
|
||
});
|
||
|
||
it("should handle text deletion", async () => {
|
||
const mockTexts = [{ id: "text-1", text: "Text to delete" }];
|
||
|
||
render(TextManager, {
|
||
props: {
|
||
texts: mockTexts,
|
||
onTextAdd: mockOnTextAdd,
|
||
onTextUpdate: mockOnTextUpdate,
|
||
onTextDelete: mockOnTextDelete,
|
||
},
|
||
});
|
||
|
||
// Find delete button (might be an X button or similar)
|
||
const buttons = screen.getAllByRole("button");
|
||
const deleteButton = buttons.find(
|
||
(button) =>
|
||
button.textContent?.includes("Delete") ||
|
||
button.textContent?.includes("Remove") ||
|
||
button.textContent?.includes("×") ||
|
||
button.textContent?.includes("X"),
|
||
);
|
||
|
||
if (deleteButton) {
|
||
await fireEvent.click(deleteButton);
|
||
expect(mockOnTextDelete).toHaveBeenCalledWith("text-1");
|
||
}
|
||
});
|
||
|
||
it("should handle font size changes", async () => {
|
||
const { container } = render(TextManager, {
|
||
props: {
|
||
texts: [],
|
||
onTextAdd: mockOnTextAdd,
|
||
onTextUpdate: mockOnTextUpdate,
|
||
onTextDelete: mockOnTextDelete,
|
||
},
|
||
});
|
||
|
||
// Find font size input (number input)
|
||
const numberInputs = container.querySelectorAll('input[type="number"]');
|
||
if (numberInputs.length > 0) {
|
||
await fireEvent.input(numberInputs[0], { target: { value: "24" } });
|
||
|
||
// Font size change should be handled in the component
|
||
expect(container).toBeTruthy(); // Basic check that component still renders
|
||
}
|
||
});
|
||
|
||
it("should handle color changes", async () => {
|
||
const { container } = render(TextManager, {
|
||
props: {
|
||
texts: [],
|
||
onTextAdd: mockOnTextAdd,
|
||
onTextUpdate: mockOnTextUpdate,
|
||
onTextDelete: mockOnTextDelete,
|
||
},
|
||
});
|
||
|
||
// Find color input
|
||
const colorInputs = container.querySelectorAll('input[type="color"]');
|
||
if (colorInputs.length > 0) {
|
||
await fireEvent.input(colorInputs[0], { target: { value: "#ff0000" } });
|
||
|
||
// Color change should be handled in the component
|
||
expect(container).toBeTruthy(); // Basic check that component still renders
|
||
}
|
||
});
|
||
|
||
it("should handle text alignment changes", async () => {
|
||
const { container } = render(TextManager, {
|
||
props: {
|
||
texts: [],
|
||
onTextAdd: mockOnTextAdd,
|
||
onTextUpdate: mockOnTextUpdate,
|
||
onTextDelete: mockOnTextDelete,
|
||
},
|
||
});
|
||
|
||
// Look for alignment buttons or radio buttons
|
||
const radioButtons = screen.getAllByRole("radio");
|
||
if (radioButtons.length > 0) {
|
||
await fireEvent.click(radioButtons[0]);
|
||
expect(container).toBeTruthy(); // Basic check that component still renders
|
||
}
|
||
});
|
||
|
||
it("should call updateAllTextSettings when update all button is clicked", async () => {
|
||
const { updateAllTextSettings } = await import("$stores/panelStore");
|
||
|
||
render(TextManager, {
|
||
props: {
|
||
texts: [],
|
||
onTextAdd: mockOnTextAdd,
|
||
onTextUpdate: mockOnTextUpdate,
|
||
onTextDelete: mockOnTextDelete,
|
||
},
|
||
});
|
||
|
||
// Look for "Update All" or similar button
|
||
const buttons = screen.getAllByRole("button");
|
||
const updateAllButton = buttons.find(
|
||
(button) =>
|
||
button.textContent?.includes("Update All") ||
|
||
button.textContent?.includes("Apply to All") ||
|
||
button.textContent?.includes("Сохранить"),
|
||
);
|
||
|
||
if (updateAllButton) {
|
||
await fireEvent.click(updateAllButton);
|
||
expect(updateAllTextSettings).toHaveBeenCalled();
|
||
}
|
||
});
|
||
});
|