070959e133
landing-page-staging / Deploy landing page to staging (push) Has been skipped
landing-page-ci / Validate landing page (push) Failing after 4s
visual-baseline / Capture visual baselines (push) Has been cancelled
bake-plugin-previews / Bake plugin previews (push) Has been cancelled
77 lines
2.5 KiB
TypeScript
77 lines
2.5 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import { renderHook, waitFor } from '@testing-library/react';
|
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
import { useProjectDetail } from '../../src/hooks/useProjectDetail';
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
function mockFetchOnce(body: unknown, init?: { ok?: boolean; status?: number }) {
|
|
const ok = init?.ok ?? true;
|
|
const status = init?.status ?? 200;
|
|
return vi.spyOn(globalThis, 'fetch').mockImplementation(async () => {
|
|
return new Response(JSON.stringify(body), {
|
|
status,
|
|
headers: { 'content-type': 'application/json' },
|
|
});
|
|
});
|
|
}
|
|
|
|
describe('useProjectDetail', () => {
|
|
it('surfaces resolvedDir when the daemon includes it in the response', async () => {
|
|
mockFetchOnce({
|
|
project: { id: 'p1', name: 'Acme', skillId: null, designSystemId: null, createdAt: 1, updatedAt: 1 },
|
|
resolvedDir: '/tmp/od/projects/p1',
|
|
});
|
|
|
|
const { result } = renderHook(() => useProjectDetail('p1'));
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
expect(result.current.error).toBeNull();
|
|
expect(result.current.resolvedDir).toBe('/tmp/od/projects/p1');
|
|
expect(result.current.project?.id).toBe('p1');
|
|
});
|
|
|
|
it('falls back to metadata.baseDir when the daemon omits resolvedDir', async () => {
|
|
mockFetchOnce({
|
|
project: {
|
|
id: 'p2',
|
|
name: 'Imported',
|
|
skillId: null,
|
|
designSystemId: null,
|
|
createdAt: 1,
|
|
updatedAt: 1,
|
|
metadata: { kind: 'prototype', baseDir: '/Users/me/projects/imported' },
|
|
},
|
|
});
|
|
|
|
const { result } = renderHook(() => useProjectDetail('p2'));
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
expect(result.current.resolvedDir).toBe('/Users/me/projects/imported');
|
|
});
|
|
|
|
it('returns resolvedDir: null when neither resolvedDir nor metadata.baseDir is present', async () => {
|
|
mockFetchOnce({
|
|
project: { id: 'p3', name: 'Stale daemon', skillId: null, designSystemId: null, createdAt: 1, updatedAt: 1 },
|
|
});
|
|
|
|
const { result } = renderHook(() => useProjectDetail('p3'));
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
expect(result.current.resolvedDir).toBeNull();
|
|
});
|
|
|
|
it('captures error state when the request returns non-OK', async () => {
|
|
mockFetchOnce({}, { ok: false, status: 500 });
|
|
|
|
const { result } = renderHook(() => useProjectDetail('p4'));
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
expect(result.current.error).not.toBeNull();
|
|
});
|
|
});
|