Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fs-syncer

Package Overview
Dependencies
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fs-syncer

A helper to recursively read and write text files to a specified directory

  • 0.5.3
  • latest
  • npm
  • Socket score

Version published
Weekly downloads
1.4K
increased by25.36%
Maintainers
1
Weekly downloads
 
Created
Source

fs-syncer

A helper to recursively read and write text files to a specified directory.

CI npm version

The idea

It's a pain to write tests for tools that interact with the filesystem. It would be useful to write assertions that look something like:

expect(someDirectory.read()).toEqual({
  'file1.txt': 'some info',
  'file2.log': 'something logged',
  nested: {
    sub: {
      directory: {
        'deeply-nested-file.sql': 'SELECT * FROM abc'
      },
    },
  },
})

Similarly, as part of test setup, you might want to write several files, e.g.:

write({
  migrations: {
    'migration1.sql': 'create table one(id text)',
    'migration2.sql': 'create table two(id text)',
    down: {
      'migration1.sql': 'drop table one',
      'migration2.sql': 'drop table two',
    },
  },
})

The problem is that usually, you have to write a recursive directory-walker function, an object-to-filepath converter function, a nested-object-getter-function and a few more functions that tie them all together.

Then, if you have the energy, you should also write a function that cleans up any extraneous files after tests have been run. Or, you can pull in several dependencies that do some of these things for you, then write some functions that tie them together.

Now, you can just use fs-syncer, which does all of the above. Here's the API:

import {fsSyncer} from 'fs-syncer'

const syncer = fsSyncer(__dirname + '/migrations', {
  'migration1.sql': 'create table one(id text)',
  'migration2.sql': 'create table two(id text)',
  down: {
    'migration1.sql': 'drop table one',
    'migration2.sql': 'drop table two',
  },
})

syncer.sync() // replaces all content in `./migrations` with what's described in the target state

syncer.read() // returns the filesystem state as an object, in the same format as the target state

// write a file that's not in part of the target state
require('fs').writeFileSync(__dirname + '/migrations/extraneous.txt', 'abc', 'utf8')

syncer.read() // includes `extraneous.txt: 'abc'`

syncer.sync() // 'extraneous.txt' will now have been removed

syncer.write() // like `syncer.sync()`, but doesn't remove extraneous files

Usage with vitest or jest

⚠️⚠️⚠️ This feature is new and experimental - if you try it out, be aware that the API is in flux. Feedback is welcome! ⚠️⚠️⚠️

If you happen to want to use this in a jest test, there's an opinionated helper which allows you to avoid supplying a baseDir parameter.

Let's say you want to test a file modification tool, which appends // comments to all the files it finds under a certain directory, and also creates a log file:

import {testFixture} from 'fs-syncer'

import {fileModificationToolThatYouWantToTest} from '../src/your-library'

test('files are modified', async () => {
  const fixture = testFixture({
    expect,
    targetState: {
      'file1.txt': 'hello I am a file',
      nested: {
        'file2.txt': 'I am also a file',
      }
    }
  })

  fixture.sync()

  await fileModificationToolThatYouWantToTest.run({
    directory: fixture.baseDir,
    logFile: 'abc.log',
  })

  expect(fixture.yaml()).toMatchInlineSnapshot()
})

fixture.yaml() is a helper that returns a yaml string representing the file tree. It's intended to be human-readable and familiar, and should not be relied on to be valid yaml, it's mostly for test snapshots.

Let's assume the test file containing this test is called my-test-file.test.ts. When run, the above test will generate a directory fixtures/my-test-file.test.ts/files-are-modified next to the test file. The directory structure described in targetState will be created inside that folder. The test above might end up looking something like when run:

import {testFixture} from 'fs-syncer'

import {fileModificationToolThatYouWantToTest} from '../src/your-library'

test('files are modified', async () => {
  const fixture = testFixture({
    expect,
    targetState: {
      'file1.txt': 'hello I am a file',
      nested: {
        'file2.txt': 'I am also a file',
      }
    }
  })

  fixture.sync()

  await fileModificationToolThatYouWantToTest.run({
    directory: fixture.baseDir,
    logFile: 'abc.log',
  })

  expect(fixture.yaml()).toMatchInlineSnapshot(
    `"---
    abc.log: |-
      added content to file1.txt
      added content to nested/file2.txt
    file1.txt: |-
      hello I am a file

      // this content was auto-generated by the tool
    nested:
      file2.txt: |-
        hello I am a file

        // this content was auto-generated by the tool
    "`
  )
})

Not supported (right now)

  • File content other than text, e.g. Buffers. The library assumes you are solely dealing with utf8 strings.
  • Any performance optimisations - you will probably have a bad time if you try to use it to read or write a very large number of files.
  • Any custom symlink behaviour.

Comparison with mock-fs

This isn't a mocking library. There's no magic under the hood, it just calls fs.readFileSync, fs.writeFileSync and fs.mkdirSync directly. Which means you can use it anywhere - it could even be a runtime dependency as a wrapper for the fs module. And using it doesn't have any weird side-effects like breaking jest snapshot testing. Not being a mocking library means you could use it in combination with mock-fs, if you really wanted.

FAQs

Package last updated on 23 Feb 2024

Did you know?

Socket

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.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc