UNPKG

@jungvonmatt/sb-migrate

Version:

CLI tool for managing Storyblok schema and content migrations

255 lines (250 loc) 14.4 kB
"use strict"; 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