Files
bruno/tests/import/postman/import-partial-collection.spec.ts
sanish chirayath 244f528277 feat(import): enhance import functionality with issue tracking and logging (#8098)
* feat: enhance import functionality with issue tracking and logging

- Updated the import process to return both collections and issues for better error handling.
- Introduced a new toast notification for displaying import issues, allowing users to copy or report them.
- Enhanced logging for import issues, capturing errors and warnings during the import process.
- Added new components for actionable toasts and import issues display.
- Updated tests to validate the new import behavior and issue tracking.

* feat: enhance import issues handling with new toast notifications and tests

- Added optional testId prop to ActionableToast for better test targeting.
- Updated ImportIssuesToast to include data-testid attributes for improved e2e testing.
- Introduced a new Postman collection fixture to test partial import scenarios.
- Created new tests to validate the import process, including issue reporting and copying functionality.
- Implemented utility functions to manage import issues toasts during tests.

* fix: improve clipboard copy functionality and handle import issues more robustly

- Updated BulkImportCollectionLocation to always set import issues, ensuring consistent state management.
- Enhanced clipboard copy functionality in ImportIssuesToast and BulkImportCollectionLocation to handle errors gracefully with user feedback.
- Added aria-label for better accessibility in ActionableToast close button.

* refactor: enhance import issue logging and toast notifications

- Improved logging in BulkImportCollectionLocation and ImportCollectionLocation to provide detailed summaries of import issues, including counts of skipped items and warnings.
- Updated ImportIssuesToast to handle long issue descriptions and provide user feedback for copying issue details to the clipboard.
- Removed ActionableToast component and its styles, consolidating toast functionality within ImportIssuesToast for better maintainability.
- Enhanced styling for ImportIssuesToast to improve user experience and accessibility.

* refactor: update logging level for import issues in BulkImportCollectionLocation and ImportCollectionLocation

- Changed log type from 'error' to 'warn' for import issue summaries in both components to better reflect the severity of the messages.
- This adjustment improves clarity in the logging system and aligns with the intended handling of import warnings.

* feat: enhance ImportIssuesToast with URL length warning and styling improvements

- Added an alert icon and improved styling for the URL-too-long warning in ImportIssuesToast to enhance user experience.
- Introduced a new test for verifying the display of the URL length warning when importing collections with many issues.
- Updated locators to include a test ID for the URL-too-long warning, facilitating better end-to-end testing.

* style: update ImportIssuesToast styling for improved user experience

- Changed background and border colors in StyledWrapper for better visual consistency.
- Enhanced box-shadow and close button styles for improved accessibility and interaction.
- Adjusted padding and gap in warning messages for better layout and readability.
2026-05-28 19:41:03 +05:30

119 lines
5.2 KiB
TypeScript

import { test, expect } from '../../../playwright';
import * as path from 'path';
import { closeAllCollections, dismissImportIssuesToasts, importCollection } from '../../utils/page';
import { buildCommonLocators } from '../../utils/page/locators';
test.describe('Import Postman Collection with partial import issues', () => {
test.afterEach(async ({ page }) => {
await dismissImportIssuesToasts(page);
await closeAllCollections(page);
});
test('should import valid requests and show issues toast for skipped items', async ({ page, createTmpDir }) => {
const postmanFile = path.resolve(__dirname, 'fixtures', 'postman-with-import-issues.json');
const tmpDir = await createTmpDir('postman-partial-import');
const locators = buildCommonLocators(page);
await importCollection(page, postmanFile, tmpDir, {
expectedCollectionName: 'Import Issues Test Collection',
expectIssues: true
});
await test.step('Verify import issues toast content', async () => {
const toastTitle = locators.import.issuesToastTitle();
await expect(toastTitle).toBeVisible();
await expect(toastTitle).toContainText('item(s) skipped');
});
await test.step('Verify toast action buttons are visible', async () => {
await expect(locators.import.issuesToastCopyBtn()).toBeVisible();
await expect(locators.import.issuesToastReportBtn()).toBeVisible();
});
await test.step('Verify include items checkbox is visible', async () => {
await expect(locators.import.issuesToastIncludeItemsCheckbox()).toBeVisible();
});
await test.step('Verify valid top-level requests were imported', async () => {
await expect(locators.sidebar.request('Valid GET Request')).toBeVisible();
await expect(locators.sidebar.request('Valid POST Request')).toBeVisible();
await expect(locators.sidebar.request('Valid PUT Request')).toBeVisible();
await expect(locators.sidebar.request('Valid PATCH Request')).toBeVisible();
});
await test.step('Verify skipped requests are NOT in the sidebar', async () => {
await expect(locators.sidebar.request('Missing Method (null)')).not.toBeVisible();
await expect(locators.sidebar.request('Missing Method (absent)')).not.toBeVisible();
await expect(locators.sidebar.request('Empty String Method')).not.toBeVisible();
await expect(locators.sidebar.request('Whitespace-Only Method')).not.toBeVisible();
});
await test.step('Verify folder and nested valid requests were imported', async () => {
const folder = locators.sidebar.folder('API Folder');
await expect(folder).toBeVisible();
await folder.click();
await expect(locators.sidebar.request('Valid Nested GET')).toBeVisible();
const subfolder = locators.sidebar.folder('Deep Subfolder');
await expect(subfolder).toBeVisible();
await subfolder.click();
await expect(locators.sidebar.request('Deep Valid Request')).toBeVisible();
});
await test.step('Verify nested skipped requests are NOT in the sidebar', async () => {
await expect(locators.sidebar.request('Nested Missing Method')).not.toBeVisible();
await expect(locators.sidebar.request('Deep Bad Method')).not.toBeVisible();
});
});
test('should allow copying import issues to clipboard', async ({ page, createTmpDir }) => {
const postmanFile = path.resolve(__dirname, 'fixtures', 'postman-with-import-issues.json');
const tmpDir = await createTmpDir('postman-partial-import-copy');
const locators = buildCommonLocators(page);
await importCollection(page, postmanFile, tmpDir, {
expectedCollectionName: 'Import Issues Test Collection',
expectIssues: true
});
await test.step('Click copy button and verify success toast', async () => {
await locators.import.issuesToastCopyBtn().click();
await expect(page.getByText('Copied to clipboard')).toBeVisible({ timeout: 3000 });
});
});
test('should open GitHub issue with prefilled details when clicking Report on GitHub', async ({ page, createTmpDir }) => {
const postmanFile = path.resolve(__dirname, 'fixtures', 'postman-with-import-issues.json');
const tmpDir = await createTmpDir('postman-partial-import-report');
const locators = buildCommonLocators(page);
await importCollection(page, postmanFile, tmpDir, {
expectedCollectionName: 'Import Issues Test Collection',
expectIssues: true
});
await test.step('Mock window.open and click Report on GitHub', async () => {
// Mock window.open to capture the URL instead of opening a browser
await page.evaluate(() => {
(window as any).__capturedOpenUrl = null;
window.open = (url?: string | URL) => {
(window as any).__capturedOpenUrl = url != null ? String(url) : '';
return null;
};
});
await locators.import.issuesToastReportBtn().click();
const openedUrl = await page.evaluate(() => (window as any).__capturedOpenUrl as string);
expect(openedUrl).toContain('https://github.com/usebruno/bruno/issues/new');
expect(openedUrl).toContain('title=');
expect(openedUrl).toContain('Postman+import');
expect(openedUrl).toContain('labels=bug');
expect(openedUrl).toContain('Missing+or+invalid+request+method');
});
});
});