Skip to content

Commit 1acd763

Browse files
committed
create test fixtures
1 parent 3afb6a4 commit 1acd763

File tree

4 files changed

+133
-92
lines changed

4 files changed

+133
-92
lines changed

ui/desktop/tests/e2e/chat.spec.ts

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,16 @@
11
import { test } from './fixtures.electron.packaged';
22
import { expect } from '@playwright/test';
3-
import { expectChatContainsMessage, expectLastChatMessageContains, expectChatMessageCount, expectSessionCount, goToChatHistory, goToHome, openSession, sendMessage } from './helpers/test-steps';
3+
import { changeWorkingDirectory, expectChatContainsMessage, expectCostIsNonZero, expectCostIsZero, expectLastChatMessageContains, expectChatMessageCount, expectSessionCount, expectToolCallContainsText, expectToolCallCount, getChatInput, goToChatHistory, goToHome, openSession, sendMessage, startNewChat } from './helpers/test-steps';
44

55
test.describe('Goose App', {tag: '@release'}, () => {
66
test('goose conversation', async ({ goosePage }) => {
7-
8-
await goosePage.getByTestId('sidebar-chat-button').click();
9-
await expect(goosePage.getByRole('button', { name: 'New Chat' }).first()).toBeVisible();
10-
await expect(goosePage.getByTestId('chat-show-all')).toHaveCount(0);
11-
127
await goToHome(goosePage);
13-
14-
const costTrigger = goosePage.getByTestId('bottom-menu-cost-trigger').first();
15-
const costTooltip = goosePage.getByTestId('bottom-menu-cost-tooltip').first();
16-
await expect(costTrigger).toContainText('0.0000');
17-
await costTrigger.hover();
18-
await expect(costTooltip).toContainText(
19-
'Input: 0 tokens ($0.000000) | Output: 0 tokens ($0.000000)'
20-
);
8+
await expectCostIsZero(goosePage);
219

2210
await sendMessage(goosePage, 'Hello First');
23-
2411
await sendMessage(goosePage, 'Hello Second');
25-
26-
await costTrigger.hover();
27-
await expect(costTrigger).not.toContainText('0.0000');
28-
await expect(costTooltip).not.toContainText(
29-
'Input: 0 tokens ($0.000000) | Output: 0 tokens ($0.000000)'
30-
);
12+
13+
await expectCostIsNonZero(goosePage);
3114

3215
await goToChatHistory(goosePage);
3316
await expectSessionCount(goosePage, 1);
@@ -43,45 +26,31 @@ test.describe('Goose App', {tag: '@release'}, () => {
4326
await openSession(goosePage, 2);
4427
await expectChatContainsMessage(goosePage, 'Hello Second');
4528

46-
const workingDirButton = goosePage.locator('[data-testid="bottom-menu-dir-switcher"]:visible').first();
47-
await expect(workingDirButton).toBeVisible();
48-
const oldWorkingDir = (await workingDirButton.textContent())?.trim() ?? '';
49-
await workingDirButton.click();
50-
if (oldWorkingDir) {
51-
await expect(workingDirButton).not.toContainText(oldWorkingDir);
52-
}
53-
const updatedWorkingDir = (await workingDirButton.textContent())?.trim() ?? '';
54-
expect(updatedWorkingDir.length).toBeGreaterThan(0);
29+
const updatedWorkingDir = await changeWorkingDirectory(goosePage);
5530

5631
await sendMessage(goosePage, 'what is your working directory? reply with exact path only');
5732
await expectLastChatMessageContains(goosePage, updatedWorkingDir);
5833
});
5934

6035
test('developer tool is called', async ({ goosePage }) => {
6136

62-
await goToHome(goosePage);
37+
await startNewChat(goosePage);
6338

64-
const toolCalls = goosePage.locator('.goose-message-tool');
65-
await expect(toolCalls).toHaveCount(0);
39+
await expectToolCallCount(goosePage, 0);
6640

6741
await sendMessage(goosePage, 'show the number of files in current directory');
6842

69-
await expect(toolCalls).toHaveCount(1);
70-
const newestToolCall = toolCalls.first();
71-
await expect(newestToolCall).toBeVisible();
72-
const tooltipTrigger = newestToolCall.locator('button.group.w-full span.cursor-pointer').first();
73-
await expect(tooltipTrigger).toBeVisible();
74-
await tooltipTrigger.hover();
75-
await expect(goosePage.getByTestId('tooltip-wrapper-content').first()).toContainText('developer extension');
43+
await expectToolCallCount(goosePage, 1);
44+
await expectToolCallContainsText(goosePage, 1, 'developer extension');
7645
});
7746

7847
test('verify chat history', async ({ goosePage }) => {
7948
await expectChatMessageCount(goosePage, 0);
8049
await sendMessage(goosePage, 'What is 2+2?');
8150
await expectChatMessageCount(goosePage, 2);
8251

83-
const chatInputForHistory = goosePage.getByTestId('chat-input');
84-
await chatInputForHistory.press('Control+ArrowUp');
85-
await expect(chatInputForHistory).toHaveValue('What is 2+2?');
52+
const chatInput = getChatInput(goosePage);
53+
await chatInput.press('Control+ArrowUp');
54+
await expect(chatInput).toHaveValue('What is 2+2?');
8655
});
8756
});

ui/desktop/tests/e2e/extensions.spec.ts

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test } from './fixtures.electron.packaged';
22
import { expect } from '@playwright/test';
3-
import { expectLastChatMessageContains, goToHome, sendMessage } from './helpers/test-steps';
3+
import { createCustomExtension, expectExtensionIsEnabled, expectLastChatMessageContains, getLastAssistantMessageText, getToolCalls, goToExtensions, goToHome, sendMessage } from './helpers/test-steps';
44
import { join } from 'path';
55

66
const { runningQuotes } = require('./basic-mcp');
@@ -9,7 +9,7 @@ const PLAYWRIGHT_DEEPLINK =
99

1010
test.describe('Goose App Extensions', {tag: '@release'}, () => {
1111
test('install playwright extension', async ({ goosePage }) => {
12-
await goosePage.getByTestId('sidebar-extensions-button').click();
12+
await goToExtensions(goosePage);
1313

1414
await goosePage.evaluate((link) => {
1515
// ExtensionInstallModal listener expects (_event, ...args), with deeplink in args[0].
@@ -19,20 +19,14 @@ test.describe('Goose App Extensions', {tag: '@release'}, () => {
1919
const installButton = goosePage
2020
.getByRole('button', { name: /^(Yes|Install Anyway)$/ })
2121
.first();
22-
await installButton.waitFor({ state: 'visible', timeout: 20000 }).catch(() => {});
23-
if (await installButton.isVisible().catch(() => false)) {
24-
await installButton.click();
25-
}
22+
await installButton.click();
2623

27-
await expect(goosePage.locator('#extension-playwright')).toBeVisible();
28-
await expect(
29-
goosePage.locator('#extension-playwright button[role="switch"][data-state="checked"]')
30-
).toBeVisible();
24+
await expectExtensionIsEnabled(goosePage, 'playwright');
3125

3226
await goToHome(goosePage);
3327
await sendMessage(goosePage, 'open a browser and search on google for cats');
3428

35-
const toolCalls = goosePage.locator('.goose-message-tool');
29+
const toolCalls = getToolCalls(goosePage);
3630
await expect(toolCalls.first()).toBeVisible();
3731

3832
const toolCallsText = ((await toolCalls.allTextContents()) || []).join(' ').toLowerCase();
@@ -42,30 +36,24 @@ test.describe('Goose App Extensions', {tag: '@release'}, () => {
4236
});
4337

4438
test('add custom extension', async ({ goosePage }) => {
45-
await goosePage.getByTestId('sidebar-extensions-button').click();
39+
await goToExtensions(goosePage);
4640

47-
await goosePage.getByRole('button', { name: 'Add custom extension' }).click();
48-
49-
await goosePage.getByPlaceholder('Enter extension name...').fill('Running Quotes');
50-
await goosePage.getByPlaceholder('Optional description...').fill('Inspirational running quotes MCP server');
5141
const mcpScriptPath = join(__dirname, 'basic-mcp.ts');
52-
await goosePage.getByPlaceholder('e.g. npx -y @modelcontextprotocol/my-extension <filepath>').fill(`node ${mcpScriptPath}`);
53-
54-
await goosePage.getByTestId('extension-submit-btn').click();
42+
await createCustomExtension(goosePage, {
43+
name: 'Running Quotes',
44+
description: 'Inspirational running quotes MCP server',
45+
command: `node ${mcpScriptPath}`,
46+
});
5547

56-
await expect(goosePage.locator('#extension-running-quotes')).toBeVisible();
57-
await expect(
58-
goosePage.locator('#extension-running-quotes button[role="switch"][data-state="checked"]')
59-
).toBeVisible();
48+
await expectExtensionIsEnabled(goosePage, 'running-quotes');
6049

6150
await goToHome(goosePage);
6251
await sendMessage(goosePage, 'Can you give me an inspirational running quote using the runningQuote tool?');
6352

64-
const lastMessage = goosePage.locator('.goose-message').last();
65-
const outputText = await lastMessage.textContent();
53+
const outputText = await getLastAssistantMessageText(goosePage);
6654

6755
const containsKnownQuote = runningQuotes.some(({ quote, author }) =>
68-
outputText?.includes(`"${quote}" - ${author}`)
56+
outputText.includes(`"${quote}" - ${author}`)
6957
);
7058
expect(containsKnownQuote).toBe(true);
7159
});

ui/desktop/tests/e2e/helpers/test-steps.ts

Lines changed: 107 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,137 @@ import { waitForLoadingDone } from './video';
33

44
export const LLM_TIMEOUT = 30000;
55

6-
export async function sendMessage(page: Page, text: string): Promise<void> {
7-
const chatInput = page.locator('[data-testid="chat-input"]:visible').first();
6+
export const getChatInput = (page: Page) =>
7+
page.locator('[data-testid="chat-input"]:visible').first();
8+
9+
export const sendMessage = async (page: Page, text: string) => {
10+
const chatInput = getChatInput(page);
811
await chatInput.fill(text);
912
await chatInput.press('Enter');
1013
await waitForLoadingDone(page, LLM_TIMEOUT);
11-
}
14+
};
1215

13-
export async function expectChatMessageCount(page: Page, count: number): Promise<void> {
16+
export const expectChatMessageCount = async (page: Page, count: number) => {
1417
await expect(page.locator('[data-testid="message-container"]:visible')).toHaveCount(count);
15-
}
18+
};
1619

17-
export async function expectChatContainsMessage(page: Page, text: string): Promise<void> {
20+
export const expectChatContainsMessage = async (page: Page, text: string) => {
1821
await expect(
1922
page.locator('[data-testid="message-container"]:visible').filter({ hasText: text }).first()
2023
).toBeVisible();
21-
}
24+
};
2225

23-
export async function expectLastChatMessageContains(page: Page, text: string | RegExp): Promise<void> {
26+
export const expectLastChatMessageContains = async (page: Page, text: string | RegExp) => {
2427
await expect(page.locator('[data-testid="message-container"]:visible').last()).toContainText(text);
25-
}
28+
};
29+
30+
export const getToolCalls = (page: Page) =>
31+
page.locator('.goose-message-tool');
32+
33+
export const expectToolCallCount = async (page: Page, count: number) => {
34+
await expect(getToolCalls(page)).toHaveCount(count);
35+
};
36+
37+
export const expectToolCallContainsText = async (page: Page, position: number, expectedText: string | RegExp) => {
38+
const toolCall = getToolCalls(page).nth(position - 1);
39+
await expect(toolCall).toBeVisible();
40+
const tooltipTrigger = toolCall.locator('button.group.w-full span.cursor-pointer').first();
41+
await expect(tooltipTrigger).toBeVisible();
42+
await tooltipTrigger.hover();
43+
await expect(page.getByTestId('tooltip-wrapper-content').first()).toContainText(expectedText);
44+
};
45+
46+
export const getLastAssistantMessageText = async (page: Page) => {
47+
return (await page.locator('.goose-message').last().textContent()) ?? '';
48+
};
2649

27-
export async function goToHome(page: Page): Promise<void> {
50+
export const goToHome = async (page: Page) => {
2851
await page.getByTestId('sidebar-home-button').click();
29-
}
52+
};
3053

31-
export async function expectSessionCount(page: Page, count: number): Promise<void> {
54+
export const expectSessionCount = async (page: Page, count: number) => {
3255
await expect(page.getByTestId('session-history-card')).toHaveCount(count);
33-
}
56+
};
3457

35-
export async function goToChatHistory(page: Page): Promise<void> {
58+
export const clickSidebarChat = async (page: Page) => {
59+
await page.getByTestId('sidebar-chat-button').click();
60+
};
61+
62+
export const goToChatHistory = async (page: Page) => {
3663
const showAll = page.getByTestId('chat-show-all').first();
3764
if (!(await showAll.isVisible().catch(() => false))) {
38-
await page.getByTestId('sidebar-chat-button').click();
65+
await clickSidebarChat(page);
3966
}
4067
await expect(showAll).toBeVisible();
4168
await showAll.click();
4269
await expect(page.getByRole('heading', { name: 'Chat history' })).toBeVisible();
43-
}
70+
};
4471

45-
export async function openSession(page: Page, position: number): Promise<void> {
72+
export const openSession = async (page: Page, position: number) => {
4673
await page.getByTestId('session-history-card').nth(position - 1).click();
47-
}
74+
};
75+
76+
export const startNewChat = async (page: Page) => {
77+
const newChatButton = page.getByRole('button', { name: 'New Chat' }).first();
78+
if (!(await newChatButton.isVisible().catch(() => false))) {
79+
await clickSidebarChat(page);
80+
}
81+
await newChatButton.click();
82+
};
83+
84+
export const goToExtensions = async (page: Page) => {
85+
await page.getByTestId('sidebar-extensions-button').click();
86+
};
87+
88+
export const expectExtensionIsEnabled = async (page: Page, extensionId: string) => {
89+
await expect(page.locator(`#extension-${extensionId}`)).toBeVisible();
90+
await expect(
91+
page.locator(`#extension-${extensionId} button[role="switch"][data-state="checked"]`)
92+
).toBeVisible();
93+
};
94+
95+
export const createCustomExtension = async (page: Page, opts: { name: string; description: string; command: string }) => {
96+
await page.getByRole('button', { name: 'Add custom extension' }).click();
97+
await page.getByPlaceholder('Enter extension name...').fill(opts.name);
98+
await page.getByPlaceholder('Optional description...').fill(opts.description);
99+
await page.getByPlaceholder('e.g. npx -y @modelcontextprotocol/my-extension <filepath>').fill(opts.command);
100+
await page.getByTestId('extension-submit-btn').click();
101+
};
102+
103+
export const expectCostIsZero = async (page: Page) => {
104+
const costTrigger = page.getByTestId('bottom-menu-cost-trigger').first();
105+
const costTooltip = page.getByTestId('bottom-menu-cost-tooltip').first();
106+
await expect(costTrigger).toContainText('0.0000');
107+
await costTrigger.hover();
108+
await expect(costTooltip).toContainText(
109+
'Input: 0 tokens ($0.000000) | Output: 0 tokens ($0.000000)'
110+
);
111+
};
112+
113+
export const expectCostIsNonZero = async (page: Page) => {
114+
const costTrigger = page.getByTestId('bottom-menu-cost-trigger').first();
115+
const costTooltip = page.getByTestId('bottom-menu-cost-tooltip').first();
116+
await costTrigger.hover();
117+
await expect(costTrigger).not.toContainText('0.0000');
118+
await expect(costTooltip).not.toContainText(
119+
'Input: 0 tokens ($0.000000) | Output: 0 tokens ($0.000000)'
120+
);
121+
};
122+
123+
export const changeWorkingDirectory = async (page: Page) => {
124+
const workingDirButton = page.locator('[data-testid="bottom-menu-dir-switcher"]:visible').first();
125+
await expect(workingDirButton).toBeVisible();
126+
const oldWorkingDir = (await workingDirButton.textContent())?.trim() ?? '';
127+
await workingDirButton.click();
128+
if (oldWorkingDir) {
129+
await expect(workingDirButton).not.toContainText(oldWorkingDir);
130+
}
131+
const updatedWorkingDir = (await workingDirButton.textContent())?.trim() ?? '';
132+
expect(updatedWorkingDir.length).toBeGreaterThan(0);
133+
return updatedWorkingDir;
134+
};
48135

49-
export async function openSettingsAppTab(page: Page): Promise<void> {
136+
export const openSettingsAppTab = async (page: Page) => {
50137
await page.getByTestId('sidebar-settings-button').click();
51138
await page.getByTestId('settings-app-tab').click();
52-
}
139+
};

ui/desktop/tests/e2e/settings.spec.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import { goToHome, openSettingsAppTab } from './helpers/test-steps';
44

55
test.describe('Settings', {tag: '@release'}, () => {
66
test('dark mode toggle', async ({ goosePage }) => {
7-
console.log('Testing dark mode toggle...');
8-
97
await openSettingsAppTab(goosePage);
108

119
const darkModeButton = goosePage.getByTestId('dark-mode-button');
@@ -15,7 +13,6 @@ test.describe('Settings', {tag: '@release'}, () => {
1513
await expect(darkModeButton).toBeVisible();
1614

1715
const isDarkMode = await goosePage.evaluate(() => document.documentElement.classList.contains('dark'));
18-
console.log('Initial dark mode state:', isDarkMode);
1916

2017
if (isDarkMode) {
2118
await lightModeButton.click();

0 commit comments

Comments
 (0)