Files
bruno/tests/mounting/tree-construction.spec.ts
2026-06-08 20:57:33 +05:30

173 lines
6.2 KiB
TypeScript

import * as path from 'path';
import { test, expect, ElectronApplication, Page } from '../../playwright';
import { setupTestFixture, setupStaticFixture, TestFixture, StaticTestFixture } from '../utils/fixtures';
import { getCollectionTreeStructure, CollectionTreeItem, closeAllCollections } from '../utils/page';
const formats = ['bru', 'yml'] as const;
for (const format of formats) {
test.describe(`[${format}] Collection Tree Construction`, () => {
let fixture: TestFixture;
let app: ElectronApplication;
let page: Page;
test.beforeAll(async ({ launchElectronApp }) => {
fixture = await setupTestFixture({
name: 'Tree Test Collection',
requestCount: 10,
depth: 2,
foldersPerLevel: 2,
format,
environmentCount: 2,
mixedMethods: true
});
app = await launchElectronApp({ userDataPath: fixture.userDataPath });
page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
});
test.afterAll(async () => {
if (page) {
await closeAllCollections(page);
}
if (app) {
await app.context().close();
await app.close();
}
if (fixture) {
await fixture.cleanup();
}
});
test('should render folders with correct hierarchy', async () => {
const tree = await getCollectionTreeStructure(page, 'Tree Test Collection');
// Verify collection name
expect(tree.name).toBe('Tree Test Collection');
// With depth=2 and foldersPerLevel=2, we expect:
// - 2 top-level folders (F1, F2)
// - Each top-level folder has 2 nested folders (F1-F1, F1-F2, etc.)
const folders = tree.items.filter((item) => item.type === 'folder');
expect(folders.length).toBeGreaterThanOrEqual(2);
// Check that folders have the expected naming pattern (F1, F2)
const folderNames = folders.map((f) => f.name);
expect(folderNames.some((name) => /^F\d+$/.test(name))).toBe(true);
});
test('should render requests under correct parent folders', async () => {
const tree = await getCollectionTreeStructure(page, 'Tree Test Collection');
// Helper to count requests recursively
const countRequests = (items: CollectionTreeItem[]): number => {
return items.reduce((count, item) => {
if (item.type === 'request') {
return count + 1;
}
if (item.type === 'folder' && item.items) {
return count + countRequests(item.items);
}
return count;
}, 0);
};
// We generated 10 requests, they should all be present
const totalRequests = countRequests(tree.items);
expect(totalRequests).toBe(fixture.collection.requestCount);
// Verify requests exist at various levels (root and in folders)
const rootRequests = tree.items.filter((item) => item.type === 'request');
const folders = tree.items.filter((item) => item.type === 'folder');
// Requests should be distributed - some at root, some in folders
const hasRequestsInFolders = folders.some(
(folder) => folder.items && folder.items.some((item) => item.type === 'request')
);
// Either we have root requests or requests in folders (distribution depends on generator)
expect(rootRequests.length > 0 || hasRequestsInFolders).toBe(true);
});
test('should have correct parent-child relationships via naming convention', async () => {
const tree = await getCollectionTreeStructure(page, 'Tree Test Collection');
// Verify items are named with their parent prefix:
// - Root requests: R1, R2, ...
// - Folder F1 requests: F1-R1, F1-R2, ...
// - Nested folder F1-F1 requests: F1-F1-R1, ...
const verifyNaming = (items: CollectionTreeItem[], parentPrefix: string) => {
for (const item of items) {
if (item.type === 'request') {
// Request should start with parent prefix (or be R1, R2 at root)
if (parentPrefix) {
expect(item.name.startsWith(parentPrefix + '-R')).toBe(true);
} else {
expect(item.name).toMatch(/^R\d+$/);
}
}
if (item.type === 'folder') {
// Folder should start with parent prefix (or be F1, F2 at root)
if (parentPrefix) {
expect(item.name.startsWith(parentPrefix + '-F')).toBe(true);
} else {
expect(item.name).toMatch(/^F\d+$/);
}
// Recursively verify children
if (item.items) {
verifyNaming(item.items, item.name);
}
}
}
};
verifyNaming(tree.items, '');
});
});
}
// Method indicators are verified against a static, hand-authored collection with
// exactly one request per HTTP method, so the expected badge set is fixed rather
// than dependent on the generator's method-cycling behaviour.
for (const format of formats) {
test.describe(`[${format}] Request Method Indicators`, () => {
let fixture: StaticTestFixture;
let app: ElectronApplication;
let page: Page;
test.beforeAll(async ({ launchElectronApp }) => {
fixture = await setupStaticFixture(
path.join(__dirname, 'fixtures', 'method-indicators', format)
);
app = await launchElectronApp({ userDataPath: fixture.userDataPath });
page = await app.firstWindow();
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
});
test.afterAll(async () => {
if (page) {
await closeAllCollections(page);
}
if (app) {
await app.context().close();
await app.close();
}
if (fixture) {
await fixture.cleanup();
}
});
test('should display correct request method indicators', async () => {
const tree = await getCollectionTreeStructure(page, 'Method Indicators');
const requests = tree.items.filter((item) => item.type === 'request');
const methods = requests.map((r) => r.method).filter(Boolean);
// One request per method. UI truncates methods > 5 chars to 3 chars (DELETE -> DEL).
expect(new Set(methods)).toEqual(new Set(['GET', 'POST', 'PUT', 'DEL', 'PATCH']));
});
});
}