@jungvonmatt/sb-migrate
Version:
CLI tool for managing Storyblok schema and content migrations
255 lines (250 loc) • 14.4 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable @typescript-eslint/no-unused-vars */
const vitest_1 = require("vitest");
const generate_migration_1 = require("../../commands/generate-migration");
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const prompts_1 = require("@inquirer/prompts");
vitest_1.vi.mock("fs");
vitest_1.vi.mock("path");
vitest_1.vi.mock("@inquirer/prompts");
vitest_1.vi.mock("picocolors", () => ({
default: {
green: vitest_1.vi.fn((str) => str),
red: vitest_1.vi.fn((str) => str),
yellow: vitest_1.vi.fn((str) => str),
},
}));
// Mock some of the migration templates
const SCHEMA_TEMPLATE = `import { defineMigration } from "@jungvonmatt/sb-migrate";
export default defineMigration({
type: "{{migrationType}}",
description: "{{migrationName}}",
// Schema migration template content
});`;
const CONTENT_TEMPLATE = `import { defineMigration } from "@jungvonmatt/sb-migrate";
export default defineMigration({
type: "{{migrationType}}",
description: "{{migrationName}}",
// Content migration template content
});`;
const CREATE_COMPONENT_TEMPLATE = `import { defineMigration, textField, customField } from "@jungvonmatt/sb-migrate";
export default defineMigration({
type: "create-component",
description: "{{migrationName}}",
schema: {
name: "{{migrationName}}",
display_name: "Example Component",
// Component definition
}
});`;
// Add more template mocks
const DATASOURCE_TEMPLATE = `import { defineMigration } from "@jungvonmatt/sb-migrate";
export default defineMigration({
type: "{{migrationType}}",
description: "{{migrationName}}",
// Datasource migration template content
});`;
const COMPONENT_GROUP_TEMPLATE = `import { defineMigration } from "@jungvonmatt/sb-migrate";
export default defineMigration({
type: "{{migrationType}}",
description: "{{migrationName}}",
// Component group migration template content
});`;
(0, vitest_1.describe)("generate-migration command", () => {
let consoleLogSpy;
let consoleErrorSpy;
let processExitSpy;
(0, vitest_1.beforeEach)(() => {
consoleLogSpy = vitest_1.vi.spyOn(console, "log").mockImplementation(() => { });
consoleErrorSpy = vitest_1.vi.spyOn(console, "error").mockImplementation(() => { });
processExitSpy = vitest_1.vi
.spyOn(process, "exit")
.mockImplementation((_code) => {
throw new Error("process.exit called");
});
// Mock file system operations
vitest_1.vi.mocked(fs_1.default.existsSync).mockImplementation((path) => {
const pathStr = String(path);
if (pathStr.includes("templates") && pathStr.includes(".ts")) {
return true;
}
return false;
});
vitest_1.vi.mocked(fs_1.default.readFileSync).mockImplementation((path) => {
const pathStr = String(path);
if (pathStr.includes("schema-migration.ts")) {
return SCHEMA_TEMPLATE;
}
else if (pathStr.includes("content-migration.ts")) {
return CONTENT_TEMPLATE;
}
else if (pathStr.includes("create-component.ts")) {
return CREATE_COMPONENT_TEMPLATE;
}
else if (pathStr.includes("create-story.ts")) {
return CONTENT_TEMPLATE;
}
else if (pathStr.includes("datasource-migration.ts") ||
pathStr.includes("create-datasource.ts")) {
return DATASOURCE_TEMPLATE;
}
else if (pathStr.includes("component-group") ||
pathStr.includes("create-component-group.ts")) {
return COMPONENT_GROUP_TEMPLATE;
}
else if (pathStr.includes("migration.ts")) {
// For any other migration type, return appropriate template
return pathStr.includes("schema") ? SCHEMA_TEMPLATE : CONTENT_TEMPLATE;
}
throw new Error(`Unexpected file read: ${pathStr}`);
});
vitest_1.vi.mocked(fs_1.default.mkdirSync).mockImplementation(() => undefined);
vitest_1.vi.mocked(fs_1.default.writeFileSync).mockImplementation(() => undefined);
vitest_1.vi.mocked(path_1.default.join).mockImplementation((...args) => args.join("/"));
const mockSelect = Promise.resolve("schema");
mockSelect.cancel = () => { };
vitest_1.vi.mocked(prompts_1.select).mockImplementation(() => mockSelect);
const mockTypeSelect = Promise.resolve("create-component");
mockTypeSelect.cancel = () => { };
vitest_1.vi.mocked(prompts_1.select)
.mockImplementationOnce(() => mockSelect)
.mockImplementationOnce(() => mockTypeSelect);
const mockInput = Promise.resolve("test-migration");
mockInput.cancel = () => { };
vitest_1.vi.mocked(prompts_1.input).mockImplementation(() => mockInput);
vitest_1.vi.useFakeTimers();
vitest_1.vi.setSystemTime(new Date("2023-01-01T12:00:00Z"));
});
(0, vitest_1.afterEach)(() => {
consoleLogSpy.mockRestore();
consoleErrorSpy.mockRestore();
processExitSpy.mockRestore();
vitest_1.vi.useRealTimers();
});
(0, vitest_1.describe)("template generation", () => {
(0, vitest_1.it)("should generate a schema migration with correct template", async () => {
await (0, generate_migration_1.generateMigration)({
type: "create-component",
name: "test-component",
});
(0, vitest_1.expect)(fs_1.default.writeFileSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("20230101120000-test-component.ts"), vitest_1.expect.stringContaining('type: "create-component"'));
(0, vitest_1.expect)(fs_1.default.writeFileSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("20230101120000-test-component.ts"), vitest_1.expect.stringContaining('description: "test-component"'));
});
(0, vitest_1.it)("should generate a content migration with correct template", async () => {
await (0, generate_migration_1.generateMigration)({
type: "create-story",
name: "test-story",
});
(0, vitest_1.expect)(fs_1.default.writeFileSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("20230101120000-test-story.ts"), vitest_1.expect.stringContaining('type: "create-story"'));
(0, vitest_1.expect)(fs_1.default.writeFileSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("20230101120000-test-story.ts"), vitest_1.expect.stringContaining('description: "test-story"'));
});
(0, vitest_1.it)("should generate a datasource migration with correct template", async () => {
await (0, generate_migration_1.generateMigration)({
type: "create-datasource",
name: "test-datasource",
});
(0, vitest_1.expect)(fs_1.default.writeFileSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("20230101120000-test-datasource.ts"), vitest_1.expect.stringContaining('type: "create-datasource"'));
(0, vitest_1.expect)(fs_1.default.writeFileSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("20230101120000-test-datasource.ts"), vitest_1.expect.stringContaining('description: "test-datasource"'));
});
(0, vitest_1.it)("should handle template file path resolution", async () => {
// Mock template file not found in first path
vitest_1.vi.mocked(fs_1.default.existsSync).mockImplementation((path) => {
const pathStr = String(path);
// Return true for the src/templates path to simulate finding the template
return pathStr.includes("src/templates/create-component.ts");
});
await (0, generate_migration_1.generateMigration)({
type: "create-component",
name: "test-component",
});
// Get all paths that were checked
const checkedPaths = vitest_1.vi
.mocked(fs_1.default.existsSync)
.mock.calls.map((call) => String(call[0]));
// Verify that the command tried to find the template in the expected locations
const hasSrcTemplate = checkedPaths.some((p) => p.includes("/src/templates/create-component.ts"));
const hasDistTemplate = checkedPaths.some((p) => p.includes("/dist/templates/create-component.ts"));
const hasCategoryTemplate = checkedPaths.some((p) => p.includes("/templates/schema-migration.ts"));
// At least one of these paths should have been checked
(0, vitest_1.expect)(hasSrcTemplate || hasDistTemplate || hasCategoryTemplate).toBe(true);
// Specifically verify that the src/templates path was checked
(0, vitest_1.expect)(hasSrcTemplate).toBe(true);
});
(0, vitest_1.it)("should throw error when template file is not found", async () => {
// Mock all template paths as not existing
vitest_1.vi.mocked(fs_1.default.existsSync).mockImplementation(() => false);
// Mock console.error to capture the error message
const errorSpy = vitest_1.vi.spyOn(console, "error");
await (0, vitest_1.expect)((0, generate_migration_1.generateMigration)({
type: "create-component",
name: "test-component",
})).rejects.toThrow("process.exit called");
// Verify the error message was logged
(0, vitest_1.expect)(errorSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining("Could not find template file for create-component migration"));
});
(0, vitest_1.it)("should correctly interpolate template variables", async () => {
await (0, generate_migration_1.generateMigration)({
type: "create-component",
name: "test-component",
});
const writeCall = vitest_1.vi.mocked(fs_1.default.writeFileSync).mock.calls[0];
const content = writeCall[1];
// Check that template variables are replaced
(0, vitest_1.expect)(content).not.toContain("{{migrationName}}");
(0, vitest_1.expect)(content).not.toContain("{{migrationType}}");
(0, vitest_1.expect)(content).toContain('description: "test-component"');
(0, vitest_1.expect)(content).toContain('type: "create-component"');
});
});
(0, vitest_1.it)("should create a schema migration file", async () => {
await (0, generate_migration_1.generateMigration)();
(0, vitest_1.expect)(fs_1.default.mkdirSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("migrations/schema"), vitest_1.expect.any(Object));
(0, vitest_1.expect)(fs_1.default.writeFileSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("20230101120000-test-migration.ts"), vitest_1.expect.stringContaining('description: "test-migration"'));
(0, vitest_1.expect)(consoleLogSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining("Migration created"));
});
(0, vitest_1.it)("should create a content migration file", async () => {
vitest_1.vi.mocked(prompts_1.select).mockReset();
const mockCategorySelect = Promise.resolve("content");
mockCategorySelect.cancel = () => { };
const mockTypeSelect = Promise.resolve("create-story");
mockTypeSelect.cancel = () => { };
vitest_1.vi.mocked(prompts_1.select)
.mockImplementationOnce(() => mockCategorySelect)
.mockImplementationOnce(() => mockTypeSelect);
await (0, generate_migration_1.generateMigration)();
(0, vitest_1.expect)(fs_1.default.mkdirSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("migrations/content"), vitest_1.expect.any(Object));
(0, vitest_1.expect)(fs_1.default.writeFileSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("20230101120000-test-migration.ts"), vitest_1.expect.stringContaining('description: "test-migration"'));
});
(0, vitest_1.it)("should handle errors", async () => {
vitest_1.vi.mocked(fs_1.default.mkdirSync).mockImplementation(() => {
throw new Error("Test error");
});
await (0, vitest_1.expect)((0, generate_migration_1.generateMigration)()).rejects.toThrow("process.exit called");
(0, vitest_1.expect)(consoleErrorSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining("Failed to generate migration"));
});
(0, vitest_1.it)("should use provided type and name options without prompting", async () => {
vitest_1.vi.mocked(prompts_1.select).mockClear();
vitest_1.vi.mocked(prompts_1.input).mockClear();
await (0, generate_migration_1.generateMigration)({
type: "create-component",
name: "cli-option-test",
});
// Verify the prompts were not called
(0, vitest_1.expect)(prompts_1.select).not.toHaveBeenCalled();
(0, vitest_1.expect)(prompts_1.input).not.toHaveBeenCalled();
// Verify the correct migration was created
(0, vitest_1.expect)(fs_1.default.mkdirSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("migrations/schema"), vitest_1.expect.any(Object));
(0, vitest_1.expect)(fs_1.default.writeFileSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("20230101120000-cli-option-test.ts"), vitest_1.expect.any(String));
});
(0, vitest_1.it)("should validate the type option and exit on invalid type", async () => {
await (0, vitest_1.expect)((0, generate_migration_1.generateMigration)({ type: "invalid-type" })).rejects.toThrow("process.exit called");
(0, vitest_1.expect)(consoleErrorSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining("Invalid migration type: invalid-type"));
(0, vitest_1.expect)(processExitSpy).toHaveBeenCalledWith(1);
});
});
//# sourceMappingURL=generate-migration.test.js.map