Overview
I think you all know the popular library for creating CLIs called yargs. That is what we are going to be using. Our CLI should reverse a string.
$ reverse reverse --string string
gnirts
Setup
Create a folder for your project. Then run these commands inside of it.
$ npm init -y
$ npm install -D typescript @types/yargs @types/node
$ npm install --save yargs
Make sure you set the bin
attribute of your package.json
to dist/cli.js
and the main
to dist/index.js
. Make your tsconfig.json
look like this:
{
"compilerOptions": {
"esModuleInterop": true,
"module": "CommonJS",
"moduleResolution": "node",
"outDir": "./dist",
"target": "ESNext"
},
"exclude": ["node_modules", "**/*.spec.ts"],
"include": ["src/**/*"]
}
Creating The CLI
Inside src/cli.ts
, write this:
#!/usr/bin/env node
import yargs from "yargs";
yargs
.scriptName("reverse")
.usage("$0 <cmd> [args]")
.command(
"reverse [string]",
"reverse the string",
(y) => {
y.positional("string", {
type: "string",
default: "string",
describe: "string to reverse",
});
},
(argv) => {
console.log(argv.string.split("").reverse().join(""));
}
)
.help().argv;
and now you have a working CLI!
Unit Testing API
First before we create actual tests, we need to change the structure of the project. Create a file called src/index.ts
and put this inside of it:
export function reverseString(str: string) {
return str.split("").reverse().join("");
}
Inside of src/cli.ts
add an import statement to the top to import reverseString
from index.ts
and change the callback to do this:
console.log(reverseString((argv.string as string)));
So now our CLI has the structure to support unit testing!
So now run these commands:
$ npm install -D mocha chai
Also, set your test
script to tsc && mocha test/**/*.js
.
Now under test/api/reverseString.spec.js
write this:
const { expect } = require("chai");
const { reverseString } = require("../../dist/index");
describe(".reverseString", () => {
it("should reverse properly", () => {
expect(reverseString("foo")).to.equal("oof");
});
});
But, this really isn't testing the actual CLI, just the API under it.
Testing the CLI
Under test/cli/reverse.spec.js
write this:
const { expect } = require("chai");
const { execSync } = require("child_process");
const test = (args) => {
return execSync(`node dist/cli.js reverse ${args}`).toString();
};
describe("CLI", () => {
it("should use the positional argument", () => {
expect(test("--string foo")).to.equal("oof\n");
});
it("should use the non positional argument", () => {
expect(test("foo")).to.equal("oof\n");
});
});
This is probably the worst way to test it, so if you have a better way, feel free to put it in the comments.
Top comments (0)