mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-02 17:08:32 +00:00
* feat: add functionality to retrieve collection path from transient file requests in IPC module * feat: implement transient directory handling in collection mounting process * add action to store transient directory paths in Redux state * update IPC handler to create and return a temporary directory for collections * modify collection mount action to dispatch transient directory addition * feat: add CreateTransientRequest component for managing transient requests * implement CreateTransientRequest component to facilitate the creation of HTTP, GraphQL, gRPC, and WebSocket transient requests * integrate the component into RequestTabs for user interaction * update collection and request handling to differentiate between transient and non-transient requests * enhance Redux actions to support transient request creation and management * feat: enhance transient request handling and add temp directory watcher * refactor Redux actions for HTTP, gRPC, and WebSocket requests to utilize a unified task queue for transient requests * implement a new helper function to retrieve collection paths from temporary directory metadata * add functionality to watch transient directories for file changes, excluding metadata.json * integrate transient directory watcher into the collection mounting process * feat: enhance transient request management with temp directory integration * update generateTransientRequestName function to accept tempDirectory parameter for improved request naming * modify CreateTransientRequest component to utilize tempDirectory for transient request creation * adjust middleware to check for transient status based on tempDirectory * implement transient file and directory identification in collections slice for better state management * feat: add SaveTransientRequest component for managing transient requests * implement SaveTransientRequest component to facilitate saving transient requests to selected folders * create StyledWrapper for component styling * introduce useCollectionFolderTree hook for managing folder navigation and state * update Redux actions to handle saving requests from transient state * feat: implement SaveTransientRequestContainer and enhance modal management * add SaveTransientRequestContainer to manage multiple transient request modals * refactor SaveTransientRequest component to utilize Redux for modal state management * implement open and close actions for transient request modals in Redux slice * update Bruno page to include SaveTransientRequestContainer for improved UI integration * feat: enhance SaveTransientRequest component with new folder creation functionality * add input for creating new folders within the SaveTransientRequest component * implement validation for new folder names and filesystem names * integrate folder creation logic with Redux actions for better state management * update styling for new folder input elements in StyledWrapper * improve modal behavior to reset state when opened * feat: update CreateTransientRequest to utilize collection presets for request URLs * Refactored CreateTransientRequest component to retrieve request URLs from collection presets. * Enhanced request handling by dynamically setting request URLs based on the selected collection's configuration. * refactor: clean up unused imports and adjust request handling in collections actions * Removed unused imports from actions.js to streamline the code. * Updated the saveRequest function to reject the modal instead of resolving it when handling transient requests. * Cleaned up comments in index.js for better clarity. * refactor: streamline transient request handling and improve save functionality * Removed success toast notifications from CreateTransientRequest component to simplify user feedback. * Enhanced SaveTransientRequest component to handle transient requests more effectively, including improved filename resolution and validation. * Added IPC handler for saving transient requests, ensuring proper file management and error handling. * Updated Redux actions to check for duplicate transient request names within the temporary directory. * feat: enhance request handling in ConfirmCollectionCloseDrafts component * Added logic to differentiate between transient and non-transient drafts, ensuring transient requests are saved individually before closing the collection. * Improved user feedback by displaying unsaved changes for both regular and transient requests. * Updated save and discard functionality to handle all drafts appropriately, enhancing overall user experience. * fix:fixed useCallback dependency array * fix:added request name checks before save * fix: added isTransient to files * fix: added watcher cleanup for temp directory * refactor: enhance transient request handling and optimize component logic * Updated CreateTransientRequest to utilize useMemo for improved performance and prevent unnecessary re-renders. * Refactored generateTransientRequestName to focus solely on transient requests, removing tempDirectory dependency. * Streamlined SaveTransientRequest by consolidating form reset logic and removing unused state variables. * Improved ConfirmCollectionCloseDrafts to differentiate between transient and non-transient drafts more effectively. * Cleaned up imports and optimized Redux actions for better maintainability. * feat: implement transient request file deletion on tab close * Added middleware to handle the deletion of transient request files when tabs are closed. * Enhanced collection-watcher to unlink temporary files, ensuring metadata.json is skipped and only request files are processed. * Improved error handling for file deletion operations. * feat: enhance autosave middleware to skip transient requests * Updated autosave middleware to check for transient requests and skip auto-save operations accordingly. * fix: update ConfirmCollectionCloseDrafts to display all transient drafts * Modified the ConfirmCollectionCloseDrafts component to show all transient drafts without limiting the display to a maximum number. * Removed the conditional message for additional drafts not shown, enhancing the user experience by providing complete visibility of transient requests. * feat: enhance SaveTransientRequest component for better modal management * Refactored SaveTransientRequest and its container to improve modal handling for unsaved transient requests. * Introduced state management for opening specific modals and added functionality to discard all unsaved requests. * Updated Redux actions to manage transient request modals more effectively, ensuring no duplicates are added. * Enhanced user interface to display a list of unsaved requests with options to save or discard them. * feat: improve modal management in SaveTransientRequestContainer * Added useEffect to reset openItemUid when the corresponding modal is no longer present. * Implemented functionality to close all tabs associated with transient requests and show a success message upon discarding them. * Removed unnecessary modal close handler and streamlined modal opening logic for better clarity and performance. * refactor: streamline code formatting and improve readability in collection actions * Consolidated multiple lines of code into single lines for better readability in ConfirmCollectionCloseDrafts and actions.js. * Enhanced consistency in the formatting of function parameters and return statements across the collections slice. * Removed unnecessary line breaks and improved the structure of the code for easier maintenance. * refactor: improve code readability and structure in middleware and actions * Consolidated multiple lines of code into single lines for better readability in middleware.js and actions.js. * Enhanced consistency in formatting function parameters and return statements across the collections slice. * Removed unnecessary line breaks and improved the structure of the code for easier maintenance. * Streamlined dispatch calls for better clarity and performance. * refactor: enhance code readability and consistency in middleware and actions * Improved formatting and structure in middleware.js for dispatch calls. * Streamlined comments and indentation in actions.js for better clarity. * Consolidated multiple lines into single lines where appropriate to enhance readability. * refactor: enhance transient request handling and modal interactions * Improved the modal handling logic for removing collections to differentiate between regular and drafts confirmation modals. * Added new tests for creating and saving transient requests (HTTP, GraphQL, gRPC, WebSocket) ensuring they do not appear in the sidebar until saved. * Introduced utility functions for creating transient requests and filling request URLs, improving code reusability and clarity. * refactor: simplify transient request modal rendering and improve collection watcher logic * Introduced a new TransientRequestModalsRenderer component to streamline modal rendering based on the number of transient requests. * Refactored the collection watcher logic to enhance readability by removing unnecessary setTimeout and consolidating file handling functions. * Improved error handling and logging for the temp directory watcher. * fix: correct spelling of 'WebSocket' in transient request components and tests * Updated the spelling of 'Websocket' to 'WebSocket' in CreateTransientRequest component, transient requests test, and action type definitions for consistency and accuracy.
226 lines
8.9 KiB
TypeScript
226 lines
8.9 KiB
TypeScript
import { test, expect } from '../../playwright';
|
|
import { createTransientRequest, fillRequestUrl, closeAllCollections, createCollection, sendRequest, clickResponseAction, selectRequestPaneTab } from '../utils/page';
|
|
import { buildCommonLocators, buildWebsocketCommonLocators } from '../utils/page/locators';
|
|
|
|
test.describe.serial('Transient Requests', () => {
|
|
let locators: ReturnType<typeof buildCommonLocators>;
|
|
|
|
test.beforeAll(async ({ page, createTmpDir }) => {
|
|
locators = buildCommonLocators(page);
|
|
|
|
// Create a temporary collection
|
|
const collectionPath = await createTmpDir('transient-collection');
|
|
await createCollection(page, 'transient-requests-test', collectionPath);
|
|
|
|
// Verify the collection is loaded
|
|
await test.step('Verify test collection is loaded', async () => {
|
|
await expect(locators.sidebar.collection('transient-requests-test')).toBeVisible();
|
|
await locators.sidebar.collection('transient-requests-test').click();
|
|
});
|
|
});
|
|
|
|
test.afterAll(async ({ page }) => {
|
|
// Clean up all collections
|
|
await closeAllCollections(page);
|
|
});
|
|
|
|
test('Create transient HTTP request - should not appear in sidebar', async ({ page }) => {
|
|
await test.step('Create transient HTTP request', async () => {
|
|
await createTransientRequest(page, {
|
|
requestType: 'HTTP'
|
|
});
|
|
await fillRequestUrl(page, 'http://localhost:8081/ping');
|
|
});
|
|
|
|
await test.step('Verify HTTP request tab is open', async () => {
|
|
const activeTab = page.locator('.request-tab.active');
|
|
await expect(activeTab).toBeVisible();
|
|
await expect(activeTab).toContainText('Untitled');
|
|
});
|
|
|
|
await test.step('Verify request is NOT in sidebar', async () => {
|
|
// Click on the collection to ensure it's expanded
|
|
await locators.sidebar.collection('transient-requests-test').click();
|
|
await page.waitForTimeout(300);
|
|
|
|
// Check that there are no requests in the collection
|
|
// Transient requests should not appear in the sidebar
|
|
const collectionItems = page.locator('.collection-item-name');
|
|
await expect(collectionItems).toHaveCount(0);
|
|
});
|
|
});
|
|
|
|
test('Create transient GraphQL request - should not appear in sidebar', async ({ page }) => {
|
|
await test.step('Create transient GraphQL request', async () => {
|
|
await createTransientRequest(page, {
|
|
requestType: 'GraphQL'
|
|
});
|
|
await fillRequestUrl(page, 'https://api.example.com/graphql');
|
|
});
|
|
|
|
await test.step('Verify GraphQL request tab is open', async () => {
|
|
const activeTab = page.locator('.request-tab.active');
|
|
await expect(activeTab).toBeVisible();
|
|
await expect(activeTab).toContainText('Untitled');
|
|
});
|
|
|
|
await test.step('Verify request is NOT in sidebar', async () => {
|
|
// Check that there are still no requests in the collection
|
|
const collectionItems = page.locator('.collection-item-name');
|
|
await expect(collectionItems).toHaveCount(0);
|
|
});
|
|
});
|
|
|
|
test('Create transient gRPC request - should not appear in sidebar', async ({ page }) => {
|
|
await test.step('Create transient gRPC request', async () => {
|
|
await createTransientRequest(page, {
|
|
requestType: 'gRPC'
|
|
});
|
|
await fillRequestUrl(page, 'grpc://localhost:50051');
|
|
});
|
|
|
|
await test.step('Verify gRPC request tab is open', async () => {
|
|
const activeTab = page.locator('.request-tab.active');
|
|
await expect(activeTab).toBeVisible();
|
|
await expect(activeTab).toContainText('Untitled');
|
|
});
|
|
|
|
await test.step('Verify request is NOT in sidebar', async () => {
|
|
// Check that there are still no requests in the collection
|
|
const collectionItems = page.locator('.collection-item-name');
|
|
await expect(collectionItems).toHaveCount(0);
|
|
});
|
|
});
|
|
|
|
test('Create transient WebSocket request - should not appear in sidebar', async ({ page }) => {
|
|
await test.step('Create transient WebSocket request', async () => {
|
|
await createTransientRequest(page, {
|
|
requestType: 'WebSocket'
|
|
});
|
|
await fillRequestUrl(page, 'ws://localhost:8082');
|
|
});
|
|
|
|
await test.step('Verify WebSocket request tab is open', async () => {
|
|
const activeTab = page.locator('.request-tab.active');
|
|
await expect(activeTab).toBeVisible();
|
|
await expect(activeTab).toContainText('Untitled');
|
|
});
|
|
|
|
await test.step('Verify request is NOT in sidebar', async () => {
|
|
// Check that there are still no requests in the collection
|
|
const collectionItems = page.locator('.collection-item-name');
|
|
await expect(collectionItems).toHaveCount(0);
|
|
});
|
|
});
|
|
|
|
test('Save transient HTTP request - should appear in sidebar after save', async ({ page }) => {
|
|
await test.step('Create transient HTTP request', async () => {
|
|
await createTransientRequest(page, {
|
|
requestType: 'HTTP'
|
|
});
|
|
await fillRequestUrl(page, 'http://localhost:8081/echo');
|
|
});
|
|
|
|
await test.step('Trigger save action using keyboard shortcut', async () => {
|
|
// Try to save using Cmd+S (Mac) or Ctrl+S (other platforms)
|
|
await page.keyboard.press('Meta+s');
|
|
await page.waitForTimeout(500);
|
|
});
|
|
|
|
await test.step('Fill in save dialog', async () => {
|
|
// Wait for save modal to appear
|
|
const saveModal = page.locator('.bruno-modal-card').filter({ hasText: 'Save Request' });
|
|
await expect(saveModal).toBeVisible({ timeout: 5000 });
|
|
|
|
// Fill in request name
|
|
const requestNameInput = saveModal.locator('#request-name');
|
|
await requestNameInput.clear();
|
|
await requestNameInput.fill('Saved HTTP Request');
|
|
|
|
// Click Save button
|
|
await saveModal.getByRole('button', { name: 'Save' }).click();
|
|
|
|
// Wait for success toast
|
|
await page.waitForTimeout(1000);
|
|
});
|
|
|
|
await test.step('Verify saved request appears in sidebar', async () => {
|
|
// Check collection is expanded
|
|
await locators.sidebar.collection('transient-requests-test').click();
|
|
|
|
// Look for the saved request in sidebar
|
|
const savedRequest = locators.sidebar.request('Saved HTTP Request');
|
|
await expect(savedRequest).toBeVisible();
|
|
});
|
|
|
|
await test.step('Cleanup: Delete the saved request', async () => {
|
|
await locators.sidebar.request('Saved HTTP Request').hover();
|
|
await locators.actions.collectionItemActions('Saved HTTP Request').click();
|
|
await locators.dropdown.item('Delete').click();
|
|
await locators.modal.button('Delete').click();
|
|
await expect(locators.sidebar.request('Saved HTTP Request')).not.toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('Save transient GraphQL request - should appear in sidebar after save', async ({ page }) => {
|
|
await test.step('Create transient GraphQL request', async () => {
|
|
await createTransientRequest(page, {
|
|
requestType: 'GraphQL'
|
|
});
|
|
await fillRequestUrl(page, 'https://api.example.com/graphql');
|
|
});
|
|
|
|
await test.step('Trigger save action using keyboard shortcut', async () => {
|
|
await page.keyboard.press('Meta+s');
|
|
await page.waitForTimeout(500);
|
|
});
|
|
|
|
await test.step('Fill in save dialog', async () => {
|
|
const saveModal = page.locator('.bruno-modal-card').filter({ hasText: 'Save Request' });
|
|
await expect(saveModal).toBeVisible({ timeout: 5000 });
|
|
|
|
const requestNameInput = saveModal.locator('#request-name');
|
|
await requestNameInput.clear();
|
|
await requestNameInput.fill('Saved GraphQL Request');
|
|
|
|
await saveModal.getByRole('button', { name: 'Save' }).click();
|
|
await page.waitForTimeout(1000);
|
|
});
|
|
|
|
await test.step('Verify saved request appears in sidebar', async () => {
|
|
await locators.sidebar.collection('transient-requests-test').click();
|
|
const savedRequest = locators.sidebar.request('Saved GraphQL Request');
|
|
await expect(savedRequest).toBeVisible();
|
|
});
|
|
|
|
await test.step('Cleanup: Delete the saved request', async () => {
|
|
await locators.sidebar.request('Saved GraphQL Request').hover();
|
|
await locators.actions.collectionItemActions('Saved GraphQL Request').click();
|
|
await locators.dropdown.item('Delete').click();
|
|
await locators.modal.button('Delete').click();
|
|
await expect(locators.sidebar.request('Saved GraphQL Request')).not.toBeVisible();
|
|
});
|
|
});
|
|
|
|
test('Send transient HTTP request - verify response', async ({ page }) => {
|
|
await test.step('Create transient HTTP request', async () => {
|
|
await createTransientRequest(page, {
|
|
requestType: 'HTTP'
|
|
});
|
|
await fillRequestUrl(page, 'http://localhost:8081/ping');
|
|
});
|
|
|
|
await test.step('Send request and verify response', async () => {
|
|
// Send request using the helper function
|
|
await sendRequest(page, 200);
|
|
|
|
// Copy response to clipboard and verify
|
|
await clickResponseAction(page, 'response-copy-btn');
|
|
await expect(page.getByText('Response copied to clipboard')).toBeVisible();
|
|
|
|
const clipboardText = await page.evaluate(() => navigator.clipboard.readText());
|
|
expect(clipboardText).toBe('pong');
|
|
});
|
|
});
|
|
});
|