Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ const EnvironmentVariablesTable = ({
}) => {
const { storedTheme } = useTheme();
const { globalEnvironments, activeGlobalEnvironmentUid } = useSelector((state) => state.globalEnvironments);
const activeWorkspace = useSelector((state) => {
const uid = state.workspaces?.activeWorkspaceUid;
return state.workspaces?.workspaces?.find((w) => w.uid === uid);
});

const dispatch = useDispatch();
const tabs = useSelector((state) => state.tabs.tabs);
Expand Down Expand Up @@ -138,6 +142,12 @@ const EnvironmentVariablesTable = ({
_collection.globalEnvironmentVariables = globalEnvironmentVariables;
}

// When collection is null (global/workspace environments), populate process env
// variables from the active workspace so that {{process.env.X}} can resolve
if (!collection && activeWorkspace?.processEnvVariables) {
_collection.workspaceProcessEnvVariables = activeWorkspace.processEnvVariables;
}

const initialValues = useMemo(() => {
const vars = environment.variables || [];
return [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ const CollapsibleSection = ({
onToggle,
badge,
actions,
children
children,
testId
}) => {
return (
<StyledWrapper className={expanded ? 'expanded' : 'collapsed'}>
<div className="section-header" onClick={onToggle}>
<div className="section-header" onClick={onToggle} data-testid={testId}>
<div className="section-title-wrapper">
<IconChevronRight
size={14}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const DotEnvFileDetails = ({
className={`toggle-btn ${viewMode === 'raw' ? 'active' : ''}`}
onClick={() => onViewModeChange?.('raw')}
aria-pressed={viewMode === 'raw'}
data-testid="dotenv-view-raw"
>
Raw
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const DotEnvRawView = ({
}) => {
return (
<>
<div className="raw-editor-container">
<div className="raw-editor-container" data-testid="dotenv-raw-editor">
<CodeEditor
collection={collection}
item={item}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const EnvironmentListContent = ({
</div>
</ToolHint>
<div className="dropdown-item configure-button">
<button onClick={onSettingsClick} id="configure-env">
<button onClick={onSettingsClick} id="configure-env" data-testid="configure-env">
<IconSettings size={16} strokeWidth={1.5} />
<span>Configure</span>
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,7 @@ const EnvironmentList = ({

<CollapsibleSection
title=".env Files"
testId="dotenv-files-section"
expanded={dotEnvExpanded}
onToggle={() => setDotEnvExpanded(!dotEnvExpanded)}
badge={dotEnvFiles.length}
Expand All @@ -744,6 +745,7 @@ const EnvironmentList = ({
className="btn-action"
onClick={handleCreateDotEnvInlineClick}
title="Create .env file"
data-testid="create-dotenv-file"
>
<IconPlus size={14} strokeWidth={1.5} />
</button>
Expand All @@ -768,6 +770,7 @@ const EnvironmentList = ({
ref={dotEnvInputRef}
type="text"
className="environment-name-input"
data-testid="dotenv-name-input"
value={newDotEnvName}
onChange={handleDotEnvNameChange}
onKeyDown={handleDotEnvNameKeyDown}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,7 @@ const EnvironmentList = ({

<CollapsibleSection
title=".env Files"
testId="dotenv-files-section"
expanded={dotEnvExpanded}
onToggle={() => setDotEnvExpanded(!dotEnvExpanded)}
badge={dotEnvFiles.length}
Expand All @@ -739,6 +740,7 @@ const EnvironmentList = ({
className="btn-action"
onClick={handleCreateDotEnvInlineClick}
title="Create .env file"
data-testid="create-dotenv-file"
>
<IconPlus size={14} strokeWidth={1.5} />
</button>
Expand All @@ -763,6 +765,7 @@ const EnvironmentList = ({
ref={dotEnvInputRef}
type="text"
className="environment-name-input"
data-testid="dotenv-name-input"
value={newDotEnvName}
onChange={handleDotEnvNameChange}
onKeyDown={handleDotEnvNameKeyDown}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,11 @@ export const mountScratchCollection = (workspaceUid) => {
brunoConfig
});

// Map scratch collection to workspace so getProcessEnvVars can resolve workspace .env values
if (workspace.pathname) {
await ipcRenderer.invoke('renderer:set-collection-workspace', scratchCollectionUid, workspace.pathname);
}

await dispatch(openScratchCollectionEvent(scratchCollectionUid, tempDirectoryPath, brunoConfig));

dispatch(setWorkspaceScratchCollection({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"version": "1",
"name": "process-env-global-test",
"type": "collection"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
meta {
name: echo-post
type: http
seq: 1
}

post {
url: https://echo.usebruno.com
body: json
auth: none
}

body:json {
{
"value": "{{testVar}}"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { test, expect } from '../../../playwright';
import {
openCollection,
openEnvironmentSelector,
openRequest,
sendRequest,
expectResponseContains
} from '../../utils/page';

test.describe('Global Environment process.env Resolution', () => {
test('should resolve process.env variables referenced in global environment', async ({
pageWithUserData: page
}) => {
await test.step('Open collection', async () => {
await openCollection(page, 'process-env-global-test');
});

await test.step('Create .env file with variable via UI', async () => {
// Open global environment configuration
await openEnvironmentSelector(page, 'global');
await page.getByTestId('configure-env').click();

// Expand the .env Files section
const dotEnvSection = page.getByTestId('dotenv-files-section');
await dotEnvSection.waitFor({ state: 'visible' });
await dotEnvSection.click();

// Click + to create a new .env file
await page.getByTestId('create-dotenv-file').click();

// Accept the default name (.env) and press Enter
await page.getByTestId('dotenv-name-input').press('Enter');
await expect(page.getByText('.env file created!')).toBeVisible();

// Switch to Raw mode to type the variable
await page.getByTestId('dotenv-view-raw').click();

// Type the variable into the raw editor
const rawEditor = page.getByTestId('dotenv-raw-editor').locator('.CodeMirror');
await rawEditor.click();
await page.keyboard.type('MY_SECRET=hello-from-dotenv');

// Save the .env file
await page.getByTestId('save-dotenv-raw').click();
});

await test.step('Verify global environment is active', async () => {
await expect(page.locator('.current-environment')).toContainText('ProcessEnv Test');
});

await test.step('Open request', async () => {
await openRequest(page, 'process-env-global-test', 'echo-post');
});

await test.step('Send request and verify process.env resolved', async () => {
await sendRequest(page, 200);
});

await test.step('Verify response contains resolved value from .env file', async () => {
await expectResponseContains(page, ['hello-from-dotenv']);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"collections": [
{
"path": "{{collectionPath}}",
"securityConfig": {
"jsSandboxMode": "safe"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"environments": [
{
"uid": "pEnvTestGlobalEnvUi01",
"name": "ProcessEnv Test",
"variables": [
{
"uid": "pEnvTestVarUid0000001",
"name": "testVar",
"value": "{{process.env.MY_SECRET}}",
"type": "text",
"secret": false,
"enabled": true
}
]
}
],
"activeGlobalEnvironmentUid": "pEnvTestGlobalEnvUi01"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"maximized": false,
"lastOpenedCollections": [
"{{collectionPath}}"
],
"preferences": {
"onboarding": {
"hasLaunchedBefore": true,
"hasSeenWelcomeModal": true
}
}
}
Loading