一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
112 行
4.4 KiB
TypeScript
112 行
4.4 KiB
TypeScript
import { setupDatabaseAndSynchronizer, switchClient } from '../../testing/test-utils';
|
|
import Setting from '../../models/Setting';
|
|
import aiSettingsTransition from './aiSettingsTransition';
|
|
|
|
describe('aiSettingsTransition', () => {
|
|
|
|
beforeEach(async () => {
|
|
await setupDatabaseAndSynchronizer(1);
|
|
await switchClient(1);
|
|
});
|
|
|
|
it('marks providerType as configured when the user changes a provider field', async () => {
|
|
Setting.setValue('ai.enabled', true);
|
|
Setting.setValue('ai.allowRemote', true);
|
|
Setting.setValue('ai.chat.providerType', 'openai-compatible');
|
|
Setting.setValue('ai.chat.providerType.configured', false);
|
|
|
|
const pending: { changedKeys: string[]; settings: Record<string, unknown> } = {
|
|
changedKeys: ['ai.chat.providerType'],
|
|
settings: { 'ai.chat.providerType': 'anthropic', 'ai.chat.apiKey': 'sk-x' },
|
|
};
|
|
aiSettingsTransition(pending);
|
|
expect(pending.settings['ai.chat.providerType.configured']).toBe(true);
|
|
expect(pending.changedKeys).toContain('ai.chat.providerType.configured');
|
|
});
|
|
|
|
it('resets token usage counters when the active endpoint changes', async () => {
|
|
Setting.setValue('ai.enabled', true);
|
|
Setting.setValue('ai.allowRemote', true);
|
|
Setting.setValue('ai.chat.providerType', 'openai-compatible');
|
|
Setting.setValue('ai.chat.baseUrl', 'https://api.openai.com/v1');
|
|
Setting.setValue('ai.usage.inputTokens', 1234);
|
|
Setting.setValue('ai.usage.outputTokens', 5678);
|
|
|
|
const pending: { changedKeys: string[]; settings: Record<string, unknown> } = {
|
|
changedKeys: ['ai.chat.baseUrl'],
|
|
settings: {
|
|
'ai.chat.providerType': 'openai-compatible',
|
|
'ai.chat.baseUrl': 'https://api.mistral.ai/v1',
|
|
},
|
|
};
|
|
aiSettingsTransition(pending);
|
|
expect(pending.settings['ai.usage.inputTokens']).toBe(0);
|
|
expect(pending.settings['ai.usage.outputTokens']).toBe(0);
|
|
});
|
|
|
|
it('does not reset counters when only the API key changes', async () => {
|
|
Setting.setValue('ai.enabled', true);
|
|
Setting.setValue('ai.allowRemote', true);
|
|
Setting.setValue('ai.chat.providerType', 'anthropic');
|
|
Setting.setValue('ai.chat.baseUrl', '');
|
|
Setting.setValue('ai.usage.inputTokens', 1234);
|
|
|
|
const pending: { changedKeys: string[]; settings: Record<string, unknown> } = {
|
|
changedKeys: ['ai.chat.apiKey'],
|
|
settings: {
|
|
'ai.chat.providerType': 'anthropic',
|
|
'ai.chat.baseUrl': '',
|
|
'ai.chat.apiKey': 'new-key',
|
|
},
|
|
};
|
|
aiSettingsTransition(pending);
|
|
expect(pending.settings['ai.usage.inputTokens']).toBeUndefined();
|
|
});
|
|
|
|
it('writes joplin-cloud default when enabling AI on Joplin Cloud sync for the first time', async () => {
|
|
Setting.setValue('sync.target', 10);
|
|
Setting.setValue('ai.enabled', false);
|
|
Setting.setValue('ai.chat.providerType', 'openai-compatible');
|
|
Setting.setValue('ai.chat.providerType.configured', false);
|
|
|
|
const pending: { changedKeys: string[]; settings: Record<string, unknown> } = {
|
|
changedKeys: ['ai.enabled'],
|
|
settings: { 'ai.enabled': true },
|
|
};
|
|
aiSettingsTransition(pending);
|
|
expect(pending.settings['ai.chat.providerType']).toBe('joplin-cloud');
|
|
expect(pending.settings['ai.chat.providerType.configured']).toBe(true);
|
|
expect(pending.changedKeys).toContain('ai.chat.providerType');
|
|
expect(pending.changedKeys).toContain('ai.chat.providerType.configured');
|
|
});
|
|
|
|
it('leaves providerType alone when enabling AI without Joplin Cloud sync', async () => {
|
|
Setting.setValue('sync.target', 7);
|
|
Setting.setValue('ai.enabled', false);
|
|
Setting.setValue('ai.chat.providerType', 'openai-compatible');
|
|
Setting.setValue('ai.chat.providerType.configured', false);
|
|
|
|
const pending: { changedKeys: string[]; settings: Record<string, unknown> } = {
|
|
changedKeys: ['ai.enabled'],
|
|
settings: { 'ai.enabled': true },
|
|
};
|
|
aiSettingsTransition(pending);
|
|
expect(pending.settings['ai.chat.providerType']).toBeUndefined();
|
|
expect(pending.settings['ai.chat.providerType.configured']).toBe(true);
|
|
});
|
|
|
|
it('does not overwrite an explicit provider choice on subsequent enable', async () => {
|
|
Setting.setValue('sync.target', 10);
|
|
Setting.setValue('ai.enabled', false);
|
|
Setting.setValue('ai.chat.providerType', 'anthropic');
|
|
Setting.setValue('ai.chat.providerType.configured', true);
|
|
|
|
const pending: { changedKeys: string[]; settings: Record<string, unknown> } = {
|
|
changedKeys: ['ai.enabled'],
|
|
settings: { 'ai.enabled': true },
|
|
};
|
|
aiSettingsTransition(pending);
|
|
expect(pending.settings['ai.chat.providerType']).toBeUndefined();
|
|
});
|
|
});
|