Files
Mujoco_WASM/web_platform/src/app/hooks/useProjectSource.test.ts
T
chenlin 26bb5634bd
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
web-platform-ci / Standalone decision service (no cloud credentials) (pull_request) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (pull_request) Has been cancelled
web-platform-ci / Playwright E2E (pull_request) Has been cancelled
lekiwi-compatibility / cpu-compatibility (pull_request) Has been cancelled
refactor: release v1.0.5 安全精简与网站发布
2026-09-29 09:55:08 +08:00

103 lines
4.1 KiB
TypeScript

import { act, renderHook } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { downloadBytes, readCachedText } from '../../project/cachedFiles';
import type { ProjectManifest } from '../../project/types';
import type { PhysicsAdapter } from '../../simulation/PhysicsAdapter';
import { useProjectSource } from './useProjectSource';
vi.mock('../../project/cachedFiles', async (importOriginal) => ({
...(await importOriginal<typeof import('../../project/cachedFiles')>()),
downloadBytes: vi.fn(),
}));
beforeEach(() => vi.clearAllMocks());
function fixture() {
const text = '<robot name="test"><link name="base"/></robot>',
data = new TextEncoder().encode(text);
const manifest = {
current: {
id: 'p',
name: '测试 工程.zip',
files: [{ path: 'robot.urdf', data, size: data.length, source: 'zip', mimeType: '' }],
entries: [{ path: 'robot.urdf', format: 'urdf', label: 'robot' }],
maps: [],
totalBytes: data.length,
} as ProjectManifest | null,
};
const exported = new TextEncoder().encode('<mujoco><worldbody/></mujoco>');
const backend = {
describeRobot: () => ({ profileId: 'lekiwi-v1' }),
exportMjcf: vi.fn(() => exported),
cachedSupportFiles: () => [],
};
const events: string[] = [];
const options: Parameters<typeof useProjectSource>[0] = {
manifest,
adapter: { current: backend as unknown as PhysicsAdapter },
robotProfiles: { current: new Map() },
selectedEntry: 'robot.urdf',
selectedFormat: 'urdf',
onProjectUpdated: vi.fn(() => {
events.push('project');
}),
onDiagnostic: vi.fn(),
notify: vi.fn(() => {
events.push('notice');
}),
loadEntry: vi.fn(async () => {
events.push('load');
return false;
}),
};
return { options, backend, events, text, exported };
}
describe('工程源码与导出动作', () => {
it('先保留 profile/写缓存/发布清单和通知,再调用加载;编译失败仍保留可修改源码', async () => {
const { options, events } = fixture();
const { result } = renderHook(() => useProjectSource(options));
await act(async () => {
await result.current.saveCachedSource('cache.xml', '<mujoco model="edited"/>');
});
expect(events).toEqual(['project', 'notice', 'load']);
expect(options.robotProfiles.current.get('cache.xml')).toBe('lekiwi-v1');
expect(readCachedText(options.manifest.current!, 'cache.xml')).toBe('<mujoco model="edited"/>');
expect(options.loadEntry).toHaveBeenCalledWith('cache.xml');
});
it('URDF 导出读取当前缓存,切换格式后入口失效;MJCF 保留 XML 资源提示', () => {
const { options, text, exported } = fixture();
const { result, rerender } = renderHook((opts) => useProjectSource(opts), {
initialProps: options,
});
result.current.exportUrdf();
expect(downloadBytes).toHaveBeenCalledWith(new TextEncoder().encode(text), '测试_工程.urdf');
vi.mocked(downloadBytes).mockClear();
rerender({ ...options, selectedFormat: 'mjcf' });
result.current.exportUrdf();
expect(downloadBytes).not.toHaveBeenCalled();
result.current.exportMjcf();
expect(downloadBytes).toHaveBeenCalledWith(exported, '测试_工程.xml');
expect(options.notify).toHaveBeenCalledWith('MJCF 已导出', expect.stringContaining('仅 XML'));
});
it('MJCF/ZIP 导出异常保留不同诊断类别与入口路径', () => {
const { options, backend } = fixture();
backend.exportMjcf.mockImplementation(() => {
throw new Error('导出失败');
});
const { result } = renderHook(() => useProjectSource(options));
result.current.exportMjcf();
result.current.exportProjectPackage();
expect(options.onDiagnostic).toHaveBeenNthCalledWith(
1,
expect.objectContaining({ category: '模型编译', path: 'robot.urdf', detail: '导出失败' }),
);
expect(options.onDiagnostic).toHaveBeenNthCalledWith(
2,
expect.objectContaining({ category: '文件系统', path: 'robot.urdf', detail: '导出失败' }),
);
expect(downloadBytes).not.toHaveBeenCalled();
});
});