create-nttb
Version:
An opinionated Next.js, TypeScript, and Tailwind boilerplate using Atomic Design Methodology for presentation components.
209 lines • 10.1 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const os_1 = __importDefault(require("os"));
const install_1 = require("./install");
jest.mock("child_process", () => ({
execSync: jest.fn(),
spawnSync: jest.fn(),
}));
const child = require("child_process");
beforeAll(() => {
jest.spyOn(console, "log").mockImplementation(() => { });
});
afterAll(() => {
console.log.mockRestore();
});
function makeTempDir() {
return fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), "create-nttb-"));
}
function readPkg(dir) {
return JSON.parse(fs_1.default.readFileSync(path_1.default.join(dir, "package.json"), "utf8"));
}
describe("create-nttb helpers", () => {
let tempDir;
let projectDir;
const name = "jest-app";
beforeEach(() => {
tempDir = makeTempDir();
projectDir = path_1.default.join(tempDir, name);
});
afterEach(() => {
fs_1.default.rmSync(tempDir, { recursive: true, force: true });
});
describe("validateProjectName", () => {
test("passes for valid names", () => {
expect(() => (0, install_1.validateProjectName)("my-app")).not.toThrow();
expect(() => (0, install_1.validateProjectName)("myapp")).not.toThrow();
expect(() => (0, install_1.validateProjectName)("my_app")).not.toThrow();
expect(() => (0, install_1.validateProjectName)("App123")).not.toThrow();
});
test("throws for name with spaces", () => {
expect(() => (0, install_1.validateProjectName)("my app")).toThrow(/Invalid project name/);
});
test("throws for name with special characters", () => {
expect(() => (0, install_1.validateProjectName)("my@app")).toThrow(/Invalid project name/);
expect(() => (0, install_1.validateProjectName)("../evil")).toThrow(/Invalid project name/);
expect(() => (0, install_1.validateProjectName)("./local")).toThrow(/Invalid project name/);
});
test("throws for name starting with hyphen", () => {
expect(() => (0, install_1.validateProjectName)("-myapp")).toThrow(/Invalid project name/);
});
test("throws for name ending with hyphen", () => {
expect(() => (0, install_1.validateProjectName)("myapp-")).toThrow(/Invalid project name/);
});
test("throws for name exceeding 214 characters", () => {
expect(() => (0, install_1.validateProjectName)("a".repeat(215))).toThrow(/214 characters/);
});
test("passes for name exactly 214 characters", () => {
expect(() => (0, install_1.validateProjectName)("a".repeat(214))).not.toThrow();
});
});
describe("checkNodeVersion", () => {
test("throws for low version", () => {
const original = process.version;
Object.defineProperty(process, "version", { value: "v10.0.0" });
expect(() => (0, install_1.checkNodeVersion)(20)).toThrow(/Node\.js v20\+ required/);
Object.defineProperty(process, "version", { value: original });
});
test("passes for high version", () => {
expect(() => (0, install_1.checkNodeVersion)(10)).not.toThrow();
});
});
describe("checkNpmVersion", () => {
afterEach(() => child.execSync.mockReset());
test("passes for sufficient npm version", () => {
child.execSync.mockReturnValue("10.0.0");
expect(() => (0, install_1.checkNpmVersion)(10)).not.toThrow();
});
test("passes for higher npm version", () => {
child.execSync.mockReturnValue("11.3.0");
expect(() => (0, install_1.checkNpmVersion)(10)).not.toThrow();
});
test("throws for npm version too low", () => {
child.execSync.mockReturnValue("9.8.0");
expect(() => (0, install_1.checkNpmVersion)(10)).toThrow(/npm v10\+ required/);
});
test("throws when npm not accessible", () => {
child.execSync.mockImplementation(() => {
throw new Error("not found");
});
expect(() => (0, install_1.checkNpmVersion)(10)).toThrow(/npm is not installed/);
});
});
describe("createProjectDirectory", () => {
test("creates directory", () => {
expect(fs_1.default.existsSync(projectDir)).toBe(false);
(0, install_1.createProjectDirectory)(projectDir);
expect(fs_1.default.existsSync(projectDir)).toBe(true);
});
test("allows empty dir rerun", () => {
(0, install_1.createProjectDirectory)(projectDir);
expect(() => (0, install_1.createProjectDirectory)(projectDir)).not.toThrow();
});
test("throws if not empty", () => {
(0, install_1.createProjectDirectory)(projectDir);
fs_1.default.writeFileSync(path_1.default.join(projectDir, "x"), "x");
expect(() => (0, install_1.createProjectDirectory)(projectDir)).toThrow(/not empty/);
});
});
describe("runCommand", () => {
afterEach(() => child.spawnSync.mockReset());
test("throws on spawn error", () => {
child.spawnSync.mockReturnValue({ error: new Error("bad") });
expect(() => (0, install_1.runCommand)("bad")).toThrow(/bad/);
});
test("throws on nonzero exit", () => {
child.spawnSync.mockReturnValue({ status: 2 });
expect(() => (0, install_1.runCommand)("fail")).toThrow(/failed/);
});
test("passes on success", () => {
child.spawnSync.mockReturnValue({ status: 0 });
expect(() => (0, install_1.runCommand)("ok")).not.toThrow();
});
test("passes cwd option through", () => {
child.spawnSync.mockReturnValue({ status: 0 });
(0, install_1.runCommand)("ok", [], { cwd: "/tmp" });
expect(child.spawnSync).toHaveBeenCalledWith("ok", [], expect.objectContaining({ cwd: "/tmp" }));
});
test("passes timeout option through", () => {
child.spawnSync.mockReturnValue({ status: 0 });
(0, install_1.runCommand)("ok", [], { timeout: 60000 });
expect(child.spawnSync).toHaveBeenCalledWith("ok", [], expect.objectContaining({ timeout: 60000 }));
});
});
describe("copyTemplate", () => {
test("copies files from template to project directory", () => {
const srcDir = path_1.default.join(tempDir, "template");
fs_1.default.mkdirSync(srcDir);
fs_1.default.writeFileSync(path_1.default.join(srcDir, "package.json"), JSON.stringify({ name: "template" }));
fs_1.default.mkdirSync(projectDir);
(0, install_1.copyTemplate)(srcDir, projectDir);
expect(fs_1.default.existsSync(path_1.default.join(projectDir, "package.json"))).toBe(true);
});
test("copies nested directories", () => {
const srcDir = path_1.default.join(tempDir, "template");
fs_1.default.mkdirSync(srcDir);
fs_1.default.mkdirSync(path_1.default.join(srcDir, "src"));
fs_1.default.writeFileSync(path_1.default.join(srcDir, "src", "index.ts"), "export default {};");
fs_1.default.mkdirSync(projectDir);
(0, install_1.copyTemplate)(srcDir, projectDir);
expect(fs_1.default.existsSync(path_1.default.join(projectDir, "src", "index.ts"))).toBe(true);
});
});
describe("updatePackageJson", () => {
test("updates name, version, description and keywords", () => {
fs_1.default.mkdirSync(projectDir);
const pkg = {
name: "template",
version: "1.0.0",
private: true,
scripts: {
dev: "next dev",
build: "next build",
start: "next start",
format: "prettier --write .",
test: "jest",
"type-check": "tsc --noEmit",
},
dependencies: { next: "16.0.0" },
};
fs_1.default.writeFileSync(path_1.default.join(projectDir, "package.json"), JSON.stringify(pkg));
(0, install_1.updatePackageJson)(projectDir, name);
const updated = readPkg(projectDir);
expect(updated.name).toBe(name);
expect(updated.version).toBe("1.0.0");
expect(updated.description).toBe(`${name} app`);
expect(updated.keywords).toHaveLength(7);
expect(updated.keywords).toContain(name);
expect(updated.createNttbVersion).toBe((0, install_1.getCreateNttbVersion)());
});
test("preserves scripts and dependencies", () => {
fs_1.default.mkdirSync(projectDir);
const pkg = {
name: "template",
version: "1.0.0",
scripts: {
dev: "next dev",
build: "next build",
start: "next start",
format: "prettier --write .",
test: "jest",
"type-check": "tsc --noEmit",
},
dependencies: { next: "16.0.0" },
};
fs_1.default.writeFileSync(path_1.default.join(projectDir, "package.json"), JSON.stringify(pkg));
(0, install_1.updatePackageJson)(projectDir, name);
const updated = readPkg(projectDir);
expect(updated.scripts).toEqual(pkg.scripts);
expect(updated.dependencies).toEqual({ next: "16.0.0" });
expect(updated.createNttbVersion).toBe((0, install_1.getCreateNttbVersion)());
});
});
});
//# sourceMappingURL=install.test.js.map