node.jsjestjsargv

testing a function that takes argv as argument


how can I test a function running from the command line? so this write function takes some input data and from a file uses another function to convert it and write to another file. so the script 2args is the write function path and 3rd is the input and the 4th is the output path. the function is working properly but I need to write the tests for the function.

script is this: "theme:figmaToChakra": "ts-node --esm src/utils/theme/figmaToChakra/write/index.ts src/theme/tokens/figma.json src/theme/tokens/chakra.ts && pnpm prettier src/theme/tokens/chakra.ts --write && pnpm theme:ts",

import { readFileSync, writeFileSync } from 'fs';
import path from 'path';
import { FigmaTokens } from '../../types';
import { figmaToChakra } from '..';

type Read = (file: string | number) => Promise<FigmaTokens>;

const read: Read = async (file) => {
  const dataStr = readFileSync(file, 'utf-8');
  const data = JSON.parse(dataStr);

  return data;
};

type Write = () => void;

export const write: Write = async () => {
  const args = process.argv;

  if (args.length !== 4) {
    console.log(`usage: ${args[0]} ${args[1]} input output`);
    process.exit(1);
  }

  const data = await read(args[2]);
  const output = figmaToChakra(data);

  let p = path.relative(__dirname, 'src/utils/theme');

  if (p !== '..' && p.indexOf('/') === -1) {
    p = p.match(/\.{1,2}/g)?.join('/') || '.';
  }

  writeFileSync(
    args[3],
    `import { ChakraTokens } from '${p}';\n\nexport const tokens: ChakraTokens = ${JSON.stringify(
      output
    )} `,
    'utf8'
  );
};

write();

I wrote these tests to execute the function. path.resolve(__dirname, './index.ts') is the function path itself but the function is always giving an error jest worker encountered 4 child process exceptions, exceeding the retry limit. process.exit called with "1". How can I execute the tests properly way for this? so that i got 100%coverage

    test('...', () => {
  const originalArgv = process.argv;
  process.argv = [
    'ts-node',
    path.resolve(__dirname, './index.ts'),
    path.resolve(__dirname, './x.json'),
    path.resolve(__dirname, './x.ts'),
  ];

  write();

  process.argv = originalArgv;
});

Solution

  • The first thing you're doing wrong is test('...', () => {. You are unsure what you're trying to test and this makes it hard to answer your question.

    Your write method does a lot of things, reads data, process it, computes a path as well and then exports the data. This method look like an integration test, not a unit test to pursue 100% test coverage. Additionally, it's dependent on the current working directory, so it will be difficult to achieve 100% test coverage as you have a branch for testing if p is not .. or /.

    Additionally, it returns void so you don't have an easy way to assert if everything worked correctly or not. It makes sense to return void since it does a few operations instead of computing a result, but it makes testing a lot harder.

    I'd test figmaToChakra function, maybe extract the logic you're doing for computing that path into a function and test it as well. Your write method might as well receive an array as input and call it like write(process.argv). You wouldn't have to mock/simulate process.argv and makes testing easier.