wraith/frontend/tests/stores/connection.store.spec.ts
Vantz Stockwell f01e357647 test: frontend test suite — Vitest infrastructure, auth/connection stores, vault composable, admin middleware
28 tests across 4 spec files. Vitest + happy-dom configured with Nuxt auto-import
shims ($$fetch, navigateTo, defineNuxtRouteMiddleware) so stores and composables
resolve cleanly outside the Nuxt runtime.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 19:06:14 -04:00

125 lines
3.9 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useConnectionStore } from '../../stores/connection.store'
const mockFetch = vi.mocked($fetch as ReturnType<typeof vi.fn>)
const makeHost = (id: number) => ({
id,
name: `host-${id}`,
hostname: `192.168.1.${id}`,
port: 22,
protocol: 'ssh' as const,
groupId: null,
credentialId: null,
tags: [],
notes: null,
color: null,
lastConnectedAt: null,
group: null,
})
beforeEach(() => {
setActivePinia(createPinia())
vi.clearAllMocks()
})
// ---------------------------------------------------------------------------
// fetchHosts()
// ---------------------------------------------------------------------------
describe('fetchHosts()', () => {
it('populates hosts array and resets loading flag', async () => {
const hosts = [makeHost(1), makeHost(2)]
mockFetch.mockResolvedValueOnce(hosts)
const store = useConnectionStore()
await store.fetchHosts()
expect(store.hosts).toEqual(hosts)
expect(store.loading).toBe(false)
expect(mockFetch).toHaveBeenCalledWith('/api/hosts')
})
it('does NOT include Authorization headers (cookie-only auth)', async () => {
mockFetch.mockResolvedValueOnce([])
const store = useConnectionStore()
await store.fetchHosts()
const callArgs = mockFetch.mock.calls[0]
// fetchHosts passes no options — only the URL
expect(callArgs.length).toBe(1)
})
})
// ---------------------------------------------------------------------------
// createHost()
// ---------------------------------------------------------------------------
describe('createHost()', () => {
it('posts to /api/hosts and refreshes the list', async () => {
const newHost = makeHost(10)
// First call: POST to create, second call: GET for fetchHosts
mockFetch
.mockResolvedValueOnce(newHost) // POST
.mockResolvedValueOnce([newHost]) // GET (fetchHosts)
const store = useConnectionStore()
const result = await store.createHost({ name: 'host-10', hostname: '10.0.0.10', port: 22, protocol: 'ssh' })
expect(result).toEqual(newHost)
expect(mockFetch).toHaveBeenNthCalledWith(1, '/api/hosts', {
method: 'POST',
body: { name: 'host-10', hostname: '10.0.0.10', port: 22, protocol: 'ssh' },
})
expect(store.hosts).toEqual([newHost])
})
})
// ---------------------------------------------------------------------------
// deleteHost()
// ---------------------------------------------------------------------------
describe('deleteHost()', () => {
it('sends DELETE and refreshes the list', async () => {
mockFetch
.mockResolvedValueOnce(undefined) // DELETE
.mockResolvedValueOnce([]) // fetchHosts
const store = useConnectionStore()
await store.deleteHost(5)
expect(mockFetch).toHaveBeenNthCalledWith(1, '/api/hosts/5', { method: 'DELETE' })
expect(store.hosts).toEqual([])
})
})
// ---------------------------------------------------------------------------
// Group CRUD
// ---------------------------------------------------------------------------
describe('createGroup()', () => {
it('posts to /api/groups and refreshes the tree', async () => {
mockFetch
.mockResolvedValueOnce(undefined) // POST
.mockResolvedValueOnce([]) // fetchTree
const store = useConnectionStore()
await store.createGroup({ name: 'Dev Servers' })
expect(mockFetch).toHaveBeenNthCalledWith(1, '/api/groups', {
method: 'POST',
body: { name: 'Dev Servers' },
})
})
})
describe('deleteGroup()', () => {
it('sends DELETE and refreshes the tree', async () => {
mockFetch
.mockResolvedValueOnce(undefined) // DELETE
.mockResolvedValueOnce([]) // fetchTree
const store = useConnectionStore()
await store.deleteGroup(3)
expect(mockFetch).toHaveBeenNthCalledWith(1, '/api/groups/3', { method: 'DELETE' })
})
})