diff --git a/webui/src/__tests__/App.test.tsx b/webui/src/__tests__/App.test.tsx index 7289016..1d22531 100644 --- a/webui/src/__tests__/App.test.tsx +++ b/webui/src/__tests__/App.test.tsx @@ -1,10 +1,11 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest' +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import App from '@/App' import { InstancesProvider } from '@/contexts/InstancesContext' import { instancesApi } from '@/lib/api' import type { Instance } from '@/types/instance' +import { AuthProvider } from '@/contexts/AuthContext' // Mock the API vi.mock('@/lib/api', () => ({ @@ -35,9 +36,11 @@ vi.mock('@/lib/healthService', () => ({ function renderApp() { return render( - - - + + + + + ) } @@ -50,6 +53,12 @@ describe('App Component - Critical Business Logic Only', () => { beforeEach(() => { vi.clearAllMocks() vi.mocked(instancesApi.list).mockResolvedValue(mockInstances) + window.sessionStorage.setItem('llamactl_management_key', 'test-api-key-123') + global.fetch = vi.fn(() => Promise.resolve(new Response(null, { status: 200 }))) + }) + + afterEach(() => { + vi.restoreAllMocks() }) describe('End-to-End Instance Management', () => { @@ -167,7 +176,6 @@ describe('App Component - Critical Business Logic Only', () => { renderApp() // App should still render and show error - expect(screen.getByText('Llamactl Dashboard')).toBeInTheDocument() await waitFor(() => { expect(screen.getByText('Error loading instances')).toBeInTheDocument() }) diff --git a/webui/src/components/LoginDialog.tsx b/webui/src/components/LoginDialog.tsx index 3f29948..652f448 100644 --- a/webui/src/components/LoginDialog.tsx +++ b/webui/src/components/LoginDialog.tsx @@ -62,12 +62,6 @@ const LoginDialog: React.FC = ({ } } - const handleCancel = () => { - setApiKey('') - clearError() - onOpenChange?.(false) - } - const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !isSubmitDisabled) { // Create a synthetic FormEvent to satisfy handleSubmit's type diff --git a/webui/src/components/__tests__/InstanceCard.test.tsx b/webui/src/components/__tests__/InstanceCard.test.tsx index 743f370..4429e4f 100644 --- a/webui/src/components/__tests__/InstanceCard.test.tsx +++ b/webui/src/components/__tests__/InstanceCard.test.tsx @@ -1,4 +1,4 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest' +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import InstanceCard from '@/components/InstanceCard' @@ -27,9 +27,15 @@ describe('InstanceCard - Instance Actions and State', () => { options: { model: 'running-model.gguf' } } - beforeEach(() => { - vi.clearAllMocks() - }) +beforeEach(() => { + vi.clearAllMocks() + window.sessionStorage.setItem('llamactl_management_key', 'test-api-key-123') + global.fetch = vi.fn(() => Promise.resolve(new Response(null, { status: 200 }))) +}) + +afterEach(() => { + vi.restoreAllMocks() +}) describe('Instance Action Buttons', () => { it('calls startInstance when start button clicked on stopped instance', async () => { diff --git a/webui/src/components/__tests__/InstanceList.test.tsx b/webui/src/components/__tests__/InstanceList.test.tsx index 0d047f8..b237987 100644 --- a/webui/src/components/__tests__/InstanceList.test.tsx +++ b/webui/src/components/__tests__/InstanceList.test.tsx @@ -1,10 +1,11 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest' +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import InstanceList from '@/components/InstanceList' import { InstancesProvider } from '@/contexts/InstancesContext' import { instancesApi } from '@/lib/api' import type { Instance } from '@/types/instance' +import { AuthProvider } from '@/contexts/AuthContext' // Mock the API vi.mock('@/lib/api', () => ({ @@ -30,13 +31,16 @@ vi.mock('@/lib/healthService', () => ({ function renderInstanceList(editInstance = vi.fn()) { return render( - - - + + + + + ) } describe('InstanceList - State Management and UI Logic', () => { + const mockEditInstance = vi.fn() const mockInstances: Instance[] = [ @@ -45,12 +49,20 @@ describe('InstanceList - State Management and UI Logic', () => { { name: 'instance-3', running: false, options: { model: 'model3.gguf' } } ] + const DUMMY_API_KEY = 'test-api-key-123' + beforeEach(() => { vi.clearAllMocks() + window.sessionStorage.setItem('llamactl_management_key', DUMMY_API_KEY) + global.fetch = vi.fn(() => Promise.resolve(new Response(null, { status: 200 }))) + }) + + afterEach(() => { + vi.restoreAllMocks() }) describe('Loading State', () => { - it('shows loading spinner while instances are being fetched', async () => { + it('shows loading spinner while instances are being fetched', () => { // Mock a delayed response to test loading state vi.mocked(instancesApi.list).mockImplementation(() => new Promise(resolve => setTimeout(() => resolve(mockInstances), 100)) @@ -220,27 +232,5 @@ describe('InstanceList - State Management and UI Logic', () => { expect(await screen.findByText('Instances (3)')).toBeInTheDocument() expect(screen.queryByText('Loading instances...')).not.toBeInTheDocument() }) - - it('handles transition from error back to loaded state', async () => { - // Start with error - vi.mocked(instancesApi.list).mockRejectedValue(new Error('Network error')) - - const { rerender } = renderInstanceList(mockEditInstance) - - expect(await screen.findByText('Error loading instances')).toBeInTheDocument() - - // Simulate recovery (e.g., retry after network recovery) - vi.mocked(instancesApi.list).mockResolvedValue(mockInstances) - - rerender( - - - - ) - - // Should eventually show instances - // Note: This test is somewhat artificial since the context handles retries - expect(screen.getByText('Error loading instances')).toBeInTheDocument() - }) }) }) \ No newline at end of file diff --git a/webui/src/components/__tests__/InstanceModal.test.tsx b/webui/src/components/__tests__/InstanceModal.test.tsx index 830e2f4..926d214 100644 --- a/webui/src/components/__tests__/InstanceModal.test.tsx +++ b/webui/src/components/__tests__/InstanceModal.test.tsx @@ -1,4 +1,4 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest' +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import InstanceDialog from '@/components/InstanceDialog' @@ -8,9 +8,15 @@ describe('InstanceModal - Form Logic and Validation', () => { const mockOnSave = vi.fn() const mockOnOpenChange = vi.fn() - beforeEach(() => { - vi.clearAllMocks() - }) +beforeEach(() => { + vi.clearAllMocks() + window.sessionStorage.setItem('llamactl_management_key', 'test-api-key-123') + global.fetch = vi.fn(() => Promise.resolve(new Response(null, { status: 200 }))) +}) + +afterEach(() => { + vi.restoreAllMocks() +}) describe('Create Mode', () => { it('validates instance name is required', async () => { diff --git a/webui/src/contexts/__tests__/InstancesContext.test.tsx b/webui/src/contexts/__tests__/InstancesContext.test.tsx index d0d5fb4..aa4e8e3 100644 --- a/webui/src/contexts/__tests__/InstancesContext.test.tsx +++ b/webui/src/contexts/__tests__/InstancesContext.test.tsx @@ -1,12 +1,13 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' -import { render, screen, waitFor } from '@testing-library/react' -import type { ReactNode } from 'react' -import { InstancesProvider, useInstances } from '@/contexts/InstancesContext' -import { instancesApi } from '@/lib/api' -import type { Instance } from '@/types/instance' +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { render, screen, waitFor } from "@testing-library/react"; +import type { ReactNode } from "react"; +import { InstancesProvider, useInstances } from "@/contexts/InstancesContext"; +import { instancesApi } from "@/lib/api"; +import type { Instance } from "@/types/instance"; +import { AuthProvider } from "../AuthContext"; // Mock the API module -vi.mock('@/lib/api', () => ({ +vi.mock("@/lib/api", () => ({ instancesApi: { list: vi.fn(), create: vi.fn(), @@ -15,8 +16,8 @@ vi.mock('@/lib/api', () => ({ stop: vi.fn(), restart: vi.fn(), delete: vi.fn(), - } -})) + }, +})); // Test component to access context function TestComponent() { @@ -30,366 +31,389 @@ function TestComponent() { stopInstance, restartInstance, deleteInstance, - clearError - } = useInstances() + clearError, + } = useInstances(); return (
{loading.toString()}
-
{error || 'no-error'}
+
{error || "no-error"}
{instances.length}
- {instances.map(instance => ( + {instances.map((instance) => (
{instance.name}:{instance.running.toString()}
))} - + {/* Action buttons for testing with specific instances */} - - - - - - -
- ) + ); } function renderWithProvider(children: ReactNode) { return render( - - {children} - - ) + + {children} + + ); } -describe('InstancesContext', () => { +describe("InstancesContext", () => { const mockInstances: Instance[] = [ - { name: 'instance1', running: true, options: { model: 'model1.gguf' } }, - { name: 'instance2', running: false, options: { model: 'model2.gguf' } } - ] + { name: "instance1", running: true, options: { model: "model1.gguf" } }, + { name: "instance2", running: false, options: { model: "model2.gguf" } }, + ]; beforeEach(() => { - vi.clearAllMocks() + vi.clearAllMocks(); + window.sessionStorage.setItem('llamactl_management_key', 'test-api-key-123'); + global.fetch = vi.fn(() => Promise.resolve(new Response(null, { status: 200 }))); // Default successful API responses - vi.mocked(instancesApi.list).mockResolvedValue(mockInstances) - }) + vi.mocked(instancesApi.list).mockResolvedValue(mockInstances); + }); afterEach(() => { - vi.clearAllMocks() - }) + vi.restoreAllMocks(); + }); - describe('Initial Loading', () => { - it('loads instances on mount', async () => { - renderWithProvider() + describe("Initial Loading", () => { + it("loads instances on mount", async () => { + renderWithProvider(); // Should start loading - expect(screen.getByTestId('loading')).toHaveTextContent('true') - + expect(screen.getByTestId("loading")).toHaveTextContent("true"); + // Should fetch instances await waitFor(() => { - expect(instancesApi.list).toHaveBeenCalledOnce() - }) + expect(instancesApi.list).toHaveBeenCalledOnce(); + }); // Should display loaded instances await waitFor(() => { - expect(screen.getByTestId('loading')).toHaveTextContent('false') - expect(screen.getByTestId('instances-count')).toHaveTextContent('2') - expect(screen.getByTestId('instance-instance1')).toHaveTextContent('instance1:true') - expect(screen.getByTestId('instance-instance2')).toHaveTextContent('instance2:false') - }) - }) + expect(screen.getByTestId("loading")).toHaveTextContent("false"); + expect(screen.getByTestId("instances-count")).toHaveTextContent("2"); + expect(screen.getByTestId("instance-instance1")).toHaveTextContent( + "instance1:true" + ); + expect(screen.getByTestId("instance-instance2")).toHaveTextContent( + "instance2:false" + ); + }); + }); - it('handles API error during initial load', async () => { - const errorMessage = 'Network error' - vi.mocked(instancesApi.list).mockRejectedValue(new Error(errorMessage)) + it("handles API error during initial load", async () => { + const errorMessage = "Network error"; + vi.mocked(instancesApi.list).mockRejectedValue(new Error(errorMessage)); - renderWithProvider() + renderWithProvider(); await waitFor(() => { - expect(screen.getByTestId('loading')).toHaveTextContent('false') - expect(screen.getByTestId('error')).toHaveTextContent(errorMessage) - expect(screen.getByTestId('instances-count')).toHaveTextContent('0') - }) - }) - }) + expect(screen.getByTestId("loading")).toHaveTextContent("false"); + expect(screen.getByTestId("error")).toHaveTextContent(errorMessage); + expect(screen.getByTestId("instances-count")).toHaveTextContent("0"); + }); + }); + }); - describe('Create Instance', () => { - it('creates instance and adds it to state', async () => { - const newInstance: Instance = { - name: 'new-instance', - running: false, - options: { model: 'test.gguf' } - } - vi.mocked(instancesApi.create).mockResolvedValue(newInstance) + describe("Create Instance", () => { + it("creates instance and adds it to state", async () => { + const newInstance: Instance = { + name: "new-instance", + running: false, + options: { model: "test.gguf" }, + }; + vi.mocked(instancesApi.create).mockResolvedValue(newInstance); - renderWithProvider() + renderWithProvider(); await waitFor(() => { - expect(screen.getByTestId('loading')).toHaveTextContent('false') - expect(screen.getByTestId('instances-count')).toHaveTextContent('2') - }) + expect(screen.getByTestId("loading")).toHaveTextContent("false"); + expect(screen.getByTestId("instances-count")).toHaveTextContent("2"); + }); - screen.getByTestId('create-instance').click() + screen.getByTestId("create-instance").click(); await waitFor(() => { - expect(instancesApi.create).toHaveBeenCalledWith('new-instance', { model: 'test.gguf' }) - }) + expect(instancesApi.create).toHaveBeenCalledWith("new-instance", { + model: "test.gguf", + }); + }); await waitFor(() => { - expect(screen.getByTestId('instances-count')).toHaveTextContent('3') - expect(screen.getByTestId('instance-new-instance')).toHaveTextContent('new-instance:false') - }) - }) + expect(screen.getByTestId("instances-count")).toHaveTextContent("3"); + expect(screen.getByTestId("instance-new-instance")).toHaveTextContent( + "new-instance:false" + ); + }); + }); - it('handles create instance error without changing state', async () => { - const errorMessage = 'Instance already exists' - vi.mocked(instancesApi.create).mockRejectedValue(new Error(errorMessage)) + it("handles create instance error without changing state", async () => { + const errorMessage = "Instance already exists"; + vi.mocked(instancesApi.create).mockRejectedValue(new Error(errorMessage)); - renderWithProvider() + renderWithProvider(); await waitFor(() => { - expect(screen.getByTestId('loading')).toHaveTextContent('false') - expect(screen.getByTestId('instances-count')).toHaveTextContent('2') - }) + expect(screen.getByTestId("loading")).toHaveTextContent("false"); + expect(screen.getByTestId("instances-count")).toHaveTextContent("2"); + }); - screen.getByTestId('create-instance').click() + screen.getByTestId("create-instance").click(); await waitFor(() => { - expect(screen.getByTestId('error')).toHaveTextContent(errorMessage) - }) + expect(screen.getByTestId("error")).toHaveTextContent(errorMessage); + }); - expect(screen.getByTestId('instances-count')).toHaveTextContent('2') - expect(screen.queryByTestId('instance-new-instance')).not.toBeInTheDocument() - }) - }) + expect(screen.getByTestId("instances-count")).toHaveTextContent("2"); + expect( + screen.queryByTestId("instance-new-instance") + ).not.toBeInTheDocument(); + }); + }); - describe('Update Instance', () => { - it('updates instance and maintains it in state', async () => { - const updatedInstance: Instance = { - name: 'instance1', - running: true, - options: { model: 'updated.gguf' } - } - vi.mocked(instancesApi.update).mockResolvedValue(updatedInstance) + describe("Update Instance", () => { + it("updates instance and maintains it in state", async () => { + const updatedInstance: Instance = { + name: "instance1", + running: true, + options: { model: "updated.gguf" }, + }; + vi.mocked(instancesApi.update).mockResolvedValue(updatedInstance); - renderWithProvider() + renderWithProvider(); await waitFor(() => { - expect(screen.getByTestId('loading')).toHaveTextContent('false') - expect(screen.getByTestId('instances-count')).toHaveTextContent('2') - }) + expect(screen.getByTestId("loading")).toHaveTextContent("false"); + expect(screen.getByTestId("instances-count")).toHaveTextContent("2"); + }); - screen.getByTestId('update-instance').click() + screen.getByTestId("update-instance").click(); await waitFor(() => { - expect(instancesApi.update).toHaveBeenCalledWith('instance1', { model: 'updated.gguf' }) - }) + expect(instancesApi.update).toHaveBeenCalledWith("instance1", { + model: "updated.gguf", + }); + }); await waitFor(() => { - expect(screen.getByTestId('instances-count')).toHaveTextContent('2') - expect(screen.getByTestId('instance-instance1')).toBeInTheDocument() - }) - }) - }) + expect(screen.getByTestId("instances-count")).toHaveTextContent("2"); + expect(screen.getByTestId("instance-instance1")).toBeInTheDocument(); + }); + }); + }); - describe('Start/Stop Instance', () => { - it('starts existing instance and updates its running state', async () => { - vi.mocked(instancesApi.start).mockResolvedValue({} as Instance) + describe("Start/Stop Instance", () => { + it("starts existing instance and updates its running state", async () => { + vi.mocked(instancesApi.start).mockResolvedValue({} as Instance); - renderWithProvider() + renderWithProvider(); await waitFor(() => { - expect(screen.getByTestId('loading')).toHaveTextContent('false') + expect(screen.getByTestId("loading")).toHaveTextContent("false"); // instance2 starts as not running - expect(screen.getByTestId('instance-instance2')).toHaveTextContent('instance2:false') - }) + expect(screen.getByTestId("instance-instance2")).toHaveTextContent( + "instance2:false" + ); + }); // Start instance2 (button already configured to start instance2) - screen.getByTestId('start-instance').click() + screen.getByTestId("start-instance").click(); await waitFor(() => { - expect(instancesApi.start).toHaveBeenCalledWith('instance2') + expect(instancesApi.start).toHaveBeenCalledWith("instance2"); // The running state should be updated to true - expect(screen.getByTestId('instance-instance2')).toHaveTextContent('instance2:true') - }) - }) + expect(screen.getByTestId("instance-instance2")).toHaveTextContent( + "instance2:true" + ); + }); + }); - it('stops instance and updates running state to false', async () => { - vi.mocked(instancesApi.stop).mockResolvedValue({} as Instance) + it("stops instance and updates running state to false", async () => { + vi.mocked(instancesApi.stop).mockResolvedValue({} as Instance); - renderWithProvider() + renderWithProvider(); await waitFor(() => { - expect(screen.getByTestId('loading')).toHaveTextContent('false') + expect(screen.getByTestId("loading")).toHaveTextContent("false"); // instance1 starts as running - expect(screen.getByTestId('instance-instance1')).toHaveTextContent('instance1:true') - }) + expect(screen.getByTestId("instance-instance1")).toHaveTextContent( + "instance1:true" + ); + }); // Stop instance1 (button already configured to stop instance1) - screen.getByTestId('stop-instance').click() + screen.getByTestId("stop-instance").click(); await waitFor(() => { - expect(instancesApi.stop).toHaveBeenCalledWith('instance1') + expect(instancesApi.stop).toHaveBeenCalledWith("instance1"); // The running state should be updated to false - expect(screen.getByTestId('instance-instance1')).toHaveTextContent('instance1:false') - }) - }) + expect(screen.getByTestId("instance-instance1")).toHaveTextContent( + "instance1:false" + ); + }); + }); - it('handles start instance error', async () => { - const errorMessage = 'Failed to start instance' - vi.mocked(instancesApi.start).mockRejectedValue(new Error(errorMessage)) + it("handles start instance error", async () => { + const errorMessage = "Failed to start instance"; + vi.mocked(instancesApi.start).mockRejectedValue(new Error(errorMessage)); - renderWithProvider() + renderWithProvider(); await waitFor(() => { - expect(screen.getByTestId('loading')).toHaveTextContent('false') - }) + expect(screen.getByTestId("loading")).toHaveTextContent("false"); + }); - screen.getByTestId('start-instance').click() + screen.getByTestId("start-instance").click(); await waitFor(() => { - expect(screen.getByTestId('error')).toHaveTextContent(errorMessage) - }) - }) - }) + expect(screen.getByTestId("error")).toHaveTextContent(errorMessage); + }); + }); + }); - describe('Delete Instance', () => { - it('deletes instance and removes it from state', async () => { - vi.mocked(instancesApi.delete).mockResolvedValue(undefined) + describe("Delete Instance", () => { + it("deletes instance and removes it from state", async () => { + vi.mocked(instancesApi.delete).mockResolvedValue(undefined); - renderWithProvider() + renderWithProvider(); await waitFor(() => { - expect(screen.getByTestId('loading')).toHaveTextContent('false') - expect(screen.getByTestId('instances-count')).toHaveTextContent('2') - expect(screen.getByTestId('instance-instance2')).toBeInTheDocument() - }) + expect(screen.getByTestId("loading")).toHaveTextContent("false"); + expect(screen.getByTestId("instances-count")).toHaveTextContent("2"); + expect(screen.getByTestId("instance-instance2")).toBeInTheDocument(); + }); - screen.getByTestId('delete-instance').click() + screen.getByTestId("delete-instance").click(); await waitFor(() => { - expect(instancesApi.delete).toHaveBeenCalledWith('instance2') - }) + expect(instancesApi.delete).toHaveBeenCalledWith("instance2"); + }); await waitFor(() => { - expect(screen.getByTestId('instances-count')).toHaveTextContent('1') - expect(screen.queryByTestId('instance-instance2')).not.toBeInTheDocument() - expect(screen.getByTestId('instance-instance1')).toBeInTheDocument() // instance1 should still exist - }) - }) + expect(screen.getByTestId("instances-count")).toHaveTextContent("1"); + expect( + screen.queryByTestId("instance-instance2") + ).not.toBeInTheDocument(); + expect(screen.getByTestId("instance-instance1")).toBeInTheDocument(); // instance1 should still exist + }); + }); - it('handles delete instance error without changing state', async () => { - const errorMessage = 'Instance is running' - vi.mocked(instancesApi.delete).mockRejectedValue(new Error(errorMessage)) + it("handles delete instance error without changing state", async () => { + const errorMessage = "Instance is running"; + vi.mocked(instancesApi.delete).mockRejectedValue(new Error(errorMessage)); - renderWithProvider() + renderWithProvider(); await waitFor(() => { - expect(screen.getByTestId('loading')).toHaveTextContent('false') - expect(screen.getByTestId('instances-count')).toHaveTextContent('2') - }) + expect(screen.getByTestId("loading")).toHaveTextContent("false"); + expect(screen.getByTestId("instances-count")).toHaveTextContent("2"); + }); - screen.getByTestId('delete-instance').click() + screen.getByTestId("delete-instance").click(); await waitFor(() => { - expect(screen.getByTestId('error')).toHaveTextContent(errorMessage) - }) + expect(screen.getByTestId("error")).toHaveTextContent(errorMessage); + }); - expect(screen.getByTestId('instances-count')).toHaveTextContent('2') - expect(screen.getByTestId('instance-instance2')).toBeInTheDocument() - }) - }) + expect(screen.getByTestId("instances-count")).toHaveTextContent("2"); + expect(screen.getByTestId("instance-instance2")).toBeInTheDocument(); + }); + }); - describe('Error Management', () => { - it('clears error when clearError is called', async () => { - const errorMessage = 'Test error' - vi.mocked(instancesApi.list).mockRejectedValue(new Error(errorMessage)) + describe("Error Management", () => { + it("clears error when clearError is called", async () => { + const errorMessage = "Test error"; + vi.mocked(instancesApi.list).mockRejectedValue(new Error(errorMessage)); - renderWithProvider() + renderWithProvider(); await waitFor(() => { - expect(screen.getByTestId('error')).toHaveTextContent(errorMessage) - }) + expect(screen.getByTestId("error")).toHaveTextContent(errorMessage); + }); - screen.getByTestId('clear-error').click() + screen.getByTestId("clear-error").click(); await waitFor(() => { - expect(screen.getByTestId('error')).toHaveTextContent('no-error') - }) - }) - }) + expect(screen.getByTestId("error")).toHaveTextContent("no-error"); + }); + }); + }); - describe('State Consistency', () => { - it('maintains consistent state during multiple operations', async () => { + describe("State Consistency", () => { + it("maintains consistent state during multiple operations", async () => { // Test that operations don't interfere with each other - const newInstance: Instance = { - name: 'new-instance', - running: false, - options: {} - } - vi.mocked(instancesApi.create).mockResolvedValue(newInstance) - vi.mocked(instancesApi.start).mockResolvedValue({} as Instance) + const newInstance: Instance = { + name: "new-instance", + running: false, + options: {}, + }; + vi.mocked(instancesApi.create).mockResolvedValue(newInstance); + vi.mocked(instancesApi.start).mockResolvedValue({} as Instance); - renderWithProvider() + renderWithProvider(); await waitFor(() => { - expect(screen.getByTestId('loading')).toHaveTextContent('false') - expect(screen.getByTestId('instances-count')).toHaveTextContent('2') - }) + expect(screen.getByTestId("loading")).toHaveTextContent("false"); + expect(screen.getByTestId("instances-count")).toHaveTextContent("2"); + }); // Create new instance - screen.getByTestId('create-instance').click() + screen.getByTestId("create-instance").click(); await waitFor(() => { - expect(screen.getByTestId('instances-count')).toHaveTextContent('3') - }) + expect(screen.getByTestId("instances-count")).toHaveTextContent("3"); + }); // Start an instance (this should not affect the count) - screen.getByTestId('start-instance').click() + screen.getByTestId("start-instance").click(); await waitFor(() => { - expect(instancesApi.start).toHaveBeenCalled() - expect(screen.getByTestId('instances-count')).toHaveTextContent('3') // Still 3 + expect(instancesApi.start).toHaveBeenCalled(); + expect(screen.getByTestId("instances-count")).toHaveTextContent("3"); // Still 3 // But the running state should change - expect(screen.getByTestId('instance-instance2')).toHaveTextContent('instance2:true') - }) - }) - }) -}) \ No newline at end of file + expect(screen.getByTestId("instance-instance2")).toHaveTextContent( + "instance2:true" + ); + }); + }); + }); +});