
Product
Announcing Precomputed Reachability Analysis in Socket
Socket’s precomputed reachability slashes false positives by flagging up to 80% of vulnerabilities as irrelevant, with no setup and instant results.
A Jest & Pest inspired testing utilities for Bun. UI coming soon!
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.
bun add -d besting
import { expect, test } from 'besting'
test('basic addition', () => {
expect(1 + 1).toBe(2)
})
import { expect, test } from 'besting'
test('multiple assertions on same value', () => {
expect('Hello World')
.toContain('Hello')
.toContain('World')
.toHaveLength(11)
.toStartWith('Hello')
.toEndWith('World')
})
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)
})
})
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)
})
})
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')
})
})
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()
})
Besting includes Laravel-inspired API testing utilities for testing HTTP endpoints.
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)
})
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')
})
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')
})
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'
})
})
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')
})
Besting includes utilities for testing cache operations, inspired by Laravel's cache assertions.
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')
})
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')
})
Besting includes utilities for testing URL components.
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' }
})
Besting includes all matchers from Bun's test runner, plus additional Pest-inspired matchers:
toStartWith(prefix)
- Assert that a string starts with a prefixtoEndWith(suffix)
- Assert that a string ends with a suffixtoBeEmpty()
- Assert that a string, array, or object is emptytoPass(validator, message?)
- Assert that a value passes a custom validation functionBesting 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:
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.
MIT
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.
bun test
Please see our releases page for more information on what has changed recently.
Please see CONTRIBUTING for details.
For help, discussion about best practices, or any other conversation that would benefit from being searchable:
For casual chit-chat with others using this package:
Join the Stacks Discord Server
"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 🌎
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.
The MIT License (MIT). Please see LICENSE for more information.
Made with 💙
Besting includes Laravel-inspired database testing utilities with migrations, seeders, and factories.
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' })
})
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()
})
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()
})
Besting includes Laravel-inspired event testing utilities for testing event dispatching.
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)
})
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')
})
Besting includes Laravel-inspired authentication testing utilities.
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()
})
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)
})
Besting includes utilities for testing terminal commands, including Laravel-inspired Artisan 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')
})
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')
})
FAQs
A Bun test framework.
The npm package besting receives a total of 1 weekly downloads. As such, besting popularity was classified as not popular.
We found that besting demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
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.
Product
Socket’s precomputed reachability slashes false positives by flagging up to 80% of vulnerabilities as irrelevant, with no setup and instant results.
Product
Socket is launching experimental protection for Chrome extensions, scanning for malware and risky permissions to prevent silent supply chain attacks.
Product
Add secure dependency scanning to Claude Desktop with Socket MCP, a one-click extension that keeps your coding conversations safe from malicious packages.