You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

besting

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

besting

A Bun test framework.

0.0.4
latest
Source
npmnpm
Version published
Weekly downloads
1
Maintainers
1
Weekly downloads
 
Created
Source

Social Card of this repo

npm version GitHub Actions Commitizen friendly

Besting

A Jest & Pest inspired testing utilities for Bun. UI coming soon!

Overview

Besting is a lightweight wrapper around Bun's built-in test runner that provides a more fluent, Pest-like API for writing tests. It builds on Bun's Jest-compatible test runner and adds a more expressive, chainable API for assertions.

Installation

bun add -d besting

Features

  • Fluent, chainable assertions - Make multiple assertions on the same value with a chainable API.
  • Pest-style syntax - Use a similar style to PHP's Pest testing framework.
  • Zero overhead - Built directly on Bun's native test runner for maximum performance.
  • Full compatibility - Works with all of Bun's testing features including lifecycle hooks, snapshots, and more.
  • API Testing - Laravel-inspired API testing utilities for testing HTTP endpoints.
  • Database Testing - Laravel-inspired database testing with migrations, seeders, and factories.
  • Authentication Testing - Laravel-inspired authentication testing.
  • Event Testing - Laravel-inspired event testing with event dispatching and assertions.
  • Command Testing - Laravel-inspired command testing for terminal commands.
  • Cache Testing - Utilities for testing cache operations.
  • Cookie Testing - Utilities for testing cookies.
  • URL Testing - Utilities for testing URL components.

Basic Usage

import { expect, test } from 'besting'

test('basic addition', () => {
  expect(1 + 1).toBe(2)
})

Chainable Assertions

import { expect, test } from 'besting'

test('multiple assertions on same value', () => {
  expect('Hello World')
    .toContain('Hello')
    .toContain('World')
    .toHaveLength(11)
    .toStartWith('Hello')
    .toEndWith('World')
})

Pest-Style API

import { best } from 'besting'

const p = best()

p.describe('Calculator', () => {
  p.test('addition works', () => {
    p.it(1 + 1).toBe(2)
  })

  p.test('subtraction works', () => {
    p.it(3 - 1).toBe(2)
  })
})

Test Suites

import { describe, expect, test } from 'besting'

describe('Math operations', () => {
  test('addition works', () => {
    expect(1 + 1).toBe(2)
  })

  test('subtraction works', () => {
    expect(3 - 1).toBe(2)
  })
})

Lifecycle Hooks

import { beforeEach, describe, expect, test } from 'besting'

describe('User', () => {
  let user

  beforeEach(() => {
    user = { name: 'John', email: 'john@example.com' }
  })

  test('has correct properties', () => {
    expect(user.name).toBe('John')
    expect(user.email).toBe('john@example.com')
  })
})

Test Groups

import { testGroup } from 'besting'

testGroup('Hello World', (str) => {
  // All assertions are against the string 'Hello World'
  str.toContain('Hello')
    .toContain('World')
    .toStartWith('Hello')
    .toEndWith('World')
    .not
    .toBeEmpty()
})

API Testing

Besting includes Laravel-inspired API testing utilities for testing HTTP endpoints.

Basic API Testing

import { api, assertResponse, test } from 'besting'

test('Basic API test', async () => {
  // Make a GET request to an API
  const response = await api('https://api.example.com')
    .get('/users/1')

  // Assert on the response
  const assertion = await assertResponse(response).assertOk()
  await assertion.assertStatus(200)
  await assertion.assertHeader('content-type')

  // Get and assert on JSON data
  const data = await response.json()
  expect(data).toHaveProperty('id', 1)
})

HTTP Methods

import { api, assertResponse, test } from 'besting'

test('Testing different HTTP methods', async () => {
  const baseApi = api('https://api.example.com')

  // GET with query parameters
  const getResponse = await baseApi
    .withQuery({ filter: 'active' })
    .get('/users')

  // POST with JSON data
  const postResponse = await baseApi
    .post('/users', { name: 'John', email: 'john@example.com' })

  // PUT to update a resource
  const putResponse = await baseApi
    .put('/users/1', { name: 'Updated Name' })

  // DELETE a resource
  const deleteResponse = await baseApi
    .delete('/users/1')
})

Authentication

import { api, test } from 'besting'

test('Authenticated API requests', async () => {
  // Using Bearer token
  const tokenResponse = await api('https://api.example.com')
    .withToken('your-auth-token')
    .get('/secured-endpoint')

  // Using Basic Authentication
  const basicAuthResponse = await api('https://api.example.com')
    .withBasicAuth('username', 'password')
    .get('/secured-endpoint')
})

JSON Assertions

import { api, assertResponse, test } from 'besting'

test('Testing JSON responses', async () => {
  const response = await api('https://api.example.com')
    .get('/users/1')

  // Assert on specific JSON paths
  const assertion = await assertResponse(response)
  await assertion.assertJsonPath('name', 'John Doe')
  await assertion.assertJsonPath('email')
  await assertion.assertJsonPath('address.city', 'New York')

  // Assert on the entire JSON structure
  await assertion.assertJson({
    id: 1,
    name: 'John Doe',
    email: 'john@example.com'
  })
})

Configuration

import { api, test } from 'besting'

test('Configuring API requests', async () => {
  const response = await api('https://api.example.com')
    .withHeaders({
      'X-Custom-Header': 'Value',
      'Accept-Language': 'en-US'
    })
    .withTimeout(5000) // 5 seconds timeout
    .withJson() // Ensure JSON content type
    .get('/endpoint')
})

Cache Testing

Besting includes utilities for testing cache operations, inspired by Laravel's cache assertions.

Basic Cache Testing

import { cache, test } from 'besting'

test('Basic cache operations', async () => {
  const cacheStore = cache()

  // Store a value in cache
  await cacheStore.set('user_id', 1)

  // Assert that the key exists
  await cacheStore.assertHas('user_id')

  // Get a value from cache
  const userId = await cacheStore.get('user_id')

  // Delete a key
  await cacheStore.delete('user_id')

  // Assert that the key is gone
  await cacheStore.assertMissing('user_id')
})

Expiration Testing

import { cache, test } from 'besting'

test('Cache expiration', async () => {
  const cacheStore = cache()

  // Set a value with a 1 second TTL
  await cacheStore.set('temp', 'value', 1)

  // Value should exist initially
  await cacheStore.assertExists('temp')

  // Wait for expiration
  await new Promise(resolve => setTimeout(resolve, 1100))

  // Value should be gone after TTL expires
  await cacheStore.assertNotExists('temp')
})

Besting includes utilities for testing cookies, compatible with both browser and server environments.

import { cookie, test } from 'besting'

test('Basic cookie operations', () => {
  const cookieJar = cookie()

  // Set cookies
  cookieJar
    .set('session_id', '123456789')
    .set('theme', 'dark')

  // Assert cookies exist
  cookieJar
    .assertHas('session_id')
    .assertHas('theme')

  // Assert cookie values
  cookieJar
    .assertValue('session_id', '123456789')
    .assertValue('theme', 'dark')

  // Remove a cookie
  cookieJar.remove('theme')

  // Assert cookie is gone
  cookieJar.assertMissing('theme')
})

URL Testing

Besting includes utilities for testing URL components.

Basic URL Testing

import { test, url } from 'besting'

test('URL component testing', () => {
  const testUrl = url('https://example.com/users?sort=asc&page=1#profile')

  // Assert URL components
  testUrl
    .hasProtocol('https')
    .hasHost('example.com')
    .hasPath('/users')
    .hasQuery('sort', 'asc')
    .hasQuery('page', '1')
    .hasFragment('profile')

  // Check for absence of query parameters
  testUrl.doesntHaveQuery('filter')

  // Get URL components
  console.log(testUrl.path) // '/users'
  console.log(testUrl.queryParams) // { sort: 'asc', page: '1' }
})

Special Matchers

Besting includes all matchers from Bun's test runner, plus additional Pest-inspired matchers:

  • toStartWith(prefix) - Assert that a string starts with a prefix
  • toEndWith(suffix) - Assert that a string ends with a suffix
  • toBeEmpty() - Assert that a string, array, or object is empty
  • toPass(validator, message?) - Assert that a value passes a custom validation function

Testing

Besting uses Bun's native test runner, providing a seamless testing experience with all of Bun's built-in test features.

# Run all tests with Bun's standard test runner
bun test

# Run all tests with our custom runner (ensures all test files are executed)
bun run test:custom

# Run a specific test file
bun test path/to/test.ts

# Run tests with debugging enabled
bun run test:debug

Besting seamlessly integrates with Bun's test runner, allowing you to:

  • Use all of Bun's test features (snapshots, mocks, etc.)
  • Get beautifully formatted test output
  • Run tests in parallel for better performance

Note: Bun's test runner may sometimes have issues discovering or executing all test files (see Bun issue #3506). If you notice that some test files are not being executed, you can use our custom test runner with bun run test:custom, which ensures all test files are discovered and executed individually.

License

MIT

Get Started

It's rather simple to get your package development started:

# you may use this GitHub template or the following command:
bunx degit stacksjs/besting my-pkg
cd my-pkg

bun i # install all deps
bun run build # builds the library for production-ready use

# after you have successfully committed, you may create a "release"
bun run release # automates git commits, versioning, and changelog generations

Check out the package.json scripts for more commands.

Testing

bun test

Changelog

Please see our releases page for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Community

For help, discussion about best practices, or any other conversation that would benefit from being searchable:

Discussions on GitHub

For casual chit-chat with others using this package:

Join the Stacks Discord Server

Postcardware

"Software that is free, but hopes for a postcard." We love receiving postcards from around the world showing where Stacks is being used! We showcase them on our website too.

Our address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094, United States 🌎

Sponsors

We would like to extend our thanks to the following sponsors for funding Stacks development. If you are interested in becoming a sponsor, please reach out to us.

License

The MIT License (MIT). Please see LICENSE for more information.

Made with 💙

Database Testing

Besting includes Laravel-inspired database testing utilities with migrations, seeders, and factories.

Basic Database Testing

import { db, migration, seeder, test } from 'besting'

// Define a migration
migration(async (connection) => {
  await connection.raw('CREATE TABLE users (id INT, name TEXT, email TEXT)')
})

// Define a seeder
seeder(async (connection) => {
  await connection.table('users').insert([
    { id: 1, name: 'John', email: 'john@example.com' },
    { id: 2, name: 'Jane', email: 'jane@example.com' },
  ])
})

test('Basic database operations', async () => {
  const database = db().register(yourDatabaseConnection)

  // Run migrations and seeders
  await database.migrate()
  await database.seed()

  // Query data
  const users = await database.select('users')
  expect(users.length).toBe(2)

  // Insert data
  await database.insert('users', { id: 3, name: 'Alice', email: 'alice@example.com' })

  // Make assertions
  await database.assertExists('users', { id: 3 })
  await database.assertSame('users', { id: 3 }, { name: 'Alice' })
})

Database Transactions

import { db, test, useTransaction } from 'besting'

test('Database transactions', async () => {
  const database = db().register(yourDatabaseConnection)

  // Use transactions to isolate tests
  await database.beginTransaction()

  // Make changes
  await database.insert('users', { id: 3, name: 'Alice', email: 'alice@example.com' })

  // Rollback changes
  await database.rollbackTransaction()

  // Use the transaction helper
  const transactionTest = useTransaction(async (db) => {
    // This code runs within a transaction
    await db.insert('users', { id: 4, name: 'Bob', email: 'bob@example.com' })
  })

  await transactionTest()
})

Database Factories

import { db, test } from 'besting'

test('Database factories', async () => {
  const database = db().register(yourDatabaseConnection)

  // Create a user factory
  const userFactory = database.factory('users')
    .define({
      name: 'Default User',
      email: 'user@example.com',
    })
    .state('admin', user => ({
      ...user,
      name: 'Admin User',
      email: 'admin@example.com',
    }))

  // Create a default user
  await userFactory.create({ id: 10 })

  // Create an admin user
  await userFactory.has('admin').create({ id: 11 })

  // Create multiple users
  await userFactory.count(3).create()

  // Make model instances without persisting
  const user = userFactory.make()
})

Event Testing

Besting includes Laravel-inspired event testing utilities for testing event dispatching.

Basic Event Testing

import { defineEvent, events, fakeEvents, test } from 'besting'

// Define event classes
class UserCreated {
  constructor(public id: number, public name: string) {}
}

// Define an event using the helper
const OrderShipped = defineEvent({
  id: 0,
  trackingNumber: '',
})

test('Basic event testing', () => {
  const fake = fakeEvents()

  // Dispatch events
  events().dispatch(new UserCreated(1, 'John'))
  events().dispatch(new UserCreated(2, 'Jane'))

  // Make assertions
  fake.assertDispatched('UserCreated')
  fake.assertDispatchedTimes('UserCreated', 2)
  fake.assertNotDispatched('OrderShipped')

  // Check specific events
  fake.assertDispatched('UserCreated', event => event.id === 1)
})

Event Listeners

import { events, listener, test } from 'besting'

class UserCreated {
  constructor(public id: number, public name: string) {}
}

class EventListener {
  events: any[] = []

  @listener(UserCreated.name)
  handleUserCreated(event: UserCreated) {
    this.events.push(event)
  }
}

test('Event listeners', () => {
  const listener = new EventListener()

  // Dispatch an event
  events().dispatch(new UserCreated(1, 'John'))

  // Check that the listener received it
  expect(listener.events.length).toBe(1)
  expect(listener.events[0].name).toBe('John')
})

Authentication Testing

Besting includes Laravel-inspired authentication testing utilities.

Basic Authentication Testing

import { auth, test } from 'besting'

test('Authentication testing', () => {
  // Define a user
  const user = {
    id: 1,
    name: 'Test User',
    email: 'user@example.com',
  }

  // Set the authenticated user
  auth().actingAs(user)

  // Make assertions
  auth().assertAuthenticated()
  expect(auth().user().id).toBe(1)

  // Act as guest
  auth().actingAsGuest()
  auth().assertGuest()
})

With Auth Helper

import { auth, test, withAuth } from 'besting'

test('With auth helper', () => {
  const user = {
    id: 1,
    name: 'Test User',
    email: 'user@example.com',
  }

  // Create request with auth context
  const request = withAuth(user)

  expect(request.user).toBe(user)
  expect(request.auth.check()).toBe(true)
})

Command Testing

Besting includes utilities for testing terminal commands, including Laravel-inspired Artisan command testing.

Basic Command Testing

import { command, test } from 'besting'

test('Command testing', async () => {
  const cmd = command()

  // Execute a command
  const result = await cmd.execute('echo', ['Hello, World!'])

  // Make assertions
  cmd
    .assertExitCode(0)
    .assertOutputContains('Hello')
    .assertOutputNotContains('error')
})

Artisan Command Testing

import { artisan, test } from 'besting'

test('Artisan command testing', async () => {
  // This example shows how it would work in a Laravel project
  const result = await artisan('migrate', ['--seed'])

  expect(result.exitCode).toBe(0)
  expect(result.output).toContain('Migration')
})

Keywords

typescript

FAQs

Package last updated on 30 Apr 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts