Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:00:47 +08:00

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();
});
});