Files
bruno/tests/variable-tooltip/variable-tooltip.spec.ts
2025-11-17 16:13:09 +05:30

318 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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();
});
});
});