npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fs-fixture

v2.14.0

Published

Easily create test fixtures at a temporary file-system path

Readme

Simple API to create disposable test fixtures on disk. Tiny (1.1 kB gzipped) with zero dependencies!

Features

  • 📁 Create files & directories from simple objects
  • 🧹 Automatic cleanup with using keyword
  • 📝 Built-in JSON read/write support
  • 🔗 Symlink support
  • 💾 Binary file support with Buffers
  • 🎯 TypeScript-first with full type safety
  • 🔄 File methods inherit types directly from Node.js fs module
  • 🔌 Pluggable filesystem — use with @platformatic/vfs, memfs, or any fs/promises-compatible API

Installation

npm install fs-fixture

Quick start

import { createFixture } from 'fs-fixture'

// Create a temporary fixture
const fixture = await createFixture({
    'package.json': JSON.stringify({ name: 'my-app' }),
    'src/index.js': 'console.log("Hello world")'
})

// Read files
const content = await fixture.readFile('src/index.js', 'utf8')

// Cleanup when done
await fixture.rm()

Auto cleanup with using keyword

Uses TypeScript 5.2+ Explicit Resource Management for automatic cleanup:

await using fixture = await createFixture({
    'config.json': '{ "setting": true }'
})

// Fixture is automatically cleaned up when exiting scope

Usage

Creating fixtures

From an object:

const fixture = await createFixture({
    'package.json': '{ "name": "test" }',
    'src/index.js': 'export default () => {}',
    'src/utils': {
        'helper.js': 'export const help = () => {}'
    }
})

From a template directory:

// Copies an existing directory structure
const fixture = await createFixture('./test-templates/basic')

Empty fixture:

// Create an empty temporary directory
const fixture = await createFixture()

Working with files

File methods (readFile, writeFile, readdir) inherit their type signatures directly from Node.js fs/promises, preserving all overloads and type narrowing behavior.

Read files:

// Read as string (type: Promise<string>)
const text = await fixture.readFile('config.txt', 'utf8')

// Read as buffer (type: Promise<Buffer>)
const binary = await fixture.readFile('image.png')

Write files:

await fixture.writeFile('output.txt', 'Hello world')
await fixture.writeFile('data.bin', Buffer.from([0x89, 0x50]))

JSON operations:

// Write JSON with formatting
await fixture.writeJson('config.json', { port: 3000 })

// Read and parse JSON with type safety
type Config = { port: number }
const config = await fixture.readJson<Config>('config.json')

Working with directories

// Create directories
await fixture.mkdir('nested/folders')

// List directory contents
const files = await fixture.readdir('src')

// Copy files into fixture
await fixture.cp('/path/to/file.txt', 'copied-file.txt')

// Move or rename files
await fixture.mv('old-name.txt', 'new-name.txt')
await fixture.mv('file.txt', 'src/file.txt')

// Check if path exists
if (await fixture.exists('optional-file.txt')) {
    // ...
}

Advanced features

Dynamic content with functions:

const fixture = await createFixture({
    'target.txt': 'original file',
    'info.txt': ({ fixturePath }) => `Created at: ${fixturePath}`,
    'link.txt': ({ symlink }) => symlink('./target.txt')
})

Symlinks:

const fixture = await createFixture({
    'index.js': 'import pkg from \'pkg\'',

    // Symlink individual file or directory
    'node_modules/pkg': ({ symlink }) => symlink(process.cwd()),

    // Symlink entire directory (useful for sharing node_modules)
    node_modules: ({ symlink }) => symlink(path.resolve('node_modules'))
})

Binary files:

const fixture = await createFixture({
    'image.png': Buffer.from(imageData),
    'generated.bin': () => Buffer.from('dynamic binary content')
})

Path syntax:

const fixture = await createFixture({
    // Nested object syntax
    src: {
        utils: {
            'helper.js': 'export const help = () => {}'
        }
    },

    // Or path syntax (creates same structure)
    'src/utils/helper.js': 'export const help = () => {}'
})

[!TIP] Path syntax also works for grouped prefixes, so you can keep related files together without repeating the shared path:

await createFixture({
    'file.js': 'import { a } from "my-pkg";',

    'node_modules/my-pkg': {
        'package.json': JSON.stringify({
            name: 'my-pkg',
            type: 'module',
            exports: './index.js'
        }),
        'index.js': 'export const a = 1;'
    }
})

Custom filesystem

Pass any fs/promises-compatible API via the fs option to use a virtual filesystem instead of disk:

import { create, MemoryProvider } from '@platformatic/vfs'
import { createFixture } from 'fs-fixture'

const fs = create(new MemoryProvider()).promises
const fixture = await createFixture({
    'package.json': JSON.stringify({ name: 'test' }),
    'src/index.js': 'export default 42'
}, { fs })

await fixture.readFile('src/index.js', 'utf8') // 'export default 42'

Works with any library that implements the fs/promises API shape, including @platformatic/vfs, the future node:vfs, and memfs.

[!NOTE] With a custom fs, files only exist in that fs instance. Use fixture.readFile() or fixture.fs to access them — fixture.path is a virtual path that doesn't exist on the real disk.

[!NOTE] Template directory sources (string paths) are not supported with custom filesystems because most virtual fs implementations lack recursive cp. Use a FileTree object instead.

API

createFixture(source?, options?)

Creates a temporary fixture directory and returns a FsFixture instance.

Parameters:

  • source (optional): String path to template directory, or FileTree object defining the structure
  • options.tempDir (optional): Custom temp directory. Defaults to os.tmpdir()
  • options.templateFilter (optional): Filter function when copying from template directory
  • options.fs (optional): Custom fs/promises-compatible API for virtual filesystem support

Returns: Promise<FsFixture>

const fixture = await createFixture()
const fixture = await createFixture({ 'file.txt': 'content' })
const fixture = await createFixture('./template-dir')
const fixture = await createFixture({}, { tempDir: './custom-temp' })

FsFixture Methods

| Method | Description | |--------|-------------| | fixture.path | Absolute path to the fixture directory | | fixture.fs | The underlying fs/promises API used by the fixture | | getPath(...paths) | Get absolute path to file/directory in fixture | | exists(path?) | Check if file/directory exists | | rm(path?) | Delete file/directory (or entire fixture if no path) | | readFile(path, encoding?) | Read file as string or Buffer | | writeFile(path, content) | Write string or Buffer to file | | readJson<T>(path) | Read and parse JSON file | | writeJson(path, data, space?) | Write JSON with optional formatting | | readdir(path, options?) | List directory contents | | mkdir(path) | Create directory (recursive) | | cp(source, dest?) | Copy file/directory into fixture | | mv(source, dest) | Move or rename file/directory |

Types

type FileTree = {
    [path: string]: string | Buffer | FileTree | ((api: Api) => string | Buffer | Symlink)
}

type Api = {
    fixturePath: string // Fixture root path
    filePath: string // Current file path
    getPath: (...paths: string[]) => string // Get path from fixture root
    symlink: (target: string) => Symlink // Create a symlink
}

The subset of fs/promises methods that custom filesystem implementations must provide:

type FsPromises = {
    // Required
    readFile(path: string, options?): Promise<Buffer | string>
    writeFile(path: string, data: string | Buffer, options?): Promise<void>
    readdir(path: string, options?): Promise<string[] | Dirent[]>
    mkdir(path: string, options?): Promise<string | undefined>
    rename(oldPath: string, newPath: string): Promise<void>
    access(path: string, mode?: number): Promise<void>

    // Optional
    rm?(path: string, options?): Promise<void>
    unlink?(path: string): Promise<void>
    rmdir?(path: string): Promise<void>
    symlink?(target: string, path: string, type?: string): Promise<void>
    cp?(source: string, destination: string, options?): Promise<void>
    mkdtemp?(prefix: string): Promise<string>
}

If rm is not available, fs-fixture falls back to recursive removal using readdir({ withFileTypes }) + unlink + rmdir. If mkdtemp is not available, fixture paths are generated with a counter.

Related

manten

Lightweight testing library for Node.js