mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
Add frontend unit tests for build stores and components
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
import React from "react";
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import { TooltipProvider } from "@radix-ui/react-tooltip";
|
||||
import { DraftRecoveryPopup } from "../components/DraftRecoveryDialog/DraftRecoveryPopup";
|
||||
|
||||
const mockOnLoad = vi.fn();
|
||||
const mockOnDiscard = vi.fn();
|
||||
|
||||
vi.mock("../components/DraftRecoveryDialog/useDraftRecoveryPopup", () => ({
|
||||
useDraftRecoveryPopup: vi.fn(() => ({
|
||||
isOpen: true,
|
||||
popupRef: { current: null },
|
||||
nodeCount: 3,
|
||||
edgeCount: 2,
|
||||
diff: {
|
||||
nodes: { added: 1, removed: 0, modified: 2 },
|
||||
edges: { added: 1, removed: 1, modified: 0 },
|
||||
},
|
||||
savedAt: Date.now(),
|
||||
onLoad: mockOnLoad,
|
||||
onDiscard: mockOnDiscard,
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock("framer-motion", () => ({
|
||||
AnimatePresence: ({ children }: { children: React.ReactNode }) => (
|
||||
<>{children}</>
|
||||
),
|
||||
motion: {
|
||||
div: React.forwardRef(function MotionDiv(
|
||||
props: Record<string, unknown>,
|
||||
ref: React.Ref<HTMLDivElement>,
|
||||
) {
|
||||
const { children, initial, animate, exit, transition, ...rest } =
|
||||
props as {
|
||||
children?: React.ReactNode;
|
||||
initial?: unknown;
|
||||
animate?: unknown;
|
||||
exit?: unknown;
|
||||
transition?: unknown;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
return (
|
||||
<div ref={ref} {...rest}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
function renderWithProviders(ui: React.ReactElement) {
|
||||
return render(<TooltipProvider>{ui}</TooltipProvider>);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("DraftRecoveryPopup", () => {
|
||||
describe("when open with diff data", () => {
|
||||
it("shows the unsaved changes message", () => {
|
||||
renderWithProviders(<DraftRecoveryPopup isInitialLoadComplete={true} />);
|
||||
expect(screen.getByText("Unsaved changes found")).toBeDefined();
|
||||
});
|
||||
|
||||
it("displays diff summary", () => {
|
||||
renderWithProviders(<DraftRecoveryPopup isInitialLoadComplete={true} />);
|
||||
const text = document.body.textContent;
|
||||
expect(text).toContain("+1/~2 blocks");
|
||||
expect(text).toContain("+1/-1 connections");
|
||||
});
|
||||
|
||||
it("renders restore and discard buttons", () => {
|
||||
renderWithProviders(<DraftRecoveryPopup isInitialLoadComplete={true} />);
|
||||
expect(screen.getAllByText("Restore changes").length).toBeGreaterThan(0);
|
||||
expect(screen.getAllByText("Discard changes").length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("calls onLoad when restore is clicked", () => {
|
||||
renderWithProviders(<DraftRecoveryPopup isInitialLoadComplete={true} />);
|
||||
const buttons = screen.getAllByRole("button", {
|
||||
name: /restore changes/i,
|
||||
});
|
||||
fireEvent.click(buttons[0]);
|
||||
expect(mockOnLoad).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("calls onDiscard when discard is clicked", () => {
|
||||
renderWithProviders(<DraftRecoveryPopup isInitialLoadComplete={true} />);
|
||||
const buttons = screen.getAllByRole("button", {
|
||||
name: /discard changes/i,
|
||||
});
|
||||
fireEvent.click(buttons[0]);
|
||||
expect(mockOnDiscard).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when closed", () => {
|
||||
it("renders nothing when isOpen is false", async () => {
|
||||
const { useDraftRecoveryPopup } = await import(
|
||||
"../components/DraftRecoveryDialog/useDraftRecoveryPopup"
|
||||
);
|
||||
vi.mocked(useDraftRecoveryPopup).mockReturnValue({
|
||||
isOpen: false,
|
||||
popupRef: { current: null },
|
||||
nodeCount: 0,
|
||||
edgeCount: 0,
|
||||
diff: null,
|
||||
savedAt: 0,
|
||||
onLoad: vi.fn(),
|
||||
onDiscard: vi.fn(),
|
||||
});
|
||||
|
||||
const { container } = renderWithProviders(
|
||||
<DraftRecoveryPopup isInitialLoadComplete={true} />,
|
||||
);
|
||||
expect(container.textContent).toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
describe("when diff is null", () => {
|
||||
it("falls back to node/edge count display", async () => {
|
||||
const { useDraftRecoveryPopup } = await import(
|
||||
"../components/DraftRecoveryDialog/useDraftRecoveryPopup"
|
||||
);
|
||||
vi.mocked(useDraftRecoveryPopup).mockReturnValue({
|
||||
isOpen: true,
|
||||
popupRef: { current: null },
|
||||
nodeCount: 5,
|
||||
edgeCount: 1,
|
||||
diff: null,
|
||||
savedAt: Date.now(),
|
||||
onLoad: vi.fn(),
|
||||
onDiscard: vi.fn(),
|
||||
});
|
||||
|
||||
renderWithProviders(<DraftRecoveryPopup isInitialLoadComplete={true} />);
|
||||
const text = document.body.textContent;
|
||||
expect(text).toContain("5 blocks");
|
||||
expect(text).toContain("1 connection");
|
||||
});
|
||||
|
||||
it("uses singular for 1 block", async () => {
|
||||
const { useDraftRecoveryPopup } = await import(
|
||||
"../components/DraftRecoveryDialog/useDraftRecoveryPopup"
|
||||
);
|
||||
vi.mocked(useDraftRecoveryPopup).mockReturnValue({
|
||||
isOpen: true,
|
||||
popupRef: { current: null },
|
||||
nodeCount: 1,
|
||||
edgeCount: 0,
|
||||
diff: null,
|
||||
savedAt: Date.now(),
|
||||
onLoad: vi.fn(),
|
||||
onDiscard: vi.fn(),
|
||||
});
|
||||
|
||||
renderWithProviders(<DraftRecoveryPopup isInitialLoadComplete={true} />);
|
||||
const text = document.body.textContent;
|
||||
expect(text).toContain("1 block,");
|
||||
expect(text).toContain("0 connections");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,246 @@
|
||||
import { describe, it, expect, beforeEach } from "vitest";
|
||||
import { useBlockMenuStore } from "../stores/blockMenuStore";
|
||||
import { DefaultStateType } from "../components/NewControlPanel/NewBlockMenu/types";
|
||||
import { SearchEntryFilterAnyOfItem } from "@/app/api/__generated__/models/searchEntryFilterAnyOfItem";
|
||||
import { StoreAgent } from "@/app/api/__generated__/models/storeAgent";
|
||||
import { SearchResponseItemsItem } from "@/app/api/__generated__/models/searchResponseItemsItem";
|
||||
|
||||
beforeEach(() => {
|
||||
useBlockMenuStore.setState({
|
||||
searchQuery: "",
|
||||
searchId: undefined,
|
||||
defaultState: DefaultStateType.SUGGESTION,
|
||||
integration: undefined,
|
||||
filters: [],
|
||||
creators: [],
|
||||
creators_list: [],
|
||||
categoryCounts: {
|
||||
blocks: 0,
|
||||
integrations: 0,
|
||||
marketplace_agents: 0,
|
||||
my_agents: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe("blockMenuStore", () => {
|
||||
describe("initial state", () => {
|
||||
it("has empty search and suggestion default state", () => {
|
||||
const state = useBlockMenuStore.getState();
|
||||
expect(state.searchQuery).toBe("");
|
||||
expect(state.searchId).toBeUndefined();
|
||||
expect(state.defaultState).toBe("suggestion");
|
||||
expect(state.integration).toBeUndefined();
|
||||
expect(state.filters).toEqual([]);
|
||||
expect(state.creators).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("search state", () => {
|
||||
it("sets search query", () => {
|
||||
useBlockMenuStore.getState().setSearchQuery("weather");
|
||||
expect(useBlockMenuStore.getState().searchQuery).toBe("weather");
|
||||
});
|
||||
|
||||
it("sets search id", () => {
|
||||
useBlockMenuStore.getState().setSearchId("abc-123");
|
||||
expect(useBlockMenuStore.getState().searchId).toBe("abc-123");
|
||||
});
|
||||
|
||||
it("clears search id", () => {
|
||||
useBlockMenuStore.getState().setSearchId("abc-123");
|
||||
useBlockMenuStore.getState().setSearchId(undefined);
|
||||
expect(useBlockMenuStore.getState().searchId).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("default state", () => {
|
||||
it("sets default state", () => {
|
||||
useBlockMenuStore.getState().setDefaultState(DefaultStateType.ALL_BLOCKS);
|
||||
expect(useBlockMenuStore.getState().defaultState).toBe(
|
||||
DefaultStateType.ALL_BLOCKS,
|
||||
);
|
||||
});
|
||||
|
||||
it("changes between states", () => {
|
||||
useBlockMenuStore
|
||||
.getState()
|
||||
.setDefaultState(DefaultStateType.INTEGRATIONS);
|
||||
useBlockMenuStore.getState().setDefaultState(DefaultStateType.MY_AGENTS);
|
||||
expect(useBlockMenuStore.getState().defaultState).toBe(
|
||||
DefaultStateType.MY_AGENTS,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("integration", () => {
|
||||
it("sets integration", () => {
|
||||
useBlockMenuStore.getState().setIntegration("slack");
|
||||
expect(useBlockMenuStore.getState().integration).toBe("slack");
|
||||
});
|
||||
|
||||
it("clears integration", () => {
|
||||
useBlockMenuStore.getState().setIntegration("slack");
|
||||
useBlockMenuStore.getState().setIntegration(undefined);
|
||||
expect(useBlockMenuStore.getState().integration).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("filters", () => {
|
||||
it("adds a filter", () => {
|
||||
useBlockMenuStore.getState().addFilter(SearchEntryFilterAnyOfItem.blocks);
|
||||
expect(useBlockMenuStore.getState().filters).toEqual(["blocks"]);
|
||||
});
|
||||
|
||||
it("adds multiple filters", () => {
|
||||
useBlockMenuStore.getState().addFilter(SearchEntryFilterAnyOfItem.blocks);
|
||||
useBlockMenuStore
|
||||
.getState()
|
||||
.addFilter(SearchEntryFilterAnyOfItem.integrations);
|
||||
expect(useBlockMenuStore.getState().filters).toEqual([
|
||||
"blocks",
|
||||
"integrations",
|
||||
]);
|
||||
});
|
||||
|
||||
it("removes a filter", () => {
|
||||
useBlockMenuStore.getState().addFilter(SearchEntryFilterAnyOfItem.blocks);
|
||||
useBlockMenuStore
|
||||
.getState()
|
||||
.addFilter(SearchEntryFilterAnyOfItem.integrations);
|
||||
useBlockMenuStore
|
||||
.getState()
|
||||
.removeFilter(SearchEntryFilterAnyOfItem.blocks);
|
||||
expect(useBlockMenuStore.getState().filters).toEqual(["integrations"]);
|
||||
});
|
||||
|
||||
it("sets filters directly", () => {
|
||||
useBlockMenuStore
|
||||
.getState()
|
||||
.setFilters([
|
||||
SearchEntryFilterAnyOfItem.my_agents,
|
||||
SearchEntryFilterAnyOfItem.marketplace_agents,
|
||||
]);
|
||||
expect(useBlockMenuStore.getState().filters).toEqual([
|
||||
"my_agents",
|
||||
"marketplace_agents",
|
||||
]);
|
||||
});
|
||||
|
||||
it("removing a non-existent filter is a no-op", () => {
|
||||
useBlockMenuStore.getState().addFilter(SearchEntryFilterAnyOfItem.blocks);
|
||||
useBlockMenuStore
|
||||
.getState()
|
||||
.removeFilter(SearchEntryFilterAnyOfItem.integrations);
|
||||
expect(useBlockMenuStore.getState().filters).toEqual(["blocks"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("creators", () => {
|
||||
it("adds a creator", () => {
|
||||
useBlockMenuStore.getState().addCreator("alice");
|
||||
expect(useBlockMenuStore.getState().creators).toEqual(["alice"]);
|
||||
});
|
||||
|
||||
it("removes a creator", () => {
|
||||
useBlockMenuStore.getState().addCreator("alice");
|
||||
useBlockMenuStore.getState().addCreator("bob");
|
||||
useBlockMenuStore.getState().removeCreator("alice");
|
||||
expect(useBlockMenuStore.getState().creators).toEqual(["bob"]);
|
||||
});
|
||||
|
||||
it("sets creators directly", () => {
|
||||
useBlockMenuStore.getState().setCreators(["x", "y"]);
|
||||
expect(useBlockMenuStore.getState().creators).toEqual(["x", "y"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setCreatorsList", () => {
|
||||
it("extracts creators from store_agent items", () => {
|
||||
const items: SearchResponseItemsItem[] = [
|
||||
{
|
||||
slug: "agent-1",
|
||||
agent_name: "Agent 1",
|
||||
creator: "alice",
|
||||
} as StoreAgent,
|
||||
{
|
||||
slug: "agent-2",
|
||||
agent_name: "Agent 2",
|
||||
creator: "bob",
|
||||
} as StoreAgent,
|
||||
];
|
||||
|
||||
useBlockMenuStore.getState().setCreatorsList(items);
|
||||
const list = useBlockMenuStore.getState().creators_list;
|
||||
expect(list).toContain("alice");
|
||||
expect(list).toContain("bob");
|
||||
});
|
||||
|
||||
it("deduplicates creators across calls", () => {
|
||||
const items1 = [
|
||||
{
|
||||
slug: "a1",
|
||||
agent_name: "A1",
|
||||
creator: "alice",
|
||||
} as StoreAgent,
|
||||
] as SearchResponseItemsItem[];
|
||||
const items2 = [
|
||||
{
|
||||
slug: "a2",
|
||||
agent_name: "A2",
|
||||
creator: "alice",
|
||||
} as StoreAgent,
|
||||
] as SearchResponseItemsItem[];
|
||||
|
||||
useBlockMenuStore.getState().setCreatorsList(items1);
|
||||
useBlockMenuStore.getState().setCreatorsList(items2);
|
||||
|
||||
const aliceCount = useBlockMenuStore
|
||||
.getState()
|
||||
.creators_list.filter((c) => c === "alice").length;
|
||||
expect(aliceCount).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("categoryCounts", () => {
|
||||
it("sets category counts", () => {
|
||||
const counts = {
|
||||
blocks: 10,
|
||||
integrations: 5,
|
||||
marketplace_agents: 3,
|
||||
my_agents: 2,
|
||||
};
|
||||
useBlockMenuStore.getState().setCategoryCounts(counts);
|
||||
expect(useBlockMenuStore.getState().categoryCounts).toEqual(counts);
|
||||
});
|
||||
});
|
||||
|
||||
describe("reset", () => {
|
||||
it("resets search query, searchId, defaultState, and integration", () => {
|
||||
useBlockMenuStore.getState().setSearchQuery("test");
|
||||
useBlockMenuStore.getState().setSearchId("id-1");
|
||||
useBlockMenuStore.getState().setDefaultState(DefaultStateType.ALL_BLOCKS);
|
||||
useBlockMenuStore.getState().setIntegration("slack");
|
||||
useBlockMenuStore.getState().addFilter(SearchEntryFilterAnyOfItem.blocks);
|
||||
useBlockMenuStore.getState().addCreator("alice");
|
||||
|
||||
useBlockMenuStore.getState().reset();
|
||||
|
||||
const state = useBlockMenuStore.getState();
|
||||
expect(state.searchQuery).toBe("");
|
||||
expect(state.searchId).toBeUndefined();
|
||||
expect(state.defaultState).toBe("suggestion");
|
||||
expect(state.integration).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not clear filters or creators", () => {
|
||||
useBlockMenuStore.getState().addFilter(SearchEntryFilterAnyOfItem.blocks);
|
||||
useBlockMenuStore.getState().addCreator("alice");
|
||||
|
||||
useBlockMenuStore.getState().reset();
|
||||
|
||||
expect(useBlockMenuStore.getState().filters).toEqual(["blocks"]);
|
||||
expect(useBlockMenuStore.getState().creators).toEqual(["alice"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,104 @@
|
||||
import { describe, it, expect, beforeEach } from "vitest";
|
||||
import { useControlPanelStore } from "../stores/controlPanelStore";
|
||||
|
||||
beforeEach(() => {
|
||||
useControlPanelStore.getState().reset();
|
||||
});
|
||||
|
||||
describe("controlPanelStore", () => {
|
||||
describe("initial state", () => {
|
||||
it("starts with all panels closed", () => {
|
||||
const state = useControlPanelStore.getState();
|
||||
expect(state.blockMenuOpen).toBe(false);
|
||||
expect(state.saveControlOpen).toBe(false);
|
||||
expect(state.forceOpenBlockMenu).toBe(false);
|
||||
expect(state.forceOpenSave).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setBlockMenuOpen", () => {
|
||||
it("opens the block menu", () => {
|
||||
useControlPanelStore.getState().setBlockMenuOpen(true);
|
||||
expect(useControlPanelStore.getState().blockMenuOpen).toBe(true);
|
||||
});
|
||||
|
||||
it("closes the block menu", () => {
|
||||
useControlPanelStore.getState().setBlockMenuOpen(true);
|
||||
useControlPanelStore.getState().setBlockMenuOpen(false);
|
||||
expect(useControlPanelStore.getState().blockMenuOpen).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setSaveControlOpen", () => {
|
||||
it("opens the save control", () => {
|
||||
useControlPanelStore.getState().setSaveControlOpen(true);
|
||||
expect(useControlPanelStore.getState().saveControlOpen).toBe(true);
|
||||
});
|
||||
|
||||
it("closes the save control", () => {
|
||||
useControlPanelStore.getState().setSaveControlOpen(true);
|
||||
useControlPanelStore.getState().setSaveControlOpen(false);
|
||||
expect(useControlPanelStore.getState().saveControlOpen).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setForceOpenBlockMenu", () => {
|
||||
it("sets force open state", () => {
|
||||
useControlPanelStore.getState().setForceOpenBlockMenu(true);
|
||||
expect(useControlPanelStore.getState().forceOpenBlockMenu).toBe(true);
|
||||
});
|
||||
|
||||
it("does not affect blockMenuOpen", () => {
|
||||
useControlPanelStore.getState().setForceOpenBlockMenu(true);
|
||||
expect(useControlPanelStore.getState().blockMenuOpen).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setForceOpenSave", () => {
|
||||
it("sets force open state", () => {
|
||||
useControlPanelStore.getState().setForceOpenSave(true);
|
||||
expect(useControlPanelStore.getState().forceOpenSave).toBe(true);
|
||||
});
|
||||
|
||||
it("does not affect saveControlOpen", () => {
|
||||
useControlPanelStore.getState().setForceOpenSave(true);
|
||||
expect(useControlPanelStore.getState().saveControlOpen).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("independent panel state", () => {
|
||||
it("opening block menu does not affect save control", () => {
|
||||
useControlPanelStore.getState().setBlockMenuOpen(true);
|
||||
expect(useControlPanelStore.getState().saveControlOpen).toBe(false);
|
||||
});
|
||||
|
||||
it("opening save control does not affect block menu", () => {
|
||||
useControlPanelStore.getState().setSaveControlOpen(true);
|
||||
expect(useControlPanelStore.getState().blockMenuOpen).toBe(false);
|
||||
});
|
||||
|
||||
it("both panels can be open simultaneously", () => {
|
||||
useControlPanelStore.getState().setBlockMenuOpen(true);
|
||||
useControlPanelStore.getState().setSaveControlOpen(true);
|
||||
expect(useControlPanelStore.getState().blockMenuOpen).toBe(true);
|
||||
expect(useControlPanelStore.getState().saveControlOpen).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("reset", () => {
|
||||
it("resets all state to defaults", () => {
|
||||
useControlPanelStore.getState().setBlockMenuOpen(true);
|
||||
useControlPanelStore.getState().setSaveControlOpen(true);
|
||||
useControlPanelStore.getState().setForceOpenBlockMenu(true);
|
||||
useControlPanelStore.getState().setForceOpenSave(true);
|
||||
|
||||
useControlPanelStore.getState().reset();
|
||||
|
||||
const state = useControlPanelStore.getState();
|
||||
expect(state.blockMenuOpen).toBe(false);
|
||||
expect(state.saveControlOpen).toBe(false);
|
||||
expect(state.forceOpenBlockMenu).toBe(false);
|
||||
expect(state.forceOpenSave).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,118 @@
|
||||
import { describe, it, expect, beforeEach } from "vitest";
|
||||
import { useTutorialStore } from "../stores/tutorialStore";
|
||||
|
||||
beforeEach(() => {
|
||||
useTutorialStore.setState({
|
||||
isTutorialRunning: false,
|
||||
currentStep: 0,
|
||||
forceOpenRunInputDialog: false,
|
||||
tutorialInputValues: {},
|
||||
});
|
||||
});
|
||||
|
||||
describe("tutorialStore", () => {
|
||||
describe("initial state", () => {
|
||||
it("starts with tutorial not running at step 0", () => {
|
||||
const state = useTutorialStore.getState();
|
||||
expect(state.isTutorialRunning).toBe(false);
|
||||
expect(state.currentStep).toBe(0);
|
||||
expect(state.forceOpenRunInputDialog).toBe(false);
|
||||
expect(state.tutorialInputValues).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe("setIsTutorialRunning", () => {
|
||||
it("starts the tutorial", () => {
|
||||
useTutorialStore.getState().setIsTutorialRunning(true);
|
||||
expect(useTutorialStore.getState().isTutorialRunning).toBe(true);
|
||||
});
|
||||
|
||||
it("stops the tutorial", () => {
|
||||
useTutorialStore.getState().setIsTutorialRunning(true);
|
||||
useTutorialStore.getState().setIsTutorialRunning(false);
|
||||
expect(useTutorialStore.getState().isTutorialRunning).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setCurrentStep", () => {
|
||||
it("advances to a step", () => {
|
||||
useTutorialStore.getState().setCurrentStep(3);
|
||||
expect(useTutorialStore.getState().currentStep).toBe(3);
|
||||
});
|
||||
|
||||
it("can go back to a previous step", () => {
|
||||
useTutorialStore.getState().setCurrentStep(5);
|
||||
useTutorialStore.getState().setCurrentStep(2);
|
||||
expect(useTutorialStore.getState().currentStep).toBe(2);
|
||||
});
|
||||
|
||||
it("can reset to step 0", () => {
|
||||
useTutorialStore.getState().setCurrentStep(4);
|
||||
useTutorialStore.getState().setCurrentStep(0);
|
||||
expect(useTutorialStore.getState().currentStep).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setForceOpenRunInputDialog", () => {
|
||||
it("forces the dialog open", () => {
|
||||
useTutorialStore.getState().setForceOpenRunInputDialog(true);
|
||||
expect(useTutorialStore.getState().forceOpenRunInputDialog).toBe(true);
|
||||
});
|
||||
|
||||
it("closes the forced dialog", () => {
|
||||
useTutorialStore.getState().setForceOpenRunInputDialog(true);
|
||||
useTutorialStore.getState().setForceOpenRunInputDialog(false);
|
||||
expect(useTutorialStore.getState().forceOpenRunInputDialog).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setTutorialInputValues", () => {
|
||||
it("sets input values", () => {
|
||||
useTutorialStore
|
||||
.getState()
|
||||
.setTutorialInputValues({ topic: "AI agents" });
|
||||
expect(useTutorialStore.getState().tutorialInputValues).toEqual({
|
||||
topic: "AI agents",
|
||||
});
|
||||
});
|
||||
|
||||
it("replaces previous values entirely", () => {
|
||||
useTutorialStore.getState().setTutorialInputValues({ a: "1" });
|
||||
useTutorialStore.getState().setTutorialInputValues({ b: "2" });
|
||||
expect(useTutorialStore.getState().tutorialInputValues).toEqual({
|
||||
b: "2",
|
||||
});
|
||||
});
|
||||
|
||||
it("clears values with empty object", () => {
|
||||
useTutorialStore.getState().setTutorialInputValues({ x: "y" });
|
||||
useTutorialStore.getState().setTutorialInputValues({});
|
||||
expect(useTutorialStore.getState().tutorialInputValues).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe("step progression lifecycle", () => {
|
||||
it("simulates a full tutorial run", () => {
|
||||
useTutorialStore.getState().setIsTutorialRunning(true);
|
||||
expect(useTutorialStore.getState().isTutorialRunning).toBe(true);
|
||||
|
||||
useTutorialStore.getState().setCurrentStep(1);
|
||||
useTutorialStore.getState().setCurrentStep(2);
|
||||
useTutorialStore.getState().setCurrentStep(3);
|
||||
|
||||
useTutorialStore.getState().setForceOpenRunInputDialog(true);
|
||||
useTutorialStore
|
||||
.getState()
|
||||
.setTutorialInputValues({ prompt: "test prompt" });
|
||||
useTutorialStore.getState().setForceOpenRunInputDialog(false);
|
||||
|
||||
useTutorialStore.getState().setCurrentStep(4);
|
||||
useTutorialStore.getState().setIsTutorialRunning(false);
|
||||
useTutorialStore.getState().setCurrentStep(0);
|
||||
|
||||
const state = useTutorialStore.getState();
|
||||
expect(state.isTutorialRunning).toBe(false);
|
||||
expect(state.currentStep).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user