diff --git a/packages/bruno-app/src/components/AIAssist/index.spec.js b/packages/bruno-app/src/components/AIAssist/index.spec.js index 21a9bab1b..702e7b9cf 100644 --- a/packages/bruno-app/src/components/AIAssist/index.spec.js +++ b/packages/bruno-app/src/components/AIAssist/index.spec.js @@ -5,6 +5,7 @@ import { Provider } from 'react-redux'; import { configureStore } from '@reduxjs/toolkit'; import { ThemeProvider } from 'styled-components'; import { aiGenerateScript, stopAiGeneration } from 'utils/ai'; +import { getPlatformModifierKey } from 'utils/common/platform'; import AIAssist from './index'; jest.mock('utils/ai', () => ({ @@ -12,6 +13,11 @@ jest.mock('utils/ai', () => ({ stopAiGeneration: jest.fn() })); +jest.mock('utils/common/platform', () => ({ + ...jest.requireActual('utils/common/platform'), + getPlatformModifierKey: jest.fn() +})); + const theme = { bg: '#1e1e1e', text: '#ffffff', @@ -63,6 +69,7 @@ describe('AIAssist', () => { beforeEach(() => { jest.clearAllMocks(); aiGenerateScript.mockResolvedValue({ content: 'test("generated", () => {});' }); + getPlatformModifierKey.mockReturnValue('Ctrl'); }); describe('visibility', () => { @@ -159,6 +166,17 @@ describe('AIAssist', () => { expect(screen.queryByRole('button', { name: 'Status 200' })).not.toBeInTheDocument(); }); + it.each([ + ['macOS', '⌘'], + ['non-macOS', 'Ctrl'] + ])('shows the %s modifier in the generate shortcut hint', (_platform, modifier) => { + getPlatformModifierKey.mockReturnValue(modifier); + renderAIAssist(); + openPopup(); + + expect(screen.getByText(`${modifier} + Enter to generate`)).toBeInTheDocument(); + }); + it('keeps Generate disabled until the prompt has text', () => { renderAIAssist(); openPopup(); diff --git a/packages/bruno-app/src/components/Preferences/AI/AutocompletePane.js b/packages/bruno-app/src/components/Preferences/AI/AutocompletePane.js index 503867af2..766878f37 100644 --- a/packages/bruno-app/src/components/Preferences/AI/AutocompletePane.js +++ b/packages/bruno-app/src/components/Preferences/AI/AutocompletePane.js @@ -1,5 +1,6 @@ import { IconChevronDown } from '@tabler/icons'; import ToggleSwitch from 'components/ToggleSwitch'; +import { getPlatformModifierKey } from 'utils/common/platform'; /** * Autocomplete tab content. Sibling of the Configuration tab inside @@ -25,7 +26,7 @@ const TRIGGER_MODES = [ { value: 'manual', label: 'Manual', - description: 'Only on ⌘+\\ / Ctrl+\\' + description: `Only on ${getPlatformModifierKey()}+\\` } ]; @@ -148,7 +149,7 @@ const AutocompletePane = ({
Keymap
- Tab accept · Esc dismiss · +\ trigger + Tab accept · Esc dismiss · {getPlatformModifierKey()}+\ trigger
diff --git a/packages/bruno-app/src/components/Preferences/AI/AutocompletePane.spec.js b/packages/bruno-app/src/components/Preferences/AI/AutocompletePane.spec.js new file mode 100644 index 000000000..1edd19208 --- /dev/null +++ b/packages/bruno-app/src/components/Preferences/AI/AutocompletePane.spec.js @@ -0,0 +1,55 @@ +import '@testing-library/jest-dom'; +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { ThemeProvider } from 'styled-components'; + +global.React = React; + +jest.mock('utils/common/platform', () => ({ + getPlatformModifierKey: jest.fn(() => 'Ctrl') +})); + +import { getPlatformModifierKey } from 'utils/common/platform'; +import AutocompletePane from './AutocompletePane'; + +const theme = { + primary: { solid: '#6366f1' }, + input: { bg: '#111827' }, + colors: { text: { muted: '#9ca3af' } } +}; + +const baseProps = { + aiEnabled: true, + enabled: true, + model: '', + triggerMode: 'manual', + availableModels: [{ id: 'model-1', label: 'Model 1' }], + hasConfiguredProvider: true, + onToggleEnabled: jest.fn(), + onChangeModel: jest.fn(), + onChangeTriggerMode: jest.fn() +}; + +const renderPane = (modifier, props = {}) => { + getPlatformModifierKey.mockReturnValue(modifier); + return render( + + + + ); +}; + +describe('AutocompletePane shortcut copy', () => { + it.each([ + ['macOS', '⌘'], + ['non-macOS', 'Ctrl'] + ])('shows the %s modifier in the keymap', (_platform, modifier) => { + renderPane(modifier); + expect(screen.getByText(modifier)).toBeInTheDocument(); + }); + + it('shows the platform modifier in the manual trigger description', () => { + renderPane('Ctrl'); + expect(screen.getByText('Only on Ctrl+\\')).toBeInTheDocument(); + }); +}); diff --git a/packages/bruno-app/src/utils/common/platform.js b/packages/bruno-app/src/utils/common/platform.js index 687b19c3d..7ab3552e0 100644 --- a/packages/bruno-app/src/utils/common/platform.js +++ b/packages/bruno-app/src/utils/common/platform.js @@ -40,6 +40,10 @@ export const isLinuxOS = () => { return osFamily.includes('linux') || osFamily.includes('ubuntu') || osFamily.includes('debian') || osFamily.includes('fedora') || osFamily.includes('centos') || osFamily.includes('arch'); }; +export const getPlatformModifierKey = () => { + return isMacOS() ? '⌘' : 'Ctrl'; +}; + export const getRevealInFolderLabel = () => { if (isMacOS()) return 'Reveal in Finder'; if (isWindowsOS()) return 'Reveal in File Explorer'; diff --git a/playwright/index.ts b/playwright/index.ts index ddcb48de6..e45165126 100644 --- a/playwright/index.ts +++ b/playwright/index.ts @@ -22,6 +22,9 @@ const defaultPreferences = { hasLaunchedBefore: true, hasSeenWelcomeModal: true, lastSeenVersion: version + }, + ai: { + enabled: false } } }; diff --git a/tests/preferences/ai/ai-shortcut-hints.spec.ts b/tests/preferences/ai/ai-shortcut-hints.spec.ts new file mode 100644 index 000000000..3f6bb7d31 --- /dev/null +++ b/tests/preferences/ai/ai-shortcut-hints.spec.ts @@ -0,0 +1,17 @@ +import { test, expect } from '../../../playwright'; + +const expectedModifier = process.platform === 'darwin' ? '⌘' : 'Ctrl'; + +test.describe('AI shortcut hints', () => { + test('autocomplete keymap shows the platform-correct modifier', async ({ pageWithUserData: page }) => { + await page.locator('[data-app-state="loaded"]').waitFor(); + + await page.locator('.status-bar button[data-trigger="preferences"]').click(); + await page.getByRole('tab', { name: 'AI', exact: true }).click(); + await page.getByTestId('ai-tab-autocomplete').click(); + + const keymap = page.locator('.autocomplete-keymap'); + await expect(keymap).toBeVisible(); + await expect(keymap.getByText(expectedModifier, { exact: true })).toBeVisible(); + }); +}); diff --git a/tests/preferences/ai/init-user-data/preferences.json b/tests/preferences/ai/init-user-data/preferences.json new file mode 100644 index 000000000..b38647a42 --- /dev/null +++ b/tests/preferences/ai/init-user-data/preferences.json @@ -0,0 +1,11 @@ +{ + "preferences": { + "onboarding": { + "hasLaunchedBefore": true, + "hasSeenWelcomeModal": true + }, + "ai": { + "enabled": true + } + } +}