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

vitest-memfs

v1.5.1

Published

Custom Vitest matchers for working with memfs

Readme

vitest-memfs

Custom Vitest matchers for working with memfs.

Useful when testing code that reads/writes to the filesystem without touching the real disk.

Usage

Install with your favorite package manager:

$ pnpm add -D vitest-memfs

Add a setup file to your Vitest config:

// `vite.config.ts`
import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    setupFiles: ['tests-setup.ts'],
  },
})

Setup file:

// `tests-setup.ts`

// Register all matchers
import 'vitest-memfs/setup'

// Or only the ones you need
import { toMatchVolume } from 'vitest-memfs/matchers'
expect.extend({ toMatchVolume })

Matchers

toHaveVolumeEntries

Checks that certain paths or glob patterns exist in a memfs volume, with optional type checks.

import { Volume } from 'memfs'

it('checks that paths are present', () => {
  const vol = Volume.fromJSON({
    '/package.json': '{}',
    '/foo.txt': 'hello',
    '/src/index.ts': 'export {}',
    '/src/utils/math.ts': 'export const add = () => {}',
  })

  // exact paths
  expect(vol).toHaveVolumeEntries(['/foo.txt', '/src'])
  // with type checks
  expect(vol).toHaveVolumeEntries({
    '/foo.txt': 'file',
    '/src': 'dir',
  })

  // glob patterns
  expect(vol).toHaveVolumeEntries(['*.txt', 'src/**/*.ts'])
  expect(vol).toHaveVolumeEntries({ 'src/**/*.ts': { count: 3 } }) // ❌ found 2/3 files

  // prefix + relative paths
  expect(vol).toHaveVolumeEntries(['/foo.txt', 'utils/*.ts'], { prefix: '/src' })

  // negated assertions
  expect(vol).not.toHaveVolumeEntries(['package.json', 'src/**/*.ts'])
})

Supported Input Formats:

// string — single path or glob
expect(vol).toHaveVolumeEntries('/foo.txt')
expect(vol).toHaveVolumeEntries('src/**/*.ts')

// array — mix of strings or objects
expect(vol).toHaveVolumeEntries(['/foo.txt', { path: 'src/**/*.ts', type: 'file', count: 2 }])

// object — mapping of path/glob → type or options
expect(vol).toHaveVolumeEntries({
  '/foo.txt': 'file',
  'src/**/*.ts': { type: 'file', count: 2 },
})

Notes:

  • Supports exact paths and glob patterns (negated globs like !**/*.d.ts are not supported).
  • Types can be file | dir | symlink | any (default).
  • count can enforce a minimum number of matches (default: 1).
  • Only existence/type are checked — file contents and symlink targets are ignored.

toMatchVolume

Compare two memfs volumes (or a volume vs. JSON input).

import { Volume } from 'memfs'

it('compares volumes', () => {
  const vol1 = Volume.fromJSON({ '/foo.txt': 'hello' })
  const vol2 = Volume.fromJSON({ '/foo.txt': 'hello' })

  expect(vol1).toMatchVolume(vol2) // ✅ passes
  expect(vol1).toMatchVolume({ '/foo.txt': 'world' }) // ❌ mismatch in file "/foo.txt"

  // prefix
  const vol3 = Volume.fromJSON({ '/foo.txt': 'hello', '/src/bar.txt': 'world' })
  expect(vol3).toMatchVolume({ '/src/bar.txt': 'world' }, { prefix: '/src' })
  // ✅ passes: only `/src/bar.txt` is compared

  // ignore (exact path or glob)
  expect(vol3).toMatchVolume({ '/foo.txt': 'hello' }, { ignore: 'src/*.txt' })
  // ✅ passes: `/src/bar.txt` is skipped
})

toMatchVolumeSnapshot

Persist an entire memfs volume as a directory on disk and compare against it later.

This works like Vitest’s toMatchSnapshot, but for filesystem trees.

import { Volume } from 'memfs'

it('matches volume snapshot', async () => {
  const vol = Volume.fromJSON({ '/foo.txt': 'hello' })
  await expect(vol).toMatchVolumeSnapshot('foo-snap')

  // prefix
  const vol3 = Volume.fromJSON({ '/foo.txt': 'hello', '/src/bar.txt': 'world' })
  await expect(vol3).toMatchVolumeSnapshot('src-snap', { prefix: '/src' })
  // only files under `/src` are persisted/compared

  await expect(vol3).toMatchVolumeSnapshot('src-snap-ignore', { ignore: '*.txt' })
  // `/foo.txt` is skipped when writing or comparing the snapshot
})
  • On first run (or when using -u), a real directory is created under __snapshots__/.
  • On later runs, the volume is compared against that directory.

Options

Both toMatchVolume and toMatchVolumeSnapshot support the same options:

interface VolumeMatcherOptions {
  prefix?: string
  ignore?: string | string[]
  listMatch?: 'exact' | 'ignore-extra' | 'ignore-missing'
  contentMatch?: 'all' | 'ignore' | 'ignore-files' | 'ignore-symlinks'
  report?: 'first' | 'all'
  async?: boolean
  concurrency?: number
}
  • prefix
    • subdirectory → Limit comparisons to files under the given path (e.g. /src).
  • ignore
    • Exclude paths that match a glob, exact path or array of them (e.g. '**/*.log').
  • listMatch
    • exact → directory contents must match exactly (default).
    • ignore-extra → extra files in the received volume are ignored.
    • ignore-missing → missing files in the received volume are ignored.
  • contentMatch
    • all → compare file contents and symlink targets (default).
    • ignore → only check that paths and path types match and ignore the actual contents.
    • ignore-files → only ignore file content comparison.
    • ignore-symlinks → only ignore symlink target comparison.
  • report
    • first → stop on the first mismatch (default).
    • all → collect all mismatches and show a combined diff.
  • async
    • Run comparisons asynchronously (enabled by default for toMatchVolumeSnapshot).
  • concurrency
    • Limit async comparisons to N files at a time (default: 32).
    • Useful for throttling async work for large fixtures.

License

MIT