@hyperfrontend/testing/fsfs
Temporary directories that delete themselves, and fixture trees written into them from data the spec declares.
Usage
useTempDir registers the node:test hooks that give every test in the suite a fresh directory and delete it afterwards. The handle it returns always points at the current test's directory, so capture it once in the describe body:
import { describe, expect, it } from '@hyperfrontend/testing'
import { useTempDir } from '@hyperfrontend/testing/fs'
import { loadConfig } from './load-config'
describe('loadConfig', () => {
const dir = useTempDir({
tree: {
'package.json': { name: 'app' },
'src/index.ts': 'export const ready = true\n',
},
})
it('reads a config file beside the manifest', () => {
dir.write('hf.config.json', { strict: true })
expect(loadConfig(dir.path)).toEqual({ strict: true })
})
})
Pass scope: 'all' to share one directory across the suite instead. For a directory a single test owns, createTempDir creates it straight away and leaves removal to the caller: a matching after hook at module or suite scope, or a finally inside the one test that owns it. writeTree and writeFile write into any directory you already have.
File content
A FileTree maps relative paths to content. Parent directories are created as needed.
| Value | Written as |
|---|---|
| A string | The text, unchanged |
A Uint8Array | The bytes, unchanged |
| Any other value | Pretty-printed JSON followed by a newline |
Design
Fixtures held as data in the spec, rather than checked in as files, never look like a real manifest or lockfile to a dependency scanner, and the spec states every file it depends on.
The directory's path is reported with symbolic links resolved. On macOS the system temporary directory is a symbolic link, and on Windows it can be an 8.3 short name, so an unresolved path would differ from what process.cwd() or a resolved real path report inside the code under test. Writes refuse a path that is absolute or climbs out of the directory, since anything written there would survive the cleanup. Removal retries while Windows still holds a handle open inside the directory.
API Reference§
ƒ Functions
Use it at module or suite scope with a matching
after, or inside a single test with a finally that removes it. For a directory every test in a suite gets, useTempDir registers the hooks itself.Parameters
| Name | Type | Description |
|---|---|---|
§options | TempDirOptions | Name prefix, parent and initial files.(default: {}) |
Returns
TempDirExample
A directory one test owns
it('reads the manifest', () => {
const dir = createTempDir({ tree: { 'package.json': { name: 'app' } } })
try {
expect(readManifest(dir.path).name).toBe('app')
} finally {
dir.remove()
}
})node:test hooks that do it. Call it in a
describe body or at the top of a spec file. The returned handle reads the directory current at the time of each call, so it can be captured once and used from any test or hook. Reading it outside a test throws, since no directory exists then.Parameters
| Name | Type | Description |
|---|---|---|
§options | UseTempDirOptions | Name prefix, parent, initial files, and whether tests share one directory.(default: {}) |
Returns
TempDirExample
A fresh directory for every test
describe('loadConfig', () => {
const dir = useTempDir({ tree: { 'package.json': {} } })
it('finds a config file beside the manifest', () => {
dir.write('hf.config.json', { strict: true })
expect(loadConfig(dir.path)).toEqual({ strict: true })
})
})Parameters
| Name | Type | Description |
|---|---|---|
§root | string | The directory to write under. |
§relativePath | string | Where the file goes, relative to the root. |
§content | FileContent | What the file holds. |
Returns
stringExample
Writing a manifest as JSON
writeFile(root, 'packages/app/package.json', { name: 'app' })
// => '<root>/packages/app/package.json', holding '{\n "name": "app"\n}\n'Fixtures held as data in a spec, rather than checked in as files, never look like a real manifest or lockfile to a dependency scanner, and a spec states exactly the files it depends on. Every path must stay inside the root.
Parameters
Example
Laying out a small workspace
writeTree(root, {
'package.json': { name: 'workspace', workspaces: ['packages/*'] },
'packages/app/package.json': { name: 'app' },
'packages/app/src/index.ts': 'export const ready = true\n',
})◈ Interfaces
useTempDir creates and removes its directory.Properties
scope?:"each" | "all"each gives every test a fresh directory; all shares one across the suite. Defaults to each.◆ Types
type FileContent = string | Uint8Array | object/, which are created as needed.type FileTree = Record< string, FileContent>