feat: import modal revamp (#8121)

This commit is contained in:
prateek-bruno
2026-05-28 15:58:22 +05:30
committed by GitHub
parent 4ee9a75465
commit b43a5e6e0a
19 changed files with 822 additions and 233 deletions

View File

@@ -32,7 +32,9 @@ test.describe('Multiple Files Upload', () => {
await expect(bulkImportModal.locator('.bruno-modal-header-title')).toContainText('Bulk Import');
// Check that the Collections count shows 2 collections in the Bulk Import modal
await expect(bulkImportModal.getByText('Collections (2)')).toBeVisible();
const collectionsHeading = bulkImportModal.getByTestId('selection-heading').filter({ hasText: 'Collections' });
await expect(collectionsHeading).toBeVisible();
await expect(collectionsHeading.getByTestId('selection-count')).toHaveText('2');
// Verify collection names are displayed
await expect(bulkImportModal.getByText('Sample Postman Collection')).toBeVisible();

View File

@@ -34,7 +34,9 @@ test.describe('All Collection Types Bulk Import', () => {
await expect(bulkImportModal.locator('.bruno-modal-header-title')).toContainText('Bulk Import');
// Check that the Collections count shows 4 collections in the Bulk Import modal
await expect(bulkImportModal.getByText('Collections (4)')).toBeVisible();
const collectionsHeading = bulkImportModal.getByTestId('selection-heading').filter({ hasText: 'Collections' });
await expect(collectionsHeading).toBeVisible();
await expect(collectionsHeading.getByTestId('selection-count')).toHaveText('4');
await expect(bulkImportModal.getByText('Sample Postman Collection')).toBeVisible();
await expect(bulkImportModal.getByText('Sample Insomnia Collection')).toBeVisible();
await expect(bulkImportModal.getByText('Sample Bruno Collection')).toBeVisible();

View File

@@ -16,14 +16,13 @@ const getFullyVisibleRowNames = async (list: Locator) => {
const rect = item.getBoundingClientRect();
return rect.top >= listRect.top && rect.bottom <= listRect.bottom;
})
.map((item) => item.textContent?.trim())
.map((item) => item.querySelector('.selection-item-title')?.textContent?.trim())
.filter(Boolean);
});
};
test.describe('Bulk Import Selection List', () => {
const testDataDir = path.join(__dirname, '../test-data');
const expectedVisibleRows = 5;
test.afterEach(async ({ page }) => {
await closeAllCollections(page);
@@ -61,16 +60,18 @@ test.describe('Bulk Import Selection List', () => {
const bulkImportModal = page.getByRole('dialog');
await expect(bulkImportModal.locator('.bruno-modal-header-title')).toContainText('Bulk Import');
await expect(bulkImportModal.getByText('Collections (10)')).toBeVisible();
const collectionsHeading = bulkImportModal.getByTestId('selection-heading').filter({ hasText: 'Collections' });
await expect(collectionsHeading).toBeVisible();
await expect(collectionsHeading.getByTestId('selection-count')).toHaveText('10');
const collectionList = bulkImportModal.locator('.selection-list').first();
const collectionList = collectionsHeading.locator('..').getByTestId('selection-list');
await expect(collectionList).toBeVisible();
const initialVisibleRows = await getFullyVisibleRowNames(collectionList);
expect(initialVisibleRows).toHaveLength(expectedVisibleRows);
expect(initialVisibleRows.length).toBeGreaterThan(0);
expect(initialVisibleRows.length).toBeLessThan(10);
expect(initialVisibleRows[0]).toBe(getViewportCollectionName(1));
expect(initialVisibleRows[expectedVisibleRows - 1]).toBe(getViewportCollectionName(expectedVisibleRows));
expect(initialVisibleRows).not.toContain(getViewportCollectionName(expectedVisibleRows + 1));
expect(initialVisibleRows).not.toContain(getViewportCollectionName(10));
await collectionList.evaluate((list) => {
list.scrollTop = list.scrollHeight;
@@ -78,7 +79,7 @@ test.describe('Bulk Import Selection List', () => {
await expect(async () => {
const scrolledVisibleRows = await getFullyVisibleRowNames(collectionList);
expect(scrolledVisibleRows).toHaveLength(expectedVisibleRows);
expect(scrolledVisibleRows.length).toBeGreaterThan(0);
expect(scrolledVisibleRows).toContain(getViewportCollectionName(9));
expect(scrolledVisibleRows).toContain(getViewportCollectionName(10));
}).toPass({ timeout: 5000 });

View File

@@ -0,0 +1,137 @@
import { test, expect } from '../../../playwright';
import * as path from 'path';
import * as fs from 'fs/promises';
import { closeAllCollections } from '../../utils/page';
const getCollectionName = (index: number) => `Select All Collection ${String(index).padStart(2, '0')}`;
test.describe('Bulk Import - Select all', () => {
const testDataDir = path.join(__dirname, '../test-data');
test.afterEach(async ({ page }) => {
await closeAllCollections(page);
});
test('Select all toggles every collection on, then off, and reflects indeterminate state', async ({
page,
createTmpDir
}) => {
const sourceFile = path.join(testDataDir, 'sample-postman.json');
const tempDir = await createTmpDir('bulk-import-select-all');
const sourceContent = JSON.parse(await fs.readFile(sourceFile, 'utf-8'));
const importFiles: string[] = [];
const totalCollections = 6;
for (let index = 1; index <= totalCollections; index++) {
const filePath = path.join(tempDir, `sample-postman-${index}.json`);
const fileContent = {
...sourceContent,
info: {
...sourceContent.info,
name: getCollectionName(index)
}
};
await fs.writeFile(filePath, JSON.stringify(fileContent, null, 2), 'utf-8');
importFiles.push(filePath);
}
await page.getByTestId('collections-header-add-menu').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
const importModal = page.getByRole('dialog');
await importModal.waitFor({ state: 'visible' });
await expect(importModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
await page.setInputFiles('input[type="file"]', importFiles);
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
const bulkImportModal = page.getByRole('dialog');
await expect(bulkImportModal.locator('.bruno-modal-header-title')).toContainText('Bulk Import');
const collectionsSection = bulkImportModal.getByTestId('selection-section-collections');
await expect(collectionsSection.getByTestId('selection-count')).toHaveText(String(totalCollections));
const collectionList = collectionsSection.getByTestId('selection-list');
const itemCheckboxes = collectionList.locator('.selection-item input[type="checkbox"]');
const selectAllToggle = collectionsSection.getByTestId('selection-select-all-toggle');
const selectAllCheckbox = selectAllToggle.locator('input[type="checkbox"]');
await expect(itemCheckboxes).toHaveCount(totalCollections);
await test.step('Bulk import opens with every collection pre-selected', async () => {
await expect(selectAllCheckbox).toBeChecked();
for (let i = 0; i < totalCollections; i++) {
await expect(itemCheckboxes.nth(i)).toBeChecked();
}
});
await test.step('Clicking Select all unchecks every collection', async () => {
await selectAllToggle.click();
await expect(selectAllCheckbox).not.toBeChecked();
for (let i = 0; i < totalCollections; i++) {
await expect(itemCheckboxes.nth(i)).not.toBeChecked();
}
});
await test.step('Clicking Select all again rechecks every collection', async () => {
await selectAllToggle.click();
await expect(selectAllCheckbox).toBeChecked();
for (let i = 0; i < totalCollections; i++) {
await expect(itemCheckboxes.nth(i)).toBeChecked();
}
});
await test.step('Unchecking a single collection puts Select all into the indeterminate state', async () => {
await collectionList.locator('.selection-item').first().click();
const checkedCount = await itemCheckboxes.evaluateAll(
(nodes) => nodes.filter((node) => (node as HTMLInputElement).checked).length
);
expect(checkedCount).toBe(totalCollections - 1);
const isIndeterminate = await selectAllCheckbox.evaluate(
(node) => (node as HTMLInputElement).indeterminate
);
expect(isIndeterminate).toBe(true);
});
await test.step('Clicking Select all from indeterminate selects every collection', async () => {
await selectAllToggle.click();
await expect(selectAllCheckbox).toBeChecked();
const isIndeterminate = await selectAllCheckbox.evaluate(
(node) => (node as HTMLInputElement).indeterminate
);
expect(isIndeterminate).toBe(false);
for (let i = 0; i < totalCollections; i++) {
await expect(itemCheckboxes.nth(i)).toBeChecked();
}
});
await test.step('Search narrows Select all to the filtered subset only', async () => {
await selectAllToggle.click();
await expect(selectAllCheckbox).not.toBeChecked();
const searchInput = collectionsSection.getByTestId('selection-search-input');
await searchInput.fill('01');
const visibleCount = await itemCheckboxes.count();
expect(visibleCount).toBeGreaterThan(0);
expect(visibleCount).toBeLessThan(totalCollections);
await selectAllToggle.click();
await expect(selectAllCheckbox).toBeChecked();
for (let i = 0; i < visibleCount; i++) {
await expect(itemCheckboxes.nth(i)).toBeChecked();
}
await searchInput.fill('');
await expect(itemCheckboxes).toHaveCount(totalCollections);
const isIndeterminate = await selectAllCheckbox.evaluate(
(node) => (node as HTMLInputElement).indeterminate
);
expect(isIndeterminate).toBe(true);
});
await page.getByTestId('modal-close-button').click();
await expect(page.locator('.bruno-modal-backdrop')).toHaveCount(0);
});
});