Files
makelore/tests/unit/user-sync-routes.test.ts
inman 80e8386fa6
Some checks failed
Electron E2E / Electron E2E (macos-latest) (push) Has been cancelled
Electron E2E / Electron E2E (ubuntu-latest) (push) Has been cancelled
Electron E2E / Electron E2E (windows-latest) (push) Has been cancelled
feat: update Makelore modules and conversations
2026-07-31 10:08:41 +08:00

240 lines
7.2 KiB
TypeScript

import { EventEmitter } from 'node:events';
import type { IncomingMessage, ServerResponse } from 'http';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { handleUserSyncRoutes } from '@electron/api/routes/user-sync';
const fetchMock = vi.hoisted(() => vi.fn());
const providerServiceMock = vi.hoisted(() => ({
upsertSyncedAccountMetadata: vi.fn(),
}));
vi.mock('@electron/utils/proxy-fetch', () => ({
proxyAwareFetch: (...args: unknown[]) => fetchMock(...args),
}));
vi.mock('@electron/services/providers/provider-service', () => ({
getProviderService: () => providerServiceMock,
}));
function createResponse() {
const chunks: string[] = [];
const res = {
statusCode: 0,
setHeader: vi.fn(),
end: vi.fn((chunk?: string) => {
if (chunk) chunks.push(chunk);
}),
} as unknown as ServerResponse;
return {
res,
get statusCode() {
return res.statusCode;
},
json: () => JSON.parse(chunks.join('')) as unknown,
};
}
function createRequest(
method: string,
body?: unknown,
headers: Record<string, string> = {},
): IncomingMessage {
const req = new EventEmitter();
Object.assign(req, {
method,
headers: body === undefined
? headers
: { ...headers, 'content-type': 'application/json' },
[Symbol.asyncIterator]: async function* () {
if (body !== undefined) {
yield Buffer.from(JSON.stringify(body));
}
},
});
return req as IncomingMessage;
}
describe('user sync host api routes', () => {
beforeEach(() => {
vi.clearAllMocks();
vi.restoreAllMocks();
providerServiceMock.upsertSyncedAccountMetadata.mockResolvedValue(undefined);
});
it('requires a current user access token', async () => {
const response = createResponse();
const handled = await handleUserSyncRoutes(
createRequest('GET'),
response.res,
new URL('http://127.0.0.1/api/user-sync/bootstrap'),
{} as never,
);
expect(handled).toBe(true);
expect(response.statusCode).toBe(400);
expect(response.json()).toEqual({
success: false,
error: 'Missing x-niancode-access-token',
});
expect(fetchMock).not.toHaveBeenCalled();
});
it('fetches bootstrap, applies provider metadata, and strips secrets from the response', async () => {
fetchMock.mockResolvedValueOnce(new Response(JSON.stringify({
preferences: {
theme: 'dark',
sidebar_collapsed: true,
},
provider_accounts: [{
id: 'openai-account-1',
vendor_id: 'openai',
label: 'OpenAI',
auth_mode: 'api_key',
model: 'gpt-4.1-mini',
fallback_models: ['gpt-4o-mini'],
enabled: true,
is_default: true,
api_key: 'sk-should-not-return',
refresh_token: 'refresh-should-not-return',
headers: { Authorization: 'Bearer secret' },
updated_at: '2026-07-04T00:00:00.000Z',
}],
partners: [],
usage_aggregates: [],
}), { status: 200 }));
const response = createResponse();
const handled = await handleUserSyncRoutes(
createRequest('GET', undefined, { 'x-niancode-access-token': 'access-token' }),
response.res,
new URL('http://127.0.0.1/api/user-sync/bootstrap'),
{} as never,
);
expect(handled).toBe(true);
expect(response.statusCode).toBe(200);
expect(response.json()).toEqual({
success: true,
bootstrap: {
preferences: {
theme: 'dark',
sidebarCollapsed: true,
},
providerAccounts: [{
id: 'openai-account-1',
vendorId: 'openai',
label: 'OpenAI',
authMode: 'api_key',
model: 'gpt-4.1-mini',
fallbackModels: ['gpt-4o-mini'],
enabled: true,
isDefault: true,
metadata: {},
updatedAt: '2026-07-04T00:00:00.000Z',
}],
partners: [],
usageAggregates: [],
},
applied: { providerAccounts: 1 },
});
expect(JSON.stringify(response.json())).not.toContain('sk-should-not-return');
expect(JSON.stringify(response.json())).not.toContain('refresh-should-not-return');
expect(JSON.stringify(response.json())).not.toContain('Authorization');
expect(fetchMock).toHaveBeenCalledWith('https://square.nianxx.cn/api/me/bootstrap', {
method: 'GET',
headers: { Authorization: 'Bearer access-token' },
});
expect(providerServiceMock.upsertSyncedAccountMetadata).toHaveBeenCalledWith({
id: 'openai-account-1',
vendorId: 'openai',
label: 'OpenAI',
authMode: 'api_key',
model: 'gpt-4.1-mini',
fallbackModels: ['gpt-4o-mini'],
enabled: true,
isDefault: true,
metadata: {},
updatedAt: '2026-07-04T00:00:00.000Z',
});
});
it('proxies preferences as sanitized server payloads', async () => {
fetchMock.mockResolvedValueOnce(new Response(JSON.stringify({
preferences: { theme: 'dark' },
provider_accounts: [],
partners: [],
usage_aggregates: [],
}), { status: 200 }));
const response = createResponse();
const handled = await handleUserSyncRoutes(
createRequest('PUT', {
theme: 'dark',
language: 'zh-CN',
launchAtStartup: true,
activeProjectId: 'prj_1',
}, { 'x-niancode-access-token': 'access-token' }),
response.res,
new URL('http://127.0.0.1/api/user-sync/preferences'),
{} as never,
);
expect(handled).toBe(true);
expect(response.statusCode).toBe(200);
expect(fetchMock).toHaveBeenCalledWith('https://square.nianxx.cn/api/me/preferences', {
method: 'PUT',
headers: {
Authorization: 'Bearer access-token',
'Content-Type': 'application/json',
},
body: JSON.stringify({ theme: 'dark', language: 'zh-CN' }),
});
});
it('proxies partners as sanitized server payloads', async () => {
fetchMock.mockResolvedValueOnce(new Response(JSON.stringify({
preferences: {},
provider_accounts: [],
partners: [],
usage_aggregates: [],
}), { status: 200 }));
const response = createResponse();
const handled = await handleUserSyncRoutes(
createRequest('POST', {
id: 'makelore-pm-test',
displayName: 'PM',
templateRoleId: 'custom',
skillIds: ['pm-project-plan'],
filePath: 'D:/repo/.opencode/agent/makelore-pm-test.md',
projectRuntimeConfigsByProjectId: { prj_1: { filePath: 'D:/repo/file.md' } },
createdAt: '2026-07-04T00:00:00.000Z',
updatedAt: '2026-07-04T00:00:00.000Z',
}, { 'x-niancode-access-token': 'access-token' }),
response.res,
new URL('http://127.0.0.1/api/user-sync/partners'),
{} as never,
);
expect(handled).toBe(true);
expect(response.statusCode).toBe(200);
expect(fetchMock).toHaveBeenCalledWith('https://square.nianxx.cn/api/me/partners', {
method: 'POST',
headers: {
Authorization: 'Bearer access-token',
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: 'makelore-pm-test',
display_name: 'PM',
template_role_id: 'custom',
skill_ids: ['pm-project-plan'],
created_at: '2026-07-04T00:00:00.000Z',
updated_at: '2026-07-04T00:00:00.000Z',
}),
});
});
});