Bruno

repository·main·Indexed 12 days ago

https://github.com/usebruno/bruno

An API client and CLI for running and testing API collections. The Bruno CLI enables automation of API testing within CI/CD workflows and provides official Docker images (Alpine and Debian) for container-native environments.

Tokens
105.6K
Snippets
247
Records
379
Agent score
99%

What's inside Bruno

  1. Overview of Bruno API Client

    main

    Bruno is an open-source IDE designed for testing and exploring APIs. Unlike many other API clients, Bruno is fully offline and autonomous, prioritizing data privacy by avoiding cloud synchronization.

    Key features include:

    • Local Storage: API collections are stored directly in folders on your local disk.
    • Bru Markup Language: Bruno uses the .bru markup language to save API request information in a human-readable text format.
    • Version Control Integration: Because collections are stored as local files, you can use Git or any other version control system to collaborate with teams on API collections.
    • Cross-platform Support: Bruno is designed to run across different operating systems.
  2. What is Bruno?

    main

    Bruno is an open-source API client designed for exploring and testing APIs. Unlike many other API clients, Bruno is built around a local-first philosophy: it stores your collections directly in folders on your filesystem rather than in a proprietary cloud.

    Key characteristics include:

    • Local Storage: API request information is saved using the Bru language within your local filesystem.
    • Offline-Only: Bruno does not include cloud synchronization. It is designed to keep your data on your own device to ensure privacy.
    • Version Control Friendly: Because collections are stored as files in your filesystem, you can use Git or any other version control system to collaborate on API collections with your team.
  3. Use @usebruno/filestore for parsing and stringifying Bruno files

    main

    The @usebruno/filestore package provides a generic interface for handling Bruno's file formats. It allows you to convert raw file content (like .bru files) into JavaScript objects and vice versa. This is useful for building tools that need to programmatically manipulate Bruno collections, requests, folders, or environments.

    Currently, the package primarily supports Bruno's custom .bru format, but it is designed to support other formats like YAML in the future via an options object.

    const {
      parseRequest,
      stringifyRequest,
      parseCollection,
      stringifyCollection,
      parseEnvironment,
      stringifyEnvironment,
      parseDotEnv
    } = require('@usebruno/filestore');
    
    // Parse a .bru request file
    const requestData = parseRequest(bruContent);
    
    // Stringify request data back to .bru format
    const bruContent = stringifyRequest(requestData);
  4. Use bruno-js runtimes for scripting and testing

    main
    The bruno-js package provides the necessary runtimes for executing scripts, tests, variables, and assertions within the Bruno ecosystem. It enables the logic required to run JavaScript-based automation and validation during request execution.
  5. Separate Assertions from Actions

    main

    To maintain clear test intent, follow the separation of concerns between Actions and Specs:

    Actions (in tests/utils/page/*)

    • Purpose: Perform interactions and synchronize state.
    • Behavior: Use Playwright's synchronization utilities like locator.waitFor({ state }) or page.waitForLoadState().
    • Constraint: Actions must not contain expect(...) assertions. They should only ensure the UI is ready for the next step.

    Specs (in .spec.ts files)

    • Purpose: Define the test's intent and pass/fail criteria.
    • Behavior: This is where expect(...) belongs. The spec verifies the outcome of the actions performed.
    // Action: Synchronizes, does NOT assert
    export const openRenameModal = async (page: Page, requestName: string) => {
      await test.step(`Open rename modal for "${requestName}"`, async () => {
        const { sidebar, actions, dropdown } = buildCommonLocators(page);
        await sidebar.request(requestName).hover();
        await actions.collectionItemActions(requestName).click();
        await dropdown.item('Rename').click();
        // Synchronization: wait for the UI to be ready
        await page.locator('.bruno-modal').filter({ hasText: 'Rename Request' }).waitFor({ state: 'visible' });
      });
    };
    
    // Spec: Owns the assertion
    test('renames a request', async ({ page }) => {
      const { modal } = buildCommonLocators(page);
      // ... arrange ...
    
      await openRenameModal(page, 'Test Request');
    
      // Assertion: verifies the outcome
      await expect(modal.title('Rename Request')).toBeVisible();
    });
  6. Bruno core concepts: Offline-first and Local Storage

    main
    Bruno is designed to work exclusively in offline mode. It does not use cloud synchronization, prioritizing data privacy by keeping all collection data on your local device. Collections are saved using the Bru markup language in your local filesystem.
  7. UI Component development conventions

    main

    When building or using components within the Bruno UI system, follow these architectural conventions:

    • Controlled Components: Use the value prop combined with an onChange(value, event) callback to manage state.
    • Ref Forwarding & Prop Spreading: Components must forward ref and pass through additional props (e.g., ...rest, data-*) to ensure compatibility.
    • Testing: Every interactive primitive accepts a dataTestId prop for testing purposes.
    • Accessibility: Group primitives (such as RadioGroup or SegmentedControl) require an accessible name via label, ariaLabel, or ariaLabelledBy. Failure to provide these will trigger warnings in development.
    • Theming: Do not use hardcoded colors or spacing. All styling must derive from the theme via props.theme (using styled-components).