feat: add bundled OpenCode skills and refine module flow
This commit is contained in:
@@ -27,7 +27,7 @@ describe('AI module navigation', () => {
|
||||
useOpencodeStore.setState({ activeProject: null });
|
||||
});
|
||||
|
||||
it('shows the four module choices and routes enabled modules from the chooser', async () => {
|
||||
it('shows the four module choices and routes Canvas from the chooser', async () => {
|
||||
render(
|
||||
<MemoryRouter initialEntries={['/module-select']}>
|
||||
<Routes>
|
||||
@@ -43,6 +43,9 @@ describe('AI module navigation', () => {
|
||||
expect(screen.getByTestId('ai-module-options')).toHaveClass('module-selection-options');
|
||||
expect(screen.getByText('zhangsan,欢迎回来!')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('ai-module-option-programming')).toHaveClass('module-option-card', 'module-option-card-horizontal');
|
||||
for (const moduleId of ['programming', 'painting', 'learning', 'robot'] as const) {
|
||||
expect(screen.getByTestId(`ai-module-option-${moduleId}`).querySelector('.module-option-artwork')).toBeNull();
|
||||
}
|
||||
expect(screen.queryByText('先选一个入口。进入后,你还可以从左下角随时切换到其他模块。')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('选择创作空间。你可以随时从侧边栏切换。')).not.toBeInTheDocument();
|
||||
expect(screen.getByAltText('Makelore')).toHaveClass('h-8', 'w-40', 'object-cover');
|
||||
@@ -55,20 +58,35 @@ describe('AI module navigation', () => {
|
||||
expect(screen.getByAltText('数位板设计创作')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('ai-module-option-painting')).toHaveTextContent('用灵感描绘色彩缤纷的世界');
|
||||
const learningOption = screen.getByTestId('ai-module-option-learning');
|
||||
expect(learningOption).toBeDisabled();
|
||||
expect(learningOption).toHaveClass('module-option-card-disabled');
|
||||
expect(learningOption).toBeEnabled();
|
||||
expect(learningOption).not.toHaveClass('module-option-card-disabled');
|
||||
expect(learningOption).toHaveTextContent('Learning 学习');
|
||||
expect(learningOption).toHaveTextContent('用顶尖的方法解锁万物规律');
|
||||
expect(learningOption).toHaveTextContent('暂未开放');
|
||||
expect(screen.getByAltText('数学科技宇宙')).toBeInTheDocument();
|
||||
const robotOption = screen.getByTestId('ai-module-option-robot');
|
||||
expect(robotOption).toBeEnabled();
|
||||
expect(robotOption).not.toHaveClass('module-option-card-disabled');
|
||||
expect(robotOption).toHaveTextContent('Robot 机器');
|
||||
expect(robotOption).toHaveTextContent('制作你的第一个机器人小伙伴');
|
||||
expect(robotOption).not.toHaveTextContent('暂未开放');
|
||||
expect(screen.getByAltText('青少年管理机器人硬件与设备绑定')).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(robotOption);
|
||||
fireEvent.click(learningOption);
|
||||
expect(screen.getByTestId('ai-module-selection-page')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByTestId('ai-module-option-painting'));
|
||||
expect(await screen.findByTestId('location-path')).toHaveTextContent('/image-canvas');
|
||||
});
|
||||
|
||||
it('routes Robot from the chooser to the AI hardware workspace', async () => {
|
||||
render(
|
||||
<MemoryRouter initialEntries={['/module-select']}>
|
||||
<Routes>
|
||||
<Route path="/module-select" element={<ModuleSelection />} />
|
||||
<Route path="*" element={<LocationProbe />} />
|
||||
</Routes>
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByTestId('ai-module-option-robot'));
|
||||
expect(await screen.findByTestId('location-path')).toHaveTextContent('/ai-hardware');
|
||||
});
|
||||
|
||||
@@ -112,7 +130,7 @@ describe('AI module navigation', () => {
|
||||
expect(await screen.findByTestId('location-path')).toHaveTextContent('/login');
|
||||
});
|
||||
|
||||
it('keeps the current module active and switches from the Sidebar entry', async () => {
|
||||
it('returns to the module chooser from the Sidebar entry', async () => {
|
||||
render(
|
||||
<MemoryRouter initialEntries={['/image-canvas']}>
|
||||
<Routes>
|
||||
@@ -121,29 +139,16 @@ describe('AI module navigation', () => {
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('sidebar-module-switcher-trigger')).toHaveAttribute('aria-expanded', 'false');
|
||||
expect(screen.getByTestId('sidebar-module-switcher-trigger')).toHaveTextContent('绘画 Canvas');
|
||||
expect(screen.getByTestId('sidebar-module-switcher-menu')).toHaveAttribute('data-state', 'closed');
|
||||
expect(screen.getByTestId('sidebar-module-painting')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('sidebar-module-switcher-trigger')).toHaveAttribute('aria-label', '返回首页');
|
||||
expect(screen.getByTestId('sidebar-module-switcher-trigger')).toHaveClass('p-3');
|
||||
expect(screen.queryByTestId('sidebar-module-switcher-menu')).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByTestId('sidebar-module-switcher-trigger'));
|
||||
expect(screen.getByTestId('sidebar-module-switcher-menu')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('sidebar-module-painting')).toHaveAttribute('aria-current', 'page');
|
||||
expect(screen.getByTestId('sidebar-module-programming')).not.toHaveAttribute('aria-current');
|
||||
expect(screen.getByTestId('sidebar-module-robot')).not.toHaveAttribute('aria-current');
|
||||
const learningModule = screen.getByTestId('sidebar-module-learning');
|
||||
expect(learningModule).toBeDisabled();
|
||||
expect(learningModule).toHaveTextContent('学习 Learning');
|
||||
expect(learningModule).toHaveTextContent('AI 学习');
|
||||
expect(learningModule).not.toHaveAttribute('aria-current');
|
||||
fireEvent.click(learningModule);
|
||||
expect(screen.getByTestId('location-path')).toHaveTextContent('/image-canvas');
|
||||
|
||||
fireEvent.click(screen.getByTestId('sidebar-module-programming'));
|
||||
expect(await screen.findByTestId('location-path')).toHaveTextContent('/opencode-chat');
|
||||
expect(await screen.findByTestId('location-path')).toHaveTextContent('/module-select');
|
||||
});
|
||||
|
||||
it('marks Robot active on the AI hardware route and switches back to Canvas', async () => {
|
||||
it('shows Robot as the active module and returns to the chooser from the AI hardware route', async () => {
|
||||
render(
|
||||
<MemoryRouter initialEntries={['/ai-hardware']}>
|
||||
<Routes>
|
||||
@@ -154,11 +159,7 @@ describe('AI module navigation', () => {
|
||||
|
||||
expect(screen.getByTestId('sidebar-module-switcher-trigger')).toHaveTextContent('Robot 机器');
|
||||
fireEvent.click(screen.getByTestId('sidebar-module-switcher-trigger'));
|
||||
expect(screen.getByTestId('sidebar-module-robot')).toHaveAttribute('aria-current', 'page');
|
||||
expect(screen.getByTestId('sidebar-module-programming')).not.toHaveAttribute('aria-current');
|
||||
|
||||
fireEvent.click(screen.getByTestId('sidebar-module-painting'));
|
||||
expect(await screen.findByTestId('location-path')).toHaveTextContent('/image-canvas');
|
||||
expect(await screen.findByTestId('location-path')).toHaveTextContent('/module-select');
|
||||
});
|
||||
|
||||
it('keeps breathing room around the compact module switcher trigger', () => {
|
||||
@@ -169,7 +170,7 @@ describe('AI module navigation', () => {
|
||||
);
|
||||
|
||||
const trigger = screen.getByTestId('sidebar-module-switcher-trigger');
|
||||
expect(trigger).toHaveClass('inline-flex', 'w-fit', 'px-2');
|
||||
expect(trigger).toHaveClass('inline-flex', 'w-fit', 'p-2');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user