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>
125 lines
3.9 KiB
TypeScript
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' })
|
|
})
|
|
})
|