Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[WIP] test(cli): setting-up some tests for the CLI #233

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions .github/workflows/release-please.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ on:
push:
branches:
- main
- release-v4
name: release-please
jobs:
release-please:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ dist
build
lib
.vscode
.idea
src/cli/fixtures/**/*.zod.ts
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
"prepublishOnly": "yarn test:ci && rimraf lib && yarn build",
"lint": "eslint . --ext=.js,.ts,.json --report-unused-disable-directives --max-warnings 0",
"lint:fix": "npm run lint -- --fix",
"test": "jest",
"test:ci": "jest --ci --coverage && yarn gen:all && tsc --noEmit",
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
"test:ci": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --ci --coverage && yarn gen:all && tsc --noEmit",
"gen:all": "./bin/run --all",
"gen:example": "./bin/run --config example",
"gen:config": "./bin/run --config config",
Expand Down Expand Up @@ -59,6 +59,7 @@
"@babel/core": "^7.23.2",
"@babel/preset-env": "^7.23.2",
"@babel/preset-typescript": "^7.23.2",
"@oclif/test": "^4.0.3",
"@types/fs-extra": "^11.0.3",
"@types/inquirer": "^8.1.3",
"@types/jest": "^29.5.7",
Expand All @@ -69,11 +70,13 @@
"auto-changelog": "^2.4.0",
"babel-jest": "^29.7.0",
"codecov": "^3.8.3",
"cross-env": "^7.0.3",
"eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"husky": "^8.0.3",
"jest": "^29.7.0",
"mock-stdin": "^1.0.0",
"pretty-quick": "^3.1.0",
"rimraf": "^5.0.5",
"ts-node": "^10.9.1"
Expand Down
22 changes: 22 additions & 0 deletions src/__snapshots__/cli.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Config Prompt Tests Skip config prompt should have selected the right option and generated the file not in the config 1`] = `
"? You have multiple configs available in "ts-to-zod.config.js"
What do you want? (Use arrow keys)
❯ Execute all configs (--all)
Execute "example" config (--config=example)
Execute "example/person" config (--config=example/person)
Execute "config" config (--config=config)
Don't use the config ? You have multiple configs available in "ts-to-zod.config.js"
What do you want?
Execute all configs (--all)
Execute "example" config (--config=example)
Execute "example/person" config (--config=example/person)
Execute "config" config (--config=config)
❯ Don't use the config ? You have multiple configs available in "ts-to-zod.config.js"
What do you want? Don't use the config
- Validating generated types
✔ Validating generated types
🎉 Zod schemas generated!
"
`;
134 changes: 134 additions & 0 deletions src/cli.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { runCommand } from "@oclif/test";
import fs from "fs";
import { sep, posix } from "path";

/**
* For the CLI tests to run, we need to run them in a Node environment with
* the NODE_OPTIONS=--experimental-vm-modules flag. This is because Jest ships
* with experimental support for ECMAScript Modules (ESM).
* See: https://jestjs.io/docs/ecmascript-modules
*/

describe("Oclif-provided Flags Tests", () => {
describe("--help flag", () => {
it("should provide the right help message", async () => {
const { stdout } = await runCommand([".", "--help"]);

expect(stdout).toMatchInlineSnapshot(`
"Generate Zod schemas from a Typescript file

USAGE
$ ts-to-zod --all
$ ts-to-zod --config example
$ ts-to-zod --config example/person
$ ts-to-zod --config config

ARGUMENTS
INPUT input file (typescript)
OUTPUT output file (zod schemas)

FLAGS
-a, --all Execute all configs
-c, --config=<option> Execute one config
<options: example|example/person|config>
-h, --help Show CLI help.
-i, --init Create a ts-to-zod.config.js file
-k, --keepComments Keep parameters comments
-v, --version Show CLI version.
-w, --watch Watch input file(s) for changes and re-run
related task
--inferredTypes=<value> Path of z.infer<> types file
--skipParseJSDoc Skip the creation of zod validators from JSDoc
annotations
--skipValidation Skip the validation step (not recommended)

DESCRIPTION
Generate Zod schemas from a Typescript file

EXAMPLES
$ ts-to-zod src/types.ts src/types.zod.ts

"
`);
});
});
});

// describe("Ts-to-zod flags Tests", () => {});
// describe("EXIT codes Tests", () => {});

describe("Config Prompt Tests", () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let stdin: any;
beforeEach(() => {
stdin = require("mock-stdin").stdin();
});
describe("Skip config prompt", () => {
it("should have selected the right option and generated the file not in the config", async () => {
const basicInputPath = makePosixPath("src/cli/fixtures/basic/input.ts");
const basicSnapshotPath = makePosixPath(
"src/cli/fixtures/basic/output.zod.snapshot.ts"
);
const basicOutputPath = makePosixPath(
"src/cli/fixtures/basic/output.zod.ts"
);

// Up Arrow key code \u001B[A + ENTER key code \n with a delay of 2000ms
setTimeout(() => stdin.send("\u001B[A\n"), 2000);

const { stdout } = await runCommand([
".",
basicInputPath,
basicOutputPath,
]);

expect(
removeLoadingDots(replaceAngleBracket(normalizeLineEndings(stdout)))
).toMatchSnapshot();

expect(stdout).toContain("✔ Validating generated types");

expect(readFileCrossEnv(basicOutputPath)).toEqual(
readFileCrossEnv(basicSnapshotPath)
);

removeFile(basicOutputPath);
});
});
afterEach(() => {
stdin.restore();
});
});

function removeFile(filePath: string) {
fs.unlinkSync(filePath);
}

function makePosixPath(str: string) {
return str.split(sep).join(posix.sep);
}

function removeLoadingDots(content: string) {
return content.replace(/(⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧) Validating generated types/g, "");
}

function normalizeLineEndings(content: string) {
return content.replace(/\r\n/g, "\n"); // Replace Windows (\r\n) with Unix (\n)
}

/**
* Angle brackets from inquirer prompts are not the same in Windows & Unix
* This function replaces them with a consistent character
*/
function replaceAngleBracket(content: string) {
return content.replace(/>/g, "❯");
}

/**
* Gets the string content of a file and normalizes a few things to make it comparable to snapshots
*/
function readFileCrossEnv(path: string) {
return replaceAngleBracket(
normalizeLineEndings(fs.readFileSync(path, "utf-8").toString())
);
}
5 changes: 4 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,10 @@ See more help with --help`,
errors.map(this.warn.bind(this));

if (!Flags.skipValidation) {
const validatorSpinner = ora("Validating generated types").start();
const validatorSpinner = ora({
text: "Validating generated types",
stream: process.stdout,
}).start();
if (Flags.all) validatorSpinner.indent = 1;

const extraFiles = [];
Expand Down
4 changes: 4 additions & 0 deletions src/cli/fixtures/basic/input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type Test = {
name: string;
age: number;
};
7 changes: 7 additions & 0 deletions src/cli/fixtures/basic/output.zod.snapshot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Generated by ts-to-zod
import { z } from "zod";

export const testSchema = z.object({
name: z.string(),
age: z.number(),
});
4 changes: 2 additions & 2 deletions src/core/generate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1305,11 +1305,11 @@ describe("generate", () => {
"// Generated by ts-to-zod
import { z } from "zod";

import { heroSchema } from "${output}";
import { zHero } from "${output}";

export const zPerson = z.object({
id: z.number(),
hero: heroSchema
hero: zHero
});
"
`);
Expand Down
3 changes: 1 addition & 2 deletions src/core/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,7 @@ export function generate({
);

if (eligibleMapping) {
const schemaMethod =
eligibleMapping.getSchemaName || DEFAULT_GET_SCHEMA;
const schemaMethod = eligibleMapping.getSchemaName || getSchemaName;

identifiers.forEach(({ name }) =>
importedZodNamesAvailable.set(name, schemaMethod(name))
Expand Down
40 changes: 36 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1688,6 +1688,14 @@
wordwrap "^1.0.0"
wrap-ansi "^7.0.0"

"@oclif/test@^4.0.3":
version "4.0.3"
resolved "https://registry.yarnpkg.com/@oclif/test/-/test-4.0.3.tgz#718d8aabe64aca6040cd4c6085a9e34f124768db"
integrity sha512-LxcRYVFTUHoOW2Koo1lmbEwl/4HRFIdNWXuUY1/PHEawjwLvp3xwVe2rOWGqYD+vlHr+TYUw2QDQc8e2vUTDrw==
dependencies:
ansis "^3.2.0"
debug "^4.3.5"

"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
Expand Down Expand Up @@ -2085,6 +2093,11 @@ ansicolors@~0.3.2:
resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979"
integrity sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==

ansis@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ansis/-/ansis-3.2.0.tgz#0e050c5be94784f32ffdac4b84fccba064aeae4b"
integrity sha512-Yk3BkHH9U7oPyCN3gL5Tc7CpahG/+UFv/6UG03C311Vy9lzRmA5uoxDTpU9CO3rGHL6KzJz/pdDeXZCZ5Mu/Sg==

anymatch@^3.0.3:
version "3.1.1"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
Expand Down Expand Up @@ -2608,7 +2621,14 @@ create-require@^1.1.0:
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==

cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
cross-env@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
dependencies:
cross-spawn "^7.0.1"

cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
Expand Down Expand Up @@ -2638,6 +2658,13 @@ debug@^4.3.2, debug@^4.3.4:
dependencies:
ms "2.1.2"

debug@^4.3.5:
version "4.3.5"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e"
integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==
dependencies:
ms "2.1.2"

dedent@^1.0.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff"
Expand Down Expand Up @@ -4170,6 +4197,11 @@ minimist@^1.2.5:
resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==

mock-stdin@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/mock-stdin/-/mock-stdin-1.0.0.tgz#efcfaf4b18077e14541742fd758b9cae4e5365ea"
integrity sha512-tukRdb9Beu27t6dN+XztSRHq9J0B/CoAOySGzHfn8UTfmqipA5yNT/sDUEyYdAV3Hpka6Wx6kOMxuObdOex60Q==

mri@^1.1.5:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
Expand Down Expand Up @@ -4512,9 +4544,9 @@ pretty-quick@^3.1.0:
multimatch "^4.0.0"

prompts@^2.0.1:
version "2.4.0"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.0.tgz#4aa5de0723a231d1ee9121c40fdf663df73f61d7"
integrity sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==
version "2.4.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
dependencies:
kleur "^3.0.3"
sisteransi "^1.0.5"
Expand Down