fix(robot): scope devices to selected agent
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { AiHardware } from '@/pages/AiHardware';
|
||||
import {
|
||||
@@ -154,7 +154,7 @@ describe('AI hardware page', () => {
|
||||
status: 422, code: 'ai_hardware_activation_code_invalid', message: `invalid ${secret}`,
|
||||
}));
|
||||
render(<AiHardware />);
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
const input = screen.getByLabelText('6 位激活码');
|
||||
fireEvent.change(input, { target: { value: '12x' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '绑定' }));
|
||||
@@ -171,13 +171,45 @@ describe('AI hardware page', () => {
|
||||
|
||||
it('keeps the existing direct-code binding experience when guided provisioning is disabled', async () => {
|
||||
render(<AiHardware />);
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
|
||||
expect(screen.getByRole('heading', { name: '输入 6 位激活码' })).toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '开始引导配网' })).not.toBeInTheDocument();
|
||||
expect(api.openAiHardwareProvisioningPortal).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shows and binds devices for the currently selected agent', async () => {
|
||||
const agentOneDevice = { id: 'device-one', agent_id: agentOne.id, assignment_revision: 3 };
|
||||
const agentTwoDevice = { id: 'device-two', agent_id: agentTwo.id, assignment_revision: 1 };
|
||||
api.getAiHardwareOverview.mockResolvedValueOnce({
|
||||
status: 'active',
|
||||
agents: [agentOne, agentTwo],
|
||||
devices: [agentOneDevice, agentTwoDevice],
|
||||
});
|
||||
api.bindAiHardwareDevice.mockResolvedValueOnce(agentTwoDevice);
|
||||
|
||||
render(<AiHardware />);
|
||||
|
||||
expect(await screen.findByRole('button', { name: /客厅助手.*1 台设备/ })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: /书房助手.*1 台设备/ })).toBeInTheDocument();
|
||||
expect(await screen.findByText('设备 device-one')).toBeInTheDocument();
|
||||
expect(screen.queryByText('设备 device-two')).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /书房助手/ }));
|
||||
expect(await screen.findByText('设备 device-two')).toBeInTheDocument();
|
||||
expect(screen.queryByText('设备 device-one')).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
const bindingDialog = screen.getByRole('dialog');
|
||||
expect(within(bindingDialog).queryByLabelText('智能体')).not.toBeInTheDocument();
|
||||
expect(within(bindingDialog).getByText('绑定到当前智能体')).toBeInTheDocument();
|
||||
expect(within(bindingDialog).getByText('书房助手')).toBeInTheDocument();
|
||||
fireEvent.change(screen.getByLabelText('6 位激活码'), { target: { value: '654321' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '绑定' }));
|
||||
|
||||
await waitFor(() => expect(api.bindAiHardwareDevice).toHaveBeenCalledWith('654321', agentTwo.id));
|
||||
});
|
||||
|
||||
it('guides the existing hotspot flow, locks navigation while binding, and avoids online claims', async () => {
|
||||
api.getAiHardwareProvisioningCapabilities.mockResolvedValueOnce({ guidedHotspotBinding: true });
|
||||
const binding = deferred<typeof device>();
|
||||
@@ -185,7 +217,7 @@ describe('AI hardware page', () => {
|
||||
render(<AiHardware />);
|
||||
await waitFor(() => expect(api.getAiHardwareProvisioningCapabilities).toHaveBeenCalled());
|
||||
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '开始引导配网' }));
|
||||
expect(screen.getByText(/设备热点没有加密保护/)).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('button', { name: '机器人已进入配网模式' }));
|
||||
@@ -219,7 +251,7 @@ describe('AI hardware page', () => {
|
||||
api.getAiHardwareProvisioningCapabilities.mockResolvedValueOnce({ guidedHotspotBinding: true });
|
||||
render(<AiHardware />);
|
||||
await waitFor(() => expect(api.getAiHardwareProvisioningCapabilities).toHaveBeenCalled());
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '我已有 6 位激活码' }));
|
||||
expect(screen.getByRole('heading', { name: '输入 6 位激活码' })).toBeInTheDocument();
|
||||
@@ -255,12 +287,12 @@ describe('AI hardware page', () => {
|
||||
api.getAiHardwareProvisioningCapabilities.mockResolvedValueOnce({ guidedHotspotBinding: true });
|
||||
render(<AiHardware />);
|
||||
await waitFor(() => expect(api.getAiHardwareProvisioningCapabilities).toHaveBeenCalled());
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '开始引导配网' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '机器人已进入配网模式' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '取消' }));
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
expect(screen.getByRole('heading', { name: '绑定机器人设备' })).toBeInTheDocument();
|
||||
expect(api.openAiHardwareProvisioningPortal).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -271,7 +303,7 @@ describe('AI hardware page', () => {
|
||||
api.openAiHardwareProvisioningPortal.mockReturnValueOnce(opening.promise);
|
||||
render(<AiHardware />);
|
||||
await waitFor(() => expect(api.getAiHardwareProvisioningCapabilities).toHaveBeenCalled());
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '开始引导配网' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '机器人已进入配网模式' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '电脑已连接设备热点' }));
|
||||
@@ -284,7 +316,7 @@ describe('AI hardware page', () => {
|
||||
opening.resolve({ opened: true });
|
||||
fireEvent.click(await screen.findByRole('button', { name: '我已完成设备配网' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '取消' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
expect(screen.getByRole('heading', { name: '绑定机器人设备' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -304,7 +336,7 @@ describe('AI hardware page', () => {
|
||||
.mockResolvedValueOnce({ opened: true });
|
||||
render(<AiHardware />);
|
||||
await waitFor(() => expect(api.getAiHardwareProvisioningCapabilities).toHaveBeenCalled());
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '开始引导配网' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '机器人已进入配网模式' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '电脑已连接设备热点' }));
|
||||
@@ -320,7 +352,7 @@ describe('AI hardware page', () => {
|
||||
await waitFor(() => expect(api.openAiHardwareProvisioningPortal).toHaveBeenCalledTimes(2));
|
||||
fireEvent.click(screen.getByRole('button', { name: '我已完成设备配网' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '取消' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
expect(screen.getByRole('button', { name: '开始引导配网' })).toBeInTheDocument();
|
||||
expect(screen.queryByText(/不会撤销机器人已经保存的 Wi-Fi 设置/)).not.toBeInTheDocument();
|
||||
});
|
||||
@@ -508,7 +540,7 @@ describe('AI hardware page', () => {
|
||||
status: 409, code, message: 'secret detail activation=031425', retryAfterSeconds: 7,
|
||||
}));
|
||||
render(<AiHardware />);
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
fireEvent.change(screen.getByLabelText('6 位激活码'), { target: { value: '031425' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '绑定' }));
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent(expected);
|
||||
@@ -520,7 +552,7 @@ describe('AI hardware page', () => {
|
||||
status: 409, code: 'ai_hardware_operation_in_progress', message: 'private', retryAfterSeconds: 7,
|
||||
}));
|
||||
render(<AiHardware />);
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
fireEvent.change(screen.getByLabelText('6 位激活码'), { target: { value: '031425' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '绑定' }));
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent('7 秒后重试');
|
||||
@@ -536,7 +568,7 @@ describe('AI hardware page', () => {
|
||||
message: 'private upstream state',
|
||||
}));
|
||||
render(<AiHardware />);
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
fireEvent.change(screen.getByLabelText('6 位激活码'), { target: { value: '031425' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '绑定' }));
|
||||
|
||||
@@ -554,7 +586,7 @@ describe('AI hardware page', () => {
|
||||
}))
|
||||
.mockResolvedValueOnce(device);
|
||||
render(<AiHardware />);
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
const input = screen.getByLabelText('6 位激活码');
|
||||
fireEvent.change(input, { target: { value: '031425' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '绑定' }));
|
||||
@@ -580,14 +612,14 @@ describe('AI hardware page', () => {
|
||||
}))
|
||||
.mockResolvedValueOnce(device);
|
||||
const first = render(<AiHardware />);
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
fireEvent.change(screen.getByLabelText('6 位激活码'), { target: { value: '031425' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '绑定' }));
|
||||
await screen.findByLabelText('6 位激活码');
|
||||
first.unmount();
|
||||
|
||||
render(<AiHardware />);
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
fireEvent.change(screen.getByLabelText('6 位激活码'), { target: { value: '654321' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '绑定' }));
|
||||
|
||||
@@ -605,7 +637,7 @@ describe('AI hardware page', () => {
|
||||
}))
|
||||
.mockResolvedValueOnce(device);
|
||||
render(<AiHardware />);
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
const input = screen.getByLabelText('6 位激活码');
|
||||
|
||||
fireEvent.change(input, { target: { value: '031425' } });
|
||||
@@ -634,7 +666,7 @@ describe('AI hardware page', () => {
|
||||
}))
|
||||
.mockResolvedValueOnce(device);
|
||||
render(<AiHardware />);
|
||||
fireEvent.click(await screen.findByRole('button', { name: '绑定设备' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '为当前智能体绑定设备' }));
|
||||
const input = screen.getByLabelText('6 位激活码');
|
||||
|
||||
fireEvent.change(input, { target: { value: '031425' } });
|
||||
|
||||
Reference in New Issue
Block a user