Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Support flexible fixture creation API #16

Closed
mizdra opened this issue Jul 23, 2023 · 0 comments · Fixed by #20
Closed

Support flexible fixture creation API #16

mizdra opened this issue Jul 23, 2023 · 0 comments · Fixed by #20
Labels
Type: Add Add new features.
Milestone

Comments

@mizdra
Copy link
Owner

mizdra commented Jul 23, 2023

Motiavtion

The current inline-fixtures-files API does not support the creation of binary files. Also, there is no way to modify file metadata such as mode or mtime.

This proposal provides a flexible API for creating various variations of files.

Design

  • Provides a programmable file creation interface to meet diverse needs
    • e.g. await createIFF({ 'file.txt': (path) => writeFile(path, Buffer.from([0x00, 0x01])) })
  • Do not automatically create parent directories.
    • To allow users to control how parent directories are created as well, parent directories are not automatically created.

Example

import { defineIFFCreator } from '@mizdra/inline-fixture-files';
import { writeFile, utimes, cp, symlink, mkdir } from 'node:fs/promises';
import { constants } from 'node:fs';
import { dirname, join } from 'node:path';

const fixtureBaseDir = join(tmpdir(), 'your-app-name', process.env['VITEST_POOL_ID']!);
const createIFF = defineIFFCreator({
  generateRootDir: () => join(fixtureBaseDir, randomUUID()),
});

// Example: File
const iff1 = await createIFF({
  'buffer.txt': (path) => writeFile(path, Buffer.from([0x00, 0x01])),
  'encoding.txt': (path) => writeFile(path, 'text', { encoding: 'utf16le' }),
  'mode.txt': (path) => writeFile(path, 'text', { mode: 0o600 }),
  'flag.txt': (path) => writeFile(path, 'text', { flag: 'wx' }),
  'utime.txt': async (path) => {
    await writeFile(path, 'text');
    await utimes(0, 0);
  },
  'cp.txt': (path) => cp('./cp.txt', path, { mode: constants.COPYFILE_FICLONE }),
  'symlink.txt': (path) => symlink('./symlink.txt', path),
  // NOTE: The flexible file creation API does not automatically create parent directories.
  // Therefore, you must manually create the parent directories in order to create nested files.
  'nested/file.txt': async (path) => {
    await mkdir(dirname(path));
    await writeFile(path, 'text', { mode: 0o600 });
  },
});
expectType<{
  'buffer.txt'': string;
  'encoding.txt': string;
  'mode.txt': string;
  'flag.txt': string;
  'utime.txt': string;
  'cp.txt': string;
  'symlink.txt': string;
  'nested': string;
  'nested/file.txt': string;
}>(iff1.paths);

// Example: Directory
const iff2 = await createIFF({
  'mode': (path) => mkdir(path, { mode: 0o600 }),
  'cp': (path) => cp('./cp', path, { mode: constants.COPYFILE_FICLONE }),
  'symlink': (path) => symlink('./symlink', path),
  // NOTE: The flexible file creation API does not automatically create parent directories.
  // Therefore, the recursive option is required to create nested directories.
  'nested/directory': (path) => mkdir(path, { mode: 0x600, recursive: true }),
}).addFixtures({
  // Use the add function to add files to the directory created by the flexible file creation API.
  'mode': {
    'file1.txt': 'file1',
  },
  // If you want to include the paths to the files in the copied directory in `iff2.paths`,
  // you can use the following hack:
  'cp': {
    'file1.txt': () => {}, // noop
  },
});
expectType<{
  'mode': string;
  'mode/file1.txt': string;
  'cp': string;
  'cp/file1.txt': string;
  'symlink': string;
  'nested': string;
  'nested/directory': string;
}>(iff2.paths);

Drawbacks

  • A runtime error will occur if the user forgets to create the parent directory of the nested file/directory.
    • const iff1 = await createIFF({
        // A runtime error occurs that there are no nested directories.
        'nested/file.txt': (path) => writeFile(path, 'text', { mode: 0o600 }),
      });
    • This can be confusing to users.
    • I think it would be desirable to provide the ability to wrap errors and display better warnings to the user.
    • const iff1 = await createIFF({
        // IFFParentDirectoryNotFoundError: There is no parent directory (`nested`). Did you forget to create the parent directory?
        // The flexible file creation API does not automatically create the parent directory, you have to create it manually.
        'nested/file.txt': (path) => writeFile(path, 'text', { mode: 0o600 }),
      });
@mizdra mizdra added the Type: Add Add new features. label Jul 23, 2023
@mizdra mizdra changed the title Support for creating binary files Support flexible file creation API Jul 23, 2023
@mizdra mizdra added this to the 1.0.0 milestone Jul 29, 2023
@mizdra mizdra changed the title Support flexible file creation API Support flexible fixture creation API Jul 29, 2023
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Type: Add Add new features.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant