@jungvonmatt/sb-migrate
Version:
CLI tool for managing Storyblok schema and content migrations
412 lines • 16.1 kB
JavaScript
"use strict";
/**
* @file migration-handlers.test.ts
* @description Integration tests for individual migration handlers.
*
* This test suite focuses on testing the behavior of individual migration handlers
* in isolation, ensuring that each handler correctly implements its specific
* functionality and properly interacts with the Storyblok API.
*
* Key aspects tested:
* 1. Individual handler behaviors (create, update, delete operations)
* 2. Handler-specific error cases and edge conditions
* 3. API interaction patterns for each handler type
* 4. Data transformation and validation
*
* The suite is organized by handler type:
* - Component Handlers: Testing component CRUD operations
* - Component Group Handlers: Testing group management
* - Story Handlers: Testing story content operations
* - Datasource Handlers: Testing datasource and entry management
* - Transform Entries Handler: Testing content transformation
*
* This suite complements migration-flow.test.ts by providing detailed coverage
* of individual handler behaviors. While migration-flow.test.ts focuses on
* end-to-end flows, this suite ensures each handler works correctly in isolation.
*
* @see migration-flow.test.ts for end-to-end flow testing
*/
Object.defineProperty(exports, "__esModule", { value: true });
const vitest_1 = require("vitest");
const api_1 = require("../../utils/api");
const handlers_1 = require("../../handlers");
// Mock the external API calls
vitest_1.vi.mock("../../utils/api", () => {
const components = {
getAll: vitest_1.vi.fn(),
get: vitest_1.vi.fn(),
create: vitest_1.vi.fn(),
update: vitest_1.vi.fn(),
delete: vitest_1.vi.fn(),
};
const componentGroups = {
getAll: vitest_1.vi.fn(),
create: vitest_1.vi.fn(),
update: vitest_1.vi.fn(),
delete: vitest_1.vi.fn(),
};
const stories = {
getAll: vitest_1.vi.fn(),
get: vitest_1.vi.fn(),
getBySlug: vitest_1.vi.fn(),
create: vitest_1.vi.fn(),
update: vitest_1.vi.fn(),
delete: vitest_1.vi.fn(),
};
const datasources = {
getAll: vitest_1.vi.fn(),
get: vitest_1.vi.fn(),
create: vitest_1.vi.fn(),
update: vitest_1.vi.fn(),
delete: vitest_1.vi.fn(),
has: vitest_1.vi.fn(),
};
const datasourceEntries = {
getAll: vitest_1.vi.fn(),
create: vitest_1.vi.fn(),
update: vitest_1.vi.fn(),
delete: vitest_1.vi.fn(),
};
return {
// Export the api object
api: {
components,
componentGroups,
stories,
datasources,
datasourceEntries,
},
components,
componentGroups,
stories,
datasources,
datasourceEntries,
};
});
(0, vitest_1.describe)("Integration Tests: Migration Handlers", () => {
const mockComponent = {
name: "test-component",
display_name: "Test Component",
schema: {
title: { type: "text", display_name: "Title", required: true },
},
created_at: "2024-01-01T00:00:00.000Z",
id: 1,
};
const mockStory = {
id: 1,
name: "Test Story",
slug: "test-story",
full_slug: "test-story",
content: {
component: "test-component",
title: "Test Title",
},
created_at: "2024-01-01T00:00:00.000Z",
published_at: "2024-01-01T00:00:00.000Z",
};
const mockDatasource = {
id: 1,
name: "Test Datasource",
slug: "test-datasource",
dimensions: [],
created_at: "2024-01-01T00:00:00.000Z",
updated_at: "2024-01-01T00:00:00.000Z",
};
(0, vitest_1.beforeEach)(() => {
vitest_1.vi.clearAllMocks();
// Mock API responses
api_1.api.components.getAll.mockResolvedValue({
data: { components: [] },
});
api_1.api.components.create.mockResolvedValue({
data: { component: mockComponent },
});
api_1.api.components.update.mockResolvedValue({
data: { component: mockComponent },
});
api_1.api.components.delete.mockResolvedValue({
data: {},
});
api_1.api.componentGroups.getAll.mockResolvedValue({
data: { component_groups: [] },
});
api_1.api.componentGroups.create.mockResolvedValue({
data: { component_group: { id: 1, name: "test-group" } },
});
api_1.api.componentGroups.update.mockResolvedValue({
data: { component_group: { id: 1, name: "test-group" } },
});
api_1.api.componentGroups.delete.mockResolvedValue({
data: {},
});
api_1.api.stories.getAll.mockResolvedValue({
data: { stories: [] },
});
api_1.api.stories.get.mockResolvedValue({
data: { story: mockStory },
});
api_1.api.stories.getBySlug.mockResolvedValue(mockStory);
api_1.api.stories.create.mockResolvedValue({
data: { story: mockStory },
});
api_1.api.stories.update.mockResolvedValue({
data: { story: mockStory },
});
api_1.api.stories.delete.mockResolvedValue({
data: {},
});
api_1.api.datasources.getAll.mockResolvedValue({
data: { datasources: [] },
});
api_1.api.datasources.get.mockResolvedValue({
data: { datasource: mockDatasource },
});
api_1.api.datasources.create.mockResolvedValue({
data: { datasource: mockDatasource },
});
api_1.api.datasources.update.mockResolvedValue({
data: { datasource: mockDatasource },
});
api_1.api.datasources.delete.mockResolvedValue({
data: {},
});
});
(0, vitest_1.afterEach)(() => {
vitest_1.vi.resetAllMocks();
});
(0, vitest_1.describe)("Component Handlers", () => {
(0, vitest_1.it)("should handle component creation flow", async () => {
await (0, handlers_1.handleCreateComponent)({
schema: {
name: "test-component",
display_name: "Test Component",
schema: {
title: { type: "text", display_name: "Title", required: true },
},
},
}, { isDryrun: false });
(0, vitest_1.expect)(api_1.api.components.create).toHaveBeenCalled();
(0, vitest_1.expect)(api_1.api.components.update).toHaveBeenCalled();
});
(0, vitest_1.it)("should handle component update flow", async () => {
api_1.api.components.getAll.mockResolvedValue({
data: { components: [mockComponent] },
});
await (0, handlers_1.handleUpdateComponent)({
schema: {
name: "test-component",
display_name: "Updated Component",
schema: {
title: { type: "text", display_name: "Title", required: true },
description: { type: "text", display_name: "Description" },
},
},
}, { isDryrun: false });
(0, vitest_1.expect)(api_1.api.components.update).toHaveBeenCalled();
});
(0, vitest_1.it)("should handle component deletion flow", async () => {
api_1.api.components.getAll.mockResolvedValue({
data: { components: [mockComponent] },
});
await (0, handlers_1.handleDeleteComponent)({ name: "test-component" }, { isDryrun: false });
(0, vitest_1.expect)(api_1.api.components.delete).toHaveBeenCalled();
});
});
(0, vitest_1.describe)("Component Group Handlers", () => {
(0, vitest_1.it)("should handle component group creation flow", async () => {
await (0, handlers_1.handleCreateComponentGroup)({
groups: [{ name: "test-group" }],
}, { isDryrun: false });
(0, vitest_1.expect)(api_1.api.componentGroups.create).toHaveBeenCalled();
});
(0, vitest_1.it)("should handle component group update flow", async () => {
api_1.api.componentGroups.getAll.mockResolvedValue({
data: {
component_groups: [{ id: 1, name: "test-group", uuid: "123" }],
},
});
await (0, handlers_1.handleUpdateComponentGroup)({
id: 1,
group: { name: "updated-group" },
}, { isDryrun: false });
(0, vitest_1.expect)(api_1.api.componentGroups.update).toHaveBeenCalled();
});
(0, vitest_1.it)("should handle component group deletion flow", async () => {
api_1.api.componentGroups.getAll.mockResolvedValue({
data: {
component_groups: [{ id: 1, name: "test-group" }],
},
});
await (0, handlers_1.handleDeleteComponentGroup)({ id: 1 }, { isDryrun: false });
(0, vitest_1.expect)(api_1.api.componentGroups.delete).toHaveBeenCalled();
});
});
(0, vitest_1.describe)("Story Handlers", () => {
(0, vitest_1.it)("should handle story creation flow", async () => {
await (0, handlers_1.handleCreateStory)({
story: {
name: "Test Story",
content: {
component: "test-component",
title: "Test Title",
},
},
}, { isDryrun: false });
(0, vitest_1.expect)(api_1.api.stories.create).toHaveBeenCalled();
});
(0, vitest_1.it)("should handle story update flow", async () => {
await (0, handlers_1.handleUpdateStory)({
id: 1,
story: {
name: "Updated Story",
content: {
component: "test-component",
title: "Updated Title",
},
},
}, { isDryrun: false });
(0, vitest_1.expect)(api_1.api.stories.update).toHaveBeenCalled();
});
});
(0, vitest_1.describe)("Datasource Handlers", () => {
(0, vitest_1.it)("should handle datasource creation flow without errors", async () => {
vitest_1.vi.clearAllMocks();
// Create a spy to track if handlers log error messages
const errorSpy = vitest_1.vi.spyOn(console, "error");
api_1.api.datasources.getAll.mockResolvedValue({
data: { datasources: [] },
});
api_1.api.datasources.has.mockResolvedValue(false);
api_1.api.datasources.create.mockResolvedValue({
data: {
datasource: mockDatasource,
},
});
api_1.api.datasourceEntries.getAll.mockResolvedValue({
data: { datasource_entries: [] },
});
api_1.api.datasourceEntries.create.mockResolvedValue({
data: {
datasource_entry: { id: 1, name: "Test Entry", value: "test-value" },
},
});
await (0, handlers_1.handleCreateDatasource)({
datasource: {
name: "Test Datasource",
slug: "test-datasource",
},
entries: [
{
name: "Test Entry",
value: "test-value",
},
],
}, { isDryrun: false });
(0, vitest_1.expect)(errorSpy).not.toHaveBeenCalled();
});
(0, vitest_1.it)("should handle datasource update flow", async () => {
await (0, handlers_1.handleUpdateDatasource)({
id: 1,
datasource: {
name: "Updated Datasource",
},
entries: [
{
name: "Updated Entry",
value: "updated-value",
},
],
}, { isDryrun: false });
(0, vitest_1.expect)(api_1.api.datasources.update).toHaveBeenCalled();
});
});
(0, vitest_1.describe)("Transform Entries Handler", () => {
(0, vitest_1.it)("should handle transform entries flow without errors", async () => {
vitest_1.vi.clearAllMocks();
const errorSpy = vitest_1.vi.spyOn(console, "error");
api_1.api.components.getAll.mockResolvedValue({
data: { components: [mockComponent] },
});
api_1.api.components.get.mockResolvedValue({
data: { component: mockComponent },
});
api_1.api.components.update.mockResolvedValue({
data: { component: mockComponent },
});
api_1.api.stories.getAll.mockResolvedValue({
data: {
stories: [
{
id: 1,
full_slug: "test-story",
content: {
component: "test-component",
title: "Original Title",
},
},
],
},
});
api_1.api.stories.get.mockResolvedValue({
data: {
story: {
id: 1,
full_slug: "test-story",
content: {
component: "test-component",
title: "Original Title",
},
},
},
});
api_1.api.stories.update.mockResolvedValue({
data: {
story: {
id: 1,
full_slug: "test-story",
content: {
component: "test-component",
title: "Transformed Title",
},
},
},
});
await (0, handlers_1.handleTransformEntries)({
type: "transform-entries",
component: "test-component",
transform: (entry) => ({
...entry,
title: "Transformed Title",
}),
}, { isDryrun: false });
(0, vitest_1.expect)(errorSpy).not.toHaveBeenCalled();
});
});
(0, vitest_1.describe)("Error Handling", () => {
(0, vitest_1.it)("should handle API errors gracefully in component creation", async () => {
api_1.api.components.create.mockRejectedValue(new Error("API Error"));
await (0, vitest_1.expect)((0, handlers_1.handleCreateComponent)({
schema: {
name: "error-test",
display_name: "Error Test",
schema: {
title: { type: "text", display_name: "Title", required: true },
},
},
}, { isDryrun: false })).rejects.toThrow("API Error");
});
(0, vitest_1.it)("should handle not found errors in component update", async () => {
api_1.api.components.getAll.mockResolvedValue({
data: { components: [] },
});
await (0, vitest_1.expect)((0, handlers_1.handleUpdateComponent)({
schema: {
name: "non-existent",
display_name: "Non Existent",
},
}, { isDryrun: false })).rejects.toThrow();
});
});
});
//# sourceMappingURL=migration-handlers.test.js.map