remove activeEnvironmentUid and migration (#7545)

* remove activeEnvironmentUid and migration

* fix: no environment handling

* fix: standardize workspace path handling
This commit is contained in:
naman-bruno
2026-03-23 21:02:53 +05:30
committed by GitHub
parent 32b9f527ea
commit f1d7f007fe
16 changed files with 401 additions and 136 deletions

View File

@@ -737,28 +737,6 @@ export const deleteWorkspaceEnvironment = (workspaceUid, environmentUid) => {
};
};
export const selectWorkspaceEnvironment = (workspaceUid, environmentUid) => {
return async (dispatch, getState) => {
try {
const workspace = getState().workspaces.workspaces.find((w) => w.uid === workspaceUid);
if (!workspace) {
throw new Error('Workspace not found');
}
await ipcRenderer.invoke('renderer:select-workspace-environment', workspace.pathname, environmentUid);
dispatch(updateWorkspace({
uid: workspaceUid,
activeEnvironmentUid: environmentUid
}));
return true;
} catch (error) {
throw error;
}
};
};
export const importWorkspaceEnvironment = (workspaceUid, environmentData) => {
return async (dispatch, getState) => {
try {

View File

@@ -5,6 +5,49 @@ const { ipcMain } = require('electron');
const { utils: { jsonToDotenv } } = require('@usebruno/common');
const { globalEnvironmentsStore } = require('../store/global-environments');
const { generateUniqueName, sanitizeName, writeFile, isValidDotEnvFilename } = require('../utils/filesystem');
const { readWorkspaceConfig, writeWorkspaceConfig } = require('../utils/workspace-config');
/**
* Migrates activeEnvironmentUid from workspace.yml to the electron store (per-workspace).
* This handles users upgrading from versions that stored the active global env in workspace.yml.
*
* Fallback chain:
* 1. Per-workspace electron store (already migrated) - use it
* 2. workspace.yml activeEnvironmentUid - migrate to electron store, remove from file
* 3. Legacy electron store activeGlobalEnvironmentUid - migrate to per-workspace store
* 4. null (new workspace)
*/
const migrateActiveGlobalEnvironmentUid = async (workspacePath) => {
// Already in per-workspace store (null means explicitly "No Environment", undefined means not set)
const perWorkspaceUid = globalEnvironmentsStore.getActiveGlobalEnvironmentUidForWorkspace(workspacePath);
if (perWorkspaceUid !== undefined) {
return perWorkspaceUid;
}
// Try workspace.yml
try {
const config = readWorkspaceConfig(workspacePath);
if (config.activeEnvironmentUid) {
const uid = config.activeEnvironmentUid;
// Migrate to electron store
globalEnvironmentsStore.setActiveGlobalEnvironmentUidForWorkspace(workspacePath, uid);
// Rewrite workspace.yml without activeEnvironmentUid (generateYamlContent drops unknown fields)
await writeWorkspaceConfig(workspacePath, config);
return uid;
}
} catch (error) {
// workspace.yml may not exist or be unreadable, continue to next fallback
}
// Fallback to legacy single active uid
const legacyUid = globalEnvironmentsStore.getActiveGlobalEnvironmentUid();
if (legacyUid) {
globalEnvironmentsStore.setActiveGlobalEnvironmentUidForWorkspace(workspacePath, legacyUid);
return legacyUid;
}
return null;
};
const registerGlobalEnvironmentsIpc = (mainWindow, workspaceEnvironmentsManager) => {
ipcMain.handle('renderer:create-global-environment', async (event, { uid, name, variables, color, workspaceUid, workspacePath }) => {
@@ -64,23 +107,28 @@ const registerGlobalEnvironmentsIpc = (mainWindow, workspaceEnvironmentsManager)
ipcMain.handle('renderer:delete-global-environment', async (event, { environmentUid, workspaceUid, workspacePath }) => {
try {
if (workspacePath && workspaceEnvironmentsManager) {
return await workspaceEnvironmentsManager.deleteGlobalEnvironmentByPath(workspacePath, { environmentUid });
await workspaceEnvironmentsManager.deleteGlobalEnvironmentByPath(workspacePath, { environmentUid });
// Clear active environment for this workspace if the deleted one was active
const activeUid = globalEnvironmentsStore.getActiveGlobalEnvironmentUidForWorkspace(workspacePath);
if (activeUid === environmentUid) {
globalEnvironmentsStore.setActiveGlobalEnvironmentUidForWorkspace(workspacePath, null);
}
} else {
globalEnvironmentsStore.deleteGlobalEnvironment({ environmentUid });
}
globalEnvironmentsStore.deleteGlobalEnvironment({ environmentUid });
} catch (error) {
console.error('Error in renderer:delete-global-environment:', error);
return Promise.reject(error);
}
});
ipcMain.handle('renderer:select-global-environment', async (event, { environmentUid, workspaceUid, workspacePath }) => {
ipcMain.handle('renderer:select-global-environment', async (event, { environmentUid, workspacePath }) => {
try {
if (workspacePath && workspaceEnvironmentsManager) {
return await workspaceEnvironmentsManager.selectGlobalEnvironmentByPath(workspacePath, { environmentUid });
if (workspacePath) {
globalEnvironmentsStore.setActiveGlobalEnvironmentUidForWorkspace(workspacePath, environmentUid || null);
} else {
globalEnvironmentsStore.setActiveGlobalEnvironmentUid(environmentUid || null);
}
globalEnvironmentsStore.selectGlobalEnvironment({ environmentUid });
} catch (error) {
console.error('Error in renderer:select-global-environment:', error);
return Promise.reject(error);
@@ -89,13 +137,22 @@ const registerGlobalEnvironmentsIpc = (mainWindow, workspaceEnvironmentsManager)
ipcMain.handle('renderer:get-global-environments', async (event, { workspaceUid, workspacePath }) => {
try {
let globalEnvironments = [];
if (workspacePath && workspaceEnvironmentsManager) {
return await workspaceEnvironmentsManager.getGlobalEnvironmentsByPath(workspacePath);
const result = await workspaceEnvironmentsManager.getGlobalEnvironmentsByPath(workspacePath);
globalEnvironments = result?.globalEnvironments || [];
} else {
globalEnvironments = globalEnvironmentsStore.getGlobalEnvironments() || [];
}
const activeGlobalEnvironmentUid = workspacePath
? await migrateActiveGlobalEnvironmentUid(workspacePath)
: globalEnvironmentsStore.getActiveGlobalEnvironmentUid();
return {
globalEnvironments: globalEnvironmentsStore.getGlobalEnvironments() || [],
activeGlobalEnvironmentUid: globalEnvironmentsStore.getActiveGlobalEnvironmentUid()
globalEnvironments,
activeGlobalEnvironmentUid
};
} catch (error) {
console.error('Error in renderer:get-global-environments:', error);

View File

@@ -10,6 +10,7 @@ const yaml = require('js-yaml');
const LastOpenedWorkspaces = require('../store/last-opened-workspaces');
const { defaultWorkspaceManager } = require('../store/default-workspace');
const { globalEnvironmentsManager } = require('../store/workspace-environments');
const { globalEnvironmentsStore } = require('../store/global-environments');
const {
createWorkspaceConfig,
@@ -280,6 +281,7 @@ const registerWorkspaceIpc = (mainWindow, workspaceWatcher) => {
ipcMain.handle('renderer:close-workspace', async (event, workspacePath) => {
try {
lastOpenedWorkspaces.remove(workspacePath);
globalEnvironmentsStore.removeActiveGlobalEnvironmentUidForWorkspace(workspacePath);
if (workspaceWatcher) {
workspaceWatcher.removeWatcher(workspacePath);
@@ -468,14 +470,6 @@ const registerWorkspaceIpc = (mainWindow, workspaceWatcher) => {
}
});
ipcMain.handle('renderer:select-workspace-environment', async (event, workspacePath, environmentUid) => {
try {
return await globalEnvironmentsManager.selectGlobalEnvironment(workspacePath, { environmentUid });
} catch (error) {
throw error;
}
});
ipcMain.handle('renderer:import-workspace-environment', async (event, workspacePath, environmentData) => {
try {
return await globalEnvironmentsManager.createGlobalEnvironment(workspacePath, {

View File

@@ -66,7 +66,7 @@ class DefaultWorkspaceManager {
* Recovers collections and environments from an existing workspace directory
*/
recoverDataFromWorkspace(workspacePath) {
const recovered = { collections: [], environments: [], activeEnvironmentUid: null };
const recovered = { collections: [], environments: [] };
try {
// Try to read workspace config for collections
@@ -78,9 +78,6 @@ class DefaultWorkspaceManager {
return isValidCollectionDirectory(collectionPath);
});
}
if (config.activeEnvironmentUid) {
recovered.activeEnvironmentUid = config.activeEnvironmentUid;
}
} catch (error) {
console.error('Failed to read workspace config during recovery:', error);
}
@@ -273,9 +270,6 @@ class DefaultWorkspaceManager {
console.error('Failed to copy environment:', env.name, error);
}
}
if (recoveredData.activeEnvironmentUid) {
workspaceConfig.activeEnvironmentUid = recoveredData.activeEnvironmentUid;
}
}
// Apply recovered collections first (lower priority)
@@ -374,8 +368,12 @@ class DefaultWorkspaceManager {
const content = stringifyEnvironment(environment, { format: 'yml' });
await writeFile(envFilePath, content);
if (env.uid === activeGlobalEnvironmentUid && !workspaceConfig.activeEnvironmentUid) {
workspaceConfig.activeEnvironmentUid = generateUidBasedOnHash(envFilePath);
// Map the legacy active env uid to the new file-based uid in the per-workspace store
if (env.uid === activeGlobalEnvironmentUid) {
globalEnvironmentsStore.setActiveGlobalEnvironmentUidForWorkspace(
workspacePath,
generateUidBasedOnHash(envFilePath)
);
}
}
}

View File

@@ -2,6 +2,7 @@ const _ = require('lodash');
const Store = require('electron-store');
const { encryptStringSafe, decryptStringSafe } = require('../utils/encryption');
const { environmentSchema } = require('@usebruno/schema');
const { posixifyPath } = require('../utils/filesystem');
class GlobalEnvironmentsStore {
constructor() {
@@ -86,6 +87,36 @@ class GlobalEnvironmentsStore {
return this.store.get('activeGlobalEnvironmentUid', null);
}
setActiveGlobalEnvironmentUid(uid) {
return this.store.set('activeGlobalEnvironmentUid', uid);
}
getActiveGlobalEnvironmentUidForWorkspace(workspacePath) {
if (!workspacePath) return undefined;
const key = posixifyPath(workspacePath);
const mapping = this.store.get('activeGlobalEnvironmentUidByWorkspace', {});
if (key in mapping) {
return mapping[key];
}
return undefined;
}
setActiveGlobalEnvironmentUidForWorkspace(workspacePath, uid) {
if (!workspacePath) return;
const key = posixifyPath(workspacePath);
const mapping = this.store.get('activeGlobalEnvironmentUidByWorkspace', {});
mapping[key] = uid || null;
this.store.set('activeGlobalEnvironmentUidByWorkspace', mapping);
}
removeActiveGlobalEnvironmentUidForWorkspace(workspacePath) {
if (!workspacePath) return;
const key = posixifyPath(workspacePath);
const mapping = this.store.get('activeGlobalEnvironmentUidByWorkspace', {});
delete mapping[key];
this.store.set('activeGlobalEnvironmentUidByWorkspace', mapping);
}
setGlobalEnvironments(globalEnvironments) {
globalEnvironments = this.filterValidEnvironments(globalEnvironments);
@@ -93,10 +124,6 @@ class GlobalEnvironmentsStore {
return this.store.set('environments', globalEnvironments);
}
setActiveGlobalEnvironmentUid(uid) {
return this.store.set('activeGlobalEnvironmentUid', uid);
}
addGlobalEnvironment({ uid, name, variables = [], color }) {
let globalEnvironments = this.getGlobalEnvironments();
const existingEnvironment = globalEnvironments.find((env) => env?.name == name);

View File

@@ -1,18 +1,11 @@
const fs = require('fs');
const path = require('path');
const _ = require('lodash');
const yaml = require('js-yaml');
const { parseEnvironment, stringifyEnvironment } = require('@usebruno/filestore');
const { writeFile, createDirectory } = require('../utils/filesystem');
const { generateUidBasedOnHash, uuid } = require('../utils/common');
const { decryptStringSafe } = require('../utils/encryption');
const EnvironmentSecretsStore = require('./env-secrets');
const {
readWorkspaceConfig,
generateYamlContent,
writeWorkspaceFileAtomic
} = require('../utils/workspace-config');
const { withLock, getWorkspaceLockKey } = require('../utils/workspace-lock');
const environmentSecretsStore = new EnvironmentSecretsStore();
@@ -98,8 +91,7 @@ class GlobalEnvironmentsManager {
if (!fs.existsSync(environmentsDir)) {
return {
globalEnvironments: [],
activeGlobalEnvironmentUid: null
globalEnvironments: []
};
}
@@ -119,58 +111,14 @@ class GlobalEnvironmentsManager {
}
}
const activeGlobalEnvironmentUid = await this.getActiveGlobalEnvironmentUid(workspacePath);
return {
globalEnvironments: environments,
activeGlobalEnvironmentUid
globalEnvironments: environments
};
} catch (error) {
throw error;
}
}
async getActiveGlobalEnvironmentUid(workspacePath) {
try {
if (!workspacePath) {
return null;
}
const workspaceFilePath = path.join(workspacePath, 'workspace.yml');
if (!fs.existsSync(workspaceFilePath)) {
return null;
}
const yamlContent = fs.readFileSync(workspaceFilePath, 'utf8');
const workspaceConfig = yaml.load(yamlContent);
return workspaceConfig.activeEnvironmentUid || null;
} catch (error) {
return null;
}
}
async setActiveGlobalEnvironmentUid(workspacePath, environmentUid) {
if (!workspacePath) {
throw new Error('Workspace path is required');
}
const workspaceFilePath = path.join(workspacePath, 'workspace.yml');
if (!fs.existsSync(workspaceFilePath)) {
throw new Error('Invalid workspace: workspace.yml not found');
}
return withLock(getWorkspaceLockKey(workspacePath), async () => {
const workspaceConfig = readWorkspaceConfig(workspacePath);
workspaceConfig.activeEnvironmentUid = environmentUid;
const yamlOutput = generateYamlContent(workspaceConfig);
await writeWorkspaceFileAtomic(workspacePath, yamlOutput);
return true;
});
}
async createGlobalEnvironment(workspacePath, { uid, name, variables, color }) {
try {
if (!workspacePath) {
@@ -303,24 +251,6 @@ class GlobalEnvironmentsManager {
fs.unlinkSync(envFile.filePath);
const activeGlobalEnvironmentUid = await this.getActiveGlobalEnvironmentUid(workspacePath);
if (activeGlobalEnvironmentUid === environmentUid) {
await this.setActiveGlobalEnvironmentUid(workspacePath, null);
}
return true;
} catch (error) {
throw error;
}
}
async selectGlobalEnvironment(workspacePath, { environmentUid }) {
try {
if (!workspacePath) {
throw new Error('Workspace path is required');
}
await this.setActiveGlobalEnvironmentUid(workspacePath, environmentUid);
return true;
} catch (error) {
throw error;
@@ -371,10 +301,6 @@ class GlobalEnvironmentsManager {
return this.deleteGlobalEnvironment(workspacePath, params);
}
async selectGlobalEnvironmentByPath(workspacePath, params) {
return this.selectGlobalEnvironment(workspacePath, params);
}
async updateGlobalEnvironmentColorByPath(workspacePath, { environmentUid, color }) {
return this.updateGlobalEnvironmentColor(workspacePath, environmentUid, color);
}

View File

@@ -272,11 +272,6 @@ const generateYamlContent = (config) => {
yamlLines.push('docs: \'\'');
}
if (config.activeEnvironmentUid && typeof config.activeEnvironmentUid === 'string') {
yamlLines.push('');
yamlLines.push(`activeEnvironmentUid: ${config.activeEnvironmentUid}`);
}
yamlLines.push('');
return yamlLines.join('\n');

View File

@@ -0,0 +1,5 @@
{
"version": "1",
"name": "Test Collection",
"type": "collection"
}

View File

@@ -0,0 +1,4 @@
name: Alpha
variables:
- name: mode
value: alpha

View File

@@ -0,0 +1,4 @@
name: Beta
variables:
- name: mode
value: beta

View File

@@ -0,0 +1,12 @@
opencollection: 1.0.0
info:
name: "My Workspace"
type: workspace
collections:
- name: "Test Collection"
path: "collections/test-collection"
specs:
docs: ''

View File

@@ -0,0 +1,92 @@
import path from 'path';
import fs from 'fs';
import { test, expect, closeElectronApp } from '../../../playwright';
import { openCollection } from '../../utils/page';
const initUserDataPath = path.join(__dirname, 'init-user-data');
const workspaceFixturePath = path.join(__dirname, 'fixtures', 'workspace');
/**
* Replicate the uid generation from bruno-electron/src/utils/common.js
* so we can compute environment uids at test time.
*/
function simpleHash(str: string): string {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash &= hash;
}
return new Uint32Array([hash])[0].toString(36);
}
function generateUidBasedOnHash(str: string): string {
const hash = simpleHash(str);
return `${hash}`.padEnd(21, '0');
}
/**
* Copy the workspace fixture to a temp location and return the path.
*/
async function copyWorkspaceFixture(destDir: string): Promise<string> {
const workspacePath = path.join(destDir, 'workspace');
await fs.promises.cp(workspaceFixturePath, workspacePath, { recursive: true });
return workspacePath;
}
test.describe('Global Environment Migration from workspace.yml', () => {
test('should migrate activeEnvironmentUid from workspace.yml to electron store and remove from file', async ({
launchElectronApp,
createTmpDir
}) => {
const userDataPath = await createTmpDir('env-migrate-from-file');
const fixtureDir = await createTmpDir('ws-fixture');
// Copy workspace fixture to temp location
const workspacePath = await copyWorkspaceFixture(fixtureDir);
// Compute uid for the Alpha environment file at its actual path
const alphaFilePath = path.join(workspacePath, 'environments', 'Alpha.yml');
const alphaUid = generateUidBasedOnHash(alphaFilePath);
// Inject activeEnvironmentUid into workspace.yml (simulating pre-migration state)
const workspaceYmlPath = path.join(workspacePath, 'workspace.yml');
let workspaceYml = fs.readFileSync(workspaceYmlPath, 'utf8');
workspaceYml = workspaceYml.replace(
'collections:',
`activeEnvironmentUid: "${alphaUid}"\n\ncollections:`
);
fs.writeFileSync(workspaceYmlPath, workspaceYml);
// Launch with init-user-data pointing to the workspace
const app1 = await launchElectronApp({
initUserDataPath,
userDataPath,
templateVars: { workspacePath }
});
const page1 = await app1.firstWindow();
await page1.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
// Open the collection so the env selector toolbar is visible
await openCollection(page1, 'Test Collection');
// Verify "Alpha" environment is selected (migrated from workspace.yml)
await expect(page1.locator('.current-environment')).toContainText('Alpha');
// Verify workspace.yml no longer contains activeEnvironmentUid
const updatedYml = fs.readFileSync(workspaceYmlPath, 'utf8');
expect(updatedYml).not.toContain('activeEnvironmentUid');
await closeElectronApp(app1);
// Restart — should still have Alpha selected (now from electron store)
const app2 = await launchElectronApp({ userDataPath });
const page2 = await app2.firstWindow();
await page2.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await openCollection(page2, 'Test Collection');
await expect(page2.locator('.current-environment')).toContainText('Alpha');
await closeElectronApp(app2);
});
});

View File

@@ -0,0 +1,11 @@
{
"preferences": {
"onboarding": {
"hasLaunchedBefore": true,
"hasSeenWelcomeModal": true
},
"general": {
"defaultWorkspacePath": "{{workspacePath}}"
}
}
}

View File

@@ -0,0 +1,114 @@
import path from 'path';
import { test, expect, closeElectronApp } from '../../../playwright';
import {
createWorkspace,
switchWorkspace,
createCollection,
createEnvironment,
openCollection
} from '../../utils/page';
const initUserDataPath = path.join(__dirname, 'init-user-data');
test.describe('Global Environment Per-Workspace Persistence', () => {
test('should persist selected global environment across app restart', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('global-env-persist');
const wsLocation = await createTmpDir('ws-location');
const collectionDir = await createTmpDir('collection-persist');
// First launch
const app1 = await launchElectronApp({
initUserDataPath,
userDataPath,
templateVars: { wsLocation }
});
const page1 = await app1.firstWindow();
await page1.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
// Create a collection so the environment selector is visible
await createCollection(page1, 'Test Collection', collectionDir);
// Create a global environment (createEnvironment also selects it)
await createEnvironment(page1, 'Persist Test Env', 'global');
await expect(page1.locator('.current-environment')).toContainText('Persist Test Env');
await closeElectronApp(app1);
// Second launch - same userDataPath to preserve electron store
const app2 = await launchElectronApp({ userDataPath });
const page2 = await app2.firstWindow();
await page2.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
// Open the collection so the env selector is visible
await openCollection(page2, 'Test Collection');
// Verify the global environment is still selected after restart
await expect(page2.locator('.current-environment')).toContainText('Persist Test Env');
await closeElectronApp(app2);
});
test('should maintain independent global env selections per workspace', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('global-env-per-ws');
const wsLocation = await createTmpDir('ws-location-multi');
const collectionDir1 = await createTmpDir('collection-ws1');
const collectionDir2 = await createTmpDir('collection-ws2');
const app = await launchElectronApp({
initUserDataPath,
userDataPath,
templateVars: { wsLocation }
});
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
// On the default workspace, create a collection and a global env
await createCollection(page, 'WS1 Collection', collectionDir1);
await createEnvironment(page, 'Env Alpha', 'global');
await expect(page.locator('.current-environment')).toContainText('Env Alpha');
// Create a second workspace
await createWorkspace(page, 'Second Workspace');
// On the second workspace, create a collection and a different global env
await createCollection(page, 'WS2 Collection', collectionDir2);
await createEnvironment(page, 'Env Beta', 'global');
await expect(page.locator('.current-environment')).toContainText('Env Beta');
// Switch back to first workspace - "Env Alpha" should still be selected
await switchWorkspace(page, 'My Workspace');
await openCollection(page, 'WS1 Collection');
await expect(page.locator('.current-environment')).toContainText('Env Alpha');
// Switch to second workspace - "Env Beta" should still be selected
await switchWorkspace(page, 'Second Workspace');
await openCollection(page, 'WS2 Collection');
await expect(page.locator('.current-environment')).toContainText('Env Beta');
await closeElectronApp(app);
// Restart app and verify persistence across restart
const app2 = await launchElectronApp({ userDataPath });
const page2 = await app2.firstWindow();
await page2.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
// App opens to last active workspace - verify its env is still selected
const currentWorkspace = await page2.getByTestId('workspace-name').textContent();
if (currentWorkspace === 'Second Workspace') {
await openCollection(page2, 'WS2 Collection');
await expect(page2.locator('.current-environment')).toContainText('Env Beta');
await switchWorkspace(page2, 'My Workspace');
await openCollection(page2, 'WS1 Collection');
await expect(page2.locator('.current-environment')).toContainText('Env Alpha');
} else {
await openCollection(page2, 'WS1 Collection');
await expect(page2.locator('.current-environment')).toContainText('Env Alpha');
await switchWorkspace(page2, 'Second Workspace');
await openCollection(page2, 'WS2 Collection');
await expect(page2.locator('.current-environment')).toContainText('Env Beta');
}
await closeElectronApp(app2);
});
});

View File

@@ -0,0 +1,11 @@
{
"preferences": {
"onboarding": {
"hasLaunchedBefore": true,
"hasSeenWelcomeModal": true
},
"general": {
"defaultLocation": "{{wsLocation}}"
}
}
}

View File

@@ -1047,6 +1047,41 @@ const closeAllTabs = async (page: Page) => {
});
};
/**
* Create a new workspace via the title bar dropdown inline rename flow
* @param page - The page object
* @param workspaceName - The name of the workspace to create
* @returns void
*/
const createWorkspace = async (page: Page, workspaceName: string) => {
await test.step(`Create workspace "${workspaceName}"`, async () => {
await page.locator('.workspace-name-container').click();
await page.locator('.dropdown-item').filter({ hasText: 'Create workspace' }).click();
const renameInput = page.locator('.workspace-name-input');
await expect(renameInput).toBeVisible({ timeout: 5000 });
await renameInput.fill(workspaceName);
await renameInput.press('Enter');
await expect(page.getByText('Workspace created!')).toBeVisible({ timeout: 10000 });
await expect(page.getByTestId('workspace-name')).toHaveText(workspaceName, { timeout: 5000 });
});
};
/**
* Switch to an existing workspace via the title bar dropdown
* @param page - The page object
* @param workspaceName - The name of the workspace to switch to
* @returns void
*/
const switchWorkspace = async (page: Page, workspaceName: string) => {
await test.step(`Switch to workspace "${workspaceName}"`, async () => {
await page.locator('.workspace-name-container').click();
await page.locator('.workspace-item, .dropdown-item').filter({ hasText: workspaceName }).click();
await expect(page.getByTestId('workspace-name')).toHaveText(workspaceName, { timeout: 5000 });
});
};
export {
closeAllCollections,
openCollection,
@@ -1082,7 +1117,9 @@ export {
editAssertion,
deleteAssertion,
saveRequest,
closeAllTabs
closeAllTabs,
createWorkspace,
switchWorkspace
};
export type { SandboxMode, EnvironmentType, EnvironmentVariable, ImportCollectionOptions, CreateRequestOptions, CreateUntitledRequestOptions, CreateTransientRequestOptions, AssertionInput };