Files
bruno/tests/utils/page/workspace/import-workspace.ts
mohit-bruno 33e8f5ca4a test: workspace import and validation testcase (TC-969) (#8349)
* test cases for workspace import and validation TC-969, jira: https://usebruno.atlassian.net/browse/BRU-3575

* incorporated comments, moved findWorkspaceDirByName function to helpers.ts, fixed all the comments

* modified as per comment provided , removed css locators , used playwright inbuilt methods , handled timeout

* Created file structure as per comment provided, added tc-id , resolved code-rabbit review

* incorporated comments removed commented line, removed timeouts, modified package.json added package in dev dependencies

* changed const l to locators for better readbility

* - Reorganized test helpers: split title-bar locators into title-bar.ts and
  import-workspace flow into workspace/import-workspace.ts for reuse
- Replaced brittle .bruno-modal-card/CSS locators with stable role/testid/label
  based locators
- Added a data-testid for the Import Workspace modal and removed the redundant one
- Cleaned up unnecessary comments
- Updated package-lock.json

* minor changes

* minor changes

* addressed comments

* addressed comments for variable naming

* minor changes
2026-06-26 16:57:02 +05:30

111 lines
3.8 KiB
TypeScript

import AdmZip from 'adm-zip';
import * as path from 'path';
import { clickImportWorkspace } from '../title-bar';
import { test, expect, Page, Locator, ElectronApplication, waitForReadyPage } from '../../../../playwright';
/**
* Import Workspace modal locators.
*/
export const buildImportWorkspaceModalLocators = (page: Page) => {
// Scope every modal query to the dialog so we avoid the brittle
const modal = () => page.getByRole('dialog').filter({ hasText: 'Import Workspace' });
return {
// Import Workspace modal
modal,
fileInput: () => modal().getByTestId('import-workspace-file-input'),
selectedFileName: (name: string) => modal().getByText(name),
removeFileButton: () => modal().getByText('Remove'),
locationInput: () => modal().getByLabel('Extract Location'),
browseLink: () => modal().getByText('Browse', { exact: true }),
importButton: () => modal().getByTestId('modal-submit-btn')
};
};
/**
* Build a valid Bruno workspace zip on disk that the importer will accept.
* The zip contains a single `workspace.yml` (info.name + info.type: workspace).
*
* @param zipDir - directory in which to write the zip
* @param workspaceName - the workspace name embedded in workspace.yml
* @returns absolute path to the created zip file
*/
export const createWorkspaceZip = (zipDir: string, workspaceName: string): string => {
const workspaceYml = [
'opencollection: 1.0.0',
'info:',
` name: "${workspaceName}"`,
' type: workspace',
'',
'collections: []',
'specs: []',
'docs: \'\'',
''
].join('\n');
const zip = new AdmZip();
zip.addFile('workspace.yml', Buffer.from(workspaceYml, 'utf8'));
const zipPath = path.join(zipDir, `${workspaceName}.zip`);
zip.writeZip(zipPath);
return zipPath;
};
/**
* Open the workspace dropdown and launch the Import Workspace modal.
*/
export const openImportWorkspaceModal = async (page: Page) => {
const locators = buildImportWorkspaceModalLocators(page);
await clickImportWorkspace(page);
await locators.modal().waitFor({ state: 'visible' });
};
type ImportWorkspaceOptions = {
zipPath: string;
/**
* Where to extract the workspace. When omitted, the modal's pre-filled
* default location (from preferences.general.defaultLocation) is used as-is.
*/
extractLocation?: string;
app?: ElectronApplication;
};
/**
* select the zip, ensure an extract location is set, and click Import.
*/
export const submitWorkspaceImport = async (page: Page, opts: ImportWorkspaceOptions) => {
const locators = buildImportWorkspaceModalLocators(page);
await test.step('Select the workspace zip file', async () => {
await locators.fileInput().setInputFiles(opts.zipPath);
await expect(locators.selectedFileName(path.basename(opts.zipPath))).toBeVisible();
});
await test.step('Ensure an extract location is set', async () => {
if (opts.extractLocation && opts.app) {
// Stub the directory picker so Browse resolves to the desired location.
await opts.app.evaluate(({ dialog }, target: string) => {
(dialog as { showOpenDialog: typeof dialog.showOpenDialog }).showOpenDialog = () =>
Promise.resolve({ canceled: false, filePaths: [target] });
}, opts.extractLocation);
await locators.locationInput().click();
await expect(locators.locationInput()).toHaveValue(opts.extractLocation);
} else {
// Rely on the pre-filled default location.
await expect(locators.locationInput()).not.toHaveValue('');
}
});
await test.step('Submit the import', async () => {
await locators.importButton().click();
});
};
/**
* open the modal and import a zip in one call.
*/
export const importWorkspaceFromZip = async (page: Page, opts: ImportWorkspaceOptions) => {
await openImportWorkspaceModal(page);
await submitWorkspaceImport(page, opts);
};