Skip to content

Commit

Permalink
chore: add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
marvinhagemeister committed Feb 20, 2024
1 parent 4864c29 commit 30c8186
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 28 deletions.
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,26 @@
}
},
"scripts": {
"test": "node -r ts-node/register --test **/*.test.ts",
"cli": "ts-node src/bin.ts",
"build": "rimraf dist dist-esm && tsc && tsc -p tsconfig.esm.json",
"prepublishOnly": "tsc"
"prepublishOnly": "tsc && npm test"
},
"keywords": [],
"author": "",
"license": "MIT",
"files": ["dist/", "dist-esm/"],
"files": [
"dist/",
"dist-esm/"
],
"devDependencies": {
"@types/node": "^20.11.18",
"rimraf": "^5.0.5",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
},
"dependencies": {
"@std/encoding": "npm:@jsr/std__encoding@^0.216.0",
"kolorist": "^1.8.0"
}
}
33 changes: 12 additions & 21 deletions src/pkg_manager.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
import { InstallOptions } from "./commands";
import { JsrPackage, findProjectDir } from "./utils";
import { spawn } from "node:child_process";
import { JsrPackage, exec, findProjectDir } from "./utils";
import * as kl from "kolorist";

const exec = async (cmd: string, args: string[], cwd: string) => {
async function execWithLog(cmd: string, args: string[], cwd: string) {
console.log(kl.dim(`$ ${cmd} ${args.join(" ")}`));

const cp = spawn(cmd, args, { stdio: "inherit" });

return new Promise<void>((resolve) => {
cp.on("exit", (code) => {
if (code === 0) resolve();
else process.exit(code ?? 1);
});
});
};
return exec(cmd, args, cwd);
}

function modeToFlag(mode: InstallOptions["mode"]): string {
return mode === "dev"
? "--save-dev "
? "--save-dev"
: mode === "optional"
? "--save-optional "
? "--save-optional"
: "";
}

Expand All @@ -47,11 +38,11 @@ class Npm implements PackageManager {
}
args.push(...toPackageArgs(packages));

await exec("npm", args, this.cwd);
await execWithLog("npm", args, this.cwd);
}

async remove(packages: JsrPackage[]) {
await exec(
await execWithLog(
"npm",
["remove", ...packages.map((pkg) => pkg.toString())],
this.cwd
Expand All @@ -69,11 +60,11 @@ class Yarn implements PackageManager {
args.push(mode);
}
args.push(...toPackageArgs(packages));
await exec("yarn", args, this.cwd);
await execWithLog("yarn", args, this.cwd);
}

async remove(packages: JsrPackage[]) {
await exec(
await execWithLog(
"yarn",
["remove", ...packages.map((pkg) => pkg.toString())],
this.cwd
Expand All @@ -91,11 +82,11 @@ class Pnpm implements PackageManager {
args.push(mode);
}
args.push(...toPackageArgs(packages));
await exec("pnpm", args, this.cwd);
await execWithLog("pnpm", args, this.cwd);
}

async remove(packages: JsrPackage[]) {
await exec(
await execWithLog(
"yarn",
["remove", ...packages.map((pkg) => pkg.toString())],
this.cwd
Expand Down
28 changes: 23 additions & 5 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as path from "node:path";
import * as fs from "node:fs";
import { PkgManagerName } from "./pkg_manager";
import { spawn } from "node:child_process";

export let DEBUG = false;
export function setDebug(enabled: boolean) {
Expand All @@ -12,8 +13,8 @@ export function logDebug(msg: string) {
}
}

const EXTRACT_REG = /^@([a-z][a-z0-9-]+)\/([a-z0-9-]+)$/;
const EXTRACT_REG_PROXY = /^@jsr\/([a-z][a-z0-9-]+)__([a-z0-9-]+)$/;
const EXTRACT_REG = /^@([a-z][a-z0-9-]+)\/([a-z0-9-]+)(@.+)?$/;
const EXTRACT_REG_PROXY = /^@jsr\/([a-z][a-z0-9-]+)__([a-z0-9-]+)(@.+)?$/;

export class JsrPackageNameError extends Error {}

Expand All @@ -23,22 +24,28 @@ export class JsrPackage {
if (exactMatch !== null) {
const scope = exactMatch[1];
const name = exactMatch[2];
return new JsrPackage(scope, name);
const version = exactMatch[3] ?? "";
return new JsrPackage(scope, name, version);
}

const proxyMatch = input.match(EXTRACT_REG_PROXY);
if (proxyMatch !== null) {
const scope = proxyMatch[1];
const name = proxyMatch[2];
return new JsrPackage(scope, name);
const version = proxyMatch[3] ?? "";
return new JsrPackage(scope, name, version);
}

throw new JsrPackageNameError(
`Invalid jsr package name: A jsr package name must have the format @<scope>/<name>, but got "${input}"`
);
}

private constructor(public scope: string, public name: string) {}
private constructor(
public scope: string,
public name: string,
public version: string
) {}

toNpmPackage(): string {
return `@jsr/${this.scope}__${this.name}`;
Expand Down Expand Up @@ -131,3 +138,14 @@ export function prettyTime(diff: number) {

return diff + "ms";
}

export async function exec(cmd: string, args: string[], cwd: string) {
const cp = spawn(cmd, args, { stdio: "inherit", cwd });

return new Promise<void>((resolve) => {
cp.on("exit", (code) => {
if (code === 0) resolve();
else process.exit(code ?? 1);
});
});
}
188 changes: 188 additions & 0 deletions test/install.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import { describe, it } from "node:test";
import * as fs from "fs";
import * as path from "path";
import { isDirectory, isFile, runJsr, withTempEnv } from "./test_utils";
import * as assert from "node:assert/strict";

describe("install", () => {
it("jsr i @std/encoding - resolve latest version", async () => {
await withTempEnv(["i", "@std/encoding"], async (getPkgJson, dir) => {
const pkgJson = await getPkgJson();
assert(
pkgJson.dependencies && "@std/encoding" in pkgJson.dependencies,
"Missing dependency entry"
);

assert.match(
pkgJson.dependencies["@std/encoding"],
/^npm:@jsr\/std__encoding@\^\d+\.\d+\.\d+.*$/
);

const depPath = path.join(dir, "node_modules", "@std", "encoding");
assert(await isDirectory(depPath), "Not installed in node_modules");
});
});

it("jsr i @std/[email protected] - with version", async () => {
await withTempEnv(["i", "@std/[email protected]"], async (getPkgJson) => {
const pkgJson = await getPkgJson();
assert.deepEqual(pkgJson.dependencies, {
"@std/encoding": "npm:@jsr/std__encoding@^0.216.0",
});
});
});

it("jsr install @std/[email protected] - command", async () => {
await withTempEnv(["i", "@std/[email protected]"], async (getPkgJson) => {
const pkgJson = await getPkgJson();
assert.deepEqual(pkgJson.dependencies, {
"@std/encoding": "npm:@jsr/std__encoding@^0.216.0",
});
});
});

it("jsr add @std/[email protected] - command", async () => {
await withTempEnv(["i", "@std/[email protected]"], async (getPkgJson) => {
const pkgJson = await getPkgJson();
assert.deepEqual(pkgJson.dependencies, {
"@std/encoding": "npm:@jsr/std__encoding@^0.216.0",
});
});
});

it("jsr add -D @std/[email protected] - dev dependency", async () => {
await withTempEnv(
["i", "-D", "@std/[email protected]"],
async (getPkgJson) => {
const pkgJson = await getPkgJson();
assert.deepEqual(pkgJson.devDependencies, {
"@std/encoding": "npm:@jsr/std__encoding@^0.216.0",
});
}
);

await withTempEnv(
["i", "--save-dev", "@std/[email protected]"],
async (getPkgJson) => {
const pkgJson = await getPkgJson();
assert.deepEqual(pkgJson.devDependencies, {
"@std/encoding": "npm:@jsr/std__encoding@^0.216.0",
});
}
);
});

it("jsr add -O @std/[email protected] - dev dependency", async () => {
await withTempEnv(
["i", "-O", "@std/[email protected]"],
async (getPkgJson) => {
const pkgJson = await getPkgJson();
assert.deepEqual(pkgJson.optionalDependencies, {
"@std/encoding": "npm:@jsr/std__encoding@^0.216.0",
});
}
);

await withTempEnv(
["i", "--save-optional", "@std/[email protected]"],
async (getPkgJson) => {
const pkgJson = await getPkgJson();
assert.deepEqual(pkgJson.optionalDependencies, {
"@std/encoding": "npm:@jsr/std__encoding@^0.216.0",
});
}
);
});

it("jsr add --npm @std/[email protected] - forces npm", async () => {
await withTempEnv(
["i", "--npm", "@std/[email protected]"],
async (_, dir) => {
assert(
await isFile(path.join(dir, "package-lock.json")),
"npm lockfile not created"
);
}
);
});

it("jsr add --yarn @std/[email protected] - forces yarn", async () => {
await withTempEnv(
["i", "--yarn", "@std/[email protected]"],
async (_, dir) => {
assert(
await isFile(path.join(dir, "yarn.lock")),
"yarn lockfile not created"
);
}
);
});

it("jsr add --pnpm @std/[email protected] - forces pnpm", async () => {
await withTempEnv(
["i", "--pnpm", "@std/[email protected]"],
async (_, dir) => {
assert(
await isFile(path.join(dir, "pnpm-lock.yaml")),
"pnpm lockfile not created"
);
}
);
});
});

describe("remove", () => {
it("jsr r @std/[email protected] - removes node_modules", async () => {
await withTempEnv(
["i", "@std/[email protected]"],
async (getPkgJson, dir) => {
await runJsr(["r", "@std/encoding"], dir);

const pkgJson = await getPkgJson();
assert.equal(pkgJson.dependencies, undefined);

const depPath = path.join(dir, "node_modules", "@std", "encoding");
assert(
!(await isDirectory(depPath)),
"Folder in node_modules not removed"
);
}
);
});

it("jsr r @std/[email protected] - command", async () => {
await withTempEnv(
["i", "@std/[email protected]"],
async (getPkgJson, dir) => {
await runJsr(["r", "@std/encoding"], dir);

const pkgJson = await getPkgJson();
assert.equal(pkgJson.dependencies, undefined);
}
);
});

it("jsr remove @std/[email protected] - command", async () => {
await withTempEnv(
["i", "@std/[email protected]"],
async (getPkgJson, dir) => {
await runJsr(["remove", "@std/encoding"], dir);

const pkgJson = await getPkgJson();
assert.equal(pkgJson.dependencies, undefined);
}
);
});

it("jsr uninstall @std/[email protected] - command", async () => {
await withTempEnv(
["i", "@std/[email protected]"],
async (getPkgJson, dir) => {
await runJsr(["uninstall", "@std/encoding"], dir);

const pkgJson = await getPkgJson();
assert.equal(pkgJson.dependencies, undefined);
}
);
});
});
Loading

0 comments on commit 30c8186

Please sign in to comment.