Files
bruno/tests/import/openapi/api-spec-panel-validation.spec.ts
adwait-bruno ad14fdfba5 fix(openapi):validate API spec imports (#8322)
* fix(openapi):validate API spec imports and resolve preview to error state instead of hanging

* fix(openapi):allows opening of malformed files with correct extension

* fix(openapi):reject non-OpenAPI content in spec preview before timeout

* test(openapi): add unit + e2e coverage for spec import validation

* refactor(openapi):centralise spec error messages and fix dialog restore

* fix:removed nested try catch

* test:added common locators

* refactor:removed repeated lines

* refactor:removed redundant file reads

---------

Co-authored-by: Adwait Aayush <adwaitaayush@Adwaits-MacBook-Air.local>
2026-07-07 22:05:23 +05:30

75 lines
3.5 KiB
TypeScript

import { test, expect } from '../../../playwright';
import * as path from 'path';
import { openApiSpecFromDialog, openApiSpecSidebarItem } from '../../utils/page/openapi/render-spec';
import { SPEC_PREVIEW_ERRORS } from '../../../packages/bruno-app/src/components/ApiSpecPanel/constants';
import { INVALID_EXTENSION_MESSAGE } from '../../../packages/bruno-electron/src/app/apiSpecs';
test.describe('API Spec Panel - open & preview validation', () => {
test.beforeAll(async ({ electronApp }) => {
await electronApp.evaluate(({ dialog }) => {
(dialog as any).__savedShowOpenDialog = dialog.showOpenDialog;
});
});
test.afterAll(async ({ electronApp }) => {
await electronApp.evaluate(({ dialog }) => {
dialog.showOpenDialog = (dialog as any).__savedShowOpenDialog;
delete (dialog as any).__savedShowOpenDialog;
});
});
test('Reject a file with an unsupported extension', async ({ page, electronApp }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-invalid-extension.txt');
await openApiSpecFromDialog(page, electronApp, openApiFile);
await expect(
page.getByText(INVALID_EXTENSION_MESSAGE)
).toBeVisible();
});
test('Show the empty-spec message when opening an empty file', async ({ page, electronApp }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-empty.yaml');
await openApiSpecFromDialog(page, electronApp, openApiFile);
await openApiSpecSidebarItem(page, 'openapi-empty');
await expect(page.getByText(SPEC_PREVIEW_ERRORS.EMPTY)).toBeVisible();
});
test('Show a parse error when opening malformed YAML', async ({ page, electronApp }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-malformed.yaml');
await openApiSpecFromDialog(page, electronApp, openApiFile);
await openApiSpecSidebarItem(page, 'openapi-malformed');
await expect(
page.getByText(SPEC_PREVIEW_ERRORS.INVALID_YAML_JSON)
).toBeVisible();
});
test('Show a parse error when opening malformed JSON', async ({ page, electronApp }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-broken.json');
await openApiSpecFromDialog(page, electronApp, openApiFile);
await openApiSpecSidebarItem(page, 'openapi-broken');
await expect(
page.getByText(SPEC_PREVIEW_ERRORS.INVALID_YAML_JSON)
).toBeVisible();
});
test('Show a spec error when the file parses but is not a valid OpenAPI document', async ({ page, electronApp }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-missing-info.yaml');
await openApiSpecFromDialog(page, electronApp, openApiFile);
await openApiSpecSidebarItem(page, 'openapi-missing-info');
// Parses as an object but lacks the openapi/swagger + info contract, so it must fail
// fast with a precise message rather than falling through to the preview timeout.
await expect(
page.getByText(SPEC_PREVIEW_ERRORS.INVALID_OPENAPI)
).toBeVisible();
});
test('Render a valid spec without any preview error', async ({ page, electronApp }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-simple.json');
await openApiSpecFromDialog(page, electronApp, openApiFile);
await openApiSpecSidebarItem(page, 'Simple Test API');
// Panel opens for the valid spec (filename shown in the header) and no preview error appears
await expect(page.getByText('openapi-simple.json')).toBeVisible();
await expect(page.getByText(/Unable to render preview/i)).toHaveCount(0);
});
});