Merge pull request #6069 from pooja-bruno/feat/add-edit-variable-in-place

feat: edit variable in place
This commit is contained in:
Pooja
2025-11-17 16:13:09 +05:30
committed by GitHub
parent 27a7b623c7
commit 4631eda281
16 changed files with 1605 additions and 118 deletions

View File

@@ -0,0 +1,317 @@
import { test, expect } from '../../playwright';
import { createCollection, closeAllCollections } from '../utils/page';
test.describe('Variable Tooltip', () => {
test.afterEach(async ({ page }) => {
await closeAllCollections(page);
});
test('should test tooltip functionality with environment variables', async ({ page, createTmpDir }) => {
const collectionName = 'tooltip-test';
await test.step('Create collection and add environment variables', async () => {
await createCollection(page, collectionName, await createTmpDir('tooltip-collection'), {
openWithSandboxMode: 'safe'
});
await expect(page.locator('#sidebar-collection-name').filter({ hasText: collectionName })).toBeVisible();
// Open environment settings
await page.locator('[data-testid="environment-selector-trigger"]').click();
await expect(page.locator('[data-testid="env-tab-collection"]')).toHaveClass(/active/);
// Create environment
await page.locator('button[id="create-env"]').click();
await page.locator('input[name="name"]').fill('Test Env');
await page.getByRole('button', { name: 'Create' }).click();
// Add apiKey variable
await page.locator('button[data-testid="add-variable"]').click();
await page.locator('input[name="0.name"]').fill('apiKey');
await page.locator('tr').filter({ has: page.locator('input[name="0.name"]') }).locator('.CodeMirror').click();
await page.keyboard.type('test-key-123');
// Add secretToken variable
await page.locator('button[data-testid="add-variable"]').click();
await page.locator('input[name="1.name"]').fill('secretToken');
await page.locator('tr').filter({ has: page.locator('input[name="1.name"]') }).locator('.CodeMirror').click();
await page.keyboard.type('secret-xyz');
await page.locator('input[name="1.secret"]').check();
// Save and close
await page.getByRole('button', { name: 'Save' }).click();
await page.getByText('×').click();
});
await test.step('Create request and test tooltip', async () => {
// Create request
const collectionContainer = page.locator('.collection-name').filter({ hasText: collectionName });
await collectionContainer.locator('.collection-actions').hover();
await collectionContainer.locator('.collection-actions .icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'New Request' }).click();
await page.getByPlaceholder('Request Name').fill('Test Request');
await page.locator('#new-request-url .CodeMirror').click();
await page.locator('textarea').fill('https://api.example.com?key={{apiKey}}');
await page.getByRole('button', { name: 'Create' }).click();
// Open request
await page.locator('.collection-item-name').filter({ hasText: 'Test Request' }).click();
});
await test.step('Test basic tooltip', async () => {
const urlEditor = page.locator('#request-url .CodeMirror');
const apiKeyVar = urlEditor.locator('.cm-variable-valid').filter({ hasText: 'apiKey' }).first();
await apiKeyVar.hover();
const tooltip = page.locator('.CodeMirror-brunoVarInfo').first();
await expect(tooltip).toBeVisible();
await expect(tooltip.locator('.var-name')).toContainText('apiKey');
await expect(tooltip.locator('.var-scope-badge')).toContainText('Environment');
await expect(tooltip.locator('.var-value-editable-display')).toContainText('test-key-123');
await expect(tooltip.locator('.copy-button')).toBeVisible();
});
await test.step('Test secret variable with toggle', async () => {
// Move mouse away to dismiss any active tooltip
await page.mouse.move(0, 0);
// Add header with secret
await page.getByRole('tab', { name: 'Headers' }).click();
await page.locator('button.btn-action').filter({ hasText: 'Add Header' }).click();
const headerNameEditor = page.locator('table tbody tr').first().locator('td').first().locator('.CodeMirror');
await headerNameEditor.click();
await page.keyboard.type('Authorization');
const headerValueEditor = page.locator('table tbody tr').first().locator('td').nth(1).locator('.CodeMirror');
await headerValueEditor.click();
await page.keyboard.type('Bearer {{secretToken}}');
await page.keyboard.press('Control+s');
// Test tooltip with secret
const secretVar = headerValueEditor.locator('.cm-variable-valid').filter({ hasText: 'secretToken' }).first();
await secretVar.hover();
const tooltip = page.locator('.CodeMirror-brunoVarInfo').first();
await expect(tooltip).toBeVisible();
// Verify masked
const valueDisplay = tooltip.locator('.var-value-editable-display');
const maskedText = await valueDisplay.textContent();
// Check that value is masked (contains bullet points and not the actual value)
expect(maskedText).not.toContain('secret-xyz');
expect(maskedText?.length).toBeGreaterThan(0);
// Test toggle
const toggleButton = tooltip.locator('.secret-toggle-button');
await expect(toggleButton).toBeVisible();
await toggleButton.click();
await expect(valueDisplay).toContainText('secret-xyz');
// Toggle back
await toggleButton.click();
const remaskedText = await valueDisplay.textContent();
expect(remaskedText).not.toContain('secret-xyz');
expect(remaskedText?.length).toBeGreaterThan(0);
});
});
test('should test tooltip with variable references', async ({ page, createTmpDir }) => {
const collectionName = 'tooltip-reference-test';
await test.step('Create collection with interdependent variables', async () => {
await createCollection(page, collectionName, await createTmpDir('tooltip-ref-collection'), {
openWithSandboxMode: 'safe'
});
await expect(page.locator('#sidebar-collection-name').filter({ hasText: collectionName })).toBeVisible();
// Open environment settings
await page.locator('[data-testid="environment-selector-trigger"]').click();
await expect(page.locator('[data-testid="env-tab-collection"]')).toHaveClass(/active/);
// Create environment
await page.locator('button[id="create-env"]').click();
await page.locator('input[name="name"]').fill('Ref Test Env');
await page.getByRole('button', { name: 'Create' }).click();
// Add host variable
await page.locator('button[data-testid="add-variable"]').click();
await page.locator('input[name="0.name"]').fill('host');
await page.locator('tr').filter({ has: page.locator('input[name="0.name"]') }).locator('.CodeMirror').click();
await page.keyboard.type('api.example.com');
// Add endpoint that references host
await page.locator('button[data-testid="add-variable"]').click();
await page.locator('input[name="1.name"]').fill('endpoint');
await page.locator('tr').filter({ has: page.locator('input[name="1.name"]') }).locator('.CodeMirror').click();
await page.keyboard.type('https://{{host}}/users');
// Save and close
await page.getByRole('button', { name: 'Save' }).click();
await page.getByText('×').click();
});
await test.step('Create request with variable references', async () => {
const collectionContainer = page.locator('.collection-name').filter({ hasText: collectionName });
await collectionContainer.locator('.collection-actions').hover();
await collectionContainer.locator('.collection-actions .icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'New Request' }).click();
await page.getByPlaceholder('Request Name').fill('Ref Test Request');
await page.locator('#new-request-url .CodeMirror').click();
await page.locator('textarea').fill('{{endpoint}}');
await page.getByRole('button', { name: 'Create' }).click();
await page.locator('.collection-item-name').filter({ hasText: 'Ref Test Request' }).click();
});
await test.step('Test variable referencing other variables', async () => {
const urlEditor = page.locator('#request-url .CodeMirror');
const endpointVar = urlEditor.locator('.cm-variable-valid').filter({ hasText: 'endpoint' }).first();
await endpointVar.hover();
const tooltip = page.locator('.CodeMirror-brunoVarInfo').first();
await expect(tooltip).toBeVisible();
await expect(tooltip.locator('.var-name')).toContainText('endpoint');
// Should show resolved value
await expect(tooltip.locator('.var-value-editable-display')).toContainText('https://api.example.com/users');
// Should have copy button
await expect(tooltip.locator('.copy-button')).toBeVisible();
});
await test.step('Test editing variable with references', async () => {
// Move mouse away to dismiss any active tooltip
await page.mouse.move(0, 0);
// URL editor is always visible at the top
const urlEditor = page.locator('#request-url .CodeMirror');
const endpointVar = urlEditor.locator('.cm-variable-valid').filter({ hasText: 'endpoint' }).first();
await endpointVar.hover();
const tooltip = page.locator('.CodeMirror-brunoVarInfo').first();
await expect(tooltip).toBeVisible();
// Click on value to edit
const valueDisplay = tooltip.locator('.var-value-editable-display');
await valueDisplay.click();
// Should show editor with raw value (not resolved)
const editor = tooltip.locator('.var-value-editor .CodeMirror');
await expect(editor).toBeVisible();
// Verify it shows the raw value with variable references
// focus on the editor
const editorContent = await editor.locator('.CodeMirror-line').textContent();
expect(editorContent).toContain('{{host}}');
// Edit the value
await page.keyboard.press('End');
await page.keyboard.type('/posts');
// Click outside to save
await page.locator('body').click();
// Move mouse away and back to get fresh tooltip
await page.mouse.move(0, 0);
// Hover again to verify the change
await endpointVar.hover();
const newTooltip = page.locator('.CodeMirror-brunoVarInfo').first();
await expect(newTooltip).toBeVisible();
// Should show updated resolved value
await expect(newTooltip.locator('.var-value-editable-display')).toContainText('https://api.example.com/users/posts');
});
await test.step('Test copy button', async () => {
// Move mouse away to dismiss any active tooltip
await page.mouse.move(0, 0);
const urlEditor = page.locator('#request-url .CodeMirror');
const endpointVar = urlEditor.locator('.cm-variable-valid').filter({ hasText: 'endpoint' }).first();
await endpointVar.hover();
const tooltip = page.locator('.CodeMirror-brunoVarInfo').first();
await expect(tooltip).toBeVisible();
const copyButton = tooltip.locator('.copy-button');
await expect(copyButton).toBeVisible();
// Click copy button
await copyButton.click();
// Should show success state (checkmark)
await expect(copyButton.locator('svg polyline')).toBeVisible({ timeout: 1000 });
// Wait for it to revert back to copy icon
await expect(copyButton.locator('svg rect')).toBeVisible();
});
});
test('should handle runtime and process.env variables', async ({ page, createTmpDir }) => {
const collectionName = 'tooltip-readonly-test';
await test.step('Create collection and request', async () => {
await createCollection(page, collectionName, await createTmpDir('tooltip-readonly-collection'), {
openWithSandboxMode: 'safe'
});
await expect(page.locator('#sidebar-collection-name').filter({ hasText: collectionName })).toBeVisible();
// Create environment
await page.locator('[data-testid="environment-selector-trigger"]').click();
await page.locator('button[id="create-env"]').click();
await page.locator('input[name="name"]').fill('Readonly Env');
await page.getByRole('button', { name: 'Create' }).click();
await page.getByRole('button', { name: 'Save' }).click();
await page.getByText('×').click();
// Create request
const collectionContainer = page.locator('.collection-name').filter({ hasText: collectionName });
await collectionContainer.locator('.collection-actions').hover();
await collectionContainer.locator('.collection-actions .icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'New Request' }).click();
await page.getByPlaceholder('Request Name').fill('Readonly Test');
await page.locator('#new-request-url .CodeMirror').click();
await page.locator('textarea').fill('https://example.com');
await page.getByRole('button', { name: 'Create' }).click();
await page.locator('.collection-item-name').filter({ hasText: 'Readonly Test' }).click();
});
await test.step('Test process.env variable tooltip', async () => {
// Move mouse away to dismiss any active tooltip
await page.mouse.move(0, 0);
// Add a process.env variable in URL (URL editor is always visible at the top)
const urlEditor = page.locator('#request-url .CodeMirror');
await urlEditor.click();
await page.keyboard.press('End');
await page.keyboard.type('?env={{process.env.HOME}}');
await page.keyboard.press('Control+s');
// Hover over process.env variable
const processEnvVar = urlEditor.locator('.cm-variable-valid, .cm-variable-invalid').filter({ hasText: 'process.env.HOME' }).first();
await processEnvVar.hover();
const tooltip = page.locator('.CodeMirror-brunoVarInfo').first();
await expect(tooltip).toBeVisible();
await expect(tooltip.locator('.var-name')).toContainText('process.env.HOME');
await expect(tooltip.locator('.var-scope-badge')).toContainText('Process Env');
// Should show read-only note
await expect(tooltip.locator('.var-readonly-note')).toContainText('read-only');
// Should have copy button but not be editable
await expect(tooltip.locator('.copy-button')).toBeVisible();
await expect(tooltip.locator('.var-value-editor')).not.toBeVisible();
});
});
});