完善客户端模块与工作区能力
This commit is contained in:
@@ -658,6 +658,135 @@ describe('works square host api routes', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('forwards local session data together with an Agent Profile update', async () => {
|
||||
const profile = {
|
||||
display_name: '小泥',
|
||||
age: 18,
|
||||
gender: 'female',
|
||||
share_age_with_agents: true,
|
||||
share_gender_with_agents: true,
|
||||
analysis_enabled: true,
|
||||
completed: true,
|
||||
version: 3,
|
||||
updated_at: '2026-08-13T00:00:00Z',
|
||||
};
|
||||
const sessionData = {
|
||||
project_id: 'prj_1',
|
||||
session_id: 'ses_1',
|
||||
updated_at: '2026-08-13T10:00:00.000Z',
|
||||
messages: [{ role: 'assistant', text: '这是自然语言回答。' }],
|
||||
};
|
||||
const fetchMock = vi.fn().mockResolvedValueOnce(
|
||||
new Response(JSON.stringify(profile), { status: 200 }),
|
||||
);
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
const response = createResponse();
|
||||
|
||||
const handled = await handleWorksRoutes(
|
||||
createRequest('PUT', {
|
||||
display_name: '小泥',
|
||||
age: 18,
|
||||
gender: 'female',
|
||||
share_age_with_agents: true,
|
||||
share_gender_with_agents: true,
|
||||
analysis_enabled: true,
|
||||
version: 2,
|
||||
session_data: sessionData,
|
||||
}, { 'x-niancode-access-token': 'access-token' }),
|
||||
response.res,
|
||||
new URL('http://127.0.0.1/api/works/user/agent-profile'),
|
||||
{} as never,
|
||||
);
|
||||
|
||||
expect(handled).toBe(true);
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.json()).toEqual({ success: true, profile });
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
'https://square.nianxx.cn/api/user/agent-profile',
|
||||
{
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
Authorization: 'Bearer access-token',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
display_name: '小泥',
|
||||
age: 18,
|
||||
gender: 'female',
|
||||
share_age_with_agents: true,
|
||||
share_gender_with_agents: true,
|
||||
analysis_enabled: true,
|
||||
version: 2,
|
||||
session_data: sessionData,
|
||||
}),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('forwards a prepared avatar as multipart data to the Works Square API', async () => {
|
||||
const fetchMock = vi.fn().mockResolvedValueOnce(
|
||||
new Response(JSON.stringify({ avatar_url: 'https://cdn.example/avatar.webp' }), { status: 200 }),
|
||||
);
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
const response = createResponse();
|
||||
const dataBase64 = Buffer.from('avatar-bytes').toString('base64');
|
||||
|
||||
const handled = await handleWorksRoutes(
|
||||
createRequest('POST', {
|
||||
fileName: 'avatar.webp',
|
||||
mimeType: 'image/webp',
|
||||
dataBase64,
|
||||
}, { 'x-niancode-access-token': 'access-token' }),
|
||||
response.res,
|
||||
new URL('http://127.0.0.1/api/works/user/avatar'),
|
||||
{} as never,
|
||||
);
|
||||
|
||||
expect(handled).toBe(true);
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.json()).toEqual({ success: true, avatar_url: 'https://cdn.example/avatar.webp' });
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
'https://square.nianxx.cn/api/user/avatar',
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
headers: { Authorization: 'Bearer access-token' },
|
||||
body: expect.any(FormData),
|
||||
}),
|
||||
);
|
||||
const form = fetchMock.mock.calls[0]?.[1]?.body as FormData;
|
||||
expect(form.get('file')).toBeInstanceOf(File);
|
||||
expect((form.get('file') as File).name).toBe('avatar.webp');
|
||||
expect(await (form.get('file') as File).arrayBuffer()).toEqual(
|
||||
Uint8Array.from(Buffer.from('avatar-bytes')).buffer,
|
||||
);
|
||||
});
|
||||
|
||||
it('deletes the current avatar through the Works Square API', async () => {
|
||||
const fetchMock = vi.fn().mockResolvedValueOnce(
|
||||
new Response(null, { status: 204 }),
|
||||
);
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
const response = createResponse();
|
||||
|
||||
const handled = await handleWorksRoutes(
|
||||
createRequest('DELETE', undefined, { 'x-niancode-access-token': 'access-token' }),
|
||||
response.res,
|
||||
new URL('http://127.0.0.1/api/works/user/avatar'),
|
||||
{} as never,
|
||||
);
|
||||
|
||||
expect(handled).toBe(true);
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.json()).toEqual({ success: true, avatar_url: null });
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
'https://square.nianxx.cn/api/user/avatar',
|
||||
{
|
||||
method: 'DELETE',
|
||||
headers: { Authorization: 'Bearer access-token' },
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps Agent Profile version-conflict detail available to the renderer', async () => {
|
||||
const fetchMock = vi.fn().mockResolvedValueOnce(
|
||||
new Response(JSON.stringify({
|
||||
@@ -675,6 +804,7 @@ describe('works square host api routes', () => {
|
||||
display_name: '小泥',
|
||||
age: null,
|
||||
gender: null,
|
||||
avatar_url: 'https://oss.example/avatar.webp?signature=temporary',
|
||||
share_age_with_agents: false,
|
||||
share_gender_with_agents: false,
|
||||
analysis_enabled: true,
|
||||
@@ -690,6 +820,7 @@ describe('works square host api routes', () => {
|
||||
expect(response.json()).toEqual({
|
||||
success: false,
|
||||
status: 409,
|
||||
code: 'agent_profile_version_conflict',
|
||||
error: 'Agent Profile request failed (409)',
|
||||
detail: {
|
||||
code: 'agent_profile_version_conflict',
|
||||
@@ -717,6 +848,46 @@ describe('works square host api routes', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('forwards a structured Agent Profile upstream error message', async () => {
|
||||
const fetchMock = vi.fn().mockResolvedValueOnce(
|
||||
new Response(JSON.stringify({
|
||||
detail: {
|
||||
code: 'agent_profile_storage_unavailable',
|
||||
message: 'Agent Profile database migration is pending',
|
||||
},
|
||||
}), { status: 503 }),
|
||||
);
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
const response = createResponse();
|
||||
|
||||
const handled = await handleWorksRoutes(
|
||||
createRequest('PUT', {
|
||||
display_name: '小泥',
|
||||
age: null,
|
||||
gender: null,
|
||||
share_age_with_agents: false,
|
||||
share_gender_with_agents: false,
|
||||
analysis_enabled: true,
|
||||
version: 0,
|
||||
}, { 'x-niancode-access-token': 'access-token' }),
|
||||
response.res,
|
||||
new URL('http://127.0.0.1/api/works/user/agent-profile'),
|
||||
{} as never,
|
||||
);
|
||||
|
||||
expect(handled).toBe(true);
|
||||
expect(response.json()).toEqual({
|
||||
success: false,
|
||||
status: 503,
|
||||
code: 'agent_profile_storage_unavailable',
|
||||
error: 'Agent Profile database migration is pending',
|
||||
detail: {
|
||||
code: 'agent_profile_storage_unavailable',
|
||||
message: 'Agent Profile database migration is pending',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('submits an image generation task through the Works Square AI gateway API', async () => {
|
||||
const fetchMock = vi.fn().mockResolvedValueOnce(
|
||||
new Response(JSON.stringify({
|
||||
|
||||
Reference in New Issue
Block a user