File system

File System

The file system plugin allows you to work with temporary files and directories during tests and write assertions against them.

The filesystem plugin provides the following conveniences over manually using the fs module APIs.

  • The temporary files are created inside your operating system's tmp folder. You can override the path if needed.
  • Files created during a test are auto-removed after the test is completed.
  • Assertion methods to assert a file exist, have expected content, and much more.

Installation

You can install the plugin from the npm packages registry as follows.

npm i -D @japa/file-system

And register it as a plugin within the entry point file, i.e. (bin/test.js)

import { fileSystem } from '@japa/file-system'
import { configure } from '@japa/runner'
configure({
files: ['tests/**/*.spec.js'],
plugins: [fileSystem()]
})

Basic usage

Once the plugin has been registered, you can access the fs property from the test context. The fs property exposes the helper functions to read and write files. For example:

test('read rc file', async ({ fs }) => {
await fs.writeJSON('rc.json', {
foo: 'bar'
})
await runMethodThatNeedsRcFile()
})

A few things are happening here.

  • First, you do not have to construct absolute paths to write the file. The file system plugin writes the files inside your operating system's tmp directory.
  • You do not have to clean up any files or directories. The filesystem plugin will automatically perform the cleanup after the test finishes.

You can specify a custom base directory or turn off the auto cleaning of files using the following configuration options.

{
plugins: [
fileSystem({
basePath: new URL('./tmp', import.meta.url),
autoClean: false,
})
]
}

Assertions

The filesystem plugin extends the assert plugin and adds the following assertion methods. All file system assertion methods are asynchronous.

fileExists/dirExists

Assert a file or a directory exists at a given location.

test('make controller', ({ assert, fs }) => {
await makeController(fs.basePath, 'users')
await assert.fileExists('controllers/users_controller.ts')
})
ArgumentType
filePathString

fileNotExists/dirNotExists

Assert a file or a directory should not exist at a given location.

test('make controller', ({ assert, fs }) => {
await makeController(fs.basePath, 'users', { dryRun: true })
await assert.fileNotExists('controllers/users_controller.ts')
})
ArgumentType
filePathString

fileEquals

Assert the contents of the file against a string value.

test('make controller', ({ assert, fs }) => {
await makeController(fs.basePath, 'users')
await assert.fileEquals('controllers/users_controller.ts', `
export default class UsersController {}
`)
})
ArgumentType
filePathString
contentsString

fileContains

Assert the file contents to contain a substring or match a regular expression.

test('make controller', ({ assert, fs }) => {
await makeController(fs.basePath, 'users')
await assert.fileContains(
'controllers/users_controller.ts',
'class UsersController'
)
await assert.fileContains(
'controllers/users_controller.ts',
/class UsersController/
)
})

You may pass an array of substrings to check if all the mentioned values are part of the file contents.

test('make controller', ({ assert, fs }) => {
await makeController(fs.basePath, 'users')
await assert.fileContains(
'controllers/users_controller.ts',
[
'export default class UsersController {',
'async index() {', // should have index method
'async store() {', // should have store method
]
)
})
ArgumentType
filePathString
substringString | String[] | Regexp

fileNotContains

Assert the file contents does not contain one of the unexpected values. The unexpected values can be a substring or an array of substrings.

test('make controller', ({ assert, fs }) => {
await makeController(fs.basePath, 'users')
await assert.fileNotContains(
'controllers/users_controller.ts',
[
'export default class UsersController {',
'async destroy() {', // should not have destroy method
'async update() {', // should not have update method
]
)
})
ArgumentType
filePathString
substringString | String[] |

fileSameAs

Assert the contents of the file match the contents of another file.

test('make controller', ({ assert, fs }) => {
await makeController(fs.basePath, 'users')
await assert.fileSameAs(
'controllers/users_controller.ts',
'stubs/controller/make'
)
})
ArgumentType
filePathString
otherFilePathString

fileIsEmpty

Assert the file exists and is empty or has only whitespaces.

test('make preload file', ({ assert, fs }) => {
await makePreloadFile(fs.basePath, 'routes')
await assert.fileIsEmpty('start/routes.ts')
})
ArgumentType
filePathString

fileIsNotEmpty

Assert the file exists and is not empty.

test('make routes file', ({ assert, fs }) => {
await makeRoutesFile(fs.basePath)
await assert.fileIsNotEmpty('start/routes.ts')
})
ArgumentType
filePathString

hasFiles

Assert the root of the filesystem has all the mentioned files.

test('copy stubs', ({ assert, fs }) => {
await copyStubs(fs.basePath)
await assert.hasFiles([
'make/controller/main.stub',
'make/event/main.stub',
'make/listener/main.stub',
'make/command/main.stub',
])
})
ArgumentType
filesString[]

doesNotHaveFiles

Assert the filesystem's root does not have any of the mentioned files.

test('copy stubs', ({ assert, fs }) => {
await copyStubs(fs.basePath, { dryRun: true })
await assert.doesNotHaveFiles([
'make/controller/main.stub',
'make/event/main.stub',
'make/listener/main.stub',
'make/command/main.stub',
])
})
ArgumentType
filesString[]

dirIsEmpty

Assert a given directory is empty.

test('copy stubs', ({ assert, fs }) => {
await copyStubs(fs.basePath, { dryRun: true })
await assert.dirIsEmpty('make')
})
ArgumentType
dirPathString?

dirIsNotEmpty

Assert a given directory is not empty.

test('copy stubs', ({ assert, fs }) => {
await copyStubs(fs.basePath)
await assert.dirIsNotEmpty('make')
})
ArgumentType
dirPathString?

File system API

Following is the list of methods available on the ctx.fs property. All methods accept relative paths.

cleanup

Remove the file system root directory. If you have turned off autoClean, you might want to use this method as a hook to clean up files after each test.

test.group('Make files', (group) => {
group.each.setup(({ context }) => {
return () => context.fs.cleanup()
})
})

create

Create a file at a given location. The missing directories will be created automatically.

test('read rc file', async ({ fs }) => {
await fs.write('rc.json', JSON.stringify({
foo: 'bar'
}))
})
ArgumentType
filePathString
contentsString
optionsWriteFileOptions

remove

Remove a file or a directory by its location.

test('delete rc file', async ({ fs }) => {
await fs.remove('rc.json')
})
ArgumentType
filePathString

rootExists

Check if the root directory of the file system exists. The method returns a boolean value.

test.group('Make files', (group) => {
group.each.setup(({ context }) => {
return async () => {
if (await context.fs.rootExists()) {
await context.fs.cleanup()
}
}
})
})

exists

Check if a directory exists. The method returns a boolean value.

test('do not update rc file', async ({ fs }) => {
if (await fs.exists('rc.json')) {
await fs.create('rc.json', contents)
}
})
ArgumentType
filePathString

contents

Returns the contents of a file as a string

test('read rc file', async ({ fs }) => {
const contents = await fs.contents('rc.json')
})
ArgumentType
filePathString

dump

Dump file contents to the stdout for debugging

test('read rc file', async ({ fs }) => {
await fs.dump('rc.json')
})
ArgumentType
filePathString

stats

Get fs.Stats for a file by its location.

test('read rc file', async ({ fs }) => {
const stats = await fs.stats('rc.json')
})
ArgumentType
filePathString

readDir

Get an array of files for a directory. The return value is an array of EntryInfo objects.

test('copy files', async ({ fs }) => {
const entries = await fs.readDir('make')
entries.forEach((entry) => {
console.log(entry.path)
console.log(entry.fullPath)
console.log(entry.basename)
console.log(entry.stats)
})
})
ArgumentType
filePathString

mkdir

Create a directory recursively inside the root of the file system.

test('copy files', async ({ fs }) => {
await fs.mkdir('make/controller')
})
ArgumentType
dirPathString