@jungvonmatt/sb-migrate
Version:
CLI tool for managing Storyblok schema and content migrations
365 lines • 15.1 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vitest_1 = require("vitest");
const storyblok_1 = require("../../utils/storyblok");
const api_1 = require("../../utils/api");
const fs_1 = __importDefault(require("fs"));
// Mock the API modules
vitest_1.vi.mock("../../utils/api", () => ({
components: {
getAll: vitest_1.vi.fn(),
},
datasources: {
has: vitest_1.vi.fn(),
get: vitest_1.vi.fn(),
create: vitest_1.vi.fn(),
},
datasourceEntries: {
getAll: vitest_1.vi.fn(),
create: vitest_1.vi.fn(),
delete: vitest_1.vi.fn(),
},
}));
// Mock fs module
vitest_1.vi.mock("fs", () => ({
default: {
existsSync: vitest_1.vi.fn(),
mkdirSync: vitest_1.vi.fn(),
unlinkSync: vitest_1.vi.fn(),
writeFileSync: vitest_1.vi.fn(),
},
existsSync: vitest_1.vi.fn(),
mkdirSync: vitest_1.vi.fn(),
unlinkSync: vitest_1.vi.fn(),
writeFileSync: vitest_1.vi.fn(),
}));
(0, vitest_1.describe)("Storyblok Utils", () => {
(0, vitest_1.beforeEach)(() => {
vitest_1.vi.clearAllMocks();
});
(0, vitest_1.describe)("getTranslatableComponentFields", () => {
(0, vitest_1.it)("should return translatable fields for a specific component", async () => {
// Arrange
const mockComponents = {
data: {
components: [
{
name: "component1",
schema: {
field1: { type: "text", translatable: true },
field2: { type: "text", translatable: false },
},
},
],
},
};
api_1.components.getAll.mockResolvedValue(mockComponents);
// Act
const result = await (0, storyblok_1.getTranslatableComponentFields)("component1");
// Assert
(0, vitest_1.expect)(result).toEqual(["field1"]);
});
(0, vitest_1.it)("should return empty array for non-existent component", async () => {
// Arrange
const mockComponents = {
data: {
components: [
{
name: "component1",
schema: {
field1: { type: "text", translatable: true },
},
},
],
},
};
api_1.components.getAll.mockResolvedValue(mockComponents);
// Act
const result = await (0, storyblok_1.getTranslatableComponentFields)("nonExistent");
// Assert
(0, vitest_1.expect)(result).toEqual([]);
});
});
(0, vitest_1.describe)("addOrUpdateDatasource", () => {
(0, vitest_1.it)("should create new datasource if it doesn't exist", async () => {
// Arrange
const mockDatasource = {
id: 123,
name: "test",
slug: "test",
dimensions: [],
created_at: "2024-03-20T00:00:00.000Z",
updated_at: "2024-03-20T00:00:00.000Z",
};
api_1.datasources.has.mockResolvedValue(false);
api_1.datasources.create.mockResolvedValue({
data: { datasource: mockDatasource },
});
api_1.datasourceEntries.getAll.mockResolvedValue({
data: { datasource_entries: [] },
});
api_1.datasourceEntries.create.mockResolvedValue({
data: { datasource: { id: 456 } },
});
// Act
const [datasource, entries] = await (0, storyblok_1.addOrUpdateDatasource)("test", [
{ name: "entry1", value: "value1" },
]);
// Assert
(0, vitest_1.expect)(datasource).toEqual(mockDatasource);
(0, vitest_1.expect)(entries).toHaveLength(1);
(0, vitest_1.expect)(api_1.datasources.create).toHaveBeenCalledWith({
slug: "test",
name: "test",
});
});
(0, vitest_1.it)("should update existing datasource", async () => {
// Arrange
const mockDatasource = {
id: 123,
name: "test",
slug: "test",
dimensions: [],
created_at: "2024-03-20T00:00:00.000Z",
updated_at: "2024-03-20T00:00:00.000Z",
};
const mockEntry = {
id: 456,
name: "entry1",
value: "value1",
};
api_1.datasources.has.mockResolvedValue(true);
api_1.datasources.get.mockResolvedValue({
data: { datasource: mockDatasource },
});
api_1.datasourceEntries.getAll.mockResolvedValue({
data: { datasource_entries: [mockEntry] },
});
// Act
const [datasource, entries] = await (0, storyblok_1.addOrUpdateDatasource)("test", [
{ name: "entry1", value: "value1" },
]);
// Assert
(0, vitest_1.expect)(datasource).toEqual(mockDatasource);
(0, vitest_1.expect)(entries).toHaveLength(1);
(0, vitest_1.expect)(api_1.datasources.get).toHaveBeenCalledWith("test");
});
});
(0, vitest_1.describe)("Tab Management Functions", () => {
const mockComponent = {
name: "test",
id: 123,
created_at: "2024-03-20T00:00:00.000Z",
schema: {
"tab-content": {
type: "tab",
display_name: "Content",
keys: ["field1", "field2"],
},
"tab-settings": {
type: "tab",
display_name: "Settings",
keys: ["field3"],
},
},
};
(0, vitest_1.describe)("resetTab", () => {
(0, vitest_1.it)("should reset keys in an existing tab", () => {
// Act
const result = (0, storyblok_1.resetTab)(mockComponent, "Content");
// Assert
const tab = result?.schema?.["tab-content"];
(0, vitest_1.expect)(tab.keys).toEqual([]);
});
(0, vitest_1.it)("should create new tab if it doesn't exist", () => {
// Act
const result = (0, storyblok_1.resetTab)(mockComponent, "New Tab");
// Assert
const tab = result?.schema?.["tab-New Tab"];
(0, vitest_1.expect)(tab).toBeDefined();
(0, vitest_1.expect)(tab.keys).toEqual([]);
});
});
(0, vitest_1.describe)("moveToTab", () => {
(0, vitest_1.it)("should move fields to an existing tab", () => {
// Act
const result = (0, storyblok_1.moveToTab)(mockComponent, "Content", [
"field4",
"field5",
]);
// Assert
const tab = result?.schema?.["tab-content"];
(0, vitest_1.expect)(tab.keys).toEqual(["field4", "field5"]);
});
(0, vitest_1.it)("should create new tab if it doesn't exist", () => {
// Act
const result = (0, storyblok_1.moveToTab)(mockComponent, "New Tab", [
"field4",
"field5",
]);
// Assert
const tab = result?.schema?.["tab-New Tab"];
(0, vitest_1.expect)(tab).toBeDefined();
(0, vitest_1.expect)(tab.keys).toEqual(["field4", "field5"]);
});
});
(0, vitest_1.describe)("getDeprecatedTab", () => {
(0, vitest_1.it)("should return existing deprecated tab", () => {
const componentWithDeprecated = {
...mockComponent,
schema: {
...mockComponent.schema,
"tab-deprecated": {
type: "tab",
display_name: "Deprecated",
keys: ["oldField"],
},
},
};
// Act
const [key, tab] = (0, storyblok_1.getDeprecatedTab)(componentWithDeprecated);
// Assert
(0, vitest_1.expect)(key).toBe("tab-deprecated");
(0, vitest_1.expect)(tab.display_name).toBe("Deprecated");
});
(0, vitest_1.it)("should create new deprecated tab if it doesn't exist", () => {
// Act
const [key, tab] = (0, storyblok_1.getDeprecatedTab)(mockComponent);
// Assert
(0, vitest_1.expect)(key).toBe("tab-deprecated");
(0, vitest_1.expect)(tab.display_name).toBe("deprecated");
});
});
(0, vitest_1.describe)("moveToDeprecated", () => {
(0, vitest_1.it)("should move fields to deprecated tab", () => {
// Act
const result = (0, storyblok_1.moveToDeprecated)(mockComponent, [
"oldField1",
"oldField2",
]);
// Assert
const tab = result?.schema?.["tab-deprecated"];
(0, vitest_1.expect)(tab.keys).toEqual(["oldField1", "oldField2"]);
});
});
(0, vitest_1.describe)("moveToSettings", () => {
(0, vitest_1.it)("should move fields to settings tab", () => {
// Act
const result = (0, storyblok_1.moveToSettings)(mockComponent, ["setting1", "setting2"]);
// Assert
const tab = result?.schema?.["tab-settings"];
(0, vitest_1.expect)(tab.keys).toEqual(["setting1", "setting2"]);
});
});
});
(0, vitest_1.describe)("addOrUpdateFields", () => {
(0, vitest_1.it)("should add new fields to component schema", () => {
// Arrange
const component = {
name: "test",
id: 123,
created_at: "2024-03-20T00:00:00.000Z",
schema: {
field1: { type: "text", display_name: "Field 1" },
},
};
const newFields = {
field2: { type: "text", display_name: "Field 2" },
field3: { type: "text", display_name: "Field 3" },
};
// Act
const result = (0, storyblok_1.addOrUpdateFields)(component, newFields);
// Assert
(0, vitest_1.expect)(result.schema).toEqual({
...newFields,
...component.schema,
...newFields,
});
});
});
(0, vitest_1.describe)("createRollbackFile", () => {
(0, vitest_1.it)("should create rollback file with correct data", async () => {
// Arrange
const rollbackData = [{ id: 1, name: "test" }];
const mockDate = "2024-03-20";
vitest_1.vi.spyOn(Date.prototype, "toISOString").mockReturnValue(`${mockDate}T00:00:00.000Z`);
fs_1.default.existsSync.mockReturnValue(false);
// Act
const result = await (0, storyblok_1.createRollbackFile)(rollbackData, "test", "field");
// Assert
(0, vitest_1.expect)(result).toEqual({ component: "test", created: true });
(0, vitest_1.expect)(fs_1.default.mkdirSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining("migrations/rollback"), { recursive: true });
(0, vitest_1.expect)(fs_1.default.writeFileSync).toHaveBeenCalledWith(vitest_1.expect.stringContaining(`${mockDate}_rollback_test_field.json`), JSON.stringify(rollbackData, null, 2));
});
(0, vitest_1.it)("should handle existing rollback file", async () => {
// Arrange
const rollbackData = [{ id: 1, name: "test" }];
fs_1.default.existsSync.mockReturnValue(true);
// Act
const result = await (0, storyblok_1.createRollbackFile)(rollbackData, "test", "field");
// Assert
(0, vitest_1.expect)(result).toEqual({ component: "test", created: true });
(0, vitest_1.expect)(fs_1.default.unlinkSync).toHaveBeenCalled();
});
});
(0, vitest_1.describe)("processMigration", () => {
(0, vitest_1.it)("should process matching component", async () => {
// Arrange
const content = {
component: "test",
field1: "value1",
};
const migrationFn = vitest_1.vi.fn();
// Act
await (0, storyblok_1.processMigration)(content, "test", migrationFn, "test-story");
// Assert
(0, vitest_1.expect)(migrationFn).toHaveBeenCalledWith(content);
});
(0, vitest_1.it)("should process nested components", async () => {
// Arrange
const content = {
component: "parent",
blocks: [
{
component: "test",
field1: "value1",
},
],
};
const migrationFn = vitest_1.vi.fn();
// Act
await (0, storyblok_1.processMigration)(content, "test", migrationFn, "test-story");
// Assert
(0, vitest_1.expect)(migrationFn).toHaveBeenCalledWith(content.blocks[0]);
});
(0, vitest_1.it)("should process rich text bloks", async () => {
// Arrange
const content = {
component: "parent",
content: {
type: "doc",
content: [
{
type: "blok",
attrs: {
body: {
component: "test",
field1: "value1",
},
},
},
],
},
};
const migrationFn = vitest_1.vi.fn();
// Act
await (0, storyblok_1.processMigration)(content, "test", migrationFn, "test-story");
// Assert
(0, vitest_1.expect)(migrationFn).toHaveBeenCalledWith(content.content.content[0].attrs.body);
});
});
});
//# sourceMappingURL=storyblok.test.js.map