add: tests

This commit is contained in:
naman-bruno
2025-12-11 16:35:52 +05:30
committed by Bijin A B
parent f3fd8a1ce0
commit 9053c47789
3 changed files with 435 additions and 14 deletions

View File

@@ -78,11 +78,10 @@ class DefaultWorkspaceManager {
};
}
// Need to create/recreate default workspace
this.initializationPromise = (async () => {
try {
const shouldMigrate = this.needsMigration();
const newWorkspacePath = await this.initializeDefaultWorkspace(existingPath, { migrateFromPreferences: shouldMigrate });
const newWorkspacePath = await this.initializeDefaultWorkspace({ migrateFromPreferences: shouldMigrate });
return {
workspacePath: newWorkspacePath,
@@ -99,21 +98,17 @@ class DefaultWorkspaceManager {
return this.initializationPromise;
}
async initializeDefaultWorkspace(existingPath = null, options = {}) {
async initializeDefaultWorkspace(options = {}) {
const { migrateFromPreferences = true } = options;
let workspacePath = existingPath;
const configDir = app.getPath('userData');
const baseWorkspacePath = path.join(configDir, 'default-workspace');
if (!workspacePath || !fs.existsSync(workspacePath)) {
const configDir = app.getPath('userData');
const baseWorkspacePath = path.join(configDir, 'default-workspace');
workspacePath = baseWorkspacePath;
let counter = 1;
while (fs.existsSync(workspacePath)) {
workspacePath = `${baseWorkspacePath}-${counter}`;
counter++;
}
let workspacePath = baseWorkspacePath;
let counter = 1;
while (fs.existsSync(workspacePath)) {
workspacePath = `${baseWorkspacePath}-${counter}`;
counter++;
}
fs.mkdirSync(workspacePath, { recursive: true });

View File

@@ -0,0 +1,222 @@
import path from 'path';
import fs from 'fs';
import { test, expect } from '../../../playwright';
test.describe('Default Workspace', () => {
test.describe('First Launch', () => {
test('should create default workspace with "My Workspace" name on first launch', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-first-launch');
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
// Verify the workspace name is "My Workspace" in the title bar
const workspaceName = page.locator('.workspace-name');
await expect(workspaceName).toContainText('My Workspace');
await app.close();
});
});
test.describe('Persistence', () => {
test('should persist default workspace across app restarts', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-persistence');
// First launch
const app1 = await launchElectronApp({ userDataPath });
const page1 = await app1.firstWindow();
await page1.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await expect(page1.locator('.workspace-name')).toContainText('My Workspace');
await app1.close();
// Second launch - same workspace should be loaded
const app2 = await launchElectronApp({ userDataPath });
const page2 = await app2.firstWindow();
await page2.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await expect(page2.locator('.workspace-name')).toContainText('My Workspace');
await app2.close();
});
});
test.describe('Recovery - Creates NEW workspace (never modifies existing)', () => {
test('should create NEW workspace when existing workspace.yml is deleted', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-recovery-deleted');
// Create a corrupted default workspace BEFORE launching app
const defaultWorkspacePath = path.join(userDataPath, 'default-workspace');
fs.mkdirSync(defaultWorkspacePath, { recursive: true });
fs.mkdirSync(path.join(defaultWorkspacePath, 'collections'), { recursive: true });
// Note: NOT creating workspace.yml - simulating deleted file
// Create preferences pointing to the corrupted workspace
fs.writeFileSync(
path.join(userDataPath, 'preferences.json'),
JSON.stringify({
general: {
defaultWorkspacePath: defaultWorkspacePath
}
})
);
// Launch app - should create NEW workspace
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
// Should show "My Workspace"
await expect(page.locator('.workspace-name')).toContainText('My Workspace');
// Old directory should still exist (never deleted)
expect(fs.existsSync(defaultWorkspacePath)).toBe(true);
// New workspace directory should have been created (default-workspace-1 since default-workspace exists)
const newWorkspacePath = path.join(userDataPath, 'default-workspace-1');
expect(fs.existsSync(newWorkspacePath)).toBe(true);
expect(fs.existsSync(path.join(newWorkspacePath, 'workspace.yml'))).toBe(true);
await app.close();
});
test('should create NEW workspace when workspace.yml has invalid YAML', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-recovery-invalid');
// Create workspace with invalid YAML BEFORE launching app
const defaultWorkspacePath = path.join(userDataPath, 'default-workspace');
fs.mkdirSync(defaultWorkspacePath, { recursive: true });
fs.writeFileSync(path.join(defaultWorkspacePath, 'workspace.yml'), 'invalid: yaml: [[[');
// Create preferences pointing to the corrupted workspace
fs.writeFileSync(
path.join(userDataPath, 'preferences.json'),
JSON.stringify({
general: {
defaultWorkspacePath: defaultWorkspacePath
}
})
);
// Launch app - should create NEW workspace
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await expect(page.locator('.workspace-name')).toContainText('My Workspace');
// Old corrupted file should still exist (never deleted)
const oldContent = fs.readFileSync(path.join(defaultWorkspacePath, 'workspace.yml'), 'utf8');
expect(oldContent).toContain('invalid: yaml: [[[');
// New workspace should have been created
const newWorkspacePath = path.join(userDataPath, 'default-workspace-1');
expect(fs.existsSync(newWorkspacePath)).toBe(true);
await app.close();
});
test('should create NEW workspace when workspace.yml has wrong type', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-recovery-wrong-type');
// Create workspace with wrong type BEFORE launching app
const defaultWorkspacePath = path.join(userDataPath, 'default-workspace');
fs.mkdirSync(defaultWorkspacePath, { recursive: true });
fs.writeFileSync(path.join(defaultWorkspacePath, 'workspace.yml'), `opencollection: 1.0.0
info:
name: My Workspace
type: collection
collections:
specs:
docs: ''
`);
// Create preferences pointing to the invalid workspace
fs.writeFileSync(
path.join(userDataPath, 'preferences.json'),
JSON.stringify({
general: {
defaultWorkspacePath: defaultWorkspacePath
}
})
);
// Launch app
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await expect(page.locator('.workspace-name')).toContainText('My Workspace');
// New workspace should have been created
const newWorkspacePath = path.join(userDataPath, 'default-workspace-1');
expect(fs.existsSync(newWorkspacePath)).toBe(true);
await app.close();
});
test('should create NEW workspace when directory does not exist', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-recovery-dir-missing');
// Create preferences pointing to non-existent directory
const nonExistentPath = path.join(userDataPath, 'non-existent-workspace');
fs.writeFileSync(
path.join(userDataPath, 'preferences.json'),
JSON.stringify({
general: {
defaultWorkspacePath: nonExistentPath
}
})
);
// Launch app
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await expect(page.locator('.workspace-name')).toContainText('My Workspace');
// New workspace should have been created (default-workspace since non-existent doesn't block)
const newWorkspacePath = path.join(userDataPath, 'default-workspace');
expect(fs.existsSync(newWorkspacePath)).toBe(true);
expect(fs.existsSync(path.join(newWorkspacePath, 'workspace.yml'))).toBe(true);
await app.close();
});
});
test.describe('UI Behavior', () => {
test('should display default workspace in workspace dropdown', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-ui-dropdown');
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
// Click on workspace name to open dropdown
await page.locator('.workspace-name-container').click();
// Verify default workspace is shown
const workspaceItem = page.locator('.workspace-item, .dropdown-item').filter({ hasText: 'My Workspace' });
await expect(workspaceItem.first()).toBeVisible();
await app.close();
});
test('should not show pin button for default workspace', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-ui-no-pin');
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await page.locator('.workspace-name-container').click();
const workspaceItem = page.locator('.workspace-item').filter({ hasText: 'My Workspace' });
// Default workspace should NOT have pin button
await expect(workspaceItem.locator('.pin-btn')).not.toBeVisible();
await app.close();
});
});
});

View File

@@ -0,0 +1,204 @@
import path from 'path';
import fs from 'fs';
import { test, expect } from '../../../playwright';
const env = {
DISABLE_SAMPLE_COLLECTION_IMPORT: 'false'
};
test.describe('Default Workspace Migration', () => {
test.describe('Migration from lastOpenedCollections', () => {
test('should migrate collections from lastOpenedCollections to new workspace', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-migration');
// Create a test collection that would have been opened before
const testCollectionPath = path.join(userDataPath, 'my-old-collection');
fs.mkdirSync(testCollectionPath, { recursive: true });
fs.writeFileSync(
path.join(testCollectionPath, 'bruno.json'),
JSON.stringify({
version: '1',
name: 'My Old Collection',
type: 'collection'
})
);
fs.writeFileSync(
path.join(userDataPath, 'preferences.json'),
JSON.stringify({
lastOpenedCollections: [testCollectionPath]
})
);
// Launch app - should migrate
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
// Verify default workspace is created with correct name
await expect(page.locator('.workspace-name')).toContainText('My Workspace');
// Verify workspace was created
const workspacePath = path.join(userDataPath, 'default-workspace');
expect(fs.existsSync(workspacePath)).toBe(true);
// Verify workspace.yml exists and contains the migrated collection
const workspaceYmlPath = path.join(workspacePath, 'workspace.yml');
if (fs.existsSync(workspaceYmlPath)) {
const workspaceYml = fs.readFileSync(workspaceYmlPath, 'utf8');
expect(workspaceYml).toContain('collections:');
// Collection should be referenced
expect(workspaceYml).toContain('my-old-collection');
}
await app.close();
});
test('should migrate multiple collections from lastOpenedCollections', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-migration-multiple');
// Create multiple test collections
const collection1Path = path.join(userDataPath, 'collection-1');
const collection2Path = path.join(userDataPath, 'collection-2');
for (const collPath of [collection1Path, collection2Path]) {
fs.mkdirSync(collPath, { recursive: true });
fs.writeFileSync(
path.join(collPath, 'bruno.json'),
JSON.stringify({
version: '1',
name: path.basename(collPath),
type: 'collection'
})
);
}
// Create old-style preferences
fs.writeFileSync(
path.join(userDataPath, 'preferences.json'),
JSON.stringify({
lastOpenedCollections: [collection1Path, collection2Path]
})
);
// Launch app
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await expect(page.locator('.workspace-name')).toContainText('My Workspace');
// Verify workspace.yml has both collections
const workspacePath = path.join(userDataPath, 'default-workspace');
const workspaceYmlPath = path.join(workspacePath, 'workspace.yml');
if (fs.existsSync(workspaceYmlPath)) {
const workspaceYml = fs.readFileSync(workspaceYmlPath, 'utf8');
expect(workspaceYml).toContain('collection-1');
expect(workspaceYml).toContain('collection-2');
}
await app.close();
});
});
test.describe('Migration does not affect existing users', () => {
test('should skip sample collection when user has existing collections', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-existing-user');
// Create a test collection (simulating existing user)
const oldCollectionPath = path.join(userDataPath, 'old-user-collection');
fs.mkdirSync(oldCollectionPath, { recursive: true });
fs.writeFileSync(
path.join(oldCollectionPath, 'bruno.json'),
JSON.stringify({
version: '1',
name: 'Old User Collection',
type: 'collection'
})
);
// Create old-style preferences with lastOpenedCollections
fs.writeFileSync(
path.join(userDataPath, 'preferences.json'),
JSON.stringify({
lastOpenedCollections: [oldCollectionPath]
})
);
// Launch app - sample collection should NOT be created (existing user)
const app = await launchElectronApp({ userDataPath, dotEnv: env });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
// Verify default workspace is created
await expect(page.locator('.workspace-name')).toContainText('My Workspace');
// Sample collection should NOT be created (because user has existing collections)
const sampleCollection = page.locator('#sidebar-collection-name').getByText('Sample API Collection');
await expect(sampleCollection).not.toBeVisible();
await app.close();
});
});
test.describe('No duplicate workspaces on restart', () => {
test('should reuse existing workspace on subsequent launches', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-reuse');
// First launch - creates workspace
const app1 = await launchElectronApp({ userDataPath });
const page1 = await app1.firstWindow();
await page1.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await expect(page1.locator('.workspace-name')).toContainText('My Workspace');
// Verify initial workspace was created
const workspacePath = path.join(userDataPath, 'default-workspace');
expect(fs.existsSync(workspacePath)).toBe(true);
const originalYmlContent = fs.readFileSync(path.join(workspacePath, 'workspace.yml'), 'utf8');
await app1.close();
// Second launch - should reuse existing workspace
const app2 = await launchElectronApp({ userDataPath });
const page2 = await app2.firstWindow();
await page2.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await expect(page2.locator('.workspace-name')).toContainText('My Workspace');
// workspace.yml should NOT have been modified
const currentYmlContent = fs.readFileSync(path.join(workspacePath, 'workspace.yml'), 'utf8');
expect(currentYmlContent).toBe(originalYmlContent);
// No new workspace should have been created
expect(fs.existsSync(path.join(userDataPath, 'default-workspace-1'))).toBe(false);
await app2.close();
});
});
test.describe('Clean installation', () => {
test('should create empty workspace on fresh install without old preferences', async ({ launchElectronApp, createTmpDir }) => {
const userDataPath = await createTmpDir('default-workspace-clean');
// Launch with completely empty user data (no preferences file)
const app = await launchElectronApp({ userDataPath });
const page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
await expect(page.locator('.workspace-name')).toContainText('My Workspace');
// Verify workspace was created
const workspacePath = path.join(userDataPath, 'default-workspace');
expect(fs.existsSync(workspacePath)).toBe(true);
// Verify workspace has empty collections section
const workspaceYmlPath = path.join(workspacePath, 'workspace.yml');
if (fs.existsSync(workspaceYmlPath)) {
const workspaceYml = fs.readFileSync(workspaceYmlPath, 'utf8');
// Collections should be empty (just the key)
expect(workspaceYml).toMatch(/collections:\s*\n/);
}
await app.close();
});
});
});