Files
bruno/tests/shortcuts/bound-actions.spec.ts
2026-05-14 17:38:55 +05:30

2017 lines
88 KiB
TypeScript

import { test, expect, Page } from '../../playwright';
import {
createCollection,
createRequest,
openRequest as openRequestBase,
closeAllCollections,
createFolder,
openCollection,
selectRequestPaneTab
} from '../utils/page';
const modifier = process.platform === 'darwin' ? 'Meta' : 'Control';
const collectionName = 'kb-collection';
const baseRequests = ['req-1', 'req-2', 'req-3', 'req-4', 'req-5', 'req-6', 'req-7', 'req-8', 'req-9'];
const setupBoundActionsData = async (page: Page, createTmpDir: (prefix: string) => Promise<string>) => {
await closeAllCollections(page);
const path = await createTmpDir('kb-collection-path');
await createCollection(page, collectionName, path);
await createFolder(page, 'kb-folder', collectionName, true);
await createFolder(page, 'kb-draft-folder', collectionName, true);
await createFolder(page, 'kb-terminal-folder', collectionName, true);
};
const checkIfRequestExists = async (page: Page, requestName: string) => {
await openCollection(page, collectionName);
const request = page.getByTestId('collections').locator('.collection-item-name').filter({ hasText: requestName }).first();
return (await request.count()) > 0;
};
const openRequest = async (...args: Parameters<typeof openRequestBase>) => {
const [page, targetCollectionName, requestName] = args;
if (
targetCollectionName === collectionName
&& baseRequests.includes(requestName)
&& !(await checkIfRequestExists(page, requestName))
) {
await createRequest(page, requestName, targetCollectionName);
}
return openRequestBase(...args);
};
const openKeybindingsTab = async (page: Page) => {
await page.getByRole('button', { name: 'Open Preferences' }).click();
await page.getByRole('tab', { name: 'Keybindings' }).click();
await expect(page.locator('.section-header').filter({ hasText: 'Keybindings' })).toBeVisible();
};
/**
* Close the Preferences tab by clicking its close button.
* Using the close button avoids depending on any keyboard shortcut that may
* have just been reconfigured.
*/
const closePreferencesTab = async (page: Page) => {
const prefTab = page.locator('.request-tab').filter({ hasText: 'Preferences' });
await prefTab.hover();
await prefTab.getByTestId('request-tab-close-icon').click({ force: true });
await expect(prefTab).not.toBeVisible({ timeout: 8000 });
};
const closeTabByName = async (page: any, name: string | RegExp) => {
const tab = page.locator('.request-tab').filter({ hasText: name });
await tab.click();
await tab.hover();
await tab.getByTestId('request-tab-close-icon').click({ force: true });
await expect(tab).not.toBeVisible({ timeout: 2000 });
};
const openFolderSettingsTab = async (page: Page, folderName: string) => {
await openCollection(page, collectionName);
const folderRow = page.locator('.collection-item-name').filter({ hasText: folderName }).first();
await expect(folderRow).toBeVisible({ timeout: 5000 });
await folderRow.dblclick();
await expect(page.locator('.request-tab').filter({ hasText: folderName })).toBeVisible({ timeout: 3000 });
};
const reopenClosedTab = async (page: Page, shortcut: () => Promise<void>, expectedTabName: string | RegExp) => {
for (let attempt = 0; attempt < 3; attempt++) {
await page.locator('.request-tab').first().click();
await page.waitForTimeout(150);
await shortcut();
const reopenedTab = page.locator('.request-tab').filter({ hasText: expectedTabName });
if ((await reopenedTab.count()) > 0) {
await expect(reopenedTab).toBeVisible({ timeout: 3000 });
return;
}
await page.waitForTimeout(200);
}
await expect(page.locator('.request-tab').filter({ hasText: expectedTabName })).toBeVisible({ timeout: 5000 });
};
const remapKeybinding = async (
page: Page,
action: string,
pressShortcut: () => Promise<void>
) => {
await openKeybindingsTab(page);
const row = page.getByTestId(`keybinding-row-${action}`);
await expect(row).toBeVisible({ timeout: 5000 });
await row.scrollIntoViewIfNeeded();
await row.hover();
const editButton = row.getByTestId(`keybinding-edit-${action}`);
const keybindingInput = page.getByTestId(`keybinding-input-${action}`);
if (await editButton.isVisible().catch(() => false)) {
await editButton.click({ force: true });
} else {
await row.click({ force: true });
if (await editButton.isVisible().catch(() => false)) {
await editButton.click({ force: true });
}
}
await expect(keybindingInput).toBeVisible({ timeout: 5000 });
await page.keyboard.press('Backspace');
await pressShortcut();
await closePreferencesTab(page);
};
const getTabIndex = async (page: Page, name: string) => {
const tabs = page.locator('.request-tab .tab-label');
const count = await tabs.count();
for (let i = 0; i < count; i++) {
const text = (await tabs.nth(i).innerText()).trim();
if (text.includes(name)) {
return i;
}
}
return -1;
};
// ─── Tests ────
test.describe('Shortcut Keys - BOUND_ACTIONS', () => {
test.beforeEach(async ({ page, createTmpDir }) => {
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 5000 });
await setupBoundActionsData(page, createTmpDir);
});
test.afterAll(async ({ page }) => {
await closeAllCollections(page);
});
test.describe('TABS', () => {
test.describe('SHORTCUT: Close Tab', () => {
test('default Cmd/Ctrl+W closes the active tab', async ({ page, createTmpDir }) => {
await openRequest(page, collectionName, 'req-1', { persist: true });
const reqTab = page.locator('.request-tab').filter({ hasText: 'req-1' });
// Click the tab to guarantee it's the focused/active tab before firing the shortcut.
await reqTab.click();
await expect(reqTab).toHaveClass(/active/, { timeout: 2000 });
await page.keyboard.press(`${modifier}+KeyW`);
await expect(page.locator('.request-tab')).toHaveCount(2, { timeout: 3000 });
});
test('customized Cmd/Ctrl+Shift+X closes the active tab', async ({ page, createTmpDir }) => {
// Remap closeTab to Cmd/Ctrl+Shift+X
await openKeybindingsTab(page);
const row = page.getByTestId(`keybinding-row-closeTab`);
await row.hover();
await page.getByTestId(`keybinding-edit-closeTab`).click();
// Wait for input to enter recording mode
await expect(page.getByTestId(`keybinding-input-closeTab`)).toBeVisible({ timeout: 2000 });
// Remove the old keybindings
await page.keyboard.down('Backspace');
await page.keyboard.down('Shift');
await page.keyboard.down('KeyX');
await page.keyboard.up('KeyX');
await page.keyboard.up('Shift');
await closePreferencesTab(page);
await openRequest(page, collectionName, 'req-1', { persist: true });
await expect(page.locator('.request-tab').filter({ hasText: 'req-1' })).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Shift');
await page.keyboard.down('KeyX');
await page.keyboard.up('KeyX');
await page.keyboard.up('Shift');
await expect(page.locator('.request-tab')).toHaveCount(2, { timeout: 3000 });
});
});
test.describe('SHORTCUT: Close All Tabs', () => {
test('default Cmd/Ctrl+Shift+W closes all tabs', async ({ page }) => {
await openRequest(page, collectionName, 'req-1', { persist: true });
await openRequest(page, collectionName, 'req-2', { persist: true });
await openRequest(page, collectionName, 'req-3', { persist: true });
await page.getByTestId('runner').click();
await expect(page.locator('.request-tab').filter({ hasText: 'req-1' })).toBeVisible({ timeout: 2000 });
await expect(page.locator('.request-tab').filter({ hasText: 'req-2' })).toBeVisible({ timeout: 2000 });
await expect(page.locator('.request-tab').filter({ hasText: 'req-3' })).toBeVisible({ timeout: 2000 });
await page.keyboard.down(modifier);
await page.keyboard.down('Shift');
await page.keyboard.down('KeyW');
await page.keyboard.up('KeyW');
await page.keyboard.up('Shift');
await page.keyboard.up(modifier);
await expect(page.locator('.request-tab')).toHaveCount(2, { timeout: 3000 });
});
test('customized Alt+Y closes all tabs', async ({ page }) => {
// Remap closeAllTabs to Alt+Y
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-closeAllTabs');
await row.hover();
await page.getByTestId('keybinding-row-closeAllTabs').click();
await expect(page.getByTestId('keybinding-input-closeAllTabs')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await closePreferencesTab(page);
await openRequest(page, collectionName, 'req-1', { persist: true });
await openRequest(page, collectionName, 'req-2', { persist: true });
await openRequest(page, collectionName, 'req-3', { persist: true });
await expect(page.locator('.request-tab').filter({ hasText: 'req-1' })).toBeVisible({ timeout: 2000 });
await expect(page.locator('.request-tab').filter({ hasText: 'req-2' })).toBeVisible({ timeout: 2000 });
await expect(page.locator('.request-tab').filter({ hasText: 'req-3' })).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await expect(page.locator('.request-tab')).toHaveCount(2, { timeout: 3000 });
});
});
test.describe('SHORTCUT: Save', () => {
test('default Cmd/Ctrl+S save tab', async ({ page, createTmpDir }) => {
await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick();
await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 });
// Verify initially there is NO draft indicator (close icon is present)
const collectionTab = page.locator('.request-tab').filter({ has: page.locator('.tab-label', { hasText: 'Collection' }) });
await expect(collectionTab.locator('.close-icon')).toBeVisible();
await expect(collectionTab.locator('.has-changes-icon')).not.toBeVisible();
await page.locator('.tab.headers').click();
const headerTable = page.locator('table').first();
const headerRow = headerTable.locator('tbody tr').first();
const nameEditor = headerRow.locator('.CodeMirror').first();
await nameEditor.click();
await page.keyboard.type('X-Custom-Header');
const valueEditor = headerRow.locator('.CodeMirror').nth(1);
await valueEditor.click();
await page.keyboard.type('custom-value');
// Verify draft indicator appears in the tab
await expect(collectionTab.locator('.has-changes-icon')).toBeVisible();
await expect(collectionTab.locator('.close-icon')).not.toBeVisible();
// Save the changes
await page.keyboard.down(modifier);
await page.keyboard.down('KeyS');
await page.keyboard.up('KeyS');
await page.keyboard.up(modifier);
// Verify draft indicator is gone after saving
await expect(collectionTab.locator('.close-icon')).toBeVisible();
await expect(collectionTab.locator('.has-changes-icon')).not.toBeVisible();
});
test('customized Alt+S save tab', async ({ page, createTmpDir }) => {
// Remap save to Alt+S
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-save');
await row.hover();
await page.getByTestId('keybinding-edit-save').click();
await expect(page.getByTestId('keybinding-input-save')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyS');
await page.keyboard.up('KeyS');
await page.keyboard.up('Alt');
await closePreferencesTab(page);
await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick();
await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 });
// Verify initially there is NO draft indicator (close icon is present)
const collectionTab = page.locator('.request-tab').filter({ has: page.locator('.tab-label', { hasText: 'Collection' }) });
await expect(collectionTab.locator('.close-icon')).toBeVisible();
await expect(collectionTab.locator('.has-changes-icon')).not.toBeVisible();
await page.locator('.tab.headers').click();
const headerTable = page.locator('table').first();
const headerRow = headerTable.locator('tbody tr').first();
const nameEditor = headerRow.locator('.CodeMirror').first();
await nameEditor.click();
await page.keyboard.type('X-Custom-Header');
const valueEditor = headerRow.locator('.CodeMirror').nth(1);
await valueEditor.click();
await page.keyboard.type('custom-value');
// Verify draft indicator appears in the tab
await expect(collectionTab.locator('.has-changes-icon')).toBeVisible();
await expect(collectionTab.locator('.close-icon')).not.toBeVisible();
await page.locator('body').click({ position: { x: 1, y: 1 } });
// Save the changes
await page.keyboard.down('Alt');
await page.keyboard.down('KeyS');
await page.keyboard.up('KeyS');
await page.keyboard.up('Alt');
// Verify draft indicator is gone after saving
await expect(collectionTab.locator('.close-icon')).toBeVisible();
await expect(collectionTab.locator('.has-changes-icon')).not.toBeVisible();
});
});
test.describe('SHORTCUT: Save All Tabs', () => {
test('default Cmd/Ctrl+Shift+S save all tabs', async ({ page }) => {
await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick();
await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 });
// Verify initially there is NO draft indicator (close icon is present)
const collectionTab = page.locator('.request-tab').filter({ has: page.locator('.tab-label', { hasText: 'Collection' }) });
await expect(collectionTab.locator('.close-icon')).toBeVisible();
await expect(collectionTab.locator('.has-changes-icon')).not.toBeVisible();
await page.locator('.tab.headers').click();
const headerTable = page.locator('table').first();
const headerRow = headerTable.locator('tbody tr').first();
const nameEditor = headerRow.locator('.CodeMirror').first();
await nameEditor.click();
await page.keyboard.type('X-Custom-Header');
const valueEditor = headerRow.locator('.CodeMirror').nth(1);
await valueEditor.click();
await page.keyboard.type('custom-value');
// Verify draft indicator appears in the tab
await expect(collectionTab.locator('.has-changes-icon')).toBeVisible();
await expect(collectionTab.locator('.close-icon')).not.toBeVisible();
// Open Folder-Settings tab (create folder + double-click)
await page.locator('.collection-item-name').filter({ hasText: 'kb-draft-folder' }).dblclick();
// Verify folder settings tab is open
const folderTab = page.locator('.request-tab').filter({ has: page.locator('.tab-label', { hasText: 'kb-draft-folder' }) });
await expect(folderTab).toBeVisible();
await expect(folderTab.locator('.close-icon')).toBeVisible();
await expect(folderTab.locator('.has-changes-icon')).not.toBeVisible();
const folderHeaderTable = page.locator('table').first();
const folderHeaderRow = folderHeaderTable.locator('tbody tr').first();
const folderNameEditor = folderHeaderRow.locator('.CodeMirror').first();
await folderNameEditor.click();
await page.keyboard.type('X-Folder-Header');
const folderValueEditor = folderHeaderRow.locator('.CodeMirror').nth(1);
await folderValueEditor.click();
await page.keyboard.type('folder-value');
// Verify draft indicator appears in the folder tab
await expect(folderTab.locator('.has-changes-icon')).toBeVisible();
await expect(folderTab.locator('.close-icon')).not.toBeVisible();
// Save the changes
await page.keyboard.down(modifier);
await page.keyboard.down('Shift');
await page.keyboard.down('KeyS');
await page.keyboard.up('KeyS');
await page.keyboard.up('Shift');
await page.keyboard.up(modifier);
// Verify draft indicator is gone after saving
await expect(folderTab.locator('.close-icon')).toBeVisible();
await expect(folderTab.locator('.has-changes-icon')).not.toBeVisible();
// Verify draft indicator is gone after saving
await expect(collectionTab.locator('.close-icon')).toBeVisible();
await expect(collectionTab.locator('.has-changes-icon')).not.toBeVisible();
});
test('customized Alt+Shift+S save all tabs', async ({ page }) => {
// Remap saveAllTabs to Alt+Shift+S
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-saveAllTabs');
await row.hover();
await page.getByTestId('keybinding-edit-saveAllTabs').click();
await expect(page.getByTestId('keybinding-input-saveAllTabs')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('Shift');
await page.keyboard.down('KeyS');
await page.keyboard.up('KeyS');
await page.keyboard.up('Shift');
await page.keyboard.up('Alt');
await closePreferencesTab(page);
await page.locator('.collection-name').filter({ hasText: collectionName }).dblclick();
await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 });
// Verify initially there is NO draft indicator (close icon is present)
const collectionTab = page.locator('.request-tab').filter({ has: page.locator('.tab-label', { hasText: 'Collection' }) });
await expect(collectionTab.locator('.close-icon')).toBeVisible();
await expect(collectionTab.locator('.has-changes-icon')).not.toBeVisible();
await page.locator('.tab.headers').click();
const headerTable = page.locator('table').first();
const headerRow = headerTable.locator('tbody tr').first();
const nameEditor = headerRow.locator('.CodeMirror').first();
await nameEditor.click();
await page.keyboard.type('X-Custom-Header');
const valueEditor = headerRow.locator('.CodeMirror').nth(1);
await valueEditor.click();
await page.keyboard.type('custom-value');
// Verify draft indicator appears in the tab
await expect(collectionTab.locator('.has-changes-icon')).toBeVisible();
await expect(collectionTab.locator('.close-icon')).not.toBeVisible();
// Open Folder-Settings tab (create folder + double-click)
await page.locator('.collection-item-name').filter({ hasText: 'kb-draft-folder' }).dblclick();
// Verify folder settings tab is open
const folderTab = page.locator('.request-tab').filter({ has: page.locator('.tab-label', { hasText: 'kb-draft-folder' }) });
await expect(folderTab).toBeVisible();
await expect(folderTab.locator('.close-icon')).toBeVisible();
await expect(folderTab.locator('.has-changes-icon')).not.toBeVisible();
const folderHeaderTable = page.locator('table').first();
const folderHeaderRow = folderHeaderTable.locator('tbody tr').first();
const folderNameEditor = folderHeaderRow.locator('.CodeMirror').first();
await folderNameEditor.click();
await page.keyboard.type('X-Folder-Header');
const folderValueEditor = folderHeaderRow.locator('.CodeMirror').nth(1);
await folderValueEditor.click();
await page.keyboard.type('folder-value');
// Verify draft indicator appears in the folder tab
await expect(folderTab.locator('.has-changes-icon')).toBeVisible();
await expect(folderTab.locator('.close-icon')).not.toBeVisible();
// Save the changes
await page.keyboard.down('Alt');
await page.keyboard.down('Shift');
await page.keyboard.down('KeyS');
await page.keyboard.up('KeyS');
await page.keyboard.up('Shift');
await page.keyboard.up('Alt');
// Verify draft indicator is gone after saving
await expect(folderTab.locator('.close-icon')).toBeVisible();
await expect(folderTab.locator('.has-changes-icon')).not.toBeVisible();
// Verify draft indicator is gone after saving
await expect(collectionTab.locator('.close-icon')).toBeVisible();
await expect(collectionTab.locator('.has-changes-icon')).not.toBeVisible();
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
});
});
test.describe('SHORTCUT: Switch to Previous Tab', () => {
test('default Cmd/Ctrl+Shift+[ switches to previous tab', async ({ page }) => {
await openRequest(page, collectionName, 'req-4', { persist: true });
await openRequest(page, collectionName, 'req-5', { persist: true });
await openRequest(page, collectionName, 'req-6', { persist: true });
await expect(page.locator('.request-tab').filter({ hasText: 'req-6' })).toBeVisible({ timeout: 2000 });
// req-6 is active (last opened) — press previous → req-5
await page.keyboard.press(`${modifier}+Shift+BracketLeft`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-5/, { timeout: 3000 });
// Press again → req-4
await page.keyboard.press(`${modifier}+Shift+BracketLeft`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-4/, { timeout: 3000 });
});
test('customized Shift+P switches to previous tab', async ({ page }) => {
// Remap switchToPreviousTab to Shift+P
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-switchToPreviousTab');
await row.hover();
await page.getByTestId('keybinding-edit-switchToPreviousTab').click();
await expect(page.getByTestId('keybinding-input-switchToPreviousTab')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Shift');
await page.keyboard.down('KeyP');
await page.keyboard.up('KeyP');
await page.keyboard.up('Shift');
await closePreferencesTab(page);
// Reuse the same requests opened in the default test
await openRequest(page, collectionName, 'req-4', { persist: true });
await openRequest(page, collectionName, 'req-5', { persist: true });
await openRequest(page, collectionName, 'req-6', { persist: true });
await expect(page.locator('.request-tab').filter({ hasText: 'req-6' })).toBeVisible({ timeout: 2000 });
// req-6 is active — press Shift+P → req-5
await page.keyboard.down('Shift');
await page.keyboard.down('KeyP');
await page.keyboard.up('KeyP');
await page.keyboard.up('Shift');
await expect(page.locator('li.request-tab.active')).toHaveText(/req-5/, { timeout: 3000 });
});
});
test.describe('SHORTCUT: Switch to Next Tab', () => {
test('default Cmd/Ctrl+Shift+] switches to next tab', async ({ page }) => {
await openRequest(page, collectionName, 'req-4', { persist: true });
await openRequest(page, collectionName, 'req-5', { persist: true });
await openRequest(page, collectionName, 'req-6', { persist: true });
// Go back to req-4 to start from the left
await openRequest(page, 'kb-collection', 'req-4', { persist: true });
await expect(page.locator('li.request-tab.active')).toHaveText(/req-4/);
// req-4 is active — press next → req-5
await page.keyboard.press(`${modifier}+Shift+BracketRight`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-5/, { timeout: 3000 });
// Press again → req-6
await page.keyboard.press(`${modifier}+Shift+BracketRight`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-6/, { timeout: 3000 });
});
test('customized Shift+N switches to next tab', async ({ page }) => {
// Remap switchToNextTab to Shift+N
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-switchToNextTab');
await row.hover();
await page.getByTestId('keybinding-edit-switchToNextTab').click();
await expect(page.getByTestId('keybinding-input-switchToNextTab')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Shift');
await page.keyboard.down('KeyN');
await page.keyboard.up('KeyN');
await page.keyboard.up('Shift');
await closePreferencesTab(page);
await openRequest(page, collectionName, 'req-4', { persist: true });
await openRequest(page, collectionName, 'req-5', { persist: true });
await openRequest(page, collectionName, 'req-6', { persist: true });
// Go back to req-4
await openRequest(page, 'kb-collection', 'req-4', { persist: true });
await expect(page.locator('li.request-tab.active')).toHaveText(/req-4/);
// req-4 is active — press Shift+N → req-5
await page.keyboard.down('Shift');
await page.keyboard.down('KeyN');
await page.keyboard.up('KeyN');
await page.keyboard.up('Shift');
await expect(page.locator('li.request-tab.active')).toHaveText(/req-5/, { timeout: 3000 });
});
});
test.describe('SHORTCUT: Move Tab Left', () => {
test('default Cmd/Ctrl+[ moves active tab left', async ({ page }) => {
await openRequest(page, collectionName, 'req-7', { persist: true });
await openRequest(page, collectionName, 'req-8', { persist: true });
await openRequest(page, collectionName, 'req-9', { persist: true });
// req-9 is active and last
const tabs = page.locator('.request-tab');
const totalTabs = await tabs.count();
await expect(tabs.nth(totalTabs - 1)).toHaveText(/req-9/);
// Press Cmd/Ctrl+[ → req-9 moves left, req-8 becomes last
await page.keyboard.press(`${modifier}+BracketLeft`);
await expect(tabs.nth(totalTabs - 1)).toHaveText(/req-8/, { timeout: 3000 });
await expect(tabs.nth(totalTabs - 2)).toHaveText(/req-9/);
// Press again → req-9 moves one more position left
await page.keyboard.press(`${modifier}+BracketLeft`);
await expect(tabs.nth(totalTabs - 3)).toHaveText(/req-9/, { timeout: 3000 });
});
test('customized Alt+L moves active tab left', async ({ page }) => {
// Remap moveTabLeft to Alt+L
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-moveTabLeft');
await row.hover();
await page.getByTestId('keybinding-edit-moveTabLeft').click();
await expect(page.getByTestId('keybinding-input-moveTabLeft')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyL');
await page.keyboard.up('KeyL');
await page.keyboard.up('Alt');
await closePreferencesTab(page);
await openRequest(page, 'kb-collection', 'req-7', { persist: true });
await openRequest(page, 'kb-collection', 'req-8', { persist: true });
await openRequest(page, 'kb-collection', 'req-9', { persist: true });
// req-9 is active
const tabs = page.locator('.request-tab');
// Press Alt+L → req-9 moves left, req-8 becomes last
await page.keyboard.down('Alt');
await page.keyboard.down('KeyL');
await page.keyboard.up('KeyL');
await page.keyboard.up('Alt');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyL');
await page.keyboard.up('KeyL');
await page.keyboard.up('Alt');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyL');
await page.keyboard.up('KeyL');
await page.keyboard.up('Alt');
await expect(tabs.nth(0)).toHaveText(/req-9/);
});
});
test.describe('SHORTCUT: Move Tab Right', () => {
test('default Cmd/Ctrl+] moves active tab right', async ({ page }) => {
await openRequest(page, collectionName, 'req-6', { persist: true });
await openRequest(page, collectionName, 'req-7', { persist: true });
await openRequest(page, collectionName, 'req-8', { persist: true });
await openRequest(page, collectionName, 'req-9', { persist: true });
// Move req-9 to first position first
await page.keyboard.press(`${modifier}+BracketLeft`);
await page.keyboard.press(`${modifier}+BracketLeft`);
await page.keyboard.press(`${modifier}+BracketLeft`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-9/);
const startIndex = await getTabIndex(page, 'req-9');
expect(startIndex).toBeGreaterThanOrEqual(0);
await page.keyboard.press(`${modifier}+BracketRight`);
const indexAfterOneMove = await getTabIndex(page, 'req-9');
expect(indexAfterOneMove).toBeGreaterThanOrEqual(startIndex);
await page.keyboard.press(`${modifier}+BracketRight`);
const indexAfterTwoMoves = await getTabIndex(page, 'req-9');
expect(indexAfterTwoMoves).toBeGreaterThanOrEqual(indexAfterOneMove);
await page.keyboard.press(`${modifier}+BracketRight`);
const indexAfterThreeMoves = await getTabIndex(page, 'req-9');
expect(indexAfterThreeMoves).toBeGreaterThanOrEqual(indexAfterTwoMoves);
});
test('customized Alt+R moves active tab right', async ({ page }) => {
// Remap moveTabRight to Alt+R
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-moveTabRight');
await row.hover();
await page.getByTestId('keybinding-edit-moveTabRight').click();
await expect(page.getByTestId('keybinding-input-moveTabRight')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyR');
await page.keyboard.up('KeyR');
await page.keyboard.up('Alt');
await closePreferencesTab(page);
await openRequest(page, collectionName, 'req-6', { persist: true });
await openRequest(page, collectionName, 'req-7', { persist: true });
await openRequest(page, collectionName, 'req-8', { persist: true });
await openRequest(page, collectionName, 'req-9', { persist: true });
const req7Tab = page.locator('.request-tab').filter({ hasText: 'req-7' }).first();
await req7Tab.click();
await expect(req7Tab).toHaveClass(/active/);
const startIndex = await getTabIndex(page, 'req-7');
expect(startIndex).toBeGreaterThanOrEqual(0);
// Press Alt+L → req-9 moves right, req-8 becomes last
await page.keyboard.down('Alt');
await page.keyboard.down('KeyR');
await page.keyboard.up('KeyR');
await page.keyboard.up('Alt');
const indexAfterOneMove = await getTabIndex(page, 'req-7');
expect(indexAfterOneMove).toBeGreaterThan(startIndex);
await page.keyboard.down('Alt');
await page.keyboard.down('KeyR');
await page.keyboard.up('KeyR');
await page.keyboard.up('Alt');
const indexAfterTwoMoves = await getTabIndex(page, 'req-7');
expect(indexAfterTwoMoves).toBeGreaterThanOrEqual(indexAfterOneMove);
await page.keyboard.down('Alt');
await page.keyboard.down('KeyR');
await page.keyboard.up('KeyR');
await page.keyboard.up('Alt');
const indexAfterThreeMoves = await getTabIndex(page, 'req-7');
expect(indexAfterThreeMoves).toBeGreaterThanOrEqual(indexAfterTwoMoves);
// Close all tabs
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
});
});
test.describe('SHORTCUT: Switch to Tab at Position', () => {
test('default Cmd/Ctrl+1-8 open tab from 1-8', async ({ page }) => {
await openRequest(page, 'kb-collection', 'req-1', { persist: true });
await openRequest(page, 'kb-collection', 'req-2', { persist: true });
await openRequest(page, 'kb-collection', 'req-3', { persist: true });
await openRequest(page, 'kb-collection', 'req-4', { persist: true });
await openRequest(page, 'kb-collection', 'req-5', { persist: true });
await openRequest(page, 'kb-collection', 'req-6', { persist: true });
await openRequest(page, 'kb-collection', 'req-7', { persist: true });
await openRequest(page, 'kb-collection', 'req-8', { persist: true });
await openRequest(page, 'kb-collection', 'req-9', { persist: true });
await expect(page.locator('.request-tab')).toHaveCount(9, { timeout: 2000 });
const tabs = page.locator('.request-tab');
await expect(tabs.nth(0)).toHaveText(/req-1/, { timeout: 2000 });
await page.keyboard.press(`${modifier}+1`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-1/, { timeout: 3000 });
await page.keyboard.press(`${modifier}+2`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-2/, { timeout: 3000 });
await page.keyboard.press(`${modifier}+3`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-3/, { timeout: 3000 });
await page.keyboard.press(`${modifier}+4`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-4/, { timeout: 3000 });
await page.keyboard.press(`${modifier}+5`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-5/, { timeout: 3000 });
await page.keyboard.press(`${modifier}+6`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-6/, { timeout: 3000 });
await page.keyboard.press(`${modifier}+7`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-7/, { timeout: 3000 });
await page.keyboard.press(`${modifier}+8`);
await expect(page.locator('li.request-tab.active')).toHaveText(/req-8/, { timeout: 3000 });
});
});
test.describe('SHORTCUT: Reopen Last Closed Tab', () => {
test('default Cmd/Ctrl+Shift+T reopens last closed request tab', async ({ page }) => {
await openRequest(page, collectionName, 'req-2', { persist: true });
await openRequest(page, collectionName, 'req-1', { persist: true });
const req1Tab = page.locator('.request-tab').filter({ hasText: 'req-1' }).first();
await req1Tab.click();
await expect(req1Tab).toHaveClass(/active/);
await closeTabByName(page, 'req-1');
await reopenClosedTab(page, async () => page.keyboard.press(`${modifier}+Shift+t`), 'req-1');
});
test('default Cmd/Ctrl+Shift+T reopens multiple tab types in LIFO order', async ({ page }) => {
await openRequest(page, collectionName, 'req-2', { persist: true });
// Open Collection-Settings tab (double-click collection name)
await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick();
await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 });
// Open Runner tab
await page.getByTestId('runner').click();
await expect(page.locator('.request-tab').filter({ hasText: 'Runner' })).toBeVisible({ timeout: 2000 });
// Open Variables tab
await page.getByTestId('more-actions').click();
await page.getByTestId('more-actions-variables').click();
await expect(page.locator('.request-tab').filter({ hasText: 'Variables' })).toBeVisible({ timeout: 2000 });
// Open Folder-Settings tab (create folder + double-click)
await page.locator('.collection-item-name').filter({ hasText: 'kb-folder' }).dblclick();
// Close in order: kb-folder (first closed) → Collection → Variables → Runner (last closed)
await closeTabByName(page, 'kb-folder');
await closeTabByName(page, 'Collection');
await closeTabByName(page, 'Variables');
await closeTabByName(page, 'Runner');
// Reopen LIFO: Runner was closed last → reopens first
await reopenClosedTab(page, async () => page.keyboard.press(`${modifier}+Shift+t`), 'Runner');
await reopenClosedTab(page, async () => page.keyboard.press(`${modifier}+Shift+t`), /variables/i);
await reopenClosedTab(page, async () => page.keyboard.press(`${modifier}+Shift+t`), 'Collection');
await reopenClosedTab(page, async () => page.keyboard.press(`${modifier}+Shift+t`), 'kb-folder');
});
test('customized Alt+Z reopens last closed tab', async ({ page }) => {
await remapKeybinding(page, 'reopenLastClosedTab', async () => {
await page.keyboard.press('Alt+z');
});
await openRequest(page, collectionName, 'req-2', { persist: true });
await openRequest(page, collectionName, 'req-1', { persist: true });
const req1Tab = page.locator('.request-tab').filter({ hasText: 'req-1' }).first();
await req1Tab.click();
await expect(req1Tab).toHaveClass(/active/);
await closeTabByName(page, 'req-1');
await reopenClosedTab(page, async () => {
await page.keyboard.press('Alt+z');
}, 'req-1');
});
});
});
test.describe('SIDEBAR', () => {
test.describe('SHORTCUT: Sidebar search', () => {
test('default Cmd/Ctrl+F open sidebar search', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await page.keyboard.press(`${modifier}+KeyF`);
// await expect(page.getByPlaceholder('Search requests...')).toBeVisible({ timeout: 3000 });
await expect(page.getByTestId('sidebar-search-input')).toBeVisible({ timeout: 3000 });
await page.getByTitle('Search requests').click();
});
test('customized Alt+F opens sidebar search', async ({ page }) => {
// Remap sidebarSearch to Alt+F
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-sidebarSearch');
await row.hover();
await page.getByTestId('keybinding-edit-sidebarSearch').click();
await expect(page.getByTestId('keybinding-input-sidebarSearch')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyF');
await page.keyboard.up('KeyF');
await page.keyboard.up('Alt');
// Press Cmd/Ctrl+T to open sidebar search
await page.keyboard.down('Alt');
await page.keyboard.down('KeyF');
await page.keyboard.up('KeyF');
await page.keyboard.up('Alt');
await expect(page.getByTestId('sidebar-search-input')).toBeVisible({ timeout: 2000 });
await page.getByTitle('Search requests').click();
});
});
test.describe('SHORTCUT: New request', () => {
test('default Cmd/Ctrl+N open new request modal', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await page.locator('.collection-item-name').filter({ hasText: 'kb-folder' }).click();
await page.keyboard.press(`${modifier}+KeyN`);
await page.getByTestId('request-name').fill('nr-folder');
await page.getByTestId('new-request-url').locator('.CodeMirror').click();
await page.keyboard.type('https://echo.usebruno.com');
await page.getByTestId('create-new-request-button').click();
await expect(page.locator('.request-tab').filter({ hasText: 'nr-folder' })).toBeVisible({ timeout: 2000 });
});
test('customized Alt+N open new request modal', async ({ page, createTmpDir }) => {
// Remap newRequest to Alt+N
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-newRequest');
await row.hover();
await page.getByTestId('keybinding-edit-newRequest').click();
await expect(page.getByTestId('keybinding-input-newRequest')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyN');
await page.keyboard.up('KeyN');
await page.keyboard.up('Alt');
await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).click();
await page.keyboard.down('Alt');
await page.keyboard.down('KeyN');
await page.keyboard.up('KeyN');
await page.keyboard.up('Alt');
await page.getByTestId('request-name').fill('nr-collection');
await page.getByTestId('new-request-url').locator('.CodeMirror').click();
await page.keyboard.type('https://echo.usebruno.com');
await page.getByTestId('create-new-request-button').click();
await expect(page.locator('.request-tab').filter({ hasText: 'nr-collection' })).toBeVisible({ timeout: 2000 });
});
});
test.describe('SHORTCUT: Rename Item', () => {
test('default Cmd/Ctrl+R open rename item modal for request', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick();
await openRequest(page, 'kb-collection', 'req-1', { persist: true });
await page.keyboard.press(`${modifier}+KeyR`);
// Verify rename modal opens
const renameModal = page.locator('.bruno-modal-card').filter({ hasText: /rename request/i });
await expect(renameModal).toBeVisible({ timeout: 3000 });
// Fill in the rename req name
const requestNameInput = page.locator('#collection-item-name');
await requestNameInput.fill('req-1-renamed');
// Click the rename button
await page.getByTestId('rename-item-button').click();
// Verify renamed request appears in sidebar
// await expect(page.locator('.collection-item-name').filter({ hasText: 'req-1' })).toBeVisible({ timeout: 2000 });
await expect(page.locator('.collection-item-name').filter({ hasText: 'req-1-rename' })).toBeVisible({ timeout: 2000 });
});
test('default Cmd/Ctrl+R open rename item modal for folder', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await page.locator('.collection-item-name').filter({ hasText: 'kb-folder' }).dblclick();
await page.keyboard.press(`${modifier}+KeyR`);
// Verify rename modal opens
const renameModal = page.locator('.bruno-modal-card').filter({ hasText: /rename folder/i });
await expect(renameModal).toBeVisible({ timeout: 3000 });
// Fill in the rename req name
const folderNameInput = page.locator('#collection-item-name');
await folderNameInput.fill('kb-folder-renamed');
// Click the rename button
await page.getByTestId('rename-item-button').click();
// Verify renamed request appears in sidebar
await expect(page.locator('.collection-item-name').filter({ hasText: 'kb-folder-renamed' })).toBeVisible({ timeout: 2000 });
});
test('default Cmd/Ctrl+R open rename item modal for collection', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).click();
await page.keyboard.press(`${modifier}+KeyR`);
// Verify rename modal opens
const renameModal = page.locator('.bruno-modal-card').filter({ hasText: /rename collection/i });
await expect(renameModal).toBeVisible({ timeout: 3000 });
// Fill in the rename req name
const collectionInput = page.locator('#collection-name');
await collectionInput.fill('kb-collection-renamed');
// Click the rename button
await page.locator('.submit').click();
// Verify renamed request appears in sidebar
await expect(page.locator('.collection-name').filter({ hasText: 'kb-collection-renamed' })).toBeVisible({ timeout: 3000 });
});
test('customized Alt+X open rename item modal for request', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
// Remap renameItem to Alt+R
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-renameItem');
await row.hover();
await page.getByTestId('keybinding-edit-renameItem').click();
await expect(page.getByTestId('keybinding-input-renameItem')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyX');
await page.keyboard.up('KeyX');
await page.keyboard.up('Alt');
await openRequest(page, collectionName, 'req-1', { persist: true });
await page.keyboard.down('Alt');
await page.keyboard.down('KeyX');
await page.keyboard.up('KeyX');
await page.keyboard.up('Alt');
// Verify rename modal opens
const renameModal = page.locator('.bruno-modal-card').filter({ hasText: /rename request/i });
await expect(renameModal).toBeVisible({ timeout: 3000 });
// Fill in the rename req name
const requestNameInput = page.locator('#collection-item-name');
await requestNameInput.fill('req-1-renamed-altx');
// Click the rename button
await page.getByTestId('rename-item-button').click();
// Verify renamed request appears in sidebar
await expect(page.locator('.collection-item-name').filter({ hasText: 'req-1-renamed-altx' })).toBeVisible({ timeout: 2000 });
});
test('customized Alt+R open rename item modal for folder', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await remapKeybinding(page, 'renameItem', async () => {
await page.keyboard.press('Alt+KeyX');
});
await createFolder(page, 'kb-folder-rename-src', collectionName, true);
await openFolderSettingsTab(page, 'kb-folder-rename-src');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyX');
await page.keyboard.up('KeyX');
await page.keyboard.up('Alt');
// Verify rename modal opens
const renameModal = page.locator('.bruno-modal-card').filter({ hasText: /rename folder/i });
await expect(renameModal).toBeVisible({ timeout: 3000 });
// Fill in the rename req name
const folderNameInput = page.locator('#collection-item-name');
await folderNameInput.fill('kb-folder-renamed-altx-src');
// Click the rename button
await page.getByTestId('rename-item-button').click();
// Verify renamed request appears in sidebar
await expect(page.locator('.collection-item-name').filter({ hasText: 'kb-folder-renamed-altx-src' })).toBeVisible({ timeout: 2000 });
});
test('customized Alt+R open rename item modal for collection', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await remapKeybinding(page, 'renameItem', async () => {
await page.keyboard.press('Alt+KeyX');
});
await page.locator('.collection-name').filter({ hasText: collectionName }).click();
await page.keyboard.down('Alt');
await page.keyboard.down('KeyX');
await page.keyboard.up('KeyX');
await page.keyboard.up('Alt');
// Verify rename modal opens
const renameModal = page.locator('.bruno-modal-card').filter({ hasText: /rename collection/i });
await expect(renameModal).toBeVisible({ timeout: 3000 });
// Fill in the rename req name
const collectionInput = page.locator('#collection-name');
await collectionInput.fill('kb-collection-renamed-altx');
// Click the rename button
await page.locator('.submit').click();
// Verify renamed request appears in sidebar
await expect(page.locator('.collection-name').filter({ hasText: 'kb-collection-renamed-altx' })).toBeVisible({ timeout: 2000 });
});
});
test.describe('SHORTCUT: Clone Item', () => {
test('default Cmd/Ctrl+D open clone item modal for request', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await openRequest(page, 'kb-collection', 'req-1', { persist: true });
await page.keyboard.press(`${modifier}+KeyD`);
// Verify clone modal opens
const cloneModal = page.locator('.bruno-modal-card').filter({ hasText: /clone request/i });
await expect(cloneModal).toBeVisible({ timeout: 3000 });
// Fill in the clone req name
const requestNameInput = page.locator('#collection-item-name');
await requestNameInput.fill('req-1 clone 1');
// Click the clone button
await page.getByTestId('clone-item-button').click();
// Verify cloned request appears in sidebar
await expect(page.locator('.collection-item-name').filter({ hasText: 'req-1 clone 1' })).toBeVisible({ timeout: 2000 });
});
test('default Cmd/Ctrl+D open clone item modal for folder', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await page.locator('.collection-item-name').filter({ hasText: 'kb-folder' }).dblclick();
await page.keyboard.press(`${modifier}+KeyD`);
// Verify clone modal opens
const cloneModal = page.locator('.bruno-modal-card').filter({ hasText: /clone folder/i });
await expect(cloneModal).toBeVisible({ timeout: 3000 });
// Fill in the clone kb-folder name
const folderNameInput = page.locator('#collection-item-name');
await folderNameInput.fill('kb-folder clone 1');
// Click the clone button
await page.getByTestId('clone-item-button').click();
// Verify cloned request appears in sidebar
await expect(page.locator('.collection-item-name').filter({ hasText: 'kb-folder clone 1' })).toBeVisible({ timeout: 2000 });
});
test('customized Alt+D open clone item modal for request', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
// Remap cloneItem to Alt+D
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-cloneItem');
await row.hover();
await page.getByTestId('keybinding-edit-cloneItem').click();
await expect(page.getByTestId('keybinding-input-cloneItem')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyD');
await page.keyboard.up('KeyD');
await page.keyboard.up('Alt');
await openRequest(page, 'kb-collection', 'req-2', { persist: true });
await page.keyboard.down('Alt');
await page.keyboard.down('KeyD');
await page.keyboard.up('KeyD');
await page.keyboard.up('Alt');
// Verify clone modal opens
const cloneModal = page.locator('.bruno-modal-card').filter({ hasText: /clone request/i });
await expect(cloneModal).toBeVisible({ timeout: 3000 });
// Fill in the clone req name
const requestNameInput = page.locator('#collection-item-name');
await requestNameInput.fill('req-2 clone 1');
// Click the clone button
await page.getByTestId('clone-item-button').click();
// Verify renamed request appears in sidebar
await expect(page.locator('.collection-item-name').filter({ hasText: 'req-2 clone 1' })).toBeVisible({ timeout: 2000 });
});
test('customized Alt+D open clone item modal for folder', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await createFolder(page, 'kb-folder-clone-src', collectionName, true);
await openCollection(page, collectionName);
await page.locator('.collection-item-name').filter({ hasText: 'kb-folder-clone-src' }).first().click();
await page.keyboard.down('Alt');
await page.keyboard.down('KeyD');
await page.keyboard.up('KeyD');
await page.keyboard.up('Alt');
// Verify clone modal opens
const cloneModal = page.locator('.bruno-modal-card').filter({ hasText: /clone folder/i });
await expect(cloneModal).toBeVisible({ timeout: 3000 });
// Fill in the clone req name
const folderNameInput = page.locator('#collection-item-name');
await folderNameInput.fill('kb-folder-clone-src copy 1');
// Click the clone button
await page.getByTestId('clone-item-button').click();
// Verify renamed request appears in sidebar
await expect(page.locator('.collection-item-name').filter({ hasText: 'kb-folder-clone-src copy 1' })).toBeVisible({ timeout: 2000 });
});
});
test.describe('SHORTCUT: Copy Paste Item', () => {
test('default Cmd/Ctrl+C/V copy paste item for request', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await openRequest(page, 'kb-collection', 'req-3', { persist: true });
await page.keyboard.press(`${modifier}+KeyC`);
await page.keyboard.press(`${modifier}+KeyV`);
// Verify cloned request appears in sidebar
await expect(page.locator('.collection-item-name').filter({ hasText: 'req-3 (1)' })).toBeVisible({ timeout: 2000 });
});
test('default Cmd/Ctrl+C/V copy paste item for folder', async ({ page }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await openRequest(page, collectionName, 'kb-folder', { persist: true });
await page.keyboard.press(`${modifier}+KeyC`);
await page.keyboard.press(`${modifier}+KeyV`);
// Verify copied item appears in sidebar as child of folder
await expect(page.locator('.collection-item-name').filter({ hasText: 'kb-folder' })).toHaveCount(2);
});
test('customized Alt+C/V copy paste item for request', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
// Remap copyItem to Alt+D
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-copyItem');
await row.hover();
await page.getByTestId('keybinding-edit-copyItem').click();
await expect(page.getByTestId('keybinding-input-copyItem')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyC');
await page.keyboard.up('KeyC');
await page.keyboard.up('Alt');
// Remap pasteItem to Alt+V
await openKeybindingsTab(page);
const row2 = page.getByTestId('keybinding-row-pasteItem');
await row2.hover();
await page.getByTestId('keybinding-edit-pasteItem').click();
await expect(page.getByTestId('keybinding-input-pasteItem')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyV');
await page.keyboard.up('KeyV');
await page.keyboard.up('Alt');
await openRequest(page, 'kb-collection', 'req-4', { persist: true });
await page.keyboard.down('Alt');
await page.keyboard.down('KeyC');
await page.keyboard.up('KeyC');
await page.keyboard.up('Alt');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyV');
await page.keyboard.up('KeyV');
await page.keyboard.up('Alt');
// Verify cloned request appears in sidebar
await expect(page.locator('.collection-item-name').filter({ hasText: 'req-4 (1)' })).toBeVisible({ timeout: 2000 });
});
test('customized Alt+C/V copy paste item for folder', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await remapKeybinding(page, 'copyItem', async () => {
await page.keyboard.press('Alt+KeyC');
});
await remapKeybinding(page, 'pasteItem', async () => {
await page.keyboard.press('Alt+KeyV');
});
await createFolder(page, 'kb-folder-copy-src', collectionName, true);
await openFolderSettingsTab(page, 'kb-folder-copy-src');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyC');
await page.keyboard.up('KeyC');
await page.keyboard.up('Alt');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyV');
await page.keyboard.up('KeyV');
await page.keyboard.up('Alt');
// Verify copied item appears in sidebar as child of folder
await expect(page.locator('.collection-item-name').filter({ hasText: 'kb-folder-copy-src' })).toHaveCount(2);
});
});
test.describe('SHORTCUT: Collapse Sidebar', () => {
test('default collapse sidebar using default Cmd/Ctrl+\\', async ({ page, createTmpDir }) => {
await expect(page.getByTestId('collections')).toBeVisible();
await page.locator('body').click({ position: { x: 1, y: 1 } });
// Press Cmd/Ctrl+\ to collapse sidebar
await page.keyboard.press(`${modifier}+Backslash`);
await expect.poll(
() => page.locator('aside.sidebar').evaluate((el) => parseFloat(getComputedStyle(el).width)),
{ timeout: 5000 }
).toBeLessThan(5);
// Press Cmd/Ctrl+\ to collapse expanded sidebar
await page.keyboard.press(`${modifier}+Backslash`);
await expect.poll(
() => page.locator('aside.sidebar').evaluate((el) => parseFloat(getComputedStyle(el).width)),
{ timeout: 5000 }
).toBeGreaterThan(200);
});
test('should expand -> collapse -> expand the sidebar using customized Shift+G', async ({ page, createTmpDir }) => {
// Remap collapseSidebar to Shift+G
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-collapseSidebar');
await row.hover();
await page.getByTestId('keybinding-edit-collapseSidebar').click();
await expect(page.getByTestId('keybinding-input-collapseSidebar')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Shift');
await page.keyboard.down('KeyG');
await page.keyboard.up('KeyG');
await page.keyboard.up('Shift');
await closePreferencesTab(page);
// Trigger the remapped shortcut to collapse sidebar
await page.keyboard.down('Shift');
await page.keyboard.down('KeyG');
await page.keyboard.up('KeyG');
await page.keyboard.up('Shift');
// Verify sidebar collapsed to 0px
await expect.poll(
() => page.locator('aside.sidebar').evaluate((el) => getComputedStyle(el).width),
{ timeout: 5000 }
).toBe('0px');
// Trigger the remapped shortcut to expand sidebar
await page.keyboard.down('Shift');
await page.keyboard.down('KeyG');
await page.keyboard.up('KeyG');
await page.keyboard.up('Shift');
await expect.poll(
() => page.locator('aside.sidebar').evaluate((el) => getComputedStyle(el).width),
{ timeout: 5000 }
).toBe('250px');
});
});
});
test.describe('DEVELOPER TOOLS', () => {
test.describe('SHORTCUT: Open Terminal', () => {
test('default Cmd/Ctrl+T opens terminal', async ({ page, createTmpDir }) => {
// Open Collection-Settings tab (double-click collection name)
await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).click();
await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 });
// Press Cmd/Ctrl+T to open terminal at workspace level
await page.keyboard.press(`${modifier}+KeyT`);
// Verify terminal session is visible using data-testid
const collectionTerminalSession = page.getByTestId('session-list-0');
await expect(collectionTerminalSession).toBeVisible({ timeout: 2000 });
const collectionSession = collectionTerminalSession;
await expect(collectionSession).toContainText('kb-collection');
await page.getByTitle('Close console').click();
// Open Folder-Settings tab (create folder + double-click)
// Open folder settings
await page.locator('.collection-item-name').filter({ hasText: 'kb-terminal-folder' }).dblclick();
await expect(page.locator('.request-tab').filter({ hasText: 'kb-terminal-folder' })).toBeVisible({ timeout: 2000 });
await page.keyboard.press(`${modifier}+KeyT`);
const folderTerminalSession = page.getByTestId('session-list-1');
await expect(folderTerminalSession).toBeVisible({ timeout: 2000 });
// Verify the terminal session name is the workspace name (default_workspace)
const folderSessionName = folderTerminalSession;
await expect(folderSessionName).toContainText('kb-terminal-folder');
// Close all sessions with terminal tab
await page.getByTestId('session-close-1').click();
await page.waitForTimeout(1000);
await page.getByTestId('session-close-0').click();
await expect(page.getByTestId('session-close-0')).not.toBeVisible({ timeout: 3000 });
await page.getByTitle('Close console').click();
});
test('customized Alt+T opens terminal', async ({ page, createTmpDir }) => {
// Remap openTerminal to Alt+T
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-openTerminal');
await row.hover();
await page.getByTestId('keybinding-edit-openTerminal').click();
await expect(page.getByTestId('keybinding-input-openTerminal')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyT');
await page.keyboard.up('KeyT');
await page.keyboard.up('Alt');
await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).click();
await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 });
// Press Cmd/Ctrl+T to open terminal at workspace level
await page.keyboard.down('Alt');
await page.keyboard.down('KeyT');
await page.keyboard.up('KeyT');
await page.keyboard.up('Alt');
await page.waitForTimeout(500);
// Verify terminal session is visible using data-testid
const collectionTerminalSession = page.getByTestId('session-list-0');
await expect(collectionTerminalSession).toBeVisible({ timeout: 2000 });
const collectionSession = collectionTerminalSession;
await expect(collectionSession).toContainText('kb-collection');
// Open folder settings
await page.locator('.collection-item-name').filter({ hasText: 'kb-terminal-folder' }).dblclick();
await page.keyboard.down('Alt');
await page.keyboard.down('KeyT');
await page.keyboard.up('KeyT');
await page.keyboard.up('Alt');
const folderTerminalSession = page.getByTestId('session-list-1');
await expect(folderTerminalSession).toBeVisible({ timeout: 2000 });
// Verify the terminal session name is the workspace name (default_workspace)
const folderSessionName = folderTerminalSession;
await expect(folderSessionName).toContainText('kb-terminal-folder');
// Close all sessions with terminal tab
await page.getByTestId('session-close-1').click();
await page.waitForTimeout(1000);
await page.getByTestId('session-close-0').click();
await expect(page.getByTestId('session-close-0')).not.toBeVisible({ timeout: 3000 });
await page.getByTitle('Close console').click();
});
});
});
test.describe('LAYOUT', () => {
test.describe('SHORTCUT: Change Layout', () => {
test('default Cmd/Ctrl+J change layout orientation', async ({ page, createTmpDir }) => {
await openRequest(page, 'kb-collection', 'req-5', { persist: true });
// Press Cmd/Ctrl+J to change layout
await page.keyboard.press(`${modifier}+KeyJ`);
await expect(
page.getByTestId('response-layout-toggle-btn')
).toHaveAttribute('title', 'Switch to horizontal layout', { timeout: 2000 });
// Press Cmd/Ctrl+J to change layout
await page.keyboard.press(`${modifier}+KeyJ`);
await expect(
page.getByTestId('response-layout-toggle-btn')
).toHaveAttribute('title', 'Switch to vertical layout', { timeout: 2000 });
// Press Cmd/Ctrl+J to change layout
await page.keyboard.press(`${modifier}+KeyJ`);
await expect(
page.getByTestId('response-layout-toggle-btn')
).toHaveAttribute('title', 'Switch to horizontal layout', { timeout: 2000 });
});
test('customized Alt+Shift+Y change layout orientation', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
// Remap changeLayout to Alt+D
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-changeLayout');
await row.hover();
await page.getByTestId('keybinding-edit-changeLayout').click();
await expect(page.getByTestId('keybinding-input-changeLayout')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('Shift');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Shift');
await page.keyboard.up('Alt');
await openRequest(page, 'kb-collection', 'req-5', { persist: true });
await page.keyboard.down('Alt');
await page.keyboard.down('Shift');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Shift');
await page.keyboard.up('Alt');
await expect(
page.getByTestId('response-layout-toggle-btn')
).toHaveAttribute('title', 'Switch to vertical layout', { timeout: 2000 });
// Press Cmd/Ctrl+J to change layout
await page.keyboard.down('Alt');
await page.keyboard.down('Shift');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Shift');
await page.keyboard.up('Alt');
await expect(
page.getByTestId('response-layout-toggle-btn')
).toHaveAttribute('title', 'Switch to horizontal layout', { timeout: 2000 });
// Press Cmd/Ctrl+J to change layout
await page.keyboard.down('Alt');
await page.keyboard.down('Shift');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Shift');
await page.keyboard.up('Alt');
await expect(
page.getByTestId('response-layout-toggle-btn')
).toHaveAttribute('title', 'Switch to vertical layout', { timeout: 2000 });
});
});
test.describe('SHORTCUT: Open Preferences', () => {
test('default Cmd/Ctrl+, open preferences', async ({ page }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
// Press Cmd/Ctrl+J to change layout
await page.keyboard.down(modifier);
await page.keyboard.down('Comma');
await page.keyboard.up('Comma');
await page.keyboard.up(modifier);
await expect(page.locator('.request-tab').filter({ hasText: 'Preferences' })).toBeVisible({ timeout: 3000 });
});
test('customized Cmd/Ctrl+P open preferences', async ({ page }) => {
// Remap openPreferences to Ctrl+P
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-openPreferences');
await row.hover();
await page.getByTestId('keybinding-edit-openPreferences').click();
await expect(page.getByTestId('keybinding-input-openPreferences')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down(modifier);
await page.keyboard.down('KeyP');
await page.keyboard.up('KeyP');
await page.keyboard.up(modifier);
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
// Press Cmd/Ctrl+J to change layout
await page.keyboard.down(modifier);
await page.keyboard.down('KeyP');
await page.keyboard.up('KeyP');
await page.keyboard.up(modifier);
await expect(page.locator('.request-tab').filter({ hasText: 'Preferences' })).toBeVisible({ timeout: 3000 });
});
});
});
test.describe('SEARCH', () => {
test.describe('SHORTCUT: Global Search', () => {
test('default Cmd/Ctrl+K Global Search Modal', async ({ page, createTmpDir }) => {
// Press Cmd/Ctrl+K to global search modal
await page.keyboard.press(`${modifier}+KeyK`);
await page.keyboard.down(modifier);
await page.keyboard.down('KeyK');
await page.keyboard.up('KeyK');
await page.keyboard.up(modifier);
await page.getByTestId('global-search-input').click();
await expect(page.getByTestId('global-search-input')).toBeVisible({ timeout: 2000 });
// await page.waitForTimeout(500);
await page.keyboard.down('Escape');
await page.keyboard.up('Escape');
});
test('customized Alt+K Global Search Modal', async ({ page, createTmpDir }) => {
// Remap globalSearch to Alt+K
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-globalSearch');
await row.hover();
await page.getByTestId('keybinding-edit-globalSearch').click();
await expect(page.getByTestId('keybinding-input-globalSearch')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyK');
await page.keyboard.up('KeyK');
await page.keyboard.up('Alt');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyK');
await page.keyboard.up('KeyK');
await page.keyboard.up('Alt');
await page.getByTestId('global-search-input').click();
await expect(page.getByTestId('global-search-input')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Escape');
await page.keyboard.up('Escape');
});
});
});
test.describe('SHORTCUT: Edit Environment', () => {
test('open environment tab of collection Cmd/Ctrl+E', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await openRequest(page, 'kb-collection', 'req-7', { persist: true });
await page.keyboard.down(modifier);
await page.keyboard.down('KeyE');
await page.keyboard.up('KeyE');
await page.keyboard.up(modifier);
await expect(page.locator('.request-tab').filter({ hasText: 'Environments' })).toBeVisible({ timeout: 2000 });
});
test('open environment tab of collection customized Alt+E', async ({ page, createTmpDir }) => {
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
// Remap editEnvironment to Alt+E
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-editEnvironment');
await row.hover();
await page.getByTestId('keybinding-edit-editEnvironment').click();
await expect(page.getByTestId('keybinding-input-editEnvironment')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Alt');
await page.keyboard.down('KeyE');
await page.keyboard.up('KeyE');
await page.keyboard.up('Alt');
await openRequest(page, 'kb-collection', 'req-7', { persist: true });
await page.keyboard.down('Alt');
await page.keyboard.down('KeyE');
await page.keyboard.up('KeyE');
await page.keyboard.up('Alt');
await expect(page.locator('.request-tab').filter({ hasText: 'Environments' })).toBeVisible({ timeout: 2000 });
// Rest Default - just in case to not fail shortcuts in other places
await openKeybindingsTab(page);
await page.getByTestId('reset-all-keybindings-btn').click({ timeout: 2000 });
});
});
test.describe('REQUESTS', () => {
test.describe('SHORTCUT: Send Request from CodeEditor (Cmd/Ctrl+Enter)', () => {
test('sends request when cursor is in JSON body editor', async ({ page }) => {
// Close existing tabs
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
// Create a POST request in the shared collection pointing to the echo server
await createRequest(page, 'cmd-enter-req-body', 'kb-collection', {
url: 'https://echo.usebruno.com',
method: 'POST'
});
await openRequest(page, 'kb-collection', 'cmd-enter-req-body', { persist: true });
// Open Body tab and select JSON mode
await selectRequestPaneTab(page, 'Body');
await page.getByTestId('request-body-mode-selector').click();
await page.locator('.dropdown-item').filter({ hasText: /^JSON$/ }).click();
// Focus the body code editor and type JSON
const bodyEditor = page.getByTestId('request-body-editor').locator('.CodeMirror');
await bodyEditor.click();
await page.keyboard.type('{"name": "Bruno", "version": 2, "tags": ["api", "client", "http"], "active": true, "meta": {"author": "user", "created": "2025-01-01", "updated": "2025-06-01"}, "counts": {"requests": 42, "collections": 7}}');
await expect(page.getByTestId('request-body-editor')).toContainText('"name": "Bruno"', { timeout: 5000 });
// Cursor is still in the body CodeMirror — press Cmd/Ctrl+Enter to send
await page.keyboard.press(`${modifier}+Enter`);
// Verify a 200 response came back
await expect(page.getByTestId('response-status-code')).toContainText('200', { timeout: 15000 });
});
test('sends request when cursor is in response body editor', async ({ page }) => {
// Close existing tabs
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await createRequest(page, 'cmd-enter-req-resp', 'kb-collection', {
url: 'https://echo.usebruno.com',
method: 'POST'
});
await openRequest(page, 'kb-collection', 'cmd-enter-req-resp', { persist: true });
await selectRequestPaneTab(page, 'Body');
await page.getByTestId('request-body-mode-selector').click();
await page.locator('.dropdown-item').filter({ hasText: /^JSON$/ }).click();
const bodyEditor = page.getByTestId('request-body-editor').locator('.CodeMirror');
await bodyEditor.click();
await page.keyboard.type('{"name": "Bruno", "version": 2, "tags": ["api", "client", "http"], "active": true, "meta": {"author": "user", "created": "2025-01-01", "updated": "2025-06-01"}, "counts": {"requests": 42, "collections": 7}}');
await expect(page.getByTestId('request-body-editor')).toContainText('"name": "Bruno"', { timeout: 5000 });
// First send to populate response
await page.keyboard.press(`${modifier}+Enter`);
await expect(page.getByTestId('response-status-code')).toContainText('200', { timeout: 15000 });
// Focus cursor inside the response body CodeMirror
const responseEditor = page.getByTestId('response-preview-container').locator('.CodeMirror').first();
await responseEditor.waitFor({ state: 'visible', timeout: 5000 });
await responseEditor.click();
// Press Cmd/Ctrl+Enter again — should re-send the request
await page.keyboard.press(`${modifier}+Enter`);
// Verify a 200 response came back (no error, status stays/refreshes to 200)
await expect(page.getByTestId('response-status-code')).toContainText('200', { timeout: 15000 });
});
test('sends request when cursor is in pre-request Vars value editor', async ({ page }) => {
// Close existing tabs
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
await createRequest(page, 'cmd-enter-req-vars', 'kb-collection', {
url: 'https://echo.usebruno.com',
method: 'POST'
});
await openRequest(page, 'kb-collection', 'cmd-enter-req-vars', { persist: true });
// Open Vars tab — request Vars has a Pre Request section as the first table
await selectRequestPaneTab(page, 'Vars');
// Fill the first var row: name=var-1
const varsTable = page.getByTestId('request-pane').locator('table').first();
const firstRow = varsTable.locator('tbody tr').first();
const nameInput = firstRow.locator('input[type="text"]').first();
await nameInput.click();
await nameInput.fill('var-1');
// Click the value CodeMirror editor and type a multi-line value
const valueEditor = firstRow.locator('.CodeMirror').first();
await valueEditor.click();
await page.keyboard.type('val-1');
await page.keyboard.press('Enter'); // insert newline in value editor
await page.keyboard.type('val-2');
// Cursor is still in the value CodeMirror — press Cmd/Ctrl+Enter to send
// (should NOT insert a newline; should fire sendRequest)
await page.keyboard.press(`${modifier}+Enter`);
// Verify a 200 response came back
await expect(page.getByTestId('response-status-code')).toContainText('200', { timeout: 15000 });
});
});
test.describe('SHORTCUT: Send Request from CodeEditor (customized Shift+Enter)', () => {
test('customized Shift+Enter sends request when cursor is in JSON body editor', async ({ page }) => {
// Close existing tabs
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
// Remap sendRequest to Shift+Enter
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-sendRequest');
await row.hover();
await page.getByTestId('keybinding-edit-sendRequest').click();
await expect(page.getByTestId('keybinding-input-sendRequest')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Shift');
await page.keyboard.down('Enter');
await page.keyboard.up('Enter');
await page.keyboard.up('Shift');
// await closePreferencesTab(page);
// Create a POST request in the shared collection pointing to the echo server
await createRequest(page, 'shift-enter-req-body', 'kb-collection', {
url: 'https://echo.usebruno.com',
method: 'POST'
});
await openRequest(page, 'kb-collection', 'shift-enter-req-body', { persist: true });
// Open Body tab and select JSON mode
await selectRequestPaneTab(page, 'Body');
await page.getByTestId('request-body-mode-selector').click();
await page.locator('.dropdown-item').filter({ hasText: /^JSON$/ }).click();
const bodyEditor = page.getByTestId('request-body-editor').locator('.CodeMirror');
await bodyEditor.click();
await page.keyboard.type('{"name": "Bruno", "version": 2, "tags": ["api", "client", "http"], "active": true, "meta": {"author": "user", "created": "2025-01-01", "updated": "2025-06-01"}, "counts": {"requests": 42, "collections": 7}}');
await expect(page.getByTestId('request-body-editor')).toContainText('"name": "Bruno"', { timeout: 5000 });
// Cursor is still in the body CodeMirror — press Shift+Enter (customized) to send
await page.keyboard.press('Shift+Enter');
await expect(page.getByTestId('response-status-code')).toContainText('200', { timeout: 15000 });
// Reset Default
await openKeybindingsTab(page);
await page.getByTestId('reset-all-keybindings-btn').click({ timeout: 2000 });
});
test('customized Shift+Enter sends request when cursor is in response body editor', async ({ page }) => {
// Close existing tabs
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
// Remap sendRequest to Shift+Enter
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-sendRequest');
await row.hover();
await page.getByTestId('keybinding-edit-sendRequest').click();
await expect(page.getByTestId('keybinding-input-sendRequest')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Shift');
await page.keyboard.down('Enter');
await page.keyboard.up('Enter');
await page.keyboard.up('Shift');
// await closePreferencesTab(page);
await createRequest(page, 'shift-enter-req-resp', 'kb-collection', {
url: 'https://echo.usebruno.com',
method: 'POST'
});
await openRequest(page, 'kb-collection', 'shift-enter-req-resp', { persist: true });
await selectRequestPaneTab(page, 'Body');
await page.getByTestId('request-body-mode-selector').click();
await page.locator('.dropdown-item').filter({ hasText: /^JSON$/ }).click();
const bodyEditor = page.getByTestId('request-body-editor').locator('.CodeMirror');
await bodyEditor.click();
await page.keyboard.type('{"name": "Bruno", "version": 2, "tags": ["api", "client", "http"], "active": true, "meta": {"author": "user", "created": "2025-01-01", "updated": "2025-06-01"}, "counts": {"requests": 42, "collections": 7}}');
await expect(page.getByTestId('request-body-editor')).toContainText('"name": "Bruno"', { timeout: 5000 });
// First send with Shift+Enter to populate response
await page.keyboard.press('Shift+Enter');
await expect(page.getByTestId('response-status-code')).toContainText('200', { timeout: 15000 });
// Focus cursor inside the response body CodeMirror
const responseEditor = page.getByTestId('response-preview-container').locator('.CodeMirror').first();
await responseEditor.waitFor({ state: 'visible', timeout: 5000 });
await responseEditor.click();
// Press Shift+Enter again — should re-send the request
await page.keyboard.press('Shift+Enter');
await expect(page.getByTestId('response-status-code')).toContainText('200', { timeout: 15000 });
// Reset Default
await openKeybindingsTab(page);
await page.getByTestId('reset-all-keybindings-btn').click({ timeout: 2000 });
});
test('customized Shift+Enter sends request when cursor is in pre-request Vars value editor', async ({ page }) => {
// Close existing tabs
await page.keyboard.down('Alt');
await page.keyboard.down('KeyY');
await page.keyboard.up('KeyY');
await page.keyboard.up('Alt');
// Remap sendRequest to Shift+Enter
await openKeybindingsTab(page);
const row = page.getByTestId('keybinding-row-sendRequest');
await row.hover();
await page.getByTestId('keybinding-edit-sendRequest').click();
await expect(page.getByTestId('keybinding-input-sendRequest')).toBeVisible({ timeout: 2000 });
await page.keyboard.down('Backspace');
await page.keyboard.down('Shift');
await page.keyboard.down('Enter');
await page.keyboard.up('Enter');
await page.keyboard.up('Shift');
// await closePreferencesTab(page);
await createRequest(page, 'shift-enter-req-vars', 'kb-collection', {
url: 'https://echo.usebruno.com',
method: 'POST'
});
await openRequest(page, 'kb-collection', 'shift-enter-req-vars', { persist: true });
await selectRequestPaneTab(page, 'Vars');
const varsTable = page.getByTestId('request-pane').locator('table').first();
const firstRow = varsTable.locator('tbody tr').first();
const nameInput = firstRow.locator('input[type="text"]').first();
await nameInput.click();
await nameInput.fill('var-1');
const valueEditor = firstRow.locator('.CodeMirror').first();
await valueEditor.click();
await page.keyboard.type('val-1');
await page.keyboard.press('Enter'); // insert newline in value editor
await page.keyboard.type('val-2');
// Cursor is still in the value CodeMirror — press Shift+Enter (customized) to send
await page.keyboard.press('Shift+Enter');
await expect(page.getByTestId('response-status-code')).toContainText('200', { timeout: 15000 });
// Reset Default
await openKeybindingsTab(page);
await page.getByTestId('reset-all-keybindings-btn').click({ timeout: 2000 });
});
});
});
});