Skip to content

Commit 866ac19

Browse files
committed
Fix UI tests
1 parent 0746db0 commit 866ac19

6 files changed

Lines changed: 67 additions & 45 deletions

File tree

packages/agent/src/agent.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,9 @@ export class AgentManager implements IAgentManager {
576576
}
577577

578578
if (!this._agent) {
579-
throw new Error('Failed to initialize agent');
579+
throw new Error(
580+
'Failed to initialize agent.\nPlease configure your AI settings first. Open the AI Settings to set your API key and model.'
581+
);
580582
}
581583

582584
let continueLoop = true;

packages/ai/schema/chat.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"jupyter.lab.shortcuts": [],
3-
"title": "JupyterLite AI Chat",
3+
"title": "AI Chat",
44
"jupyter.lab.setting-icon": "@jupyternaut/agent:jupyternaut",
55
"description": "Configuration for JupyterLite AI chat behavior",
66
"type": "object",

packages/ai/src/chat-model.ts

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,17 @@ import { ISettingRegistry } from '@jupyterlab/settingregistry';
1717

1818
import { Contents } from '@jupyterlab/services';
1919

20-
import { AI_AVATAR } from '@jupyternaut/agent';
21-
2220
import type {
2321
IAgentManager,
2422
IAISettingsModel,
2523
ITokenUsage
2624
} from '@jupyternaut/agent';
2725

28-
import { IPersona, IPersonaRegistry } from '@jupyternaut/persona';
26+
import {
27+
DEFAULT_PERSONA,
28+
IPersona,
29+
IPersonaRegistry
30+
} from '@jupyternaut/persona';
2931

3032
import type { ModelMessage } from 'ai';
3133

@@ -312,15 +314,6 @@ export class AIChatModel extends AbstractChatModel implements IAIChatModel {
312314
// Check if we have valid configuration
313315
if (!this.agentManager?.hasValidConfig()) {
314316
this.messageAdded(userMessage);
315-
const errorMessage: IMessageContent = {
316-
body: 'Please configure your AI settings first. Open the AI Settings to set your API key and model.',
317-
sender: this._getAIUser(),
318-
id: UUID.uuid4(),
319-
time: Date.now() / 1000,
320-
type: 'msg',
321-
raw_time: false
322-
};
323-
this.messageAdded(errorMessage);
324317
return;
325318
}
326319

@@ -656,13 +649,7 @@ export class AIChatModel extends AbstractChatModel implements IAIChatModel {
656649
* Gets the AI user information for system messages.
657650
*/
658651
private _getAIUser(): IUser {
659-
return {
660-
username: 'ai-assistant',
661-
display_name: 'Jupyternaut',
662-
initials: 'JN',
663-
color: '#2196F3',
664-
avatar_url: AI_AVATAR
665-
};
652+
return DEFAULT_PERSONA;
666653
}
667654

668655
/**

ui-tests/tests/chat-panel.spec.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import {
99
CHAT_PANEL_ID,
1010
CHAT_PANEL_TITLE,
1111
TEST_PROVIDERS,
12-
openChatPanel
12+
openChatPanel,
13+
openSettings
1314
} from './test-utils';
1415

1516
const NOT_CONFIGURED_TEXT = 'Please configure your AI settings first';
@@ -232,12 +233,22 @@ TEST_PROVIDERS.forEach(({ name, settings }) =>
232233
}) => {
233234
const panel = await openChatPanel(page);
234235

235-
await panel.getByTitle('Open AI Settings').click();
236-
237-
const aiSettingsWidget = page.locator('#jupyternaut-persona-settings');
238-
await expect(aiSettingsWidget).toBeVisible();
239-
await aiSettingsWidget.getByRole('tab', { name: 'Behavior' }).click();
240-
await aiSettingsWidget.getByLabel('Show Context Usage').click();
236+
const settings = await openSettings(page);
237+
await settings
238+
?.getByRole('checkbox', {
239+
name: 'Show Context Usage'
240+
})
241+
.check();
242+
243+
// wait for the settings to be saved
244+
await expect(page.activity.getTabLocator('Settings')).toHaveAttribute(
245+
'class',
246+
/jp-mod-dirty/
247+
);
248+
await expect(page.activity.getTabLocator('Settings')).not.toHaveAttribute(
249+
'class',
250+
/jp-mod-dirty/
251+
);
241252

242253
await expect(
243254
panel.getByTitle(/Context Usage unavailable\./)

ui-tests/tests/chat-save-restore.spec.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import { expect, galata, test } from '@jupyterlab/galata';
77
import {
88
DEFAULT_GENERIC_PROVIDER_SETTINGS,
99
QWEN_MODEL_NAME,
10-
openChatPanel
10+
openChatPanel,
11+
openSettings
1112
} from './test-utils';
1213

1314
const BACKUP_FILE = `${QWEN_MODEL_NAME}.chat`;
@@ -169,20 +170,21 @@ test.describe('#chatSaveRestore', () => {
169170
const panel = await openChatPanel(page);
170171

171172
// Update the backup directory in settings
172-
const settingsButton = panel.getByTitle('Open AI Settings');
173-
await settingsButton.click();
174-
const aiSettingsWidget = page.locator('#jupyternaut-persona-settings');
175-
await expect(aiSettingsWidget).toBeVisible();
176-
await aiSettingsWidget.getByText('BEHAVIOR').click();
177-
178-
const backupDirectoryInput = aiSettingsWidget.getByLabel(
179-
'Chat Backup Directory'
173+
const settings = await openSettings(page);
174+
const defaultDirectory = settings.locator(
175+
'input[label="Chat Backup Directory"]'
176+
);
177+
await defaultDirectory.pressSequentially(customDir, { delay: 100 });
178+
179+
// wait for the settings to be saved
180+
await expect(page.activity.getTabLocator('Settings')).toHaveAttribute(
181+
'class',
182+
/jp-mod-dirty/
183+
);
184+
await expect(page.activity.getTabLocator('Settings')).not.toHaveAttribute(
185+
'class',
186+
/jp-mod-dirty/
180187
);
181-
// Sometime clear method does nothing on MUI input.
182-
while (await backupDirectoryInput.inputValue()) {
183-
await backupDirectoryInput.clear();
184-
}
185-
await backupDirectoryInput.pressSequentially(customDir, { delay: 100 });
186188

187189
// Send a message
188190
const input = panel

ui-tests/tests/test-utils.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ export const DEFAULT_GENERIC_PROVIDER_SETTINGS = {
3030
}
3131
],
3232
toolsEnabled: false,
33-
useSameProviderForChatAndCompleter: true
33+
useSameProviderForChatAndCompleter: true,
34+
useSecretsManager: false
3435
},
3536
'@jupyterlite/ai:chat': {
36-
showTokenUsage: false,
37-
useSecretsManager: false
37+
showTokenUsage: false
3838
}
3939
};
4040

@@ -57,3 +57,23 @@ export async function openChatPanel(
5757
}
5858
return panel;
5959
}
60+
61+
export const openSettings = async (
62+
page: IJupyterLabPageFixture,
63+
globalSettings?: boolean
64+
): Promise<Locator> => {
65+
const args = globalSettings ? {} : { query: 'AI Chat' };
66+
await page.evaluate(async args => {
67+
await window.jupyterapp.commands.execute('settingeditor:open', args);
68+
}, args);
69+
70+
// Activate the settings tab, sometimes it does not automatically.
71+
const settingsTab = page
72+
.getByRole('main')
73+
.getByRole('tab', { name: 'Settings', exact: true });
74+
await settingsTab.click();
75+
await page.waitForCondition(
76+
async () => (await settingsTab.getAttribute('aria-selected')) === 'true'
77+
);
78+
return (await page.activity.getPanelLocator('Settings')) as Locator;
79+
};

0 commit comments

Comments
 (0)